diff --git a/app/Filament/Resources/SeguimientoProcesoResource.php b/app/Filament/Resources/SeguimientoProcesoResource.php new file mode 100644 index 0000000..bb33e88 --- /dev/null +++ b/app/Filament/Resources/SeguimientoProcesoResource.php @@ -0,0 +1,276 @@ +schema([]); + } + + public static function table(Table $table): Table + { + return $table + ->query( + OrdenProduccion::query() + ->orderBy('created_at', 'desc') + ) + ->columns([ + Tables\Columns\TextColumn::make('numero_orden') + ->label('Orden') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('prenda_modelo') + ->label('Prenda') + ->searchable() + ->limit(30), + + Tables\Columns\TextColumn::make('referencia') + ->label('Referencia') + ->searchable() + ->toggleable(), + + Tables\Columns\TextColumn::make('cantidad_total') + ->label('Total') + ->alignCenter() + ->sortable(), + + Tables\Columns\TextColumn::make('estado') + ->badge() + ->colors([ + 'danger' => 'cancelada', + 'warning' => fn ($state) => in_array($state, ['pendiente', 'en_confeccion', 'en_tintoreria', 'en_acabados']), + 'success' => 'finalizada', + 'primary' => 'en_proceso', + ]), + + Tables\Columns\TextColumn::make('confeccion') + ->label('📦 Confección') + ->alignCenter() + ->state(function (OrdenProduccion $record): string { + $enviadas = $record->confecciones()->sum('cantidad_enviada'); + $recibidas = $record->confecciones() + ->whereNotNull('fecha_recepcion') + ->sum('cantidad_recibida'); + + // Calcular disponibles (recibidas - arreglos - cobros - enviadas a ojales) + $arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class) + ->whereHas('referencia', function($q) use ($record) { + $q->where('orden_produccion_id', $record->id); + })->where('tipo', 'arreglo')->sum('cantidad'); + + $cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class) + ->whereHas('referencia', function($q) use ($record) { + $q->where('orden_produccion_id', $record->id); + })->sum('cantidad'); + + $disponiblesConfeccion = $recibidas - $arreglos - $cobros; + $enviadasOjales = $record->ojales()->sum('cantidad_enviada'); + $pendientes = max(0, $disponiblesConfeccion - $enviadasOjales); + + return "E:{$enviadas} R:{$recibidas} P:{$pendientes}"; + }) + ->color(fn (OrdenProduccion $record) => $this->getPendienteConfeccion($record) > 0 ? 'warning' : 'gray') + ->tooltip('E=Enviadas, R=Recibidas, P=Pendientes'), + + Tables\Columns\TextColumn::make('ojales') + ->label('🔘 Ojales') + ->alignCenter() + ->state(function (OrdenProduccion $record): string { + $enviadas = $record->ojales()->sum('cantidad_enviada'); + $terminadas = $record->ojales()->where('terminada', true)->sum('cantidad_enviada'); + $pendientes = max(0, $enviadas - $terminadas); + + return "E:{$enviadas} T:{$terminadas} P:{$pendientes}"; + }) + ->color(fn (OrdenProduccion $record) => $this->getPendienteOjales($record) > 0 ? 'warning' : 'gray') + ->tooltip('E=Enviadas, T=Terminadas, P=Pendientes'), + + Tables\Columns\TextColumn::make('tintoreria') + ->label('🎨 Tintorería') + ->alignCenter() + ->state(function (OrdenProduccion $record): string { + $enviadas = $record->tintorerias()->sum('cantidad_enviada'); + + $recepciones = 0; + foreach ($record->tintorerias as $tintoreria) { + $recepciones += (int) $tintoreria->recepciones() + ->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + } + + $pendientes = max(0, $enviadas - $recepciones); + + return "E:{$enviadas} R:{$recepciones} P:{$pendientes}"; + }) + ->color(fn (OrdenProduccion $record) => $this->getPendienteTintoreria($record) > 0 ? 'warning' : 'gray') + ->tooltip('E=Enviadas, R=Recibidas, P=Pendientes'), + + Tables\Columns\TextColumn::make('acabados') + ->label('✨ Acabados') + ->alignCenter() + ->state(function (OrdenProduccion $record): string { + // Disponibles desde tintorería + $disponibles = 0; + foreach ($record->tintorerias as $tintoreria) { + $recep = (int) $tintoreria->recepciones() + ->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $reprocesos = (int) $tintoreria->ajustes() + ->where('tipo', 'reproceso')->sum('cantidad'); + $cobros = (int) $tintoreria->cobros()->sum('cantidad'); + $disponibles += ($recep - $reprocesos - $cobros); + } + + $enviadasAcabados = $record->procesosAcabado()->sum('cantidad_enviada'); + $recibidasAcabados = $record->procesosAcabado() + ->whereNotNull('fecha_recepcion') + ->sum('cantidad_recibida'); + $pendientes = max(0, $disponibles - $enviadasAcabados); + + return "D:{$disponibles} E:{$enviadasAcabados} P:{$pendientes}"; + }) + ->color(fn (OrdenProduccion $record) => $this->getPendienteAcabados($record) > 0 ? 'warning' : 'gray') + ->tooltip('D=Disponibles, E=Enviadas, P=Pendientes'), + + Tables\Columns\TextColumn::make('bodega') + ->label('📦 Bodega') + ->alignCenter() + ->state(function (OrdenProduccion $record): string { + $total = $record->inventarioPrenda()->sum('cantidad_terminada'); + $disponible = $record->inventarioPrenda()->sum('cantidad_disponible'); + + return "T:{$total} D:{$disponible}"; + }) + ->color(fn (OrdenProduccion $record) => $this->getEnBodega($record) > 0 ? 'success' : 'gray') + ->tooltip('T=Total, D=Disponible'), + ]) + ->filters([ + Tables\Filters\SelectFilter::make('estado') + ->options([ + 'pendiente' => 'Pendiente', + 'en_proceso' => 'En Proceso', + 'en_confeccion' => 'En Confección', + 'en_tintoreria' => 'En Tintorería', + 'en_acabados' => 'En Acabados', + 'finalizada' => 'Finalizada', + 'cancelada' => 'Cancelada', + ]), + + Tables\Filters\Filter::make('con_pendientes') + ->label('Solo con pendientes') + ->query(fn (Builder $query) => $query->whereIn('estado', ['en_proceso', 'en_confeccion', 'en_tintoreria', 'en_acabados'])), + ]) + ->actions([]) + ->bulkActions([]) + ->defaultSort('created_at', 'desc') + ->paginated([10, 25, 50, 100]) + ->poll('30s'); + } + + protected static function getPendienteConfeccion(OrdenProduccion $record): int + { + $recibidas = $record->confecciones() + ->whereNotNull('fecha_recepcion') + ->sum('cantidad_recibida'); + + $arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class) + ->whereHas('referencia', function($q) use ($record) { + $q->where('orden_produccion_id', $record->id); + })->where('tipo', 'arreglo')->sum('cantidad'); + + $cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class) + ->whereHas('referencia', function($q) use ($record) { + $q->where('orden_produccion_id', $record->id); + })->sum('cantidad'); + + $disponiblesConfeccion = $recibidas - $arreglos - $cobros; + $enviadasOjales = $record->ojales()->sum('cantidad_enviada'); + + return max(0, $disponiblesConfeccion - $enviadasOjales); + } + + protected static function getPendienteOjales(OrdenProduccion $record): int + { + $enviadas = $record->ojales()->sum('cantidad_enviada'); + $terminadas = $record->ojales()->where('terminada', true)->sum('cantidad_enviada'); + + return max(0, $enviadas - $terminadas); + } + + protected static function getPendienteTintoreria(OrdenProduccion $record): int + { + $enviadas = $record->tintorerias()->sum('cantidad_enviada'); + + $recepciones = 0; + foreach ($record->tintorerias as $tintoreria) { + $recepciones += (int) $tintoreria->recepciones() + ->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + } + + return max(0, $enviadas - $recepciones); + } + + protected static function getPendienteAcabados(OrdenProduccion $record): int + { + $disponibles = 0; + foreach ($record->tintorerias as $tintoreria) { + $recep = (int) $tintoreria->recepciones() + ->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $reprocesos = (int) $tintoreria->ajustes() + ->where('tipo', 'reproceso')->sum('cantidad'); + $cobros = (int) $tintoreria->cobros()->sum('cantidad'); + $disponibles += ($recep - $reprocesos - $cobros); + } + + $enviadasAcabados = $record->procesosAcabado()->sum('cantidad_enviada'); + + return max(0, $disponibles - $enviadasAcabados); + } + + protected static function getEnBodega(OrdenProduccion $record): int + { + return $record->inventarioPrenda()->sum('cantidad_disponible'); + } + + public static function getRelations(): array + { + return []; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListSeguimientoProcesos::route('/'), + ]; + } +} diff --git a/app/Filament/Resources/SeguimientoProcesoResource/Pages/ListSeguimientoProcesos.php b/app/Filament/Resources/SeguimientoProcesoResource/Pages/ListSeguimientoProcesos.php new file mode 100644 index 0000000..bdbca7e --- /dev/null +++ b/app/Filament/Resources/SeguimientoProcesoResource/Pages/ListSeguimientoProcesos.php @@ -0,0 +1,16 @@ +query( + OrdenProduccion::query() + ->whereIn('estado', ['en_proceso', 'en_confeccion', 'en_tintoreria', 'en_acabados']) + ->orderBy('created_at', 'desc') + ) + ->columns([ + Tables\Columns\TextColumn::make('numero_orden') + ->label('Orden') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('prenda_modelo') + ->label('Prenda') + ->searchable() + ->limit(30), + + Tables\Columns\TextColumn::make('cantidad_total') + ->label('Total OP') + ->alignCenter(), + + Tables\Columns\TextColumn::make('pendiente_confeccion') + ->label('Pend. Confección') + ->alignCenter() + ->state(function (OrdenProduccion $record): int { + // Recibidas en confección - Enviadas a ojales + $recibidas = $record->confecciones() + ->whereNotNull('fecha_recepcion') + ->sum('cantidad_recibida'); + + // Restamos arreglos y cobros de confección + $arreglos = \App\Models\Ajuste::where('referencia_type', \App\Models\Confeccion::class) + ->whereHas('referencia', function($q) use ($record) { + $q->where('orden_produccion_id', $record->id); + })->where('tipo', 'arreglo')->sum('cantidad'); + + $cobros = \App\Models\Cobro::where('referencia_type', \App\Models\Confeccion::class) + ->whereHas('referencia', function($q) use ($record) { + $q->where('orden_produccion_id', $record->id); + })->sum('cantidad'); + + $disponiblesConfeccion = $recibidas - $arreglos - $cobros; + + $enviadasOjales = $record->ojales()->sum('cantidad_enviada'); + + return max(0, $disponiblesConfeccion - $enviadasOjales); + }) + ->color(fn ($state) => $state > 0 ? 'warning' : 'gray') + ->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'), + + Tables\Columns\TextColumn::make('pendiente_ojales') + ->label('Pend. Ojales') + ->alignCenter() + ->state(function (OrdenProduccion $record): int { + // Enviadas a ojales - Terminadas en ojales + $enviadas = $record->ojales()->sum('cantidad_enviada'); + $terminadas = $record->ojales() + ->where('terminada', true) + ->sum('cantidad_enviada'); + + return max(0, $enviadas - $terminadas); + }) + ->color(fn ($state) => $state > 0 ? 'warning' : 'gray') + ->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'), + + Tables\Columns\TextColumn::make('pendiente_tintoreria') + ->label('Pend. Tintorería') + ->alignCenter() + ->state(function (OrdenProduccion $record): int { + // Enviadas a tintorería - Recibidas de tintorería + $enviadas = $record->tintorerias() + ->sum('cantidad_enviada'); + + $recepciones = 0; + foreach ($record->tintorerias as $tintoreria) { + $recepciones += (int) $tintoreria->recepciones() + ->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + } + + return max(0, $enviadas - $recepciones); + }) + ->color(fn ($state) => $state > 0 ? 'warning' : 'gray') + ->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'), + + Tables\Columns\TextColumn::make('pendiente_acabados') + ->label('Pend. Acabados') + ->alignCenter() + ->state(function (OrdenProduccion $record): int { + // Disponibles desde tintorería - Enviadas a acabados + $recepciones = 0; + foreach ($record->tintorerias as $tintoreria) { + $recep = (int) $tintoreria->recepciones() + ->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)')); + $reprocesos = (int) $tintoreria->ajustes() + ->where('tipo', 'reproceso')->sum('cantidad'); + $cobros = (int) $tintoreria->cobros()->sum('cantidad'); + $recepciones += ($recep - $reprocesos - $cobros); + } + + $enviadasAcabados = $record->procesosAcabado() + ->sum('cantidad_enviada'); + + return max(0, $recepciones - $enviadasAcabados); + }) + ->color(fn ($state) => $state > 0 ? 'warning' : 'gray') + ->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'), + + Tables\Columns\TextColumn::make('en_bodega') + ->label('En Bodega') + ->alignCenter() + ->state(function (OrdenProduccion $record): int { + // Inventario disponible + return $record->inventarioPrenda() + ->sum('cantidad_disponible'); + }) + ->color(fn ($state) => $state > 0 ? 'success' : 'gray') + ->weight(fn ($state) => $state > 0 ? 'bold' : 'normal'), + ]) + ->paginated([10, 25, 50]) + ->defaultPaginationPageOption(25); + } +}