diff --git a/app/Filament/Resources/OjalPresillaResource.php b/app/Filament/Resources/OjalPresillaResource.php index 9bce8f6..2c42182 100644 --- a/app/Filament/Resources/OjalPresillaResource.php +++ b/app/Filament/Resources/OjalPresillaResource.php @@ -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') + ->label('Cantidad') ->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); - } - - if ($suma > $total) { - throw \Illuminate\Validation\ValidationException::withMessages([ - 'cantidad' => "La suma de las distribuciones ({$suma}) excede el total disponible ({$total})." - ]); - } - }), - ]) - ->defaultItems(1) - ->addActionLabel('Agregar proveedor') + ->required() + ->minValue(1) + ->reactive() ->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; + $opId = $get('orden_produccion_id'); + $tipo = $get('tipo'); - if ($restante < 0) { - return "⚠️ Excede el total por " . abs($restante) . " unidades"; - } elseif ($restante > 0) { - return "Faltan {$restante} unidades por distribuir"; + 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 { - return "✓ Total distribuido correctamente"; + $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}"; } - }) - ->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(), diff --git a/app/Filament/Resources/OrdenProduccionResource/Pages/VerFlujoOjalesPresillas.php b/app/Filament/Resources/OrdenProduccionResource/Pages/VerFlujoOjalesPresillas.php new file mode 100644 index 0000000..08cba4b --- /dev/null +++ b/app/Filament/Resources/OrdenProduccionResource/Pages/VerFlujoOjalesPresillas.php @@ -0,0 +1,86 @@ +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(), + ]; + } +} diff --git a/app/Filament/Resources/TintoreriaResource.php b/app/Filament/Resources/TintoreriaResource.php index b6ba13a..371c895 100644 --- a/app/Filament/Resources/TintoreriaResource.php +++ b/app/Filament/Resources/TintoreriaResource.php @@ -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); - $set('prenda_nombre_info', $orden->prenda_modelo ?? 'Sin especificar'); + + 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(), diff --git a/app/Filament/Widgets/PrendasPendientesWidget.php b/app/Filament/Widgets/PrendasPendientesWidget.php index 4b5f9f5..f3e005a 100644 --- a/app/Filament/Widgets/PrendasPendientesWidget.php +++ b/app/Filament/Widgets/PrendasPendientesWidget.php @@ -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') diff --git a/app/Models/Ojal.php b/app/Models/Ojal.php index 3fceca2..f717076 100644 --- a/app/Models/Ojal.php +++ b/app/Models/Ojal.php @@ -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); diff --git a/app/Models/OrdenProduccion.php b/app/Models/OrdenProduccion.php index ba18750..a443630 100644 --- a/app/Models/OrdenProduccion.php +++ b/app/Models/OrdenProduccion.php @@ -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() { diff --git a/app/Models/Prensilla.php b/app/Models/Prensilla.php index 501cbc2..03c51bb 100644 --- a/app/Models/Prensilla.php +++ b/app/Models/Prensilla.php @@ -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); diff --git a/database/migrations/2026_02_04_000001_add_usuario_asignado_to_ojales_prensillas.php b/database/migrations/2026_02_04_000001_add_usuario_asignado_to_ojales_prensillas.php new file mode 100644 index 0000000..ab5ee4f --- /dev/null +++ b/database/migrations/2026_02_04_000001_add_usuario_asignado_to_ojales_prensillas.php @@ -0,0 +1,38 @@ +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'); + }); + } +}; diff --git a/resources/views/filament/resources/orden-produccion-resource/pages/ver-flujo-ojales-presillas.blade.php b/resources/views/filament/resources/orden-produccion-resource/pages/ver-flujo-ojales-presillas.blade.php new file mode 100644 index 0000000..abe40cc --- /dev/null +++ b/resources/views/filament/resources/orden-produccion-resource/pages/ver-flujo-ojales-presillas.blade.php @@ -0,0 +1,175 @@ + + @php + $data = $this->getFlujoData(); + $op = $this->record; + @endphp + +
+ {{-- Información de la Orden --}} +
+

{{ $op->numero_orden }} - {{ $op->prenda_modelo }}

+
+
+

Total OP

+

{{ $op->cantidad_total }}

+
+
+

Recibidas Confección

+

{{ $data['confeccion_recibida'] }}

+
+
+

Disponible para Tintorería

+

{{ $data['disponible_tintoreria'] }}

+
+
+

Estado

+ @if($data['verificacion']['completo']) +

✓ Completo

+ @else +

En Proceso

+ @endif +
+
+
+ + {{-- Proceso de Ojales --}} +
+
+

🔘 Proceso de Ojales

+
+ Terminados: {{ $data['ojales']['terminados'] }} + Pendientes: {{ $data['ojales']['pendientes'] }} + Total: {{ $data['ojales']['total'] }} +
+
+ + @if($data['ojales']['registros']->count() > 0) +
+ + + + + + + + + + + + @foreach($data['ojales']['registros'] as $ojal) + + + + + + + + @endforeach + +
CantidadProveedorOperarioFechaEstado
{{ $ojal['cantidad'] }}{{ $ojal['proveedor'] }}{{ $ojal['operario'] }}{{ $ojal['fecha'] }} + @if($ojal['terminado']) + + ✓ Terminado + + @else + + En Proceso + + @endif +
+
+ @else +

No hay registros de ojales

+ @endif +
+ + {{-- Proceso de Prensillas --}} +
+
+

✂️ Proceso de Prensillas

+
+ Terminadas: {{ $data['prensillas']['terminadas'] }} + Pendientes: {{ $data['prensillas']['pendientes'] }} + Total: {{ $data['prensillas']['total'] }} +
+
+ + @if($data['prensillas']['registros']->count() > 0) +
+ + + + + + + + + + + + @foreach($data['prensillas']['registros'] as $prensilla) + + + + + + + + @endforeach + +
CantidadProveedorOperarioFechaEstado
{{ $prensilla['cantidad'] }}{{ $prensilla['proveedor'] }}{{ $prensilla['operario'] }}{{ $prensilla['fecha'] }} + @if($prensilla['terminado']) + + ✓ Terminado + + @else + + En Proceso + + @endif +
+
+ @else +

No hay registros de prensillas

+ @endif +
+ + {{-- Resumen de Verificación --}} +
+

📊 Estado del Flujo

+
+
+

Flujo Secuencial:

+
+ Confección + + + Ojales {{ $data['ojales']['terminados'] > 0 ? '✓' : '' }} + + + + Prensillas {{ $data['prensillas']['terminadas'] > 0 ? '✓' : '' }} + + + + Tintorería {{ $data['disponible_tintoreria'] > 0 ? '✓' : '' }} + +
+
+ +
+

Mensajes:

+ @if($data['verificacion']['faltante_ojales'] > 0) +

⚠️ Faltan {{ $data['verificacion']['faltante_ojales'] }} prendas por terminar en Ojales

+ @endif + @if($data['verificacion']['faltante_prensillas'] > 0) +

⚠️ Faltan {{ $data['verificacion']['faltante_prensillas'] }} prendas por terminar en Prensillas

+ @endif + @if($data['verificacion']['completo']) +

✓ Ambos procesos completados. {{ $data['disponible_tintoreria'] }} prendas listas para Tintorería

+ @endif +
+
+
+
+