This commit is contained in:
Lizandro Guarnizo
2026-02-04 16:35:34 -05:00
parent cb7bc1229b
commit f37b2fe8d0
9 changed files with 598 additions and 105 deletions
+162 -67
View File
@@ -101,78 +101,118 @@ class OjalPresillaResource extends Resource
->visible(fn ($get) => $get('orden_produccion_id') !== null)
->helperText('Nombre de la prenda de la orden de producción seleccionada'),
TextInput::make('tipo')
->label('Tipo')
->placeholder('Ej: Ojal, Prensilla, Botón, etc.')
Select::make('tipo')
->label('Tipo de Proceso')
->options([
'Ojal' => 'Ojal',
'Prensilla' => 'Prensilla',
])
->required()
->helperText('Especifica el tipo de accesorio'),
->reactive()
->afterStateUpdated(function ($state, $set, $get) {
$opId = $get('orden_produccion_id');
if (!$opId) return;
$op = \App\Models\OrdenProduccion::find($opId);
if (!$op) return;
// Calcular disponibilidad según el tipo
$cantidadRecibida = $op->confecciones->sum('cantidad_recibida');
$arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class)
->whereHas('referencia', function($q) use ($opId) {
$q->where('orden_produccion_id', $opId);
})->where('tipo', 'arreglo')->sum('cantidad');
$cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class)
->whereHas('referencia', function($q) use ($opId) {
$q->where('orden_produccion_id', $opId);
})->sum('cantidad');
$cantidadConfecciones = $cantidadRecibida - $arreglos - $cobros;
if ($state === 'Ojal') {
// Para ojales: disponible desde confección
$yaEnviado = \App\Models\Ojal::where('orden_produccion_id', $opId)
->sum('cantidad_enviada');
$disponible = $cantidadConfecciones - $yaEnviado;
$set('cantidad_enviada', max(0, $disponible));
} else if ($state === 'Prensilla') {
// Para prensillas: solo lo que ya terminó en ojales
$ojalesTerminados = \App\Models\Ojal::where('orden_produccion_id', $opId)
->where('terminada', true)
->sum('cantidad_enviada');
$yaEnviado = \App\Models\Prensilla::where('orden_produccion_id', $opId)
->sum('cantidad_enviada');
$disponible = $ojalesTerminados - $yaEnviado;
$set('cantidad_enviada', max(0, $disponible));
}
})
->helperText(fn ($get) => $get('tipo') === 'Prensilla'
? '⚠️ Solo se pueden enviar prendas que hayan terminado el proceso de Ojales'
: 'Primer proceso: las prendas vienen desde Confección'),
Select::make('proveedor_id')
->label('Proveedor/Usuario Principal')
->options(fn () => \App\Models\Proveedor::where('categoria', 'ojales_prensillas')
->orWhere('categoria', 'empleado')
->pluck('nombre', 'id'))
->searchable()
->preload()
->nullable()
->helperText('Principal responsable del proceso'),
Select::make('usuario_asignado_id')
->label('Usuario Asignado (Operario)')
->relationship('usuarioAsignado', 'name')
->searchable()
->preload()
->nullable()
->helperText('Usuario del sistema responsable'),
TextInput::make('cantidad_enviada')
->label('Cantidad total disponible')
->numeric()
->readOnly()
->helperText(function ($state) {
if (!$state) return 'Selecciona una OP primero';
return "Máximo disponible: {$state} unidades";
})
->live(),
Repeater::make('distribuciones')
->label('Distribución entre proveedores')
->schema([
Select::make('proveedor_id')
->label('Proveedor')
->options(fn () => \App\Models\Proveedor::where('categoria', 'empleado')->pluck('nombre', 'id'))
->searchable()
->required(),
TextInput::make('cantidad')
->label('Cantidad')
->numeric()
->required()
->minValue(1)
->live()
->afterStateUpdated(function ($state, $set, $get) {
// Validar que la suma no exceda el total
$total = (int) ($get('../../cantidad_enviada') ?? 0);
$distribuciones = $get('../../distribuciones') ?? [];
$suma = 0;
foreach ($distribuciones as $dist) {
$suma += (int) ($dist['cantidad'] ?? 0);
}
->reactive()
->helperText(function ($get) {
$opId = $get('orden_produccion_id');
$tipo = $get('tipo');
if ($suma > $total) {
throw \Illuminate\Validation\ValidationException::withMessages([
'cantidad' => "La suma de las distribuciones ({$suma}) excede el total disponible ({$total})."
]);
if (!$opId || !$tipo) return 'Selecciona una OP y tipo primero';
$op = \App\Models\OrdenProduccion::find($opId);
if (!$op) return '';
if ($tipo === 'Ojal') {
$cantidadRecibida = $op->confecciones->sum('cantidad_recibida');
$arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class)
->whereHas('referencia', function($q) use ($opId) {
$q->where('orden_produccion_id', $opId);
})->where('tipo', 'arreglo')->sum('cantidad');
$cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class)
->whereHas('referencia', function($q) use ($opId) {
$q->where('orden_produccion_id', $opId);
})->sum('cantidad');
$cantidadConfecciones = $cantidadRecibida - $arreglos - $cobros;
$yaEnviado = \App\Models\Ojal::where('orden_produccion_id', $opId)->sum('cantidad_enviada');
$disponible = $cantidadConfecciones - $yaEnviado;
return "Disponible desde Confección: {$disponible}";
} else {
$ojalesTerminados = \App\Models\Ojal::where('orden_produccion_id', $opId)
->where('terminada', true)->sum('cantidad_enviada');
$yaEnviado = \App\Models\Prensilla::where('orden_produccion_id', $opId)->sum('cantidad_enviada');
$disponible = $ojalesTerminados - $yaEnviado;
return "Disponible desde Ojales terminados: {$disponible}";
}
}),
])
->defaultItems(1)
->addActionLabel('Agregar proveedor')
->helperText(function ($get) {
$total = (int) ($get('cantidad_enviada') ?? 0);
$distribuciones = $get('distribuciones') ?? [];
$suma = 0;
foreach ($distribuciones as $dist) {
$suma += (int) ($dist['cantidad'] ?? 0);
}
$restante = $total - $suma;
if ($restante < 0) {
return "⚠️ Excede el total por " . abs($restante) . " unidades";
} elseif ($restante > 0) {
return "Faltan {$restante} unidades por distribuir";
} else {
return "✓ Total distribuido correctamente";
}
})
->live(),
Checkbox::make('terminada')
->label('Marcar como terminada')
->helperText('Al marcar terminada, se enviará automáticamente a tintorería')
->live(),
->label('Marcar como terminado')
->helperText(fn ($get) => $get('tipo') === 'Prensilla'
? '✓ Al terminar Prensillas, las prendas quedarán disponibles para Tintorería'
: '✓ Al terminar Ojales, las prendas quedarán disponibles para Prensillas')
->reactive(),
]);
}
@@ -181,31 +221,73 @@ class OjalPresillaResource extends Resource
return $table
->columns([
Tables\Columns\TextColumn::make('tipo')
->label('Tipo')
->label('Proceso')
->searchable()
->sortable()
->badge()
->color('info'),
->color(fn ($state) => $state === 'Ojal' ? 'info' : 'warning'),
Tables\Columns\TextColumn::make('ordenProduccion.numero_orden')
->label('OP')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('ordenProduccion.prenda_modelo')
->label('Prenda')
->searchable()
->limit(30)
->toggleable(),
Tables\Columns\TextColumn::make('cantidad_enviada')
->label('Cantidad')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('proveedor.nombre')
->label('Proveedor')
->searchable()
->toggleable()
->default('Sin asignar'),
Tables\Columns\TextColumn::make('usuarioAsignado.name')
->label('Operario')
->searchable()
->toggleable()
->default('-'),
Tables\Columns\IconColumn::make('terminada')
->boolean()
->label('Terminada')
->label('Terminado')
->alignCenter()
->sortable(),
Tables\Columns\BadgeColumn::make('estado_flujo')
->label('Estado en Flujo')
->getStateUsing(function ($record) {
if ($record->tipo === 'Ojal') {
if ($record->terminada) {
// Verificar si ya se creó el proceso de prensillas
$prensillasCreadas = \App\Models\Prensilla::where('orden_produccion_id', $record->orden_produccion_id)
->where('cantidad_enviada', '>', 0)
->exists();
return $prensillasCreadas ? 'En Prensillas' : 'Listo para Prensillas';
}
return 'En Proceso';
} else {
// Es Prensilla
if ($record->terminada) {
return 'Listo para Tintorería';
}
return 'En Proceso';
}
})
->colors([
'success' => fn ($state) => in_array($state, ['Listo para Prensillas', 'Listo para Tintorería']),
'primary' => 'En Prensillas',
'warning' => 'En Proceso',
]),
Tables\Columns\TextColumn::make('fecha_envio')
->date()
->label('Fecha envío')
@@ -219,13 +301,26 @@ class OjalPresillaResource extends Resource
])
->filters([
SelectFilter::make('tipo')
->label('Tipo'),
->label('Tipo de Proceso')
->options([
'Ojal' => 'Ojal',
'Prensilla' => 'Prensilla',
]),
SelectFilter::make('terminada')
->label('Estado')
->options([
'0' => 'Pendiente',
'1' => 'Terminada',
])
'0' => 'En Proceso',
'1' => 'Terminado',
]),
SelectFilter::make('proveedor_id')
->label('Proveedor')
->relationship('proveedor', 'nombre'),
SelectFilter::make('usuario_asignado_id')
->label('Operario')
->relationship('usuarioAsignado', 'name'),
])
->actions([
Tables\Actions\EditAction::make(),
@@ -0,0 +1,86 @@
<?php
namespace App\Filament\Resources\OrdenProduccionResource\Pages;
use App\Filament\Resources\OrdenProduccionResource;
use App\Models\OrdenProduccion;
use Filament\Resources\Pages\Page;
use Filament\Infolists\Infolist;
use Filament\Infolists\Components\{Section, TextEntry, Grid};
class VerFlujoOjalesPresillas extends Page
{
protected static string $resource = OrdenProduccionResource::class;
protected static string $view = 'filament.resources.orden-produccion-resource.pages.ver-flujo-ojales-presillas';
protected static ?string $title = 'Flujo de Ojales y Prensillas';
public OrdenProduccion $record;
public function mount(int | string $record): void
{
$this->record = OrdenProduccion::findOrFail($record);
}
public function getFlujoData(): array
{
$op = $this->record;
// Datos de Confección
$cantidadRecibidaConfeccion = $op->confecciones()
->whereNotNull('fecha_recepcion')
->sum('cantidad_recibida');
// Datos de Ojales
$ojales = $op->ojales;
$ojalesData = $ojales->map(function ($ojal) {
return [
'cantidad' => $ojal->cantidad_enviada,
'proveedor' => $ojal->proveedor?->nombre ?? 'Sin proveedor',
'operario' => $ojal->usuarioAsignado?->name ?? '-',
'terminado' => $ojal->terminada,
'fecha' => $ojal->fecha_envio?->format('d/m/Y') ?? '-',
];
});
$ojalesTerminados = $ojales->where('terminada', true)->sum('cantidad_enviada');
$ojalesPendientes = $ojales->where('terminada', false)->sum('cantidad_enviada');
// Datos de Prensillas
$prensillas = $op->prensillas;
$prensillasData = $prensillas->map(function ($prensilla) {
return [
'cantidad' => $prensilla->cantidad_enviada,
'proveedor' => $prensilla->proveedor?->nombre ?? 'Sin proveedor',
'operario' => $prensilla->usuarioAsignado?->name ?? '-',
'terminado' => $prensilla->terminada,
'fecha' => $prensilla->fecha_envio?->format('d/m/Y') ?? '-',
];
});
$prensillasTerminadas = $prensillas->where('terminada', true)->sum('cantidad_enviada');
$prensillasPendientes = $prensillas->where('terminada', false)->sum('cantidad_enviada');
// Verificación de ambos procesos
$verificacion = $op->verificarProcesosCompletos();
return [
'confeccion_recibida' => $cantidadRecibidaConfeccion,
'ojales' => [
'total' => $ojales->sum('cantidad_enviada'),
'terminados' => $ojalesTerminados,
'pendientes' => $ojalesPendientes,
'registros' => $ojalesData,
],
'prensillas' => [
'total' => $prensillas->sum('cantidad_enviada'),
'terminadas' => $prensillasTerminadas,
'pendientes' => $prensillasPendientes,
'registros' => $prensillasData,
],
'verificacion' => $verificacion,
'disponible_tintoreria' => $op->getCantidadDisponibleParaTintoreria(),
];
}
}
+30 -29
View File
@@ -50,24 +50,20 @@ class TintoreriaResource extends Resource
Select::make('orden_produccion_id')
->label('Orden de Producción')
->options(fn () => \App\Models\OrdenProduccion::whereHas('ojales', function ($query) {
$query->where('terminada', true);
})->get()->mapWithKeys(function ($op) {
// Calcular cantidad disponible de ojales terminados
$cantidadOjalesTerminados = \App\Models\Ojal::where('orden_produccion_id', $op->id)
->where('terminada', true)
->sum('cantidad_enviada');
->options(fn () => \App\Models\OrdenProduccion::all()->mapWithKeys(function ($op) {
// Verificar que ambos procesos estén completos
$verificacion = $op->verificarProcesosCompletos();
// Calcular cantidad ya enviada a tintorería
$enviadasEnTint = \App\Models\Tintoreria::where('orden_produccion_id', $op->id)
->whereNull('fecha_recepcion')
->sum('cantidad_enviada');
if (!$verificacion['completo']) {
// Si no están completos, no mostrar o mostrar con advertencia
return [];
}
// Calcular disponible
$disponible = $cantidadOjalesTerminados - $enviadasEnTint;
// Calcular cantidad disponible (mínimo entre ojales y prensillas terminados - ya enviadas)
$disponible = $op->getCantidadDisponibleParaTintoreria();
if ($disponible > 0) {
return [$op->id => "{$op->numero_orden} (Disponible: {$disponible})"];
return [$op->id => "{$op->numero_orden} (Disponible: {$disponible}) [O:{$verificacion['ojales_terminados']} P:{$verificacion['prensillas_terminadas']}]"];
}
return [];
})->filter())
@@ -77,27 +73,25 @@ class TintoreriaResource extends Resource
->required()
->afterStateUpdated(function ($state, $set) {
if ($state) {
// Calcular cantidad disponible de ojales terminados
$cantidadOjalesTerminados = \App\Models\Ojal::where('orden_produccion_id', $state)
->where('terminada', true)
->sum('cantidad_enviada');
$enviadasEnTint = \App\Models\Tintoreria::where('orden_produccion_id', $state)
->whereNull('fecha_recepcion')
->sum('cantidad_enviada');
$pending = max(0, (int)$cantidadOjalesTerminados - (int)$enviadasEnTint);
$set('cantidad_enviada', $pending ?: 0);
$set('fecha_envio', now()->toDateString());
$orden = \App\Models\OrdenProduccion::find($state);
if ($orden) {
$disponible = $orden->getCantidadDisponibleParaTintoreria();
$verificacion = $orden->verificarProcesosCompletos();
$set('cantidad_enviada', $disponible ?: 0);
$set('fecha_envio', now()->toDateString());
$set('prenda_nombre_info', $orden->prenda_modelo ?? 'Sin especificar');
// Información adicional sobre los procesos
$set('info_procesos', "Ojales: {$verificacion['ojales_terminados']} | Prensillas: {$verificacion['prensillas_terminadas']}");
}
} else {
$set('prenda_nombre_info', null);
$set('info_procesos', null);
}
})
->helperText('Solo se muestran órdenes con ojales/prensillas terminados'),
->helperText('Solo se muestran órdenes con AMBOS procesos (ojales Y prensillas) terminados'),
TextInput::make('prenda_nombre_info')
->label('Prenda')
@@ -106,6 +100,13 @@ class TintoreriaResource extends Resource
->visible(fn ($get) => $get('orden_produccion_id') !== null)
->helperText('Nombre de la prenda de la orden de producción seleccionada'),
TextInput::make('info_procesos')
->label('Estado de Procesos')
->disabled()
->dehydrated(false)
->visible(fn ($get) => $get('orden_produccion_id') !== null)
->helperText('Cantidad terminada en cada proceso'),
TextInput::make('tipo_proceso')
->label('Tipo de proceso')
->required(),
@@ -43,7 +43,7 @@ class PrendasPendientesWidget extends BaseWidget
->label('Pend. Confección')
->alignCenter()
->state(function (OrdenProduccion $record): int {
// Recibidas en confección - Enviadas a ojales
// Recibidas en confección - Enviadas a ojales y prensillas
$recibidas = $record->confecciones()
->whereNotNull('fecha_recepcion')
->sum('cantidad_recibida');
@@ -62,8 +62,9 @@ class PrendasPendientesWidget extends BaseWidget
$disponiblesConfeccion = $recibidas - $arreglos - $cobros;
$enviadasOjales = $record->ojales()->sum('cantidad_enviada');
$enviadasPrensillas = $record->prensillas()->sum('cantidad_enviada');
return max(0, $disponiblesConfeccion - $enviadasOjales);
return max(0, $disponiblesConfeccion - $enviadasOjales - $enviadasPrensillas);
})
->color(fn ($state) => $state > 0 ? 'warning' : 'gray')
->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'),
@@ -71,17 +72,51 @@ class PrendasPendientesWidget extends BaseWidget
Tables\Columns\TextColumn::make('pendiente_ojales')
->label('Pend. Ojales')
->alignCenter()
->state(function (OrdenProduccion $record): int {
->state(function (OrdenProduccion $record): string {
// Enviadas a ojales - Terminadas en ojales
$enviadas = $record->ojales()->sum('cantidad_enviada');
$terminadas = $record->ojales()
->where('terminada', true)
->sum('cantidad_enviada');
$pendientes = max(0, $enviadas - $terminadas);
return max(0, $enviadas - $terminadas);
return "{$terminadas}/{$enviadas}";
})
->color(fn ($state) => $state > 0 ? 'warning' : 'gray')
->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'),
->color(function (OrdenProduccion $record) {
$enviadas = $record->ojales()->sum('cantidad_enviada');
$terminadas = $record->ojales()->where('terminada', true)->sum('cantidad_enviada');
return $terminadas < $enviadas ? 'warning' : ($terminadas > 0 ? 'success' : 'gray');
})
->weight(function (OrdenProduccion $record) {
$enviadas = $record->ojales()->sum('cantidad_enviada');
$terminadas = $record->ojales()->where('terminada', true)->sum('cantidad_enviada');
return $terminadas < $enviadas ? 'bold' : 'normal';
})
->tooltip('Terminadas / Total Enviadas'),
Tables\Columns\TextColumn::make('pendiente_prensillas')
->label('Pend. Prensillas')
->alignCenter()
->state(function (OrdenProduccion $record): string {
$enviadas = $record->prensillas()->sum('cantidad_enviada');
$terminadas = $record->prensillas()
->where('terminada', true)
->sum('cantidad_enviada');
$pendientes = max(0, $enviadas - $terminadas);
return "{$terminadas}/{$enviadas}";
})
->color(function (OrdenProduccion $record) {
$enviadas = $record->prensillas()->sum('cantidad_enviada');
$terminadas = $record->prensillas()->where('terminada', true)->sum('cantidad_enviada');
return $terminadas < $enviadas ? 'warning' : ($terminadas > 0 ? 'success' : 'gray');
})
->weight(function (OrdenProduccion $record) {
$enviadas = $record->prensillas()->sum('cantidad_enviada');
$terminadas = $record->prensillas()->where('terminada', true)->sum('cantidad_enviada');
return $terminadas < $enviadas ? 'bold' : 'normal';
})
->tooltip('Terminadas / Total Enviadas'),
Tables\Columns\TextColumn::make('pendiente_tintoreria')
->label('Pend. Tintorería')
+6
View File
@@ -10,6 +10,7 @@ class Ojal extends Model
protected $fillable = [
'proveedor_id',
'usuario_asignado_id',
'orden_produccion_id',
'tipo',
'fecha_envio',
@@ -30,6 +31,11 @@ class Ojal extends Model
return $this->belongsTo(Proveedor::class);
}
public function usuarioAsignado()
{
return $this->belongsTo(\App\Models\User::class, 'usuario_asignado_id');
}
public function ordenProduccion()
{
return $this->belongsTo(OrdenProduccion::class);
+51
View File
@@ -83,7 +83,58 @@ class OrdenProduccion extends Model
return $this->belongsTo(\App\Models\Producto::class, 'producto_id');
}
/**
* Verifica si ambos procesos (ojales y prensillas) están completos para una cantidad específica
*
* @param int $cantidad Cantidad de prendas a verificar
* @return array ['completo' => bool, 'ojales_terminados' => int, 'prensillas_terminadas' => int, 'minimo' => int]
*/
public function verificarProcesosCom
pletos(int $cantidad = null): array
{
$cantidadVerificar = $cantidad ?? $this->cantidad_total;
// Cantidad de ojales terminados
$ojalesTerminados = $this->ojales()
->where('terminada', true)
->sum('cantidad_enviada');
// Cantidad de prensillas terminadas
$prensillasTerminadas = $this->prensillas()
->where('terminada', true)
->sum('cantidad_enviada');
// El mínimo entre ambos procesos
$minimoCompleto = min($ojalesTerminados, $prensillasTerminadas);
// Están completos si el mínimo cubre la cantidad requerida
$completo = $minimoCompleto >= $cantidadVerificar;
return [
'completo' => $completo,
'ojales_terminados' => $ojalesTerminados,
'prensillas_terminadas' => $prensillasTerminadas,
'minimo_completo' => $minimoCompleto,
'cantidad_requerida' => $cantidadVerificar,
'faltante_ojales' => max(0, $cantidadVerificar - $ojalesTerminados),
'faltante_prensillas' => max(0, $cantidadVerificar - $prensillasTerminadas),
];
}
/**
* Obtiene la cantidad disponible para enviar a tintorería
* (solo las prendas que tienen ambos procesos completos)
*/
public function getCantidadDisponibleParaTintoreria(): int
{
$verificacion = $this->verificarProcesosCompletos();
// Ya enviadas a tintorería
$enviadasTintoreria = $this->tintorerias()->sum('cantidad_enviada');
return max(0, $verificacion['minimo_completo'] - $enviadasTintoreria);
}
protected static function booted()
{
+6
View File
@@ -8,6 +8,7 @@ class Prensilla extends Model
{
protected $fillable = [
'proveedor_id',
'usuario_asignado_id',
'orden_produccion_id',
'tipo',
'fecha_envio',
@@ -28,6 +29,11 @@ class Prensilla extends Model
return $this->belongsTo(Proveedor::class);
}
public function usuarioAsignado()
{
return $this->belongsTo(\App\Models\User::class, 'usuario_asignado_id');
}
public function ordenProduccion()
{
return $this->belongsTo(OrdenProduccion::class);
@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
// Agregar campo usuario_asignado a ojales
if (!Schema::hasColumn('ojales', 'usuario_asignado_id')) {
Schema::table('ojales', function (Blueprint $table) {
$table->foreignId('usuario_asignado_id')->nullable()->after('proveedor_id')->constrained('users')->nullOnDelete();
});
}
// Agregar campo usuario_asignado a prensillas
if (!Schema::hasColumn('prensillas', 'usuario_asignado_id')) {
Schema::table('prensillas', function (Blueprint $table) {
$table->foreignId('usuario_asignado_id')->nullable()->after('proveedor_id')->constrained('users')->nullOnDelete();
});
}
}
public function down(): void
{
Schema::table('ojales', function (Blueprint $table) {
$table->dropForeign(['usuario_asignado_id']);
$table->dropColumn('usuario_asignado_id');
});
Schema::table('prensillas', function (Blueprint $table) {
$table->dropForeign(['usuario_asignado_id']);
$table->dropColumn('usuario_asignado_id');
});
}
};
@@ -0,0 +1,175 @@
<x-filament-panels::page>
@php
$data = $this->getFlujoData();
$op = $this->record;
@endphp
<div class="space-y-6">
{{-- Información de la Orden --}}
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<h2 class="text-xl font-bold mb-4">{{ $op->numero_orden }} - {{ $op->prenda_modelo }}</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400">Total OP</p>
<p class="text-2xl font-bold">{{ $op->cantidad_total }}</p>
</div>
<div>
<p class="text-sm text-gray-500 dark:text-gray-400">Recibidas Confección</p>
<p class="text-2xl font-bold text-blue-600">{{ $data['confeccion_recibida'] }}</p>
</div>
<div>
<p class="text-sm text-gray-500 dark:text-gray-400">Disponible para Tintorería</p>
<p class="text-2xl font-bold text-green-600">{{ $data['disponible_tintoreria'] }}</p>
</div>
<div>
<p class="text-sm text-gray-500 dark:text-gray-400">Estado</p>
@if($data['verificacion']['completo'])
<p class="text-2xl font-bold text-green-600"> Completo</p>
@else
<p class="text-2xl font-bold text-yellow-600">En Proceso</p>
@endif
</div>
</div>
</div>
{{-- Proceso de Ojales --}}
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-bold">🔘 Proceso de Ojales</h3>
<div class="flex gap-4 text-sm">
<span class="text-green-600 font-semibold">Terminados: {{ $data['ojales']['terminados'] }}</span>
<span class="text-yellow-600 font-semibold">Pendientes: {{ $data['ojales']['pendientes'] }}</span>
<span class="text-gray-600 font-semibold">Total: {{ $data['ojales']['total'] }}</span>
</div>
</div>
@if($data['ojales']['registros']->count() > 0)
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th class="px-4 py-2 text-left">Cantidad</th>
<th class="px-4 py-2 text-left">Proveedor</th>
<th class="px-4 py-2 text-left">Operario</th>
<th class="px-4 py-2 text-left">Fecha</th>
<th class="px-4 py-2 text-center">Estado</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($data['ojales']['registros'] as $ojal)
<tr>
<td class="px-4 py-2 font-semibold">{{ $ojal['cantidad'] }}</td>
<td class="px-4 py-2">{{ $ojal['proveedor'] }}</td>
<td class="px-4 py-2">{{ $ojal['operario'] }}</td>
<td class="px-4 py-2">{{ $ojal['fecha'] }}</td>
<td class="px-4 py-2 text-center">
@if($ojal['terminado'])
<span class="inline-flex items-center px-2 py-1 text-xs font-medium text-green-700 bg-green-100 rounded-full">
Terminado
</span>
@else
<span class="inline-flex items-center px-2 py-1 text-xs font-medium text-yellow-700 bg-yellow-100 rounded-full">
En Proceso
</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<p class="text-gray-500 text-center py-4">No hay registros de ojales</p>
@endif
</div>
{{-- Proceso de Prensillas --}}
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-bold">✂️ Proceso de Prensillas</h3>
<div class="flex gap-4 text-sm">
<span class="text-green-600 font-semibold">Terminadas: {{ $data['prensillas']['terminadas'] }}</span>
<span class="text-yellow-600 font-semibold">Pendientes: {{ $data['prensillas']['pendientes'] }}</span>
<span class="text-gray-600 font-semibold">Total: {{ $data['prensillas']['total'] }}</span>
</div>
</div>
@if($data['prensillas']['registros']->count() > 0)
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th class="px-4 py-2 text-left">Cantidad</th>
<th class="px-4 py-2 text-left">Proveedor</th>
<th class="px-4 py-2 text-left">Operario</th>
<th class="px-4 py-2 text-left">Fecha</th>
<th class="px-4 py-2 text-center">Estado</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($data['prensillas']['registros'] as $prensilla)
<tr>
<td class="px-4 py-2 font-semibold">{{ $prensilla['cantidad'] }}</td>
<td class="px-4 py-2">{{ $prensilla['proveedor'] }}</td>
<td class="px-4 py-2">{{ $prensilla['operario'] }}</td>
<td class="px-4 py-2">{{ $prensilla['fecha'] }}</td>
<td class="px-4 py-2 text-center">
@if($prensilla['terminado'])
<span class="inline-flex items-center px-2 py-1 text-xs font-medium text-green-700 bg-green-100 rounded-full">
Terminado
</span>
@else
<span class="inline-flex items-center px-2 py-1 text-xs font-medium text-yellow-700 bg-yellow-100 rounded-full">
En Proceso
</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<p class="text-gray-500 text-center py-4">No hay registros de prensillas</p>
@endif
</div>
{{-- Resumen de Verificación --}}
<div class="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-6">
<h3 class="text-lg font-bold mb-4">📊 Estado del Flujo</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">Flujo Secuencial:</p>
<div class="flex items-center gap-2 text-sm">
<span class="px-3 py-1 bg-blue-100 text-blue-800 rounded font-medium">Confección</span>
<span></span>
<span class="px-3 py-1 {{ $data['ojales']['terminados'] > 0 ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }} rounded font-medium">
Ojales {{ $data['ojales']['terminados'] > 0 ? '✓' : '' }}
</span>
<span></span>
<span class="px-3 py-1 {{ $data['prensillas']['terminadas'] > 0 ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }} rounded font-medium">
Prensillas {{ $data['prensillas']['terminadas'] > 0 ? '✓' : '' }}
</span>
<span></span>
<span class="px-3 py-1 {{ $data['disponible_tintoreria'] > 0 ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }} rounded font-medium">
Tintorería {{ $data['disponible_tintoreria'] > 0 ? '✓' : '' }}
</span>
</div>
</div>
<div>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">Mensajes:</p>
@if($data['verificacion']['faltante_ojales'] > 0)
<p class="text-sm text-yellow-600">⚠️ Faltan {{ $data['verificacion']['faltante_ojales'] }} prendas por terminar en Ojales</p>
@endif
@if($data['verificacion']['faltante_prensillas'] > 0)
<p class="text-sm text-yellow-600">⚠️ Faltan {{ $data['verificacion']['faltante_prensillas'] }} prendas por terminar en Prensillas</p>
@endif
@if($data['verificacion']['completo'])
<p class="text-sm text-green-600"> Ambos procesos completados. {{ $data['disponible_tintoreria'] }} prendas listas para Tintorería</p>
@endif
</div>
</div>
</div>
</div>
</x-filament-panels::page>