From 7257a2d79574075bb827a2a92de6794d76de2806 Mon Sep 17 00:00:00 2001 From: Juan Felipe Duarte Date: Thu, 15 Jan 2026 01:36:26 -0500 Subject: [PATCH] update --- app/Filament/Resources/ConfeccionResource.php | 139 ++++++++++++++++ .../Pages/CreateConfeccion.php | 12 ++ .../Pages/EditConfeccion.php | 19 +++ .../Pages/ListConfeccions.php | 19 +++ .../Resources/InventarioPrendaResource.php | 119 ++++++++++++++ .../Pages/CreateInventarioPrenda.php | 12 ++ .../Pages/EditInventarioPrenda.php | 19 +++ .../Pages/ListInventarioPrendas.php | 19 +++ .../Resources/OrdenProduccionResource.php | 145 +++++++++++++++++ .../Pages/CreateOrdenProduccion.php | 12 ++ .../Pages/EditOrdenProduccion.php | 19 +++ .../Pages/ListOrdenProduccions.php | 19 +++ .../Resources/ProcesoAcabadoResource.php | 136 ++++++++++++++++ .../Pages/CreateProcesoAcabado.php | 12 ++ .../Pages/EditProcesoAcabado.php | 19 +++ .../Pages/ListProcesoAcabados.php | 19 +++ app/Filament/Resources/ProveedorResource.php | 63 +++++--- app/Filament/Resources/TelaResource.php | 148 ++++++++++++++++++ .../TelaResource/Pages/CreateTela.php | 12 ++ .../Resources/TelaResource/Pages/EditTela.php | 19 +++ .../TelaResource/Pages/ListTelas.php | 19 +++ .../Resources/TintoreriaProcesoResource.php | 134 ++++++++++++++++ .../Pages/CreateTintoreriaProceso.php | 12 ++ .../Pages/EditTintoreriaProceso.php | 19 +++ .../Pages/ListTintoreriaProcesos.php | 19 +++ app/Models/Confeccion.php | 60 +++++++ app/Models/InventarioPrenda.php | 32 ++++ app/Models/OrdenProduccion.php | 57 +++++++ app/Models/ProcesoAcabado.php | 54 +++++++ app/Models/Proveedor.php | 14 +- app/Models/Tela.php | 31 ++++ app/Models/TintoreriaProceso.php | 52 ++++++ ...6_01_08_195707_update_proveedors_table.php | 38 +++++ .../2026_01_08_213226_create_telas_table.php | 46 ++++++ ..._141018_create_orden_produccions_table.php | 43 +++++ ..._01_10_144223_create_confeccions_table.php | 48 ++++++ ...45007_create_tintoreria_procesos_table.php | 53 +++++++ ...0_145214_create_proceso_acabados_table.php | 47 ++++++ ...145440_create_inventario_prendas_table.php | 44 ++++++ 39 files changed, 1769 insertions(+), 34 deletions(-) create mode 100644 app/Filament/Resources/ConfeccionResource.php create mode 100644 app/Filament/Resources/ConfeccionResource/Pages/CreateConfeccion.php create mode 100644 app/Filament/Resources/ConfeccionResource/Pages/EditConfeccion.php create mode 100644 app/Filament/Resources/ConfeccionResource/Pages/ListConfeccions.php create mode 100644 app/Filament/Resources/InventarioPrendaResource.php create mode 100644 app/Filament/Resources/InventarioPrendaResource/Pages/CreateInventarioPrenda.php create mode 100644 app/Filament/Resources/InventarioPrendaResource/Pages/EditInventarioPrenda.php create mode 100644 app/Filament/Resources/InventarioPrendaResource/Pages/ListInventarioPrendas.php create mode 100644 app/Filament/Resources/OrdenProduccionResource.php create mode 100644 app/Filament/Resources/OrdenProduccionResource/Pages/CreateOrdenProduccion.php create mode 100644 app/Filament/Resources/OrdenProduccionResource/Pages/EditOrdenProduccion.php create mode 100644 app/Filament/Resources/OrdenProduccionResource/Pages/ListOrdenProduccions.php create mode 100644 app/Filament/Resources/ProcesoAcabadoResource.php create mode 100644 app/Filament/Resources/ProcesoAcabadoResource/Pages/CreateProcesoAcabado.php create mode 100644 app/Filament/Resources/ProcesoAcabadoResource/Pages/EditProcesoAcabado.php create mode 100644 app/Filament/Resources/ProcesoAcabadoResource/Pages/ListProcesoAcabados.php create mode 100644 app/Filament/Resources/TelaResource.php create mode 100644 app/Filament/Resources/TelaResource/Pages/CreateTela.php create mode 100644 app/Filament/Resources/TelaResource/Pages/EditTela.php create mode 100644 app/Filament/Resources/TelaResource/Pages/ListTelas.php create mode 100644 app/Filament/Resources/TintoreriaProcesoResource.php create mode 100644 app/Filament/Resources/TintoreriaProcesoResource/Pages/CreateTintoreriaProceso.php create mode 100644 app/Filament/Resources/TintoreriaProcesoResource/Pages/EditTintoreriaProceso.php create mode 100644 app/Filament/Resources/TintoreriaProcesoResource/Pages/ListTintoreriaProcesos.php create mode 100644 app/Models/Confeccion.php create mode 100644 app/Models/InventarioPrenda.php create mode 100644 app/Models/OrdenProduccion.php create mode 100644 app/Models/ProcesoAcabado.php create mode 100644 app/Models/Tela.php create mode 100644 app/Models/TintoreriaProceso.php create mode 100644 database/migrations/2026_01_08_195707_update_proveedors_table.php create mode 100644 database/migrations/2026_01_08_213226_create_telas_table.php create mode 100644 database/migrations/2026_01_10_141018_create_orden_produccions_table.php create mode 100644 database/migrations/2026_01_10_144223_create_confeccions_table.php create mode 100644 database/migrations/2026_01_10_145007_create_tintoreria_procesos_table.php create mode 100644 database/migrations/2026_01_10_145214_create_proceso_acabados_table.php create mode 100644 database/migrations/2026_01_10_145440_create_inventario_prendas_table.php diff --git a/app/Filament/Resources/ConfeccionResource.php b/app/Filament/Resources/ConfeccionResource.php new file mode 100644 index 0000000..39efb16 --- /dev/null +++ b/app/Filament/Resources/ConfeccionResource.php @@ -0,0 +1,139 @@ +schema([ + Section::make('Datos de Confección') + ->schema([ + Select::make('proveedor_id') + ->label('Tallerista') + ->relationship( + 'proveedor', + 'nombre', + fn($query) => $query->where('categoria', 'talleres') + ) + ->searchable() + ->preload() + ->required(), + + Select::make('orden_produccion_id') + ->label('Orden de Producción') + ->relationship('ordenProduccion', 'numero_orden') + ->searchable() + ->preload() + ->required(), + + DatePicker::make('fecha_envio') + ->required(), + + TextInput::make('cantidad_enviada') + ->numeric() + ->required(), + + DatePicker::make('fecha_recepcion'), + + TextInput::make('cantidad_recibida') + ->numeric(), + + TextInput::make('prendas_defectuosas') + ->numeric() + ->default(0), + + TextInput::make('valor_por_prenda') + ->numeric() + ->prefix('$') + ->required(), + + TextInput::make('total_pagar') + ->prefix('$'), + ]) + ->columns(2), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('ordenProduccion.numero_orden') + ->label('OP') + ->searchable(), + + TextColumn::make('proveedor.nombre') + ->label('Tallerista') + ->searchable(), + + TextColumn::make('cantidad_enviada'), + + TextColumn::make('cantidad_recibida'), + + BadgeColumn::make('estado') + ->colors([ + 'warning' => 'pendiente', + 'info' => 'parcial', + 'success' => 'completo', + ]) + ->formatStateUsing(fn($state) => ucfirst($state)), + + TextColumn::make('total_pagar') + ->money('COP'), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListConfeccions::route('/'), + 'create' => Pages\CreateConfeccion::route('/create'), + 'edit' => Pages\EditConfeccion::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ConfeccionResource/Pages/CreateConfeccion.php b/app/Filament/Resources/ConfeccionResource/Pages/CreateConfeccion.php new file mode 100644 index 0000000..ecdd419 --- /dev/null +++ b/app/Filament/Resources/ConfeccionResource/Pages/CreateConfeccion.php @@ -0,0 +1,12 @@ +schema([ + Section::make('Ingreso a Inventario') + ->schema([ + Select::make('orden_produccion_id') + ->label('Orden de Producción') + ->relationship('ordenProduccion', 'numero_orden') + ->searchable() + ->required(), + + TextInput::make('cantidad_terminada') + ->numeric() + ->required(), + + TextInput::make('cantidad_disponible') + ->disabled() + ->dehydrated(false), + + DatePicker::make('fecha_ingreso') + ->required(), + + Select::make('estado') + ->options([ + 'en_bodega' => 'En bodega', + 'lista_despacho' => 'Lista para despacho', + ]) + ->required(), + ]) + ->columns(2), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('ordenProduccion.numero_orden') + ->label('OP') + ->searchable(), + + TextColumn::make('cantidad_terminada'), + + TextColumn::make('cantidad_disponible'), + + TextColumn::make('fecha_ingreso') + ->date(), + + BadgeColumn::make('estado') + ->formatStateUsing(fn ($state) => match ($state) { + 'en_bodega' => 'En bodega', + 'lista_despacho' => 'Lista para despacho', + }) + ->colors([ + 'secondary' => 'en_bodega', + 'success' => 'lista_despacho', + ]), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListInventarioPrendas::route('/'), + 'create' => Pages\CreateInventarioPrenda::route('/create'), + 'edit' => Pages\EditInventarioPrenda::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/InventarioPrendaResource/Pages/CreateInventarioPrenda.php b/app/Filament/Resources/InventarioPrendaResource/Pages/CreateInventarioPrenda.php new file mode 100644 index 0000000..c42752d --- /dev/null +++ b/app/Filament/Resources/InventarioPrendaResource/Pages/CreateInventarioPrenda.php @@ -0,0 +1,12 @@ +schema([ + Section::make('Datos de la Orden') + ->schema([ + TextInput::make('prenda_modelo') + ->label('Prenda / Modelo') + ->required() + ->maxLength(255), + + TextInput::make('referencia') + ->required() + ->maxLength(255), + + TextInput::make('cantidad_total') + ->numeric() + ->required() + ->minValue(1), + + Select::make('tela_id') + ->label('Tela asociada') + ->relationship('tela', 'codigo') + ->searchable() + ->preload() + ->nullable(), + + DatePicker::make('fecha_inicio') + ->required(), + + DatePicker::make('fecha_entrega_estimada') + ->required(), + ]) + ->columns(2), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('numero_orden') + ->label('OP') + ->sortable(), + + TextColumn::make('prenda_modelo') + ->searchable(), + + TextColumn::make('referencia') + ->searchable(), + + TextColumn::make('cantidad_total') + ->label('Cantidad'), + + TextColumn::make('tela.codigo') + ->label('Tela') + ->toggleable(), + + BadgeColumn::make('estado') + ->colors([ + 'warning' => 'en_corte', + 'info' => 'en_confeccion', + 'primary' => 'en_tintoreria', + 'secondary' => 'en_acabados', + 'success' => 'finalizada', + ]) + ->formatStateUsing(fn($state) => match ($state) { + 'en_corte' => 'En corte', + 'en_confeccion' => 'En confección', + 'en_tintoreria' => 'En tintorería', + 'en_acabados' => 'En acabados', + 'finalizada' => 'Finalizada', + }), + + TextColumn::make('fecha_entrega_estimada') + ->date(), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + // Tables\Actions\Action::make('avanzar') + // ->label('Avanzar estado') + // ->icon('heroicon-o-arrow-right') + // ->requiresConfirmation() + // ->visible(fn($record) => $record->estado !== 'finalizada') + // ->action(fn($record) => $record->avanzarEstado()), + + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListOrdenProduccions::route('/'), + 'create' => Pages\CreateOrdenProduccion::route('/create'), + 'edit' => Pages\EditOrdenProduccion::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/OrdenProduccionResource/Pages/CreateOrdenProduccion.php b/app/Filament/Resources/OrdenProduccionResource/Pages/CreateOrdenProduccion.php new file mode 100644 index 0000000..d66dd1d --- /dev/null +++ b/app/Filament/Resources/OrdenProduccionResource/Pages/CreateOrdenProduccion.php @@ -0,0 +1,12 @@ +schema([ + Section::make('Proceso de Acabado') + ->schema([ + Select::make('orden_produccion_id') + ->label('Orden de Producción') + ->relationship('ordenProduccion', 'numero_orden') + ->searchable() + ->required(), + + TextInput::make('tipo_proceso') + ->label('Tipo de proceso') + ->required(), + + Select::make('proveedor_id') + ->label('Proveedor (opcional)') + ->relationship('proveedor', 'nombre') + ->searchable() + ->nullable(), + + TextInput::make('responsable_interno') + ->label('Responsable interno') + ->nullable(), + + TextInput::make('cantidad_enviada') + ->numeric() + ->required(), + + TextInput::make('cantidad_recibida') + ->numeric(), + + DatePicker::make('fecha_envio') + ->required(), + + DatePicker::make('fecha_recepcion'), + + Textarea::make('observaciones') + ->columnSpanFull(), + ]) + ->columns(2), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('ordenProduccion.numero_orden') + ->label('OP') + ->searchable(), + + TextColumn::make('tipo_proceso'), + + TextColumn::make('proveedor.nombre') + ->label('Proveedor') + ->toggleable(), + + TextColumn::make('responsable_interno') + ->toggleable(), + + TextColumn::make('cantidad_enviada'), + + TextColumn::make('cantidad_recibida'), + + BadgeColumn::make('fecha_recepcion') + ->label('Estado') + ->formatStateUsing(fn($state) => $state ? 'Completado' : 'Pendiente') + ->colors([ + 'warning' => null, + 'success' => fn($state) => $state !== null, + ]), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListProcesoAcabados::route('/'), + 'create' => Pages\CreateProcesoAcabado::route('/create'), + 'edit' => Pages\EditProcesoAcabado::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ProcesoAcabadoResource/Pages/CreateProcesoAcabado.php b/app/Filament/Resources/ProcesoAcabadoResource/Pages/CreateProcesoAcabado.php new file mode 100644 index 0000000..e2102d6 --- /dev/null +++ b/app/Filament/Resources/ProcesoAcabadoResource/Pages/CreateProcesoAcabado.php @@ -0,0 +1,12 @@ +required() ->maxLength(255), - Forms\Components\TextInput::make('contacto') + Forms\Components\TextInput::make('nit') + ->maxLength(255), + Select::make('categoria') + ->label('Categoría') + ->options([ + 'tintoreria' => 'Tintorería', + 'talleres' => 'Talleres', + 'telas' => 'Telas', + 'otros' => 'Otros', + ]) + ->required(), Forms\Components\TextInput::make('telefono') ->tel() - ->maxLength(20), - Forms\Components\TextInput::make('correo') - ->maxLength(255), - Forms\Components\Textarea::make('direccion') - ->columnSpanFull(), + ->maxLength(20)->required(), + Forms\Components\Textarea::make('direccion'), ]); } @@ -48,28 +55,40 @@ class ProveedorResource extends Resource return $table ->columns([ Tables\Columns\TextColumn::make('nombre') + ->label('Nombre') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('nit') + ->label('NIT') ->searchable(), - Tables\Columns\TextColumn::make('contacto') - ->searchable(), + + Tables\Columns\BadgeColumn::make('categoria') + ->label('Categoría') + ->colors([ + 'primary' => 'tintoreria', + 'success' => 'talleres', + 'warning' => 'telas', + 'gray' => 'otros', + ]) + ->sortable(), + Tables\Columns\TextColumn::make('telefono') + ->label('Teléfono') ->searchable(), - Tables\Columns\TextColumn::make('correo') - ->searchable(), + + Tables\Columns\TextColumn::make('direccion') + ->label('Dirección') + ->limit(30) + ->toggleable(), + Tables\Columns\TextColumn::make('created_at') - ->dateTime() - ->sortable() - ->toggleable(isToggledHiddenByDefault: true), - Tables\Columns\TextColumn::make('updated_at') + ->label('Creado') ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) - ->paginated(true) - //->paginationPageOptions([50]) ->defaultSort('created_at', 'desc') - ->filters([ - // - ]) ->actions([ Tables\Actions\EditAction::make(), ]) diff --git a/app/Filament/Resources/TelaResource.php b/app/Filament/Resources/TelaResource.php new file mode 100644 index 0000000..94098ee --- /dev/null +++ b/app/Filament/Resources/TelaResource.php @@ -0,0 +1,148 @@ +schema([ + + TextInput::make('codigo')->required()->unique(ignoreRecord: true), + + Select::make('tipo') + ->options([ + 'algodon' => 'Algodón', + 'poliester' => 'Poliéster', + 'denim' => 'Denim', + ]) + ->required(), + + FileUpload::make('foto')->image()->directory('telas')->disk('public')->nullable()->visibility('public')->maxSize(1024)->helperText('Selecciona una imagen de la tela')->acceptedFileTypes(['image/jpeg', 'image/png', 'image/webp'])->downloadable()->openable(), + + ColorPicker::make('color')->default('#000000'), + + Select::make('proveedor_id')->relationship('proveedor', 'nombre')->searchable()->preload()->required(), + + TextInput::make('metros_comprados')->numeric()->required()->live(onBlur: true)->afterStateUpdated(function ($state, Forms\Set $set, $get) { + $valor_total = $get('valor_total'); + $metros_comprados = $state; + + if ($valor_total && $metros_comprados) { + $costo_por_metro = $valor_total / $metros_comprados; + $set('costo_por_metro', $costo_por_metro); + } + }), + + TextInput::make('valor_total')->numeric()->required()->prefix('$')->live(onBlur: true) + ->afterStateUpdated(function ($state, Forms\Set $set, $get) { + $metros_comprados = $get('metros_comprados'); + $valor_total = $state; + + if ($metros_comprados && $valor_total) { + $costo_por_metro = $valor_total / $metros_comprados; + $set('costo_por_metro', $costo_por_metro); + } + }), + + TextInput::make('costo_por_metro')->numeric()->prefix('$')->readOnly()->dehydrated()->default(0), + + TextInput::make('metros_disponibles')->numeric() + ->default(function ($get) { + return $get('metros_comprados'); + }), + + DatePicker::make('fecha_compra')->required(), + + Textarea::make('observaciones')->columnSpanFull(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('codigo') + ->searchable(), + Tables\Columns\TextColumn::make('tipo') + ->searchable(), + Tables\Columns\TextColumn::make('color') + ->searchable(), + Tables\Columns\TextColumn::make('proveedor.nombre') + ->searchable(), + Tables\Columns\TextColumn::make('metros_comprados') + ->numeric(), + Tables\Columns\TextColumn::make('metros_disponibles') + ->numeric(), + Tables\Columns\TextColumn::make('valor_total') + ->money('USD') + ->sortable(), + Tables\Columns\TextColumn::make('costo_por_metro') + ->money('USD') + ->sortable(), + Tables\Columns\TextColumn::make('fecha_compra') + ->date() + ->sortable(), + ]) + ->filters([ + Tables\Filters\SelectFilter::make('tipo') + ->options([ + 'algodon' => 'Algodón', + 'poliester' => 'Poliéster', + 'denim' => 'Denim', + ]), + Tables\Filters\SelectFilter::make('proveedor_id') + ->relationship('proveedor', 'nombre') + ->searchable() + ->preload(), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListTelas::route('/'), + 'create' => Pages\CreateTela::route('/create'), + 'edit' => Pages\EditTela::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/TelaResource/Pages/CreateTela.php b/app/Filament/Resources/TelaResource/Pages/CreateTela.php new file mode 100644 index 0000000..bba9523 --- /dev/null +++ b/app/Filament/Resources/TelaResource/Pages/CreateTela.php @@ -0,0 +1,12 @@ +schema([ + Section::make('Proceso de Tintorería') + ->schema([ + Select::make('proveedor_id') + ->label('Tintorería') + ->relationship( + 'proveedor', + 'nombre', + fn($query) => $query->where('categoria', 'tintoreria') + ) + ->searchable() + ->required(), + + Select::make('orden_produccion_id') + ->label('Orden de Producción') + ->relationship('ordenProduccion', 'numero_orden') + ->searchable() + ->required(), + + TextInput::make('tipo_proceso') + ->label('Tipo de proceso') + ->required(), + + DatePicker::make('fecha_envio') + ->required(), + + TextInput::make('cantidad_enviada') + ->numeric() + ->required(), + + DatePicker::make('fecha_recepcion'), + + TextInput::make('cantidad_recibida') + ->numeric(), + + TextInput::make('perdidas') + ->disabled() + ->dehydrated(false), + + Textarea::make('observaciones') + ->columnSpanFull(), + ]) + ->columns(2), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('ordenProduccion.numero_orden') + ->label('OP') + ->searchable(), + + TextColumn::make('proveedor.nombre') + ->label('Tintorería') + ->searchable(), + + TextColumn::make('tipo_proceso'), + + TextColumn::make('cantidad_enviada'), + + TextColumn::make('cantidad_recibida'), + + TextColumn::make('perdidas') + ->label('Pérdidas'), + + TextColumn::make('fecha_recepcion') + ->date(), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListTintoreriaProcesos::route('/'), + 'create' => Pages\CreateTintoreriaProceso::route('/create'), + 'edit' => Pages\EditTintoreriaProceso::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/TintoreriaProcesoResource/Pages/CreateTintoreriaProceso.php b/app/Filament/Resources/TintoreriaProcesoResource/Pages/CreateTintoreriaProceso.php new file mode 100644 index 0000000..9578fb5 --- /dev/null +++ b/app/Filament/Resources/TintoreriaProcesoResource/Pages/CreateTintoreriaProceso.php @@ -0,0 +1,12 @@ +belongsTo(Proveedor::class); + } + + public function ordenProduccion() + { + return $this->belongsTo(OrdenProduccion::class); + } + + /* Lógica de negocio */ + protected static function booted() + { + static::saving(function ($confeccion) { + // Total a pagar + if ($confeccion->cantidad_recibida !== null) { + $confeccion->total_pagar = + $confeccion->cantidad_recibida * $confeccion->valor_por_prenda; + } + + // Estado automático + if (!$confeccion->cantidad_recibida) { + $confeccion->estado = 'pendiente'; + } elseif ($confeccion->cantidad_recibida < $confeccion->cantidad_enviada) { + $confeccion->estado = 'parcial'; + } else { + $confeccion->estado = 'completo'; + } + }); + + // Cuando se completa la confección → avanzar OP + static::updated(function ($confeccion) { + if ($confeccion->estado === 'completo') { + $confeccion->ordenProduccion?->avanzarEstado(); + } + }); + } +} diff --git a/app/Models/InventarioPrenda.php b/app/Models/InventarioPrenda.php new file mode 100644 index 0000000..5c7f324 --- /dev/null +++ b/app/Models/InventarioPrenda.php @@ -0,0 +1,32 @@ +belongsTo(OrdenProduccion::class); + } + + protected static function booted() + { + static::creating(function ($inventario) { + // Al ingresar al inventario, todo está disponible + $inventario->cantidad_disponible = $inventario->cantidad_terminada; + + // Estado automático inicial + $inventario->estado = 'en_bodega'; + }); + } +} diff --git a/app/Models/OrdenProduccion.php b/app/Models/OrdenProduccion.php new file mode 100644 index 0000000..dc2b221 --- /dev/null +++ b/app/Models/OrdenProduccion.php @@ -0,0 +1,57 @@ +belongsTo(Tela::class); + } + + public function avanzarEstado(): void + { + $flujo = [ + 'en_corte', + 'en_confeccion', + 'en_tintoreria', + 'en_acabados', + 'finalizada', + ]; + + $actual = array_search($this->estado, $flujo, true); + + if ($actual !== false && isset($flujo[$actual + 1])) { + $this->update([ + 'estado' => $flujo[$actual + 1], + ]); + } + } + + protected static function booted() + { + static::creating(function ($orden) { + if (!$orden->numero_orden) { + $ultimoId = self::max('id') + 1; + + $orden->numero_orden = 'OP-' . str_pad($ultimoId, 6, '0', STR_PAD_LEFT); + } + }); + } +} diff --git a/app/Models/ProcesoAcabado.php b/app/Models/ProcesoAcabado.php new file mode 100644 index 0000000..4af7b08 --- /dev/null +++ b/app/Models/ProcesoAcabado.php @@ -0,0 +1,54 @@ +belongsTo(OrdenProduccion::class); + } + + public function proveedor() + { + return $this->belongsTo(Proveedor::class); + } + + /* Lógica de negocio */ + protected static function booted() + { + // Cuando se recibe el proceso + static::updated(function ($acabado) { + if ( + $acabado->fecha_recepcion && + $acabado->cantidad_recibida !== null + ) { + // Validar si ya no quedan procesos pendientes + $pendientes = self::where('orden_produccion_id', $acabado->orden_produccion_id) + ->whereNull('fecha_recepcion') + ->exists(); + + if (!$pendientes) { + $acabado->ordenProduccion?->update([ + 'estado' => 'finalizada', + ]); + } + } + }); + } +} diff --git a/app/Models/Proveedor.php b/app/Models/Proveedor.php index 78c4c0c..78f67f4 100644 --- a/app/Models/Proveedor.php +++ b/app/Models/Proveedor.php @@ -9,24 +9,14 @@ class Proveedor extends Model { use HasFactory; - /** - * The attributes that are mass assignable. - * - * @var array - */ protected $fillable = [ 'nombre', - 'contacto', + 'nit', + 'categoria', 'telefono', - 'correo', 'direccion', ]; - /** - * The attributes that should be cast to native types. - * - * @var array - */ protected $casts = [ 'id' => 'integer', ]; diff --git a/app/Models/Tela.php b/app/Models/Tela.php new file mode 100644 index 0000000..55dfd28 --- /dev/null +++ b/app/Models/Tela.php @@ -0,0 +1,31 @@ + 'string', + ]; + + public function proveedor() + { + return $this->belongsTo(Proveedor::class); + } +} diff --git a/app/Models/TintoreriaProceso.php b/app/Models/TintoreriaProceso.php new file mode 100644 index 0000000..600634e --- /dev/null +++ b/app/Models/TintoreriaProceso.php @@ -0,0 +1,52 @@ +belongsTo(Proveedor::class); + } + + public function ordenProduccion() + { + return $this->belongsTo(OrdenProduccion::class); + } + + /* Lógica de negocio */ + protected static function booted() + { + static::saving(function ($tintoreria) { + if ($tintoreria->cantidad_recibida !== null) { + $tintoreria->perdidas = + $tintoreria->cantidad_enviada - $tintoreria->cantidad_recibida; + } + }); + + // Cuando vuelve de tintorería → avanzar OP + static::updated(function ($tintoreria) { + if ( + $tintoreria->fecha_recepcion && + $tintoreria->cantidad_recibida !== null + ) { + $tintoreria->ordenProduccion?->avanzarEstado(); + } + }); + } +} diff --git a/database/migrations/2026_01_08_195707_update_proveedors_table.php b/database/migrations/2026_01_08_195707_update_proveedors_table.php new file mode 100644 index 0000000..a10ff0c --- /dev/null +++ b/database/migrations/2026_01_08_195707_update_proveedors_table.php @@ -0,0 +1,38 @@ +string('nit')->nullable()->after('nombre'); + $table->string('categoria')->after('nit'); + + // Eliminar campos que no se usarán + $table->dropColumn(['contacto', 'correo']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('proveedors', function (Blueprint $table) { + // Restaurar columnas eliminadas + $table->string('contacto')->nullable(); + $table->string('correo')->unique()->nullable(); + + // Eliminar columnas nuevas + $table->dropColumn(['nit', 'categoria']); + }); + } +}; diff --git a/database/migrations/2026_01_08_213226_create_telas_table.php b/database/migrations/2026_01_08_213226_create_telas_table.php new file mode 100644 index 0000000..1952a85 --- /dev/null +++ b/database/migrations/2026_01_08_213226_create_telas_table.php @@ -0,0 +1,46 @@ +id(); + + $table->string('codigo'); + $table->string('tipo'); + + $table->string('foto')->nullable(); + $table->string('color')->nullable(); + + $table->foreignId('proveedor_id')->constrained('proveedors')->cascadeOnDelete(); + + $table->string('metros_comprados'); + $table->string('metros_disponibles'); + + $table->date('fecha_compra'); + + $table->string('valor_total'); + $table->string('costo_por_metro'); + + $table->text('observaciones')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('telas'); + } +}; diff --git a/database/migrations/2026_01_10_141018_create_orden_produccions_table.php b/database/migrations/2026_01_10_141018_create_orden_produccions_table.php new file mode 100644 index 0000000..8fad6d6 --- /dev/null +++ b/database/migrations/2026_01_10_141018_create_orden_produccions_table.php @@ -0,0 +1,43 @@ +id(); + + $table->string('numero_orden')->unique(); + $table->string('prenda_modelo'); + $table->string('referencia'); + $table->integer('cantidad_total'); + + $table->foreignId('tela_id') + ->nullable() + ->constrained('telas') + ->nullOnDelete(); + + $table->date('fecha_inicio'); + $table->date('fecha_entrega_estimada'); + + $table->enum('estado', [ + 'en_corte', + 'en_confeccion', + 'en_tintoreria', + 'en_acabados', + 'finalizada' + ])->default('en_corte'); + + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('orden_produccions'); + } +}; diff --git a/database/migrations/2026_01_10_144223_create_confeccions_table.php b/database/migrations/2026_01_10_144223_create_confeccions_table.php new file mode 100644 index 0000000..09000dd --- /dev/null +++ b/database/migrations/2026_01_10_144223_create_confeccions_table.php @@ -0,0 +1,48 @@ +id(); + + // Relaciones + $table->foreignId('proveedor_id') + ->constrained('proveedors') + ->cascadeOnDelete(); + + $table->foreignId('orden_produccion_id') + ->constrained('orden_produccions') + ->cascadeOnDelete(); + + // Envío + $table->date('fecha_envio'); + $table->integer('cantidad_enviada'); + + // Recepción + $table->date('fecha_recepcion')->nullable(); + $table->integer('cantidad_recibida')->nullable(); + $table->integer('prendas_defectuosas')->default(0); + + // Costos + $table->decimal('valor_por_prenda', 12, 2); + $table->decimal('total_pagar', 14, 2)->default(0); + + // Estado + $table->enum('estado', ['pendiente', 'parcial', 'completo']) + ->default('pendiente'); + + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('confeccions'); + } +}; diff --git a/database/migrations/2026_01_10_145007_create_tintoreria_procesos_table.php b/database/migrations/2026_01_10_145007_create_tintoreria_procesos_table.php new file mode 100644 index 0000000..8236fcc --- /dev/null +++ b/database/migrations/2026_01_10_145007_create_tintoreria_procesos_table.php @@ -0,0 +1,53 @@ +id(); + + // Relaciones + $table->foreignId('proveedor_id') + ->constrained('proveedors') + ->cascadeOnDelete(); + + $table->foreignId('orden_produccion_id') + ->constrained('orden_produccions') + ->cascadeOnDelete(); + + // Proceso + $table->string('tipo_proceso'); + + // Envío + $table->date('fecha_envio'); + $table->integer('cantidad_enviada'); + + // Recepción + $table->date('fecha_recepcion')->nullable(); + $table->integer('cantidad_recibida')->nullable(); + + // Control + $table->integer('perdidas')->default(0); + + $table->text('observaciones')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tintoreria_procesos'); + } +}; diff --git a/database/migrations/2026_01_10_145214_create_proceso_acabados_table.php b/database/migrations/2026_01_10_145214_create_proceso_acabados_table.php new file mode 100644 index 0000000..89d29b3 --- /dev/null +++ b/database/migrations/2026_01_10_145214_create_proceso_acabados_table.php @@ -0,0 +1,47 @@ +id(); + + $table->foreignId('orden_produccion_id') + ->constrained('orden_produccions') + ->cascadeOnDelete(); + + // Proceso + $table->string('tipo_proceso'); + + // Responsable (opcional proveedor) + $table->foreignId('proveedor_id') + ->nullable() + ->constrained('proveedors') + ->nullOnDelete(); + + $table->string('responsable_interno')->nullable(); + + // Cantidades + $table->integer('cantidad_enviada'); + $table->integer('cantidad_recibida')->nullable(); + + // Fechas + $table->date('fecha_envio'); + $table->date('fecha_recepcion')->nullable(); + + $table->text('observaciones')->nullable(); + + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('proceso_acabados'); + } +}; diff --git a/database/migrations/2026_01_10_145440_create_inventario_prendas_table.php b/database/migrations/2026_01_10_145440_create_inventario_prendas_table.php new file mode 100644 index 0000000..be11ead --- /dev/null +++ b/database/migrations/2026_01_10_145440_create_inventario_prendas_table.php @@ -0,0 +1,44 @@ +id(); + + $table->foreignId('orden_produccion_id') + ->constrained('orden_produccions') + ->cascadeOnDelete(); + + // Cantidades + $table->integer('cantidad_terminada'); + $table->integer('cantidad_disponible'); + + // Control + $table->date('fecha_ingreso'); + + $table->enum('estado', [ + 'lista_despacho', + 'en_bodega' + ])->default('en_bodega'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('inventario_prendas'); + } +};