8 Commits

8 changed files with 496 additions and 176 deletions

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Filament\Exports;
use App\Models\Line;
use Filament\Actions\Exports\ExportColumn;
use Filament\Actions\Exports\Exporter;
use Filament\Actions\Exports\Models\Export;
class LineExporter extends Exporter
{
protected static ?string $model = Line::class;
public static function getColumns(): array
{
static $rowNumber = 0;
return [
// ExportColumn::make('id')
// ->label('ID'),
ExportColumn::make('no')
->label('NO')
->state(function ($record) use (&$rowNumber) {
// Increment and return the row number
return ++$rowNumber;
}),
ExportColumn::make('plant.name')
->label('PLANT'),
ExportColumn::make('name')
->label('NAME'),
ExportColumn::make('type')
->label('TYPE'),
ExportColumn::make('created_at')
->label('CREATED AT'),
ExportColumn::make('updated_at')
->label('UPDATED AT'),
ExportColumn::make('deleted_at')
->enabledByDefault(false)
->label('DELETED AT'),
];
}
public static function getCompletedNotificationBody(Export $export): string
{
$body = 'Your line export has completed and ' . number_format($export->successful_rows) . ' ' . str('row')->plural($export->successful_rows) . ' exported.';
if ($failedRowsCount = $export->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to export.';
}
return $body;
}
}

View File

@@ -13,11 +13,21 @@ class QualityValidationExporter extends Exporter
public static function getColumns(): array public static function getColumns(): array
{ {
static $rowNumber = 0;
return [ return [
ExportColumn::make('id') // ExportColumn::make('id')
->label('ID'), // ->label('ID'),
ExportColumn::make('no')
->label('NO')
->state(function ($record) use (&$rowNumber) {
// Increment and return the row number
return ++$rowNumber;
}),
ExportColumn::make('plant.name') ExportColumn::make('plant.name')
->label('PLANT'), ->label('PLANT'),
ExportColumn::make('line.name')
->label('LINE'),
ExportColumn::make('production_order') ExportColumn::make('production_order')
->label('PRODUCTION ORDER'), ->label('PRODUCTION ORDER'),
ExportColumn::make('serial_number') ExportColumn::make('serial_number')

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Imports; namespace App\Filament\Imports;
use App\Models\Item; use App\Models\Item;
use App\Models\Line;
use App\Models\Plant; use App\Models\Plant;
use App\Models\QualityValidation; use App\Models\QualityValidation;
use App\Models\StickerMaster; use App\Models\StickerMaster;
@@ -36,21 +37,28 @@ class QualityValidationImporter extends Importer
->label('Plant Name') ->label('Plant Name')
->relationship(resolveUsing:'name') ->relationship(resolveUsing:'name')
->rules(['required']), ->rules(['required']),
ImportColumn::make('sticker_master_id') // stickerMaster.item ImportColumn::make('line')
->requiredMapping()
->exampleHeader('Line Name')
->example('4 inch pump line')
->label('Line Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('sticker_master_id_code') // stickerMaster.item
->requiredMapping() ->requiredMapping()
->exampleHeader('Item Code') ->exampleHeader('Item Code')
->example('123456') ->example('123456')
->label('Item Code') ->label('Item Code'),
->relationship( // ->relationship(
name: 'stickerMaster', // name: 'stickerMaster',
resolveUsing: function ($state) { // resolveUsing: function ($state) {
$state = trim($state); // $state = trim($state);
$item = Item::where('code', $state)->first(); // $item = Item::where('code', $state)->first();
return $item // return $item
? StickerMaster::where('item_id', $item->id)->value('id') // ? StickerMaster::where('item_id', $item->id)->value('id')
: null; // : null;
} // }
), // ),
ImportColumn::make('production_order') ImportColumn::make('production_order')
->requiredMapping() ->requiredMapping()
->exampleHeader('Production Order') ->exampleHeader('Production Order')
@@ -176,16 +184,24 @@ class QualityValidationImporter extends Importer
{ {
$warnMsg = []; $warnMsg = [];
$plant = Plant::where('name', $this->data['plant'])->first(); $plant = Plant::where('name', $this->data['plant'])->first();
$line = null;
$stickMaster = null;
if (!$plant) { if (!$plant) {
$warnMsg[] = "Plant not found"; $warnMsg[] = "Plant not found";
} }
else {
$uniqueCode = trim($this->data['sticker_master_id']);// stickerMaster.item $line = Line::where('name', $this->data['line'])->where('plant_id', $plant->id)->first();
$uniqueCode = trim($this->data['sticker_master_id_code']);// stickerMaster.item
$stickMaster = StickerMaster::select('id')->with('item') $stickMaster = StickerMaster::select('id')->with('item')
->whereHas('item', function ($query) use ($uniqueCode, $plant) { ->whereHas('item', function ($query) use ($uniqueCode, $plant) {
$query->where('code', $uniqueCode)->where('plant_id', $plant->id); $query->where('code', $uniqueCode)->where('plant_id', $plant->id);
})->value('id'); })->value('id');
}
if (!$line) {
$warnMsg[] = "Line not found";
}
if (!$stickMaster) { if (!$stickMaster) {
$warnMsg[] = "Sticker item code not found"; $warnMsg[] = "Sticker item code not found";
} }
@@ -197,6 +213,7 @@ class QualityValidationImporter extends Importer
if (!ctype_alnum($this->data['serial_number']) || Str::length($this->data['serial_number']) < 9) { if (!ctype_alnum($this->data['serial_number']) || Str::length($this->data['serial_number']) < 9) {
$warnMsg[] = "Invalid serial number found"; $warnMsg[] = "Invalid serial number found";
} }
// dd($stickMaster);
// if (Str::length($this->data['uom']) < 1) { // if (Str::length($this->data['uom']) < 1) {
// $warnMsg[] = "Invalid unit of measure found"; // $warnMsg[] = "Invalid unit of measure found";
@@ -261,8 +278,10 @@ class QualityValidationImporter extends Importer
if (!empty($warnMsg)) { if (!empty($warnMsg)) {
throw new RowImportFailedException(implode(', ', $warnMsg)); throw new RowImportFailedException(implode(', ', $warnMsg));
} }
return QualityValidation::updateOrCreate([
QualityValidation::updateOrCreate([
'plant_id' => $plant->id, 'plant_id' => $plant->id,
'line_id' => $line->id,
'sticker_master_id' => $stickMaster,//->id 'sticker_master_id' => $stickMaster,//->id
'uom' => $this->data['uom'], 'uom' => $this->data['uom'],
'production_order' => $this->data['production_order'], 'production_order' => $this->data['production_order'],
@@ -289,6 +308,8 @@ class QualityValidationImporter extends Importer
'updated_at' => $tdateTime->format('Y-m-d H:i:s'),//$this->data['updated_at'], 'updated_at' => $tdateTime->format('Y-m-d H:i:s'),//$this->data['updated_at'],
'operator_id' => $this->data['operator_id'], 'operator_id' => $this->data['operator_id'],
]); ]);
return null;
// return QualityValidation::firstOrNew([ // return QualityValidation::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']` // // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'], // 'email' => $this->data['email'],

View File

@@ -2,10 +2,12 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Exports\LineExporter;
use App\Filament\Imports\LineImporter; use App\Filament\Imports\LineImporter;
use App\Filament\Resources\LineResource\Pages; use App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource\RelationManagers; use App\Filament\Resources\LineResource\RelationManagers;
use App\Models\Line; use App\Models\Line;
use Filament\Facades\Filament;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Forms\Get; use Filament\Forms\Get;
@@ -16,6 +18,7 @@ use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Tables\Actions\ExportAction;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Unique; use Illuminate\Validation\Rules\Unique;
@@ -115,9 +118,44 @@ class LineResource extends Resource
->where('plant_id', $get('plant_id')) ->where('plant_id', $get('plant_id'))
->ignore($get('id')); // Ignore current record during updates ->ignore($get('id')); // Ignore current record during updates
}), }),
Forms\Components\TextInput::make('type') // Forms\Components\TextInput::make('type')
// ->required()
// ->placeholder('Scan the valid type')
// ->reactive()
// ->afterStateUpdated(function ($state, callable $set, callable $get) {
// $lineTyp = $get('type');
// // Ensure `linestop_id` is not cleared
// if (!$lineTyp) {
// $set('lTypeError', 'Scan the valid type.');
// return;
// }
// else
// {
// $set('lTypeError', null);
// }
// })
// ->extraAttributes(fn ($get) => [
// 'class' => $get('lTypeError') ? 'border-red-500' : '',
// ])
// ->hint(fn ($get) => $get('lTypeError') ? $get('lTypeError') : null)
// ->hintColor('danger'),
Forms\Components\Select::make('type')
->label('Type')
->required() ->required()
->placeholder('Scan the valid type') ->options([
'Sub Assembly Serial' => 'Sub Assembly Serial',
'Sub Assembly Lot' => 'Sub Assembly Lot',
'Base FG Line' => 'Base FG Line',
'SFG Line' => 'SFG Line',
'FG Line' => 'FG Line',
'Machining Cell' => 'Machining Cell',
'Blanking Cell' => 'Blanking Cell',
'Forming Cell' => 'Forming Cell',
'Welding Cell' => 'Welding Cell',
'Die-Casting Cell' => 'Die-Casting Cell',
'Brazzing Cell' => 'Brazzing Cell',
])
->searchable()
->reactive() ->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) { ->afterStateUpdated(function ($state, callable $set, callable $get) {
$lineTyp = $get('type'); $lineTyp = $get('type');
@@ -148,29 +186,48 @@ class LineResource extends Resource
{ {
return $table return $table
->columns([ ->columns([
Tables\Columns\TextColumn::make('id') // Tables\Columns\TextColumn::make('id')
->label('ID') // ->label('ID')
->numeric() // ->numeric()
->sortable(), // ->sortable(),
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('name') Tables\Columns\TextColumn::make('name')
->label('Line')
->alignCenter()
->sortable() ->sortable()
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('type') Tables\Columns\TextColumn::make('type')
->label('Type')
->alignCenter()
->sortable() ->sortable()
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('plant.name') Tables\Columns\TextColumn::make('plant.name')
->label('Plant')
->alignCenter()
->sortable() ->sortable()
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('created_at') Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime() ->dateTime()
->sortable() ->alignCenter()
->toggleable(isToggledHiddenByDefault: true), ->sortable(),
Tables\Columns\TextColumn::make('updated_at') Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime() ->dateTime()
->alignCenter()
->sortable() ->sortable()
->toggleable(isToggledHiddenByDefault: true), ->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at') Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At')
->dateTime() ->dateTime()
->alignCenter()
->sortable() ->sortable()
->toggleable(isToggledHiddenByDefault: true), ->toggleable(isToggledHiddenByDefault: true),
]) ])
@@ -190,7 +247,15 @@ class LineResource extends Resource
]) ])
->headerActions([ ->headerActions([
ImportAction::make() ImportAction::make()
->importer(LineImporter::class), ->importer(LineImporter::class)
->visible(function() {
return Filament::auth()->user()->can('view import line');
}),
ExportAction::make()
->exporter(LineExporter::class)
->visible(function() {
return Filament::auth()->user()->can('view export line');
}),
]); ]);
} }

View File

@@ -7,6 +7,7 @@ use App\Filament\Imports\QualityValidationImporter;
use App\Filament\Resources\QualityValidationResource\Pages; use App\Filament\Resources\QualityValidationResource\Pages;
use App\Filament\Resources\QualityValidationResource\RelationManagers; use App\Filament\Resources\QualityValidationResource\RelationManagers;
use App\Models\Item; use App\Models\Item;
use App\Models\Line;
use App\Models\Plant; use App\Models\Plant;
use App\Models\QualityValidation; use App\Models\QualityValidation;
use App\Models\StickerMaster; use App\Models\StickerMaster;
@@ -50,12 +51,62 @@ class QualityValidationResource extends Resource
Forms\Components\Select::make('plant_id') Forms\Components\Select::make('plant_id')
->relationship('plant', 'name') ->relationship('plant', 'name')
->reactive() ->reactive()
->afterStateUpdated(fn (callable $set) => [ ->afterStateUpdated(function (callable $set, callable $get) {
$set('item_id', null), $set('item_id', null);
$set('validationError', null), $set('line_id', null);
]) $set('production_order', null);
$pId = $get('plant_id');
if (!$pId) {
$set('pqPlantError', 'Please select a plant first.');
} else {
$set('pqPlantError', null);
}
$pId = $get('line_id');
if (!$pId) {
$set('pqLineError', null);
}
})
->required() ->required()
->default(fn () => request()->query('plant_id')), ->default(fn () => request()->query('plant_id'))
->extraAttributes(fn ($get) => [
'class' => $get('pqPlantError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('pqPlantError') ? $get('pqPlantError') : null)
->hintColor('danger'),
Forms\Components\Select::make('line_id')
->relationship('line', titleAttribute: 'name')
->reactive()
->required()
->options(function (callable $get) {
$plantId = $get('plant_id');
if (!$plantId)
{
return [];
}
return Line::where('plant_id', $plantId)
->where('type', 'FG Line') // Filter by type
->pluck('name', 'id')
->toArray();
})
->afterStateUpdated(function (callable $set, callable $get) {
$set('item_id', null);
$set('production_order', null);
$pId = $get('line_id');
if (!$pId) {
$set('pqLineError', 'Please select a line.');
} else {
$set('pqLineError', null);
}
})
->extraAttributes(fn ($get) => [
'class' => $get('pqLineError') ? 'border-red-500' : '',
])
->hint(fn ($get) => $get('pqLineError') ? $get('pqLineError') : null)
->hintColor('danger'),
Forms\Components\Hidden::make('sticker_master_id') Forms\Components\Hidden::make('sticker_master_id')
// ->relationship('stickerMaster', 'id') // ->relationship('stickerMaster', 'id')
->required(), ->required(),
@@ -111,6 +162,23 @@ class QualityValidationResource extends Resource
->live() ->live()
->afterStateUpdated(function (callable $set, callable $get, ?string $state) { ->afterStateUpdated(function (callable $set, callable $get, ?string $state) {
$pId = $get('line_id');
if (!$pId) {
$set('pqLineError', 'Please select a line.');
} else {
$set('pqLineError', null);
}
$pOrder = $get('production_order');
if (!$pOrder)
{
$set('productionError', 'Production Order cant be empty.');
}
else
{
$set('productionError', null);
}
$serialFields = [ $serialFields = [
'serial_number_motor_qr', 'serial_number_pump_qr', 'serial_number_pumpset_qr', 'pack_slip_motor_qr', 'pack_slip_pump_qr', 'pack_slip_pumpset_qr', 'name_plate_motor_qr', 'name_plate_pump_qr', 'name_plate_pumpset_qr', 'tube_sticker_motor_qr', 'tube_sticker_pump_qr', 'tube_sticker_pumpset_qr', 'warranty_card_qr' 'serial_number_motor_qr', 'serial_number_pump_qr', 'serial_number_pumpset_qr', 'pack_slip_motor_qr', 'pack_slip_pump_qr', 'pack_slip_pumpset_qr', 'name_plate_motor_qr', 'name_plate_pump_qr', 'name_plate_pumpset_qr', 'tube_sticker_motor_qr', 'tube_sticker_pump_qr', 'tube_sticker_pumpset_qr', 'warranty_card_qr'
]; ];
@@ -1894,21 +1962,37 @@ class QualityValidationResource extends Resource
return $table return $table
->query(QualityValidation::query()) ->query(QualityValidation::query())
->columns([ ->columns([
Tables\Columns\TextColumn::make('id') // Tables\Columns\TextColumn::make('id')
->label('ID') // ->label('ID')
->numeric() // ->numeric()
->sortable(), // ->sortable(),
Tables\Columns\TextColumn::make('No.')
->label('No.')
->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
$paginator = $livewire->getTableRecords();
$perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
$currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
return ($currentPage - 1) * $perPage + $rowLoop->iteration;
}),
Tables\Columns\TextColumn::make('plant.name') Tables\Columns\TextColumn::make('plant.name')
->label('Plant') ->label('Plant')
->alignCenter()
->sortable(),
Tables\Columns\TextColumn::make('line.name')
->label('Line')
->alignCenter()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('production_order') Tables\Columns\TextColumn::make('production_order')
->label('Production Order') ->label('Production Order')
->alignCenter()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('serial_number') Tables\Columns\TextColumn::make('serial_number')
->label('Serial Number') ->label('Serial Number')
->alignCenter()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('stickerMaster.item.code') Tables\Columns\TextColumn::make('stickerMaster.item.code')
->label('Item Code') ->label('Item Code')
->alignCenter()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('uom') Tables\Columns\TextColumn::make('uom')
->label('Unit of Measure') ->label('Unit of Measure')
@@ -1992,20 +2076,23 @@ class QualityValidationResource extends Resource
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('sap_msg_description') Tables\Columns\TextColumn::make('sap_msg_description')
->label('SAP Message Description') ->label('SAP Message Description')
->alignCenter()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('created_at') Tables\Columns\TextColumn::make('created_at')
->label('Created At') ->label('Created At')
->dateTime() ->dateTime()
->sortable() ->alignCenter()
->toggleable(isToggledHiddenByDefault: true), ->sortable(),
Tables\Columns\TextColumn::make('updated_at') Tables\Columns\TextColumn::make('updated_at')
->label('Updated At') ->label('Updated At')
->dateTime() ->dateTime()
->alignCenter()
->sortable() ->sortable()
->toggleable(isToggledHiddenByDefault: true), ->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at') Tables\Columns\TextColumn::make('deleted_at')
->label('Deleted At') ->label('Deleted At')
->dateTime() ->dateTime()
->alignCenter()
->sortable() ->sortable()
->toggleable(isToggledHiddenByDefault: true), ->toggleable(isToggledHiddenByDefault: true),
]) ])
@@ -2027,6 +2114,26 @@ class QualityValidationResource extends Resource
$set('sticker_master_id', null); $set('sticker_master_id', null);
$set('sap_msg_status', null); $set('sap_msg_status', null);
}), }),
Select::make('Line')
->label('Select Line')
->nullable()
->options(function (callable $get) {
$plantId = $get('Plant');
if (!$plantId)
{
return [];
}
return Line::where('plant_id', $plantId)
->where('type', 'FG Line') // Filter by type
->pluck('name', 'id')
->toArray();
})
->reactive()
->afterStateUpdated(function ($state, callable $set, callable $get) {
$set('sticker_master_id', null);
$set('sap_msg_status', null);
}),
TextInput::make('production_order') TextInput::make('production_order')
->label('Production Order') ->label('Production Order')
->placeholder('Enter Production Order'), ->placeholder('Enter Production Order'),
@@ -2083,6 +2190,10 @@ class QualityValidationResource extends Resource
$query->where('plant_id', $data['Plant']); $query->where('plant_id', $data['Plant']);
} }
if (!empty($data['Line'])) {
$query->where('line_id', $data['Line']);
}
if (!empty($data['production_order'])) { if (!empty($data['production_order'])) {
$query->where('production_order', 'like', '%' . $data['production_order'] . '%'); $query->where('production_order', 'like', '%' . $data['production_order'] . '%');
} }
@@ -2120,6 +2231,10 @@ class QualityValidationResource extends Resource
$indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name'); $indicators[] = 'Plant: ' . Plant::where('id', $data['Plant'])->value('name');
} }
if (!empty($data['Line'])) {
$indicators[] = 'Line: ' . Line::where('id', $data['Line'])->value('name');
}
if (!empty($data['production_order'])) { if (!empty($data['production_order'])) {
$indicators[] = 'Production Order: ' . $data['production_order']; $indicators[] = 'Production Order: ' . $data['production_order'];
} }

View File

@@ -3,6 +3,8 @@
namespace App\Filament\Widgets; namespace App\Filament\Widgets;
use App\Models\Line; use App\Models\Line;
use App\Models\ProductionQuantity;
use App\Models\QualityValidation;
use Filament\Widgets\ChartWidget; use Filament\Widgets\ChartWidget;
class CumulativeChart extends ChartWidget class CumulativeChart extends ChartWidget
@@ -15,13 +17,77 @@ class CumulativeChart extends ChartWidget
protected int|string|array $columnSpan = 12; protected int|string|array $columnSpan = 12;
// protected function getData(): array
// {
// $selectedPlant = session('selected_plant');
// $activeFilter = $this->filter;
// // Define date range based on filter
// switch ($activeFilter) {
// case 'yesterday':
// $startDate = now()->subDay()->startOfDay();
// $endDate = now()->subDay()->endOfDay();
// break;
// case 'this_week':
// $startDate = now()->startOfWeek();
// $endDate = now()->endOfWeek();
// break;
// case 'this_month':
// $startDate = now()->startOfMonth();
// $endDate = now()->endOfMonth();
// break;
// default: // today
// $startDate = now()->startOfDay();
// $endDate = now()->endOfDay();
// break;
// }
// // Get all lines for selected plant
// $lines = Line::where('plant_id', $selectedPlant)
// ->pluck('name', 'id')
// ->toArray();
// // Get total production per line in the date range
// $production = \DB::table('production_quantities')
// ->select('line_id', \DB::raw('COUNT(*) as total_quantity'))
// ->whereBetween('created_at', [$startDate, $endDate])
// ->whereIn('line_id', array_keys($lines))
// ->groupBy('line_id')
// ->pluck('total_quantity', 'line_id')
// ->toArray();
// // Match quantities with lines (fill 0 if missing)
// $labels = [];
// $data = [];
// foreach ($lines as $lineId => $lineName) {
// $labels[] = $lineName;
// $data[] = $production[$lineId] ?? 0;
// }
// return [
// 'labels' => $labels,
// 'datasets' => [
// [
// 'label' => match ($activeFilter) {
// 'yesterday' => "Production Quantity (Yesterday)",
// 'this_week' => "Daily Production This Week",
// 'this_month' => "Weekly Production This Month",
// default => "Today's Production",
// },
// 'data' => $data,
// ],
// ],
// ];
// }
protected function getData(): array protected function getData(): array
{ {
$selectedPlant = session('selected_plant'); $selectedPlant = session('selected_plant');
$activeFilter = $this->filter; $activeFilter = $this->filter;
// Define date range based on filter // Define date range
switch ($activeFilter) { switch ($activeFilter)
{
case 'yesterday': case 'yesterday':
$startDate = now()->subDay()->startOfDay(); $startDate = now()->subDay()->startOfDay();
$endDate = now()->subDay()->endOfDay(); $endDate = now()->subDay()->endOfDay();
@@ -40,46 +106,90 @@ class CumulativeChart extends ChartWidget
break; break;
} }
// Get all lines for selected plant // Get lines with names and types
$lines = Line::where('plant_id', $selectedPlant) $lines = Line::where('plant_id', $selectedPlant)->get(['id', 'name', 'type']);
->pluck('name', 'id')
->toArray();
// Get total production per line in the date range $lineNames = [];
$production = \DB::table('production_quantities') $fgLineIds = [];
->select('line_id', \DB::raw('COUNT(*) as total_quantity')) $nonFgLineIds = [];
foreach ($lines as $line)
{
$lineNames[$line->id] = $line->name;
if ($line->type == 'FG Line')
{
$fgLineIds[] = $line->id;
}
else
{
$nonFgLineIds[] = $line->id;
}
}
//FG production from quality_validations
$fgProduction = QualityValidation::select('line_id', \DB::raw('COUNT(*) as total_quantity'))
->whereBetween('created_at', [$startDate, $endDate]) ->whereBetween('created_at', [$startDate, $endDate])
->whereIn('line_id', array_keys($lines)) ->whereIn('line_id', $fgLineIds)
->groupBy('line_id') ->groupBy('line_id')
->pluck('total_quantity', 'line_id') ->pluck('total_quantity', 'line_id')
->toArray(); ->toArray();
// Match quantities with lines (fill 0 if missing) //Non-FG production from production_quantities
$labels = []; $nonFgProduction = ProductionQuantity::select('line_id', \DB::raw('COUNT(*) as total_quantity'))
$data = []; ->whereBetween('created_at', [$startDate, $endDate])
->whereIn('line_id', $nonFgLineIds)
->groupBy('line_id')
->pluck('total_quantity', 'line_id')
->toArray();
foreach ($lines as $lineId => $lineName) { //Separate FG and non-FG into different datasets
$labels = [];
$fgData = [];
$nonFgData = [];
foreach ($lineNames as $lineId => $lineName) {
$labels[] = $lineName; $labels[] = $lineName;
$data[] = $production[$lineId] ?? 0;
if (in_array($lineId, $fgLineIds))
{
$fgData[] = $fgProduction[$lineId] ?? 0;
$nonFgData[] = null;
}
else
{
$nonFgData[] = $nonFgProduction[$lineId] ?? 0;
$fgData[] = null;
}
} }
return [ return [
'labels' => $labels, 'labels' => $labels,
'datasets' => [ 'datasets' => array_filter([
[ [
'label' => match ($activeFilter) { 'label' => match ($activeFilter) {
'yesterday' => "Production Quantity (Yesterday)", 'yesterday' => "Production Quantity (Yesterday)",
'this_week' => "Daily Production This Week", 'this_week' => "Daily Production This Week",
'this_month' => "Weekly Production This Month", 'this_month' => "Weekly Production This Month",
default => "Today's Production", default => "Today's Production",
}, },
'data' => $data, 'data' => $nonFgData,
//'backgroundColor' => '#3b82f6', // Blue for non-FG
], ],
], [
'label' => match ($activeFilter) {
'yesterday' => "FG Count (Yesterday)",
'this_week' => "FG Count This Week",
'this_month' => "FG Count This Month",
default => "Today's FG Count",
},
'data' => $fgData,
// 'backgroundColor' => '#ef4444', // Red for FG
],
]),
]; ];
} }
protected function getType(): string protected function getType(): string
{ {
return 'bar'; return 'bar';
@@ -106,7 +216,6 @@ class CumulativeChart extends ChartWidget
], ],
], ],
], ],
]; ];
} }

View File

@@ -34,129 +34,96 @@ class ItemOverview extends ChartWidget
]; ];
} }
if ($activeFilter === 'yesterday') { // Determine if line is FG Line
$startDate = now()->subDay()->setTime(8, 0, 0); // Yesterday 8:00 AM $line = \App\Models\Line::find($selectedLine);
$endDate = now()->setTime(8, 0, 0); // Today 8:00 AM $isFgLine = $line?->type == 'FG Line';
$groupBy = 'EXTRACT(HOUR FROM production_quantities.created_at)';
}
else if ($activeFilter === 'this_week') { // Set date range and groupBy logic
// Monday 8:00 AM of the current week if ($activeFilter == 'yesterday')
{
$startDate = now()->subDay()->setTime(8, 0, 0);
$endDate = now()->setTime(8, 0, 0);
$groupBy = 'EXTRACT(HOUR FROM created_at)';
}
elseif ($activeFilter == 'this_week')
{
$startDate = now()->startOfWeek()->setTime(8, 0, 0); $startDate = now()->startOfWeek()->setTime(8, 0, 0);
$endDate = now()->endOfWeek()->addDay()->setTime(8, 0, 0); $endDate = now()->endOfWeek()->addDay()->setTime(8, 0, 0);
$groupBy = 'EXTRACT(DOW FROM created_at)';
$groupBy = 'EXTRACT(DOW FROM production_quantities.created_at)'; // Group by day of week
} }
else if ($activeFilter === 'this_month') { elseif ($activeFilter == 'this_month')
{
$startDate = now()->startOfMonth(); $startDate = now()->startOfMonth();
$endDate = now()->endOfMonth(); $endDate = now()->endOfMonth();
$groupBy = "FLOOR((EXTRACT(DAY FROM production_quantities.created_at) - 1) / 7) + 1"; $groupBy = "FLOOR((EXTRACT(DAY FROM created_at) - 1) / 7) + 1";
} }
else else
{ {
$startDate = now()->setTime(8, 0, 0); // today at 8:00 AM $startDate = now()->setTime(8, 0, 0);
$endDate = now()->copy()->addDay()->setTime(8, 0, 0); // tomorrow at 8:00 AM $endDate = now()->copy()->addDay()->setTime(8, 0, 0);
$groupBy = 'EXTRACT(HOUR FROM production_quantities.created_at)'; $groupBy = 'EXTRACT(HOUR FROM created_at)';
} }
$query = \DB::table('production_quantities') $baseTable = $isFgLine ? 'quality_validations' : 'production_quantities';
->join('plants', 'production_quantities.plant_id', '=', 'plants.id') //inner join
->join('lines', 'production_quantities.line_id', '=', 'lines.id')
->selectRaw("$groupBy AS time_unit, count(*) AS total_quantity")
//->whereBetween('production_quantities.created_at', [$startDate, $endDate])
->where('production_quantities.created_at', '>=', $startDate) // $startDate should be >=
->where('production_quantities.created_at', '<', $endDate) // $endDate should be <
->when($selectedPlant, function ($q) use ($selectedPlant) {
return $q->where('plants.id', $selectedPlant);
})
->when($selectedLine, function ($q) use ($selectedLine) {
return $q->where('lines.id', $selectedLine);
})
->groupByRaw($groupBy) $query = \DB::table($baseTable)
->orderByRaw($groupBy) ->selectRaw("$groupBy AS time_unit, COUNT(*) AS total_quantity")
->pluck('total_quantity', 'time_unit') ->where('created_at', '>=', $startDate)
->toArray(); ->where('created_at', '<', $endDate)
->where('plant_id', $selectedPlant)
->where('line_id', $selectedLine)
->groupByRaw($groupBy)
->orderByRaw($groupBy)
->pluck('total_quantity', 'time_unit')
->toArray();
if ($activeFilter == 'this_month')
{
$weeksCount = ceil($endDate->day / 7);
$allWeeks = array_fill(1, $weeksCount, 0);
$data = array_replace($allWeeks, $query);
if ($activeFilter === 'this_month') { $labels = [];
$weeksCount = ceil($endDate->day / 7); // Calculate total weeks dynamically for ($i = 1; $i <= $weeksCount; $i++) {
$allWeeks = array_fill(1, $weeksCount, 0); // Initialize all weeks with 0 $weekStart = $startDate->copy()->addDays(($i - 1) * 7)->format('d M');
$data = array_replace($allWeeks, $query); // Fill missing weeks with 0 $weekEnd = $startDate->copy()->addDays($i * 7 - 1)->min($endDate)->format('d M');
$labels[] = "Week $i ($weekStart - $weekEnd)";
// Generate dynamic week labels
$labels = [];
for ($i = 1; $i <= $weeksCount; $i++) {
$weekStart = $startDate->copy()->addDays(($i - 1) * 7)->format('d M');
$weekEnd = $startDate->copy()->addDays($i * 7 - 1)->min($endDate)->format('d M');
$labels[] = "Week $i ($weekStart - $weekEnd)";
}
$orderedData = array_values($data);
} }
else if ($activeFilter === 'this_week') {
// Correct week labels: ['Mon', 'Tue', ..., 'Sun']
$labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
// Initialize default data for all 7 days $orderedData = array_values($data);
$data = array_fill(0, 7, 0); }
elseif ($activeFilter == 'this_week')
// Fill in data from query results {
foreach ($query as $dow => $count) { $labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
$data[$dow] = $count; $data = array_fill(0, 7, 0);
} foreach ($query as $dow => $count) {
$data[$dow] = $count;
// Ensure days are ordered from Monday to Sunday
$orderedData = [
$data[1] ?? 0, // Monday
$data[2] ?? 0, // Tuesday
$data[3] ?? 0, // Wednesday
$data[4] ?? 0, // Thursday
$data[5] ?? 0, // Friday
$data[6] ?? 0, // Saturday
$data[0] ?? 0, // Sunday (move to last)
];
} }
else if($activeFilter === 'yesterday') $orderedData = [
{ $data[1] ?? 0, $data[2] ?? 0, $data[3] ?? 0,
$data[4] ?? 0, $data[5] ?? 0, $data[6] ?? 0,
// Hourly data (same as before) $data[0] ?? 0,
$allHours = array_fill(0, 24, 0); ];
$data = array_replace($allHours, $query);
// Shift hours for proper display (8 AM to 7 AM)
$shiftedKeys = array_merge(range(8, 23), range(0, 7));
$orderedData = array_map(fn($hour) => $data[$hour], $shiftedKeys);
// Labels: ["8 AM", "9 AM", ..., "7 AM"]
$labels = array_map(fn ($hour) => date("g A", strtotime("$hour:00")), $shiftedKeys);
} }
else else
{ {
// Hourly data (same as before)
$allHours = array_fill(0, 24, 0); $allHours = array_fill(0, 24, 0);
$data = array_replace($allHours, $query); $data = array_replace($allHours, $query);
// Shift hours for proper display (8 AM to 7 AM)
$shiftedKeys = array_merge(range(8, 23), range(0, 7)); $shiftedKeys = array_merge(range(8, 23), range(0, 7));
$orderedData = array_map(fn($hour) => $data[$hour], $shiftedKeys); $orderedData = array_map(fn($hour) => $data[$hour], $shiftedKeys);
// Labels: ["8 AM", "9 AM", ..., "7 AM"]
$labels = array_map(fn ($hour) => date("g A", strtotime("$hour:00")), $shiftedKeys); $labels = array_map(fn ($hour) => date("g A", strtotime("$hour:00")), $shiftedKeys);
} }
return [ return [
'datasets' => [ 'datasets' => [
[ [
'label' => match ($activeFilter) { 'label' => match ($activeFilter) {
'this_week' => "Daily Production This Week", 'this_week' => $isFgLine ? 'Daily FG Count This Week' : 'Daily Production This Week',
'this_month' => "Weekly Production This Month", // Updated Label 'this_month' => $isFgLine ? 'Weekly FG Count This Month' : 'Weekly Production This Month',
'yesterday' => "Yesterday's Hourly Production", 'yesterday' => $isFgLine ? "Yesterday's FG Count" : "Yesterday's Hourly Production",
default => "Today's Hourly Production", default => $isFgLine ? "Today's FG Count" : "Today's Hourly Production",
}, },
'data' => $orderedData, 'data' => $orderedData,
'interaction' => [ 'interaction' => [
@@ -195,32 +162,6 @@ class ItemOverview extends ChartWidget
} }
// protected function getOptions(): array
// {
// return [
// 'plugins' => [
// 'datalabels' => [
// 'color' => '#3490dc',
// 'font' => [
// 'weight' => 'bold',
// 'size' => 14,
// ],
// 'backgroundColor' => 'rgba(255,255,255,0.8)',
// 'borderRadius' => 4,
// 'formatter' => \Illuminate\Support\Js::from(
// new Js('function(value, context) {
// if (Number(value) === 0) {
// return null;
// }
// return "Count: " + value;
// }')
// ),
// ]
// ]
// ];
// }
protected function getFilters(): ?array protected function getFilters(): ?array
{ {
return [ return [

View File

@@ -13,6 +13,7 @@ class QualityValidation extends Model
protected $fillable = [ protected $fillable = [
'sticker_master_id', 'sticker_master_id',
'plant_id', 'plant_id',
'line_id',
'production_order', 'production_order',
'serial_number_motor', 'serial_number_motor',
'serial_number_pump', 'serial_number_pump',
@@ -48,4 +49,9 @@ class QualityValidation extends Model
{ {
return $this->belongsTo(Plant::class); return $this->belongsTo(Plant::class);
} }
public function line(): BelongsTo
{
return $this->belongsTo(Line::class);
}
} }