up
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\SeguimientoProcesoResource\Pages;
|
||||
use App\Models\OrdenProduccion;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class SeguimientoProcesoResource extends Resource
|
||||
{
|
||||
protected static ?string $model = OrdenProduccion::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-chart-bar';
|
||||
|
||||
protected static ?string $navigationLabel = 'Seguimiento de Procesos';
|
||||
|
||||
protected static ?string $modelLabel = 'Seguimiento de Proceso';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Seguimiento de Procesos';
|
||||
|
||||
protected static ?string $navigationGroup = 'Reportes';
|
||||
|
||||
protected static ?int $navigationSort = 10;
|
||||
|
||||
public static function canCreate(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form->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('/'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\SeguimientoProcesoResource\Pages;
|
||||
|
||||
use App\Filament\Resources\SeguimientoProcesoResource;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListSeguimientoProcesos extends ListRecords
|
||||
{
|
||||
protected static string $resource = SeguimientoProcesoResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Widgets;
|
||||
|
||||
use App\Models\OrdenProduccion;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Filament\Widgets\TableWidget as BaseWidget;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class PrendasPendientesWidget extends BaseWidget
|
||||
{
|
||||
protected static ?int $sort = 2;
|
||||
protected int | string | array $columnSpan = 'full';
|
||||
|
||||
protected static ?string $heading = 'Prendas Pendientes por Proceso';
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user