diff --git a/app/Filament/Resources/OrdenProduccionResource.php b/app/Filament/Resources/OrdenProduccionResource.php index 2a5371d..3b6bde2 100644 --- a/app/Filament/Resources/OrdenProduccionResource.php +++ b/app/Filament/Resources/OrdenProduccionResource.php @@ -43,7 +43,7 @@ class OrdenProduccionResource extends Resource ->required() ->maxLength(255), - TextInput::make('referencia') + TextInput::make('referencia') ->required() ->maxLength(255), @@ -59,6 +59,15 @@ class OrdenProduccionResource extends Resource ->preload() ->nullable(), + TextInput::make('metros_requeridos') + ->label('Metros requeridos') + ->numeric() + ->required() + ->minValue(0) + ->reactive() + ->helperText(fn ($get) => $get('tela_id') ? 'Máx. disponible: ' . (\App\Models\Tela::find($get('tela_id'))->metros_disponibles ?? 0) : 'Selecciona una tela') + ->default(0), + DatePicker::make('fecha_inicio') ->required(), diff --git a/app/Models/OrdenProduccion.php b/app/Models/OrdenProduccion.php index 7e1b2f8..c64f2e8 100644 --- a/app/Models/OrdenProduccion.php +++ b/app/Models/OrdenProduccion.php @@ -18,6 +18,8 @@ class OrdenProduccion extends Model 'fecha_inicio', 'fecha_entrega_estimada', 'estado', + 'metros_requeridos', + 'tela_reservada', ]; public function tela() @@ -97,5 +99,62 @@ class OrdenProduccion extends Model $orden->numero_orden = 'OP-' . str_pad($ultimoId, 6, '0', STR_PAD_LEFT); } }); + + // Validar y reservar tela al cambiar de estado a 'en_corte' + static::updating(function ($orden) { + // Validación: si se especifica tela y metros_requeridos, verificar disponibilidad + if ($orden->tela_id && $orden->metros_requeridos !== null) { + $tela = \App\Models\Tela::find($orden->tela_id); + $originalMetros = $orden->getOriginal('metros_requeridos') ?? 0; + $reservedAlready = $orden->tela_reservada ? $originalMetros : 0; + $available = $tela ? ($tela->metros_disponibles + $reservedAlready) : null; + + if ($available !== null && $orden->metros_requeridos > $available) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'metros_requeridos' => 'No hay suficientes metros de tela disponibles. Disponibles: ' . ($available), + ]); + } + } + + $originalEstado = $orden->getOriginal('estado'); + $nuevoEstado = $orden->estado; + + // Reservar cuando pasamos a en_corte y no estaba reservado + if ($originalEstado !== 'en_corte' && $nuevoEstado === 'en_corte' && ! $orden->tela_reservada) { + if ($orden->tela_id && $orden->metros_requeridos > 0) { + $tela = \App\Models\Tela::find($orden->tela_id); + if (! $tela) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'tela_id' => 'No se encontró la tela asociada.', + ]); + } + + if ($tela->metros_disponibles < $orden->metros_requeridos) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'metros_requeridos' => 'No hay suficientes metros disponibles para reservar (' . $tela->metros_disponibles . ').', + ]); + } + + // Reservar: restar metros y marcar orden + $tela->metros_disponibles = $tela->metros_disponibles - $orden->metros_requeridos; + $tela->save(); + + $orden->tela_reservada = true; + } + } + + // Si retrocede desde en_corte y ya estaba reservado, devolver la tela + if ($originalEstado === 'en_corte' && $nuevoEstado !== 'en_corte' && $orden->tela_reservada) { + if ($orden->tela_id && $orden->metros_requeridos > 0) { + $tela = \App\Models\Tela::find($orden->tela_id); + if ($tela) { + $tela->metros_disponibles = $tela->metros_disponibles + $orden->metros_requeridos; + $tela->save(); + } + } + + $orden->tela_reservada = false; + } + }); } } diff --git a/database/migrations/2026_01_18_120000_add_metros_requeridos_and_tela_reservada_to_orden_produccions.php b/database/migrations/2026_01_18_120000_add_metros_requeridos_and_tela_reservada_to_orden_produccions.php new file mode 100644 index 0000000..296368b --- /dev/null +++ b/database/migrations/2026_01_18_120000_add_metros_requeridos_and_tela_reservada_to_orden_produccions.php @@ -0,0 +1,23 @@ +integer('metros_requeridos')->default(0); + $table->boolean('tela_reservada')->default(false); + }); + } + + public function down(): void + { + Schema::table('orden_produccions', function (Blueprint $table) { + $table->dropColumn(['metros_requeridos', 'tela_reservada']); + }); + } +}; \ No newline at end of file