diff --git a/app/Filament/Resources/ConfeccionResource.php b/app/Filament/Resources/ConfeccionResource.php index e55ae13..6d56b5e 100644 --- a/app/Filament/Resources/ConfeccionResource.php +++ b/app/Filament/Resources/ConfeccionResource.php @@ -188,6 +188,8 @@ class ConfeccionResource extends Resource { return [ RelationManagers\RecepcionesRelationManager::class, + RelationManagers\CobrosRelationManager::class, + RelationManagers\AjustesRelationManager::class, ]; } diff --git a/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php b/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php index e455785..e0b362d 100644 --- a/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php +++ b/app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php @@ -72,6 +72,74 @@ class EditConfeccion extends EditRecord // Refrescar la página para ver cambios (redirigir explicitando el record para evitar error de ruta) $this->redirect(route('filament.admin.resources.confeccions.edit', ['record' => $record->id])); }), + + // Arreglos: restar cantidad del total recibido y crear traslado de reparaciones + Actions\Action::make('arreglos') + ->label('Arreglos') + ->modalHeading('Registrar Arreglo') + ->form([ + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad a arreglar') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(fn () => $this->getRecord()->cantidad_recibida ?? 0) + ->helperText(fn () => 'Máximo: ' . ($this->getRecord()->cantidad_recibida ?? 0)), + Forms\Components\Textarea::make('notas'), + ]) + ->action(function (array $data): void { + $record = $this->getRecord(); + + $cantidad = (int) ($data['cantidad'] ?? 0); + + try { + $record->registerArreglo($cantidad, $data['notas'] ?? null, auth()->id() ?? null); + + \Filament\Notifications\Notification::make()->success()->title('Arreglo registrado')->body('Se registró el arreglo correctamente.')->send(); + } catch (\Illuminate\Validation\ValidationException $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->validator->errors()->first() ?? 'Error al registrar arreglo.')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + + $this->redirect(route('filament.admin.resources.confeccions.edit', ['record' => $record->id])); + }), + + // Cobros: descontar inventario y descontar valor del total a pagar + Actions\Action::make('cobros') + ->label('Cobros') + ->modalHeading('Registrar Cobro') + ->form([ + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad') + ->numeric() + ->required() + ->minValue(1), + Forms\Components\TextInput::make('valor') + ->label('Valor a descontar') + ->numeric() + ->required() + ->minValue(0), + Forms\Components\Textarea::make('notas'), + ]) + ->action(function (array $data): void { + $record = $this->getRecord(); + + $cantidad = (int) ($data['cantidad'] ?? 0); + $valor = (float) ($data['valor'] ?? 0); + + try { + $record->registerCobro($cantidad, $valor, $data['notas'] ?? null, auth()->id() ?? null); + + \Filament\Notifications\Notification::make()->success()->title('Cobro registrado')->body('Se descontó del inventario y se aplicó el descuento al valor a pagar.')->send(); + } catch (\Illuminate\Validation\ValidationException $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->validator->errors()->first() ?? 'Error al registrar cobro.')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + + $this->redirect(route('filament.admin.resources.confeccions.edit', ['record' => $record->id])); + }), ]; } } diff --git a/app/Filament/Resources/ConfeccionResource/RelationManagers/AjustesRelationManager.php b/app/Filament/Resources/ConfeccionResource/RelationManagers/AjustesRelationManager.php new file mode 100644 index 0000000..9002611 --- /dev/null +++ b/app/Filament/Resources/ConfeccionResource/RelationManagers/AjustesRelationManager.php @@ -0,0 +1,44 @@ +columns([ + TextColumn::make('id')->label('#'), + TextColumn::make('tipo')->label('Tipo'), + TextColumn::make('cantidad')->label('Cantidad'), + TextColumn::make('usuario.name')->label('Usuario'), + TextColumn::make('notas')->limit(80)->wrap(), + TextColumn::make('created_at')->label('Fecha')->dateTime(), + ]) + ->filters([]) + ->headerActions([ + Tables\Actions\CreateAction::make()->form([ + \Filament\Forms\Components\TextInput::make('cantidad')->numeric()->required()->minValue(1), + \Filament\Forms\Components\Textarea::make('notas'), + ])->action(function (array $data) { + $owner = $this->getOwnerRecord(); + try { + $owner->registerArreglo((int)$data['cantidad'], $data['notas'] ?? null, auth()->id() ?? null); + \Filament\Notifications\Notification::make()->success()->title('Arreglo registrado')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + }), + ]) + ->actions([]) + ->bulkActions([]); + } +} diff --git a/app/Filament/Resources/ConfeccionResource/RelationManagers/CobrosRelationManager.php b/app/Filament/Resources/ConfeccionResource/RelationManagers/CobrosRelationManager.php new file mode 100644 index 0000000..37b6c93 --- /dev/null +++ b/app/Filament/Resources/ConfeccionResource/RelationManagers/CobrosRelationManager.php @@ -0,0 +1,45 @@ +columns([ + TextColumn::make('id')->label('#'), + TextColumn::make('cantidad')->label('Cantidad'), + TextColumn::make('valor')->label('Valor')->money('USD'), + TextColumn::make('usuario.name')->label('Usuario'), + TextColumn::make('notas')->limit(80)->wrap(), + TextColumn::make('created_at')->label('Fecha')->dateTime(), + ]) + ->filters([]) + ->headerActions([ + Tables\Actions\CreateAction::make()->form([ + \Filament\Forms\Components\TextInput::make('cantidad')->numeric()->required()->minValue(1), + \Filament\Forms\Components\TextInput::make('valor')->numeric()->required()->minValue(0), + \Filament\Forms\Components\Textarea::make('notas'), + ])->action(function (array $data) { + $owner = $this->getOwnerRecord(); + try { + $owner->registerCobro((int)$data['cantidad'], (float)$data['valor'], $data['notas'] ?? null, auth()->id() ?? null); + \Filament\Notifications\Notification::make()->success()->title('Cobro registrado')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + }), + ]) + ->actions([]) + ->bulkActions([]); + } +} diff --git a/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php b/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php index 1300812..fff31a9 100644 --- a/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php +++ b/app/Filament/Resources/ConfeccionResource/RelationManagers/RecepcionesRelationManager.php @@ -31,6 +31,7 @@ class RecepcionesRelationManager extends RelationManager ->helperText(fn () => 'Máximo: ' . ($this->getOwnerRecord()?->faltantes ?? 0)), TextInput::make('prendas_defectuosas') + ->label('Faltantes') ->numeric() ->minValue(0) ->maxValue(fn ($get) => (int) ($get('cantidad') ?? 0)) @@ -47,7 +48,7 @@ class RecepcionesRelationManager extends RelationManager TextColumn::make('id')->label('#'), TextColumn::make('fecha_recepcion')->dateTime()->label('Fecha'), TextColumn::make('cantidad')->label('Cantidad'), - TextColumn::make('prendas_defectuosas')->label('Defectos'), + TextColumn::make('prendas_defectuosas')->label('Faltantes'), TextColumn::make('usuario.name')->label('Usuario'), TextColumn::make('notas')->limit(50)->wrap(), TextColumn::make('created_at')->dateTime()->label('Creado'), diff --git a/app/Filament/Resources/InventarioPrendaResource/RelationManagers/DistribucionesRelationManager.php b/app/Filament/Resources/InventarioPrendaResource/RelationManagers/DistribucionesRelationManager.php index bdfb5f6..0b9135f 100644 --- a/app/Filament/Resources/InventarioPrendaResource/RelationManagers/DistribucionesRelationManager.php +++ b/app/Filament/Resources/InventarioPrendaResource/RelationManagers/DistribucionesRelationManager.php @@ -17,7 +17,8 @@ class DistribucionesRelationManager extends RelationManager public function form(Form $form): Form { return $form->schema([ - Forms\Components\Select::make('bodega_id')->relationship('bodega', 'nombre')->required(), + Forms\Components\Select::make('bodega_id')->relationship('bodega', 'nombre')->nullable(), + Forms\Components\Select::make('proveedor_id')->relationship('proveedor', 'nombre')->nullable()->helperText('Opcional: asignar a un proveedor/operario en vez de bodega'), Forms\Components\Select::make('color_id')->relationship('color', 'name')->nullable(), Forms\Components\Select::make('size_id')->relationship('size', 'name')->nullable(), Forms\Components\TextInput::make('cantidad') @@ -33,6 +34,7 @@ class DistribucionesRelationManager extends RelationManager { return $table->columns([ Tables\Columns\TextColumn::make('bodega.nombre')->label('Bodega'), + Tables\Columns\TextColumn::make('proveedor.nombre')->label('Proveedor'), Tables\Columns\TextColumn::make('color.name')->label('Color'), Tables\Columns\TextColumn::make('size.name')->label('Talla'), Tables\Columns\TextColumn::make('cantidad'), diff --git a/app/Filament/Resources/OjalResource.php b/app/Filament/Resources/OjalResource.php new file mode 100644 index 0000000..7821a55 --- /dev/null +++ b/app/Filament/Resources/OjalResource.php @@ -0,0 +1,55 @@ +schema([ + Select::make('proveedor_id')->relationship('proveedor', 'nombre', fn($q) => $q->where('categoria', 'ojal'))->searchable()->preload()->nullable(), + Select::make('orden_produccion_id')->relationship('ordenProduccion', 'numero_orden')->searchable()->preload()->required(), + DatePicker::make('fecha_envio')->default(now()), + TextInput::make('cantidad_enviada')->numeric()->required()->minValue(1), + DatePicker::make('fecha_recepcion'), + TextInput::make('cantidad_recibida')->numeric()->nullable(), + TextInput::make('perdidas')->numeric()->default(0), + ]); + } + + public static function table(Tables\Table $table): Tables\Table + { + return $table->columns([ + Tables\Columns\TextColumn::make('id')->label('#'), + Tables\Columns\TextColumn::make('proveedor.nombre')->label('Proveedor'), + Tables\Columns\TextColumn::make('ordenProduccion.numero_orden')->label('OP'), + Tables\Columns\TextColumn::make('cantidad_enviada'), + Tables\Columns\TextColumn::make('cantidad_recibida'), + Tables\Columns\TextColumn::make('perdidas'), + Tables\Columns\TextColumn::make('fecha_envio')->date(), + Tables\Columns\TextColumn::make('fecha_recepcion')->date(), + ])->defaultSort('created_at', 'desc'); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListOjales::route('/'), + 'create' => Pages\CreateOjal::route('/create'), + 'edit' => Pages\EditOjal::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/OjalResource/Pages/CreateOjal.php b/app/Filament/Resources/OjalResource/Pages/CreateOjal.php new file mode 100644 index 0000000..2d3baa9 --- /dev/null +++ b/app/Filament/Resources/OjalResource/Pages/CreateOjal.php @@ -0,0 +1,11 @@ +label('Cantidad'), + TextColumn::make('prensillas_count') + ->label('Prensillas') + ->counts('prensillas') + ->sortable(), + + TextColumn::make('ojales_count') + ->label('Ojales') + ->counts('ojales') + ->sortable(), + TextColumn::make('realizado') ->label('Realizado') ->sortable(), @@ -220,6 +230,8 @@ class OrdenProduccionResource extends Resource { return [ RelationManagers\TrasladosRelationManager::class, + RelationManagers\PrensillasRelationManager::class, + RelationManagers\OjalesRelationManager::class, ]; } diff --git a/app/Filament/Resources/OrdenProduccionResource/RelationManagers/OjalesRelationManager.php b/app/Filament/Resources/OrdenProduccionResource/RelationManagers/OjalesRelationManager.php new file mode 100644 index 0000000..993cbf1 --- /dev/null +++ b/app/Filament/Resources/OrdenProduccionResource/RelationManagers/OjalesRelationManager.php @@ -0,0 +1,41 @@ +schema([ + Select::make('proveedor_id')->relationship('proveedor', 'nombre', fn($q) => $q->where('categoria', 'ojal'))->required(), + TextInput::make('cantidad_enviada')->numeric()->required()->minValue(1), + TextInput::make('cantidad_recibida')->numeric()->nullable(), + ]); + } + + public function table(Tables\Table $table): Tables\Table + { + return $table->columns([ + Tables\Columns\TextColumn::make('id')->label('#'), + Tables\Columns\TextColumn::make('proveedor.nombre')->label('Proveedor'), + Tables\Columns\TextColumn::make('cantidad_enviada'), + Tables\Columns\TextColumn::make('cantidad_recibida'), + Tables\Columns\TextColumn::make('created_at')->label('Creado')->dateTime(), + ])->headerActions([ + Tables\Actions\CreateAction::make(), + ])->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]); + } +} diff --git a/app/Filament/Resources/OrdenProduccionResource/RelationManagers/PrensillasRelationManager.php b/app/Filament/Resources/OrdenProduccionResource/RelationManagers/PrensillasRelationManager.php new file mode 100644 index 0000000..766ea1f --- /dev/null +++ b/app/Filament/Resources/OrdenProduccionResource/RelationManagers/PrensillasRelationManager.php @@ -0,0 +1,41 @@ +schema([ + Select::make('proveedor_id')->relationship('proveedor', 'nombre', fn($q) => $q->where('categoria', 'prensilla'))->required(), + TextInput::make('cantidad_enviada')->numeric()->required()->minValue(1), + TextInput::make('cantidad_recibida')->numeric()->nullable(), + ]); + } + + public function table(Tables\Table $table): Tables\Table + { + return $table->columns([ + Tables\Columns\TextColumn::make('id')->label('#'), + Tables\Columns\TextColumn::make('proveedor.nombre')->label('Proveedor'), + Tables\Columns\TextColumn::make('cantidad_enviada'), + Tables\Columns\TextColumn::make('cantidad_recibida'), + Tables\Columns\TextColumn::make('created_at')->label('Creado')->dateTime(), + ])->headerActions([ + Tables\Actions\CreateAction::make(), + ])->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]); + } +} diff --git a/app/Filament/Resources/OrdenProduccionResource/RelationManagers/TrasladosRelationManager.php b/app/Filament/Resources/OrdenProduccionResource/RelationManagers/TrasladosRelationManager.php index 92a3373..859e88a 100644 --- a/app/Filament/Resources/OrdenProduccionResource/RelationManagers/TrasladosRelationManager.php +++ b/app/Filament/Resources/OrdenProduccionResource/RelationManagers/TrasladosRelationManager.php @@ -46,7 +46,7 @@ class TrasladosRelationManager extends RelationManager TextColumn::make('destino'), TextColumn::make('cantidad_enviada'), TextColumn::make('cantidad_recibida'), - TextColumn::make('prendas_defectuosas'), + TextColumn::make('prendas_defectuosas')->label('Faltantes'), TextColumn::make('reparaciones'), TextColumn::make('saldos'), TextColumn::make('residual'), diff --git a/app/Filament/Resources/PrensillaResource.php b/app/Filament/Resources/PrensillaResource.php new file mode 100644 index 0000000..1cbdce3 --- /dev/null +++ b/app/Filament/Resources/PrensillaResource.php @@ -0,0 +1,55 @@ +schema([ + Select::make('proveedor_id')->relationship('proveedor', 'nombre', fn($q) => $q->where('categoria', 'prensilla'))->searchable()->preload()->nullable(), + Select::make('orden_produccion_id')->relationship('ordenProduccion', 'numero_orden')->searchable()->preload()->required(), + DatePicker::make('fecha_envio')->default(now()), + TextInput::make('cantidad_enviada')->numeric()->required()->minValue(1), + DatePicker::make('fecha_recepcion'), + TextInput::make('cantidad_recibida')->numeric()->nullable(), + TextInput::make('perdidas')->numeric()->default(0), + ]); + } + + public static function table(Tables\Table $table): Tables\Table + { + return $table->columns([ + Tables\Columns\TextColumn::make('id')->label('#'), + Tables\Columns\TextColumn::make('proveedor.nombre')->label('Proveedor'), + Tables\Columns\TextColumn::make('ordenProduccion.numero_orden')->label('OP'), + Tables\Columns\TextColumn::make('cantidad_enviada'), + Tables\Columns\TextColumn::make('cantidad_recibida'), + Tables\Columns\TextColumn::make('perdidas'), + Tables\Columns\TextColumn::make('fecha_envio')->date(), + Tables\Columns\TextColumn::make('fecha_recepcion')->date(), + ])->defaultSort('created_at', 'desc'); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListPrensillas::route('/'), + 'create' => Pages\CreatePrensilla::route('/create'), + 'edit' => Pages\EditPrensilla::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/PrensillaResource/Pages/CreatePrensilla.php b/app/Filament/Resources/PrensillaResource/Pages/CreatePrensilla.php new file mode 100644 index 0000000..705a087 --- /dev/null +++ b/app/Filament/Resources/PrensillaResource/Pages/CreatePrensilla.php @@ -0,0 +1,11 @@ + 'Tintorería', 'talleres' => 'Talleres', 'telas' => 'Telas', + 'prensilla' => 'Prensilla', + 'ojal' => 'Ojal', 'otros' => 'Otros', ]) ->required(), @@ -70,6 +72,8 @@ class ProveedorResource extends Resource 'primary' => 'tintoreria', 'success' => 'talleres', 'warning' => 'telas', + 'info' => 'prensilla', + 'secondary' => 'ojal', 'gray' => 'otros', ]) ->sortable(), diff --git a/app/Filament/Resources/TintoreriaResource.php b/app/Filament/Resources/TintoreriaResource.php index a709d3d..5eef403 100644 --- a/app/Filament/Resources/TintoreriaResource.php +++ b/app/Filament/Resources/TintoreriaResource.php @@ -189,6 +189,8 @@ class TintoreriaResource extends Resource { return [ RelationManagers\RecepcionesRelationManager::class, + RelationManagers\CobrosRelationManager::class, + RelationManagers\AjustesRelationManager::class, ]; } diff --git a/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php b/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php index cca757e..26e3877 100644 --- a/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php +++ b/app/Filament/Resources/TintoreriaResource/Pages/EditTintoreria.php @@ -71,6 +71,74 @@ class EditTintoreria extends EditRecord // Refrescar la página para ver cambios $this->redirect(route('filament.admin.resources.tintorerias.edit', ['record' => $record->id])); }), + + // Reprocesos: registrar reproceso como ajuste + Actions\Action::make('reprocesos') + ->label('Reprocesos') + ->modalHeading('Registrar Reproceso') + ->form([ + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad a reprocesar') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(fn () => $this->getRecord()->recibido_total ?? 0) + ->helperText(fn () => 'Máximo: ' . ($this->getRecord()->recibido_total ?? 0)), + Forms\Components\Textarea::make('notas'), + ]) + ->action(function (array $data): void { + $record = $this->getRecord(); + + $cantidad = (int) ($data['cantidad'] ?? 0); + + try { + $record->registerReproceso($cantidad, $data['notas'] ?? null, auth()->id() ?? null); + + \Filament\Notifications\Notification::make()->success()->title('Reproceso registrado')->body('Se registró el reproceso correctamente.')->send(); + } catch (\Illuminate\Validation\ValidationException $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->validator->errors()->first() ?? 'Error al registrar reproceso.')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + + $this->redirect(route('filament.admin.resources.tintorerias.edit', ['record' => $record->id])); + }), + + // Cobros: descontar inventario y registrar cobro + Actions\Action::make('cobros') + ->label('Cobros') + ->modalHeading('Registrar Cobro') + ->form([ + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad') + ->numeric() + ->required() + ->minValue(1), + Forms\Components\TextInput::make('valor') + ->label('Valor a descontar') + ->numeric() + ->required() + ->minValue(0), + Forms\Components\Textarea::make('notas'), + ]) + ->action(function (array $data): void { + $record = $this->getRecord(); + + $cantidad = (int) ($data['cantidad'] ?? 0); + $valor = (float) ($data['valor'] ?? 0); + + try { + $record->registerCobro($cantidad, $valor, $data['notas'] ?? null, auth()->id() ?? null); + + \Filament\Notifications\Notification::make()->success()->title('Cobro registrado')->body('Se descontó del inventario y se registró el cobro.')->send(); + } catch (\Illuminate\Validation\ValidationException $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->validator->errors()->first() ?? 'Error al registrar cobro.')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + + $this->redirect(route('filament.admin.resources.tintorerias.edit', ['record' => $record->id])); + }), ]; } } diff --git a/app/Filament/Resources/TintoreriaResource/RelationManagers/AjustesRelationManager.php b/app/Filament/Resources/TintoreriaResource/RelationManagers/AjustesRelationManager.php new file mode 100644 index 0000000..3bf86a8 --- /dev/null +++ b/app/Filament/Resources/TintoreriaResource/RelationManagers/AjustesRelationManager.php @@ -0,0 +1,43 @@ +columns([ + TextColumn::make('id')->label('#'), + TextColumn::make('tipo')->label('Tipo'), + TextColumn::make('cantidad')->label('Cantidad'), + TextColumn::make('usuario.name')->label('Usuario'), + TextColumn::make('notas')->limit(80)->wrap(), + TextColumn::make('created_at')->label('Fecha')->dateTime(), + ]) + ->filters([]) + ->headerActions([ + Tables\Actions\CreateAction::make()->form([ + \Filament\Forms\Components\TextInput::make('cantidad')->numeric()->required()->minValue(1), + \Filament\Forms\Components\Textarea::make('notas'), + ])->action(function (array $data) { + $owner = $this->getOwnerRecord(); + try { + $owner->registerReproceso((int)$data['cantidad'], $data['notas'] ?? null, auth()->id() ?? null); + \Filament\Notifications\Notification::make()->success()->title('Reproceso registrado')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + }), + ]) + ->actions([]) + ->bulkActions([]); + } +} diff --git a/app/Filament/Resources/TintoreriaResource/RelationManagers/CobrosRelationManager.php b/app/Filament/Resources/TintoreriaResource/RelationManagers/CobrosRelationManager.php new file mode 100644 index 0000000..8686bfc --- /dev/null +++ b/app/Filament/Resources/TintoreriaResource/RelationManagers/CobrosRelationManager.php @@ -0,0 +1,44 @@ +columns([ + TextColumn::make('id')->label('#'), + TextColumn::make('cantidad')->label('Cantidad'), + TextColumn::make('valor')->label('Valor')->money('USD'), + TextColumn::make('usuario.name')->label('Usuario'), + TextColumn::make('notas')->limit(80)->wrap(), + TextColumn::make('created_at')->label('Fecha')->dateTime(), + ]) + ->filters([]) + ->headerActions([ + Tables\Actions\CreateAction::make()->form([ + \Filament\Forms\Components\TextInput::make('cantidad')->numeric()->required()->minValue(1), + \Filament\Forms\Components\TextInput::make('valor')->numeric()->required()->minValue(0), + \Filament\Forms\Components\Textarea::make('notas'), + ])->action(function (array $data) { + $owner = $this->getOwnerRecord(); + try { + $owner->registerCobro((int)$data['cantidad'], (float)$data['valor'], $data['notas'] ?? null, auth()->id() ?? null); + \Filament\Notifications\Notification::make()->success()->title('Cobro registrado')->send(); + } catch (\Throwable $e) { + \Filament\Notifications\Notification::make()->danger()->title('Error')->body($e->getMessage())->send(); + } + }), + ]) + ->actions([]) + ->bulkActions([]); + } +} diff --git a/app/Filament/Resources/TintoreriaResource/RelationManagers/RecepcionesRelationManager.php b/app/Filament/Resources/TintoreriaResource/RelationManagers/RecepcionesRelationManager.php index 5550228..056bd09 100644 --- a/app/Filament/Resources/TintoreriaResource/RelationManagers/RecepcionesRelationManager.php +++ b/app/Filament/Resources/TintoreriaResource/RelationManagers/RecepcionesRelationManager.php @@ -31,6 +31,7 @@ class RecepcionesRelationManager extends RelationManager ->helperText(fn () => 'Máximo: ' . ($this->getOwnerRecord()?->faltantes ?? 0)), TextInput::make('prendas_defectuosas') + ->label('Faltantes') ->numeric() ->minValue(0) ->maxValue(fn ($get) => (int) ($get('cantidad') ?? 0)) @@ -47,7 +48,7 @@ class RecepcionesRelationManager extends RelationManager TextColumn::make('id')->label('#'), TextColumn::make('fecha_recepcion')->dateTime()->label('Fecha'), TextColumn::make('cantidad')->label('Cantidad'), - TextColumn::make('prendas_defectuosas')->label('Defectos'), + TextColumn::make('prendas_defectuosas')->label('Faltantes'), TextColumn::make('usuario.name')->label('Usuario'), TextColumn::make('notas')->limit(50)->wrap(), TextColumn::make('created_at')->dateTime()->label('Creado'), diff --git a/app/Models/Ajuste.php b/app/Models/Ajuste.php new file mode 100644 index 0000000..46210ee --- /dev/null +++ b/app/Models/Ajuste.php @@ -0,0 +1,27 @@ +morphTo(); + } + + public function usuario() + { + return $this->belongsTo(User::class, 'user_id'); + } +} diff --git a/app/Models/Cobro.php b/app/Models/Cobro.php new file mode 100644 index 0000000..19b823e --- /dev/null +++ b/app/Models/Cobro.php @@ -0,0 +1,27 @@ +morphTo(); + } + + public function usuario() + { + return $this->belongsTo(User::class, 'user_id'); + } +} diff --git a/app/Models/Confeccion.php b/app/Models/Confeccion.php index d72461d..a4cd855 100644 --- a/app/Models/Confeccion.php +++ b/app/Models/Confeccion.php @@ -17,8 +17,19 @@ class Confeccion extends Model 'valor_por_prenda', 'total_pagar', 'estado', + 'descuentos_cobros', ]; + public function cobros() + { + return $this->morphMany(\App\Models\Cobro::class, 'referencia'); + } + + public function ajustes() + { + return $this->morphMany(\App\Models\Ajuste::class, 'referencia'); + } + /* Relaciones */ public function proveedor() { @@ -52,7 +63,14 @@ class Confeccion extends Model // Total a pagar: usa cantidad_recibida si existe, sino cantidad_enviada $cantidadBase = $confeccion->cantidad_recibida ?? $confeccion->cantidad_enviada ?? 0; $valorUnitario = $confeccion->valor_por_prenda ?? 0; - $confeccion->total_pagar = $cantidadBase * $valorUnitario; + + // Aplicar descuentos de cobros si existen (se guarda también en descuentos_cobros para compatibilidad) + $descuentos = (float) ($confeccion->getCobrosTotalAttribute() ?? 0); + + $confeccion->total_pagar = max(0, ($cantidadBase * $valorUnitario) - $descuentos); + + // Mantener campo redundante 'descuentos_cobros' sincronizado + $confeccion->descuentos_cobros = $descuentos; // Estado automático if (! $confeccion->cantidad_recibida) { @@ -81,12 +99,115 @@ class Confeccion extends Model // Total recibido calculado desde recepciones (fuente de la verdad) public function getRecibidoTotalAttribute() { - return (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $recepciones = (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $ajustes = (int) $this->ajustes()->where('tipo', 'arreglo')->sum('cantidad'); + + return max(0, $recepciones - $ajustes); } - // Cuantas faltan por recibir (usa la suma real de recepciones) + // Cuantas faltan por recibir (usa la suma real de recepciones menos ajustes) public function getFaltantesAttribute() { return max(0, (int)($this->cantidad_enviada ?? 0) - $this->recibido_total); } + + // Total de cobros aplicados + public function getCobrosTotalAttribute() + { + return (float) $this->cobros()->sum('valor'); + } + + /** + * Registrar un arreglo como ajuste histórico y crear traslado de reparaciones + */ + public function registerArreglo(int $cantidad, ?string $notas = null, ?int $userId = null) + { + if ($cantidad <= 0) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad debe ser mayor que 0.']); + } + + $recibido = $this->recibido_total; + if ($cantidad > $recibido) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad supera lo recibido.']); + } + + // Crear ajuste + $aj = \App\Models\Ajuste::create([ + 'referencia_type' => self::class, + 'referencia_id' => $this->id, + 'user_id' => $userId, + 'tipo' => 'arreglo', + 'cantidad' => $cantidad, + 'notas' => $notas, + ]); + + // Crear traslado de reparaciones para reflejar la salida + \App\Models\TrasladoPrenda::create([ + 'orden_produccion_id' => $this->orden_produccion_id, + 'referencia_type' => self::class, + 'referencia_id' => $this->id, + 'origen' => 'confeccion', + 'destino' => 'reparaciones', + 'cantidad_enviada' => $cantidad, + 'cantidad_recibida' => 0, + 'prendas_defectuosas' => 0, + 'reparaciones' => $cantidad, + 'fecha_envio' => now(), + 'fecha_recepcion' => now(), + 'estado' => 'recibido', + ]); + + // Recalcular cantidad_recibida almacenada para compatibilidad con UI + $this->cantidad_recibida = $this->recibido_total; + $this->save(); + + return $aj; + } + + /** + * Registrar un cobro: descontar inventario y crear registro de cobro + */ + public function registerCobro(int $cantidad, float $valor, ?string $notas = null, ?int $userId = null) + { + if ($cantidad <= 0) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad debe ser mayor que 0.']); + } + + // Buscar inventario disponible + $inventario = \App\Models\InventarioPrenda::where('orden_produccion_id', $this->orden_produccion_id) + ->where('cantidad_disponible', '>=', $cantidad) + ->first(); + + if (! $inventario) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'No hay inventario disponible suficiente para descontar.']); + } + + // Descontar del inventario + $inventario->cantidad_disponible = $inventario->cantidad_disponible - $cantidad; + $inventario->save(); + + // Si está asociado a producto, decrementar stock + if ($inventario->producto_id) { + $producto = \App\Models\Producto::find($inventario->producto_id); + if ($producto) { + $producto->decrement('stock', $cantidad); + } + } + + // Crear registro de cobro + $c = \App\Models\Cobro::create([ + 'referencia_type' => self::class, + 'referencia_id' => $this->id, + 'user_id' => $userId, + 'cantidad' => $cantidad, + 'valor' => $valor, + 'notas' => $notas, + ]); + + // Mantener campo redundante sincronizado + $this->descuentos_cobros = $this->getCobrosTotalAttribute(); + $this->save(); + + return $c; + } } diff --git a/app/Models/InventarioPrenda.php b/app/Models/InventarioPrenda.php index b2fe8b5..f0a0dd8 100644 --- a/app/Models/InventarioPrenda.php +++ b/app/Models/InventarioPrenda.php @@ -153,6 +153,7 @@ class InventarioPrenda extends Model 'precio_venta' => 0, 'unidad_medida' => 'unidad', 'codigo_barras' => $codigo, + 'categoria_id' => \App\Models\Categoria::first()?->id ?? \App\Models\Categoria::create(['nombre' => 'Generica'])->id, ]); }); } diff --git a/app/Models/InventarioPrendaDistribucion.php b/app/Models/InventarioPrendaDistribucion.php index 2ea42e7..000e4c4 100644 --- a/app/Models/InventarioPrendaDistribucion.php +++ b/app/Models/InventarioPrendaDistribucion.php @@ -14,6 +14,7 @@ class InventarioPrendaDistribucion extends Model protected $fillable = [ 'inventario_prenda_id', 'bodega_id', + 'proveedor_id', 'color_id', 'size_id', 'cantidad', @@ -52,8 +53,8 @@ class InventarioPrendaDistribucion extends Model $cantidad = intval($dist->cantidad ?? 0); $sumExistentes = (int) self::where('inventario_prenda_id', $parentId)->sum('cantidad'); - // Validar contra la cantidad disponible actual - if (($sumExistentes + $cantidad) > (int) $parent->cantidad_disponible) { + // Validar contra la cantidad terminada total (no distribuir más del total entregado) + if (($sumExistentes + $cantidad) > (int) $parent->cantidad_terminada) { throw \Illuminate\Validation\ValidationException::withMessages([ 'cantidad' => 'No se puede añadir más prendas que las disponibles.', ]); @@ -72,8 +73,8 @@ class InventarioPrendaDistribucion extends Model ->where('id', '<>', $dist->id) ->sum('cantidad'); - // Validar contra la cantidad disponible actual (considerando otras distribuciones) - if (($othersSum + $newCantidad) > (int) $parent->cantidad_disponible) { + // Validar contra la cantidad terminada total (no distribuir más del total entregado) + if (($othersSum + $newCantidad) > (int) $parent->cantidad_terminada) { throw \Illuminate\Validation\ValidationException::withMessages([ 'cantidad' => 'No se puede añadir más prendas que las disponibles.', ]); @@ -87,6 +88,18 @@ class InventarioPrendaDistribucion extends Model $bodegaId = $dist->bodega_id; + // If a proveedor_id is present, treat as assignment to a provider/person (no warehouse stock changes) + if ($dist->proveedor_id && ! $bodegaId) { + // Just decrement disponibilidad on parent + $parent = $dist->inventarioPrenda; + if ($parent) { + $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad); + $parent->save(); + } + + return; + } + if ($dist->color_id && $dist->size_id) { // Variante // Determinar producto: preferir inventario.prenda.producto_id -> op.producto_id @@ -158,6 +171,41 @@ class InventarioPrendaDistribucion extends Model } else { // Producto $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null); + + // Si no existe producto, intentar crear/inferrir desde la Orden de Producción + if (! $productoId && $dist->inventarioPrenda && $dist->inventarioPrenda->ordenProduccion) { + $op = $dist->inventarioPrenda->ordenProduccion; + $nombre = $op->prenda_modelo ?? $op->referencia ?? ('Producto OP #' . $op->id); + + $codigo = 'AUTOP-' . $op->id . '-' . time(); + $codigo = substr($codigo, 0, 50); + while (\App\Models\Producto::where('codigo_barras', $codigo)->exists()) { + $codigo .= '-' . rand(0, 9); + $codigo = substr($codigo, 0, 50); + } + + $producto = \App\Models\Producto::create([ + 'nombre' => $nombre, + 'descripcion' => 'Creado automáticamente desde distribución (OP #' . $op->id . ')', + 'stock' => 0, + 'estado' => true, + 'precio_compra' => 0, + 'precio_venta' => 0, + 'unidad_medida' => 'unidad', + 'codigo_barras' => $codigo, + 'categoria_id' => \App\Models\Categoria::first()?->id ?? \App\Models\Categoria::create(['nombre' => 'Generica'])->id, + ]); + + $productoId = $producto->id; + + // Guardar producto en el inventario padre para futuras referencias + $parent = $dist->inventarioPrenda; + if ($parent && ! $parent->producto_id) { + $parent->producto_id = $productoId; + $parent->save(); + } + } + if ($productoId) { $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first(); if ($existing) { diff --git a/app/Models/Ojal.php b/app/Models/Ojal.php new file mode 100644 index 0000000..d77f3ce --- /dev/null +++ b/app/Models/Ojal.php @@ -0,0 +1,45 @@ +belongsTo(Proveedor::class); + } + + public function ordenProduccion() + { + return $this->belongsTo(OrdenProduccion::class); + } + + protected static function booted() + { + static::creating(function ($p) { + // Validar disponibilidad desde confecciones + $opId = $p->orden_produccion_id; + $totalProducido = \App\Models\Confeccion::where('orden_produccion_id', $opId)->sum('cantidad_recibida'); + $yaAsignado = \App\Models\Prensilla::where('orden_produccion_id', $opId)->sum('cantidad_enviada') + + \App\Models\Ojal::where('orden_produccion_id', $opId)->sum('cantidad_enviada'); + + if (($yaAsignado + ($p->cantidad_enviada ?? 0)) > $totalProducido) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad_enviada' => 'No hay suficientes unidades disponibles desde confecciones para asignar.']); + } + }); + } +} diff --git a/app/Models/OrdenProduccion.php b/app/Models/OrdenProduccion.php index 2711272..16089ea 100644 --- a/app/Models/OrdenProduccion.php +++ b/app/Models/OrdenProduccion.php @@ -53,6 +53,16 @@ class OrdenProduccion extends Model return $this->hasMany(\App\Models\Tintoreria::class); } + public function prensillas() + { + return $this->hasMany(\App\Models\Prensilla::class); + } + + public function ojales() + { + return $this->hasMany(\App\Models\Ojal::class); + } + public function procesosAcabado() { return $this->hasMany(\App\Models\ProcesoAcabado::class); diff --git a/app/Models/Prensilla.php b/app/Models/Prensilla.php new file mode 100644 index 0000000..464dac2 --- /dev/null +++ b/app/Models/Prensilla.php @@ -0,0 +1,43 @@ +belongsTo(Proveedor::class); + } + + public function ordenProduccion() + { + return $this->belongsTo(OrdenProduccion::class); + } + + protected static function booted() + { + static::creating(function ($p) { + // Validar disponibilidad desde confecciones + $opId = $p->orden_produccion_id; + $totalProducido = \App\Models\Confeccion::where('orden_produccion_id', $opId)->sum('cantidad_recibida'); + $yaAsignado = \App\Models\Prensilla::where('orden_produccion_id', $opId)->sum('cantidad_enviada') + + \App\Models\Ojal::where('orden_produccion_id', $opId)->sum('cantidad_enviada'); + + if (($yaAsignado + ($p->cantidad_enviada ?? 0)) > $totalProducido) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad_enviada' => 'No hay suficientes unidades disponibles desde confecciones para asignar.']); + } + }); + } +} diff --git a/app/Models/Tintoreria.php b/app/Models/Tintoreria.php index 1fe9be0..77c5a8e 100644 --- a/app/Models/Tintoreria.php +++ b/app/Models/Tintoreria.php @@ -63,16 +63,124 @@ class Tintoreria extends Model }); } + /** + * Registrar un reproceso: crear ajuste histórico y traslado de reproceso + */ + public function registerReproceso(int $cantidad, ?string $notas = null, ?int $userId = null) + { + if ($cantidad <= 0) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad debe ser mayor que 0.']); + } + + $recibido = $this->recibido_total; + if ($cantidad > $recibido) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad supera lo recibido.']); + } + + // Crear ajuste de tipo reproceso + $aj = \App\Models\Ajuste::create([ + 'referencia_type' => self::class, + 'referencia_id' => $this->id, + 'user_id' => $userId, + 'tipo' => 'reproceso', + 'cantidad' => $cantidad, + 'notas' => $notas, + ]); + + // Crear traslado de reprocesos para reflejar la operación + \App\Models\TrasladoPrenda::create([ + 'orden_produccion_id' => $this->orden_produccion_id, + 'referencia_type' => self::class, + 'referencia_id' => $this->id, + 'origen' => 'tintoreria', + 'destino' => 'reprocesos', + 'cantidad_enviada' => $cantidad, + 'cantidad_recibida' => 0, + 'prendas_defectuosas' => 0, + 'reparaciones' => 0, + 'saldos' => 0, + 'fecha_envio' => now(), + 'fecha_recepcion' => now(), + 'estado' => 'recibido', + ]); + + // Recalcular cantidad_recibida almacenada para compatibilidad con UI + $this->cantidad_recibida = $this->recibido_total; + $this->save(); + + return $aj; + } + + /** + * Registrar un cobro: descontar inventario y crear registro de cobro + */ + public function registerCobro(int $cantidad, float $valor, ?string $notas = null, ?int $userId = null) + { + if ($cantidad <= 0) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'La cantidad debe ser mayor que 0.']); + } + + // Buscar inventario disponible + $inventario = \App\Models\InventarioPrenda::where('orden_produccion_id', $this->orden_produccion_id) + ->where('cantidad_disponible', '>=', $cantidad) + ->first(); + + if (! $inventario) { + throw \Illuminate\Validation\ValidationException::withMessages(['cantidad' => 'No hay inventario disponible suficiente para descontar.']); + } + + // Descontar del inventario + $inventario->cantidad_disponible = $inventario->cantidad_disponible - $cantidad; + $inventario->save(); + + // Si está asociado a producto, decrementar stock + if ($inventario->producto_id) { + $producto = \App\Models\Producto::find($inventario->producto_id); + if ($producto) { + $producto->decrement('stock', $cantidad); + } + } + + // Crear registro de cobro + $c = \App\Models\Cobro::create([ + 'referencia_type' => self::class, + 'referencia_id' => $this->id, + 'user_id' => $userId, + 'cantidad' => $cantidad, + 'valor' => $valor, + 'notas' => $notas, + ]); + + // Mantener campo redundante sincronizado + $this->descuentos_cobros = $this->getCobrosTotalAttribute(); + $this->save(); + + return $c; + } + /* Recepciones polimórficas */ public function recepciones() { return $this->morphMany(\App\Models\Recepcion::class, 'referencia'); } - // Total recibido calculado desde recepciones (fuente de la verdad) + public function cobros() + { + return $this->morphMany(\App\Models\Cobro::class, 'referencia'); + } + + public function ajustes() + { + return $this->morphMany(\App\Models\Ajuste::class, 'referencia'); + } + + // Total recibido calculado desde recepciones (fuente de la verdad) menos reprocesos public function getRecibidoTotalAttribute() { - return (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $recepciones = (int) $this->recepciones()->sum(\DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $reprocesos = (int) $this->ajustes()->where('tipo', 'reproceso')->sum('cantidad'); + + return max(0, $recepciones - $reprocesos); } // Total de pérdidas registradas en las recepciones @@ -81,6 +189,11 @@ class Tintoreria extends Model return (int) $this->recepciones()->sum('prendas_defectuosas'); } + public function getCobrosTotalAttribute() + { + return (float) $this->cobros()->sum('valor'); + } + // Cuantas faltan por recibir (usa la suma real de recepciones) public function getFaltantesAttribute() { diff --git a/database/migrations/2026_01_28_201000_add_descuentos_to_confeccions_table.php b/database/migrations/2026_01_28_201000_add_descuentos_to_confeccions_table.php new file mode 100644 index 0000000..4832c27 --- /dev/null +++ b/database/migrations/2026_01_28_201000_add_descuentos_to_confeccions_table.php @@ -0,0 +1,26 @@ +decimal('descuentos_cobros', 12, 2)->default(0)->after('total_pagar'); + } + }); + } + + public function down() + { + Schema::table('confeccions', function (Blueprint $table) { + if (Schema::hasColumn('confeccions', 'descuentos_cobros')) { + $table->dropColumn('descuentos_cobros'); + } + }); + } +}; diff --git a/database/migrations/2026_01_28_202000_create_cobros_table.php b/database/migrations/2026_01_28_202000_create_cobros_table.php new file mode 100644 index 0000000..87a3857 --- /dev/null +++ b/database/migrations/2026_01_28_202000_create_cobros_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('referencia_type'); + $table->unsignedBigInteger('referencia_id'); + $table->unsignedBigInteger('user_id')->nullable(); + $table->integer('cantidad')->default(0); + $table->decimal('valor', 12, 2)->default(0); + $table->text('notas')->nullable(); + $table->timestamps(); + + $table->index(['referencia_type', 'referencia_id']); + }); + } + + public function down() + { + Schema::dropIfExists('cobros'); + } +}; diff --git a/database/migrations/2026_01_28_202100_create_ajustes_table.php b/database/migrations/2026_01_28_202100_create_ajustes_table.php new file mode 100644 index 0000000..3bb316f --- /dev/null +++ b/database/migrations/2026_01_28_202100_create_ajustes_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('referencia_type'); + $table->unsignedBigInteger('referencia_id'); + $table->unsignedBigInteger('user_id')->nullable(); + $table->string('tipo')->default('arreglo'); + $table->integer('cantidad')->default(0); + $table->text('notas')->nullable(); + $table->timestamps(); + + $table->index(['referencia_type', 'referencia_id']); + }); + } + + public function down() + { + Schema::dropIfExists('ajustes'); + } +}; diff --git a/database/migrations/2026_01_28_203000_create_prensillas_table.php b/database/migrations/2026_01_28_203000_create_prensillas_table.php new file mode 100644 index 0000000..ec52a53 --- /dev/null +++ b/database/migrations/2026_01_28_203000_create_prensillas_table.php @@ -0,0 +1,31 @@ +id(); + $table->unsignedBigInteger('proveedor_id')->nullable(); + $table->unsignedBigInteger('orden_produccion_id'); + $table->date('fecha_envio')->nullable(); + $table->integer('cantidad_enviada')->default(0); + $table->date('fecha_recepcion')->nullable(); + $table->integer('cantidad_recibida')->nullable(); + $table->integer('perdidas')->default(0); + $table->timestamps(); + + $table->foreign('proveedor_id')->references('id')->on('proveedors')->onDelete('set null'); + $table->foreign('orden_produccion_id')->references('id')->on('orden_produccions')->onDelete('cascade'); + }); + } + + public function down() + { + Schema::dropIfExists('prensillas'); + } +}; \ No newline at end of file diff --git a/database/migrations/2026_01_28_203100_create_ojales_table.php b/database/migrations/2026_01_28_203100_create_ojales_table.php new file mode 100644 index 0000000..982623f --- /dev/null +++ b/database/migrations/2026_01_28_203100_create_ojales_table.php @@ -0,0 +1,31 @@ +id(); + $table->unsignedBigInteger('proveedor_id')->nullable(); + $table->unsignedBigInteger('orden_produccion_id'); + $table->date('fecha_envio')->nullable(); + $table->integer('cantidad_enviada')->default(0); + $table->date('fecha_recepcion')->nullable(); + $table->integer('cantidad_recibida')->nullable(); + $table->integer('perdidas')->default(0); + $table->timestamps(); + + $table->foreign('proveedor_id')->references('id')->on('proveedors')->onDelete('set null'); + $table->foreign('orden_produccion_id')->references('id')->on('orden_produccions')->onDelete('cascade'); + }); + } + + public function down() + { + Schema::dropIfExists('ojales'); + } +}; \ No newline at end of file diff --git a/database/migrations/2026_01_28_204000_add_descuentos_to_tintorerias_table.php b/database/migrations/2026_01_28_204000_add_descuentos_to_tintorerias_table.php new file mode 100644 index 0000000..16de97a --- /dev/null +++ b/database/migrations/2026_01_28_204000_add_descuentos_to_tintorerias_table.php @@ -0,0 +1,26 @@ +decimal('descuentos_cobros', 12, 2)->default(0)->after('perdidas'); + } + }); + } + + public function down() + { + Schema::table('tintorerias', function (Blueprint $table) { + if (Schema::hasColumn('tintorerias', 'descuentos_cobros')) { + $table->dropColumn('descuentos_cobros'); + } + }); + } +}; \ No newline at end of file diff --git a/database/migrations/2026_01_28_205000_add_proveedor_to_inventario_prenda_distribuciones.php b/database/migrations/2026_01_28_205000_add_proveedor_to_inventario_prenda_distribuciones.php new file mode 100644 index 0000000..ddb0dc3 --- /dev/null +++ b/database/migrations/2026_01_28_205000_add_proveedor_to_inventario_prenda_distribuciones.php @@ -0,0 +1,28 @@ +unsignedBigInteger('proveedor_id')->nullable()->after('bodega_id'); + $table->foreign('proveedor_id')->references('id')->on('proveedors')->onDelete('set null'); + } + }); + } + + public function down() + { + Schema::table('inventario_prenda_distribuciones', function (Blueprint $table) { + if (Schema::hasColumn('inventario_prenda_distribuciones', 'proveedor_id')) { + $table->dropForeign(['proveedor_id']); + $table->dropColumn('proveedor_id'); + } + }); + } +}; \ No newline at end of file diff --git a/database/migrations/2026_01_29_032000_make_bodega_nullable_in_inventario_prenda_distribuciones.php b/database/migrations/2026_01_29_032000_make_bodega_nullable_in_inventario_prenda_distribuciones.php new file mode 100644 index 0000000..153eef3 --- /dev/null +++ b/database/migrations/2026_01_29_032000_make_bodega_nullable_in_inventario_prenda_distribuciones.php @@ -0,0 +1,27 @@ +dropForeign(['bodega_id']); + $table->unsignedBigInteger('bodega_id')->nullable()->change(); + $table->foreign('bodega_id')->references('id')->on('bodegas')->nullOnDelete(); + }); + } + + public function down(): void + { + Schema::table('inventario_prenda_distribuciones', function (Blueprint $table) { + $table->dropForeign(['bodega_id']); + $table->unsignedBigInteger('bodega_id')->nullable(false)->change(); + $table->foreign('bodega_id')->references('id')->on('bodegas')->cascadeOnDelete(); + }); + } +}; \ No newline at end of file diff --git a/resources/views/filament/orden_produccion/timeline.blade.php b/resources/views/filament/orden_produccion/timeline.blade.php index 1200172..cab44b3 100644 --- a/resources/views/filament/orden_produccion/timeline.blade.php +++ b/resources/views/filament/orden_produccion/timeline.blade.php @@ -11,7 +11,7 @@ if ($op) { 'tipo' => 'Confección', 'id' => $c->id, 'fecha' => $c->fecha_envio ?? $c->created_at, - 'detalle' => "Enviado: {$c->cantidad_enviada} - Recibido total: {$c->recibido_total} - Defectos: {$c->prendas_defectuosas}", + 'detalle' => "Enviado: {$c->cantidad_enviada} - Recibido total: {$c->recibido_total} - Faltantes: {$c->prendas_defectuosas}", 'link' => route('filament.admin.resources.confeccions.edit', ['record' => $c->id]), ]; @@ -148,7 +148,7 @@ if ($op) {