diff --git a/app/Filament/Resources/TintoreriaResource.php b/app/Filament/Resources/TintoreriaResource.php index b28a41d..53a2ea4 100644 --- a/app/Filament/Resources/TintoreriaResource.php +++ b/app/Filament/Resources/TintoreriaResource.php @@ -79,30 +79,35 @@ class TintoreriaResource extends Resource ]) ->columns(2), - Section::make('Recepción') + Section::make('Recepciones') + ->description('Resumen de recepciones. Para registrar recepciones múltiples use el botón "Agregar recepción" en la cabecera o la relación "Recepciones" abajo.') ->schema([ - DatePicker::make('fecha_recepcion'), + Forms\Components\Placeholder::make('recepcion_summary') + ->label('Resumen') + ->content(function ($get) { + $id = $get('id'); + if (! $id) return 'Sin recepciones registradas'; - TextInput::make('cantidad_recibida') - ->numeric() - ->reactive() - ->afterStateUpdated(function ($state, $set, $get) { - $cantidad_enviada = $get('cantidad_enviada') ?? 0; - $cantidad_recibida = $state ?? 0; - $perdidas = $cantidad_enviada - $cantidad_recibida; - if ($perdidas < 0) $perdidas = 0; - $set('perdidas', $perdidas); + $total = \App\Models\Recepcion::where('referencia_type', \App\Models\Tintoreria::class) + ->where('referencia_id', $id) + ->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + + $perdidas = \App\Models\Recepcion::where('referencia_type', \App\Models\Tintoreria::class) + ->where('referencia_id', $id) + ->sum('prendas_defectuosas'); + + $enviada = (int) ($get('cantidad_enviada') ?? 0); + $faltan = max(0, $enviada - $total - $perdidas); + + return "Total recibido: {$total} — Pérdidas: {$perdidas} — Faltan: {$faltan}"; }), - TextInput::make('perdidas') - ->numeric() - ->readOnly() - ->default(0), - - Textarea::make('observaciones') - ->columnSpanFull(), + Forms\Components\Placeholder::make('instrucciones') + ->label('Acciones') + ->content('Use el botón "Agregar recepción" en la cabecera para registrar una recepción rápida. También puede gestionar todas las recepciones en la sección relacionada al final de la página.'), ]) - ->columns(2), + ->columns(1) + ->collapsed(), ]); } diff --git a/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php b/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php index db85d2f..d24d290 100644 --- a/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php +++ b/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php @@ -14,6 +14,62 @@ class EditTintoreria extends EditRecord { return [ Actions\DeleteAction::make(), + + Actions\Action::make('agregarRecepcion') + ->label('Agregar recepción') + ->modalHeading('Agregar Recepción') + ->disabled(fn (): bool => ($this->getRecord()->faltantes ?? 0) <= 0) + ->form([ + Forms\Components\DatePicker::make('fecha_recepcion')->default(now())->required(), + Forms\Components\TextInput::make('cantidad') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(fn () => $this->getRecord()->faltantes ?? 0) + ->helperText(fn () => 'Máximo: ' . ($this->getRecord()->faltantes ?? 0)) + ->default(fn () => $this->getRecord()->faltantes ?? 0), + Forms\Components\TextInput::make('prendas_defectuosas') + ->numeric() + ->minValue(0) + ->maxValue(fn ($get) => (int) ($get('cantidad') ?? 0)) + ->helperText('Opcional. Se restará del total recibido.'), + Forms\Components\Textarea::make('notas'), + ]) + ->action(function (array $data): void { + $record = $this->getRecord(); + + try { + \App\Models\Recepcion::create([ + 'referencia_type' => \App\Models\Tintoreria::class, + 'referencia_id' => $record->id, + 'cantidad' => (int) $data['cantidad'], + 'prendas_defectuosas' => (int) ($data['prendas_defectuosas'] ?? 0), + 'fecha_recepcion' => $data['fecha_recepcion'], + 'notas' => $data['notas'] ?? null, + ]); + + \Filament\Notifications\Notification::make() + ->success() + ->title('Recepción registrada') + ->body('La recepción se creó correctamente.') + ->send(); + } catch (\Illuminate\Validation\ValidationException $e) { + \Filament\Notifications\Notification::make() + ->danger() + ->title('Error') + ->body($e->validator->errors()->first() ?? 'Error al crear la recepción.') + ->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make() + ->danger() + ->title('Error') + ->body($e->getMessage()) + ->send(); + } + + // Refrescar la página para ver cambios + $this->redirect(route('filament.admin.resources.tintorerias.edit', ['record' => $record->id])); + }), ]; } } diff --git a/app/Models/Tintoreria.php b/app/Models/Tintoreria.php index 27ed359..6c3f5a7 100644 --- a/app/Models/Tintoreria.php +++ b/app/Models/Tintoreria.php @@ -75,9 +75,15 @@ class Tintoreria extends Model return (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); } + // Total de pérdidas registradas en las recepciones + public function getPerdidasTotalAttribute() + { + return (int) $this->recepciones()->sum('prendas_defectuosas'); + } + // Cuantas faltan por recibir (usa la suma real de recepciones) public function getFaltantesAttribute() { - return max(0, (int)($this->cantidad_enviada ?? 0) - $this->recibido_total); + return max(0, (int)($this->cantidad_enviada ?? 0) - $this->recibido_total - $this->perdidas_total); } } diff --git a/tests/Feature/RecepcionTintoreriaFlowTest.php b/tests/Feature/RecepcionTintoreriaFlowTest.php new file mode 100644 index 0000000..ec5ee44 --- /dev/null +++ b/tests/Feature/RecepcionTintoreriaFlowTest.php @@ -0,0 +1,65 @@ +create(['categoria' => 'tintoreria']); + $op = OrdenProduccion::factory()->create(['cantidad_total' => 100]); + + $tint = Tintoreria::create([ + 'proveedor_id' => $proveedor->id, + 'orden_produccion_id' => $op->id, + 'cantidad_enviada' => 50, + ]); + + // Recepción parcial 30 + Recepcion::create([ + 'referencia_type' => Tintoreria::class, + 'referencia_id' => $tint->id, + 'cantidad' => 30, + 'fecha_recepcion' => now(), + ]); + + $tint->refresh(); + $this->assertEquals(30, $tint->recibido_total); + $this->assertEquals(20, $tint->faltantes); + + // Recepción con perdidas 25 y 5 defectuosas + Recepcion::create([ + 'referencia_type' => Tintoreria::class, + 'referencia_id' => $tint->id, + 'cantidad' => 25, + 'prendas_defectuosas' => 5, + 'fecha_recepcion' => now(), + ]); + + $tint->refresh(); + // recibido efectivo: 30 + (25 - 5) = 50 + $this->assertEquals(50, $tint->recibido_total); + $this->assertEquals(0, $tint->faltantes); + + // Ultimo traslado deberia tener cantidad_recibida ajustada a 20 (25-5) + $ultimoTraslado = TrasladoPrenda::where('referencia_type', Tintoreria::class) + ->where('referencia_id', $tint->id) + ->latest('id') + ->first(); + + $this->assertNotNull($ultimoTraslado); + $this->assertEquals(20, $ultimoTraslado->cantidad_recibida); + $this->assertEquals(5, $ultimoTraslado->prendas_defectuosas); + } +}