diff --git a/app/Filament/Exports/ProcessOrderExporter.php b/app/Filament/Exports/ProcessOrderExporter.php index 707cce4..833edcb 100644 --- a/app/Filament/Exports/ProcessOrderExporter.php +++ b/app/Filament/Exports/ProcessOrderExporter.php @@ -14,6 +14,7 @@ class ProcessOrderExporter extends Exporter public static function getColumns(): array { static $rowNumber = 0; + return [ ExportColumn::make('no') ->label('NO') @@ -21,39 +22,43 @@ class ProcessOrderExporter extends Exporter // Increment and return the row number return ++$rowNumber; }), - ExportColumn::make('plant.name') - ->label('PLANT NAME'), + ExportColumn::make('plant.code') + ->label('PLANT CODE'), ExportColumn::make('item.code') - ->label('ITEM CODE'), + ->label('ITEM CODE'), ExportColumn::make('process_order') - ->label('PROCESS ORDER'), + ->label('PROCESS ORDER'), ExportColumn::make('coil_number') - ->label('COIL NUMBER'), + ->label('COIL NUMBER'), ExportColumn::make('order_quantity') - ->label('ORDER QUANTITY'), + ->label('ORDER QUANTITY'), ExportColumn::make('received_quantity') - ->label('RECEIVED QUANTITY'), + ->label('RECEIVED QUANTITY'), + ExportColumn::make('sfg_number') + ->label('SFG NUMBER'), + ExportColumn::make('machine_name') + ->label('MACHINE ID'), ExportColumn::make('created_at') - ->label('CREATED AT'), + ->label('CREATED AT'), ExportColumn::make('updated_at') - ->label('UPDATED AT'), + ->label('UPDATED AT'), ExportColumn::make('created_by') - ->label('CREATED BY'), + ->label('CREATED BY'), ExportColumn::make('updated_by') - ->label('UPDATED BY'), + ->label('UPDATED BY'), ExportColumn::make('deleted_at') - ->enabledByDefault(false) - ->label('DELETED AT'), + ->enabledByDefault(false) + ->label('DELETED AT'), ]; } public static function getCompletedNotificationBody(Export $export): string { - $body = 'Your process order export has completed and ' . number_format($export->successful_rows) . ' ' . str('row')->plural($export->successful_rows) . ' exported.'; + $body = 'Your process order 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.'; + $body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to export.'; } return $body; diff --git a/app/Filament/Imports/ProcessOrderImporter.php b/app/Filament/Imports/ProcessOrderImporter.php index aa727d9..9534cb6 100644 --- a/app/Filament/Imports/ProcessOrderImporter.php +++ b/app/Filament/Imports/ProcessOrderImporter.php @@ -6,11 +6,11 @@ use App\Models\Item; use App\Models\Plant; use App\Models\ProcessOrder; use App\Models\User; +use Filament\Actions\Imports\Exceptions\RowImportFailedException; use Filament\Actions\Imports\ImportColumn; use Filament\Actions\Imports\Importer; use Filament\Actions\Imports\Models\Import; use Str; -use Filament\Actions\Imports\Exceptions\RowImportFailedException; class ProcessOrderImporter extends Importer { @@ -21,27 +21,28 @@ class ProcessOrderImporter extends Importer return [ ImportColumn::make('plant') ->requiredMapping() - ->exampleHeader('Plant Code') + ->exampleHeader('PLANT CODE') ->example('1000') - ->label('Plant Code') - ->relationship(resolveUsing:'code') + ->label('PLANT CODE') + ->relationship(resolveUsing: 'code') ->rules(['required']), ImportColumn::make('item') ->requiredMapping() - ->exampleHeader('Item Code') + ->exampleHeader('ITEM CODE') ->example('123456') - ->label('Item Code') + ->label('ITEM CODE') ->relationship(resolveUsing: 'code') ->rules(['required']), ImportColumn::make('process_order') - ->exampleHeader('Process Order') - ->example('200000166843') - ->label('Process Order') + ->exampleHeader('PROCESS ORDER') + ->example('202500123456') + ->label('PROCESS ORDER') ->rules(['required']), ImportColumn::make('created_by') - ->exampleHeader('Created By') + ->exampleHeader('CREATED BY') ->example('RAW01234') - ->label('Created By'), + ->label('CREATED BY') + ->rules(['required']), ]; } @@ -52,26 +53,23 @@ class ProcessOrderImporter extends Importer $itemCode = Item::where('code', $this->data['item'])->first(); $iCode = trim($this->data['item']); - if (!$plant) { - $warnMsg[] = "Plant not found"; - } - else if (Str::length($iCode) < 6 || !ctype_alnum($iCode)) { - $warnMsg[] = "Invalid item code found"; - } - else if(!$itemCode) - { - $warnMsg[] = "Item Code not found"; + if (! $plant) { + $warnMsg[] = 'Plant not found'; + } elseif (Str::length($iCode) < 6 || ! ctype_alnum($iCode)) { + $warnMsg[] = 'Invalid item code found'; + } elseif (! $itemCode) { + $warnMsg[] = 'Item Code not found'; } $processOrder = trim($this->data['process_order'] ?? ''); if ($processOrder == '') { - $warnMsg[] = "Process Order cannot be empty"; + $warnMsg[] = 'Process Order cannot be empty'; } $user = User::where('name', $this->data['created_by'])->first(); - if (!$user) { - $warnMsg[] = "User not found"; + if (! $user) { + $warnMsg[] = 'User not found'; } if ($plant && $processOrder != '') { @@ -81,33 +79,33 @@ class ProcessOrderImporter extends Importer ->first(); if ($existingOrder && $existingOrder->item_id !== ($itemCode->id ?? null)) { - $warnMsg[] = "Same Process Order already exists for this Plant with a different Item Code"; + $warnMsg[] = 'Same Process Order already exists for this Plant with a different Item Code'; } } - if (!empty($warnMsg)) { + if (! empty($warnMsg)) { throw new RowImportFailedException(implode(', ', $warnMsg)); } return ProcessOrder::create([ - 'plant_id' => $plant->id, - 'item_id' => $itemCode->id, - 'process_order' => trim($this->data['process_order']), - 'coil_number' => "0", - 'order_quantity' => 0, + 'plant_id' => $plant->id, + 'item_id' => $itemCode->id, + 'process_order' => trim($this->data['process_order']), + 'coil_number' => '0', + 'order_quantity' => 0, 'received_quantity' => 0, - 'created_by' => $user->name, + 'created_by' => $user->name, ]); - //return new ProcessOrder(); + // return new ProcessOrder(); } public static function getCompletedNotificationBody(Import $import): string { - $body = 'Your process order import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.'; + $body = 'Your process order import has completed and '.number_format($import->successful_rows).' '.str('row')->plural($import->successful_rows).' imported.'; if ($failedRowsCount = $import->getFailedRowsCount()) { - $body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.'; + $body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to import.'; } return $body; diff --git a/app/Filament/Resources/ProcessOrderResource.php b/app/Filament/Resources/ProcessOrderResource.php index f685d71..cbad930 100644 --- a/app/Filament/Resources/ProcessOrderResource.php +++ b/app/Filament/Resources/ProcessOrderResource.php @@ -2,29 +2,28 @@ namespace App\Filament\Resources; +use App\Filament\Exports\ProcessOrderExporter; +use App\Filament\Imports\ProcessOrderImporter; use App\Filament\Resources\ProcessOrderResource\Pages; -use App\Filament\Resources\ProcessOrderResource\RelationManagers; use App\Models\Plant; use App\Models\ProcessOrder; +use Filament\Facades\Filament; use Filament\Forms; +use Filament\Forms\Components\Actions\Action; use Filament\Forms\Form; +use Filament\Forms\Get; +use Filament\Forms\Set; +use Filament\Notifications\Notification; use Filament\Resources\Resource; use Filament\Tables; +use Filament\Tables\Actions\ExportAction; +use Filament\Tables\Actions\ImportAction; use Filament\Tables\Table; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletingScope; -use Storage; use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; -use Filament\Notifications\Notification; -use Filament\Forms\Components\Actions\Action; -use Filament\Facades\Filament; use Smalot\PdfParser\Parser; -use Filament\Tables\Actions\ExportAction; -use Filament\Tables\Actions\ImportAction; -use App\Filament\Exports\ProcessOrderExporter; -use App\Filament\Imports\ProcessOrderImporter; -use Filament\Forms\Get; -use Filament\Forms\Set; +use Storage; class ProcessOrderResource extends Resource { @@ -44,6 +43,7 @@ class ProcessOrderResource extends Resource ->relationship('plant', 'name') ->options(function (callable $get) { $userHas = Filament::auth()->user()->plant_id; + return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray(); }) ->required(), @@ -58,6 +58,7 @@ class ProcessOrderResource extends Resource if (empty($plantId)) { return []; } + return \App\Models\Item::where('plant_id', $plantId)->pluck('code', 'id'); }) ->afterStateUpdated(function (callable $set, callable $get, ?string $state) { @@ -72,8 +73,8 @@ class ProcessOrderResource extends Resource if ($itemCode) { // Now get the item description using plant_id + code $item = \App\Models\Item::where('plant_id', $plantId) - ->where('code', $itemCode) - ->first(); + ->where('code', $itemCode) + ->first(); $set('item_description', $item?->description); } else { @@ -104,7 +105,7 @@ class ProcessOrderResource extends Resource Forms\Components\TextInput::make('id') ->hidden() ->readOnly(), - // ->readOnly(true), + // ->readOnly(true), Forms\Components\TextInput::make('process_order') ->label('Process Order') ->required(), @@ -119,6 +120,12 @@ class ProcessOrderResource extends Resource ->label('Received Quantity') ->default('0') ->required(), + Forms\Components\TextInput::make('sfg_number') + ->label('SFG Number') + ->required(), + Forms\Components\TextInput::make('machine_name') + ->label('Machine ID') + ->required(), Forms\Components\FileUpload::make('attachment') ->label('PDF Upload') ->acceptedFileTypes(['application/pdf']) @@ -133,21 +140,21 @@ class ProcessOrderResource extends Resource ->action(function ($get, callable $set) { $uploadedFiles = $get('attachment'); - if (is_array($uploadedFiles) && count($uploadedFiles) > 0) - { + if (is_array($uploadedFiles) && count($uploadedFiles) > 0) { $uploaded = reset($uploadedFiles); if ($uploaded instanceof TemporaryUploadedFile) { $originalName = $uploaded->getClientOriginalName(); - $path = 'uploads/ProcessOrder/' . $originalName; + $path = 'uploads/ProcessOrder/'.$originalName; - // Check if file already exists + // Check if file already exists if (Storage::disk('local')->exists($path)) { Notification::make() ->title('Duplicate File') ->body("The file '{$originalName}' already exists in uploads/ProcessOrder.") ->warning() ->send(); + return; // Stop here } @@ -157,28 +164,25 @@ class ProcessOrderResource extends Resource 'local' ); - // $fullPath = storage_path('app/' . $storedPath); - $fullPath = storage_path('app/' . $storedPath); + // $fullPath = storage_path('app/' . $storedPath); + $fullPath = storage_path('app/'.$storedPath); // Parse PDF using smalot/pdfparser - $parser = new Parser(); + $parser = new Parser; $pdf = $parser->parseContent(file_get_contents($uploaded->getRealPath())); $text = $pdf->getText(); - // if (preg_match('/Batch ID:\s*(\d+)\s*--/i', $text, $matches)) // { // $batchId = $matches[1]; // } if (preg_match('/Batch ID:\s*(\d+)(?:\s*--)?/i', $text, $matches)) { $batchId = $matches[1]; - } - else - { + } else { $batchId = null; } - // Get the value of process_order field + // Get the value of process_order field $processOrder = $get('process_order'); if ($batchId != $processOrder) { @@ -187,11 +191,11 @@ class ProcessOrderResource extends Resource ->body("Batch ID ($batchId) does not match Process Order ($processOrder)") ->danger() ->send(); + return; } - if ($batchId == $processOrder) - { + if ($batchId == $processOrder) { // If batch matches, store the PDF permanently $storedPath = $uploaded->storeAs( 'uploads/ProcessOrder', @@ -204,17 +208,17 @@ class ProcessOrderResource extends Resource ->body("Batch ID matches Process Order: $batchId. PDF uploaded successfully.") ->success() ->send(); - return; + + return; } } - } - else - { + } else { Notification::make() ->title('No file selected to upload') ->warning() ->send(); - return; + + return; } }), @@ -223,11 +227,12 @@ class ProcessOrderResource extends Resource ->action(function ($get) { $equipmentNumber = $get('process_order'); - if (!$equipmentNumber) { + if (! $equipmentNumber) { Notification::make() ->title('No process order entered') ->danger() ->send(); + return; } @@ -241,59 +246,60 @@ class ProcessOrderResource extends Resource } } - if (!$fileToDownload) { + if (! $fileToDownload) { Notification::make() ->title('PDF not found for this process order') ->danger() ->send(); + return; } return response()->download(Storage::disk('local')->path($fileToDownload)); }), - // Action::make('removeAttachment') - // ->label('Remove PDF') - // ->action(function ($get) { - // $equipmentNumber = $get('process_order'); + // Action::make('removeAttachment') + // ->label('Remove PDF') + // ->action(function ($get) { + // $equipmentNumber = $get('process_order'); - // if (!$equipmentNumber) { - // Notification::make() - // ->title('No process order entered') - // ->danger() - // ->send(); - // return; - // } + // if (!$equipmentNumber) { + // Notification::make() + // ->title('No process order entered') + // ->danger() + // ->send(); + // return; + // } - // // Get all files from uploads/temp - // $files = Storage::disk('local')->files('uploads/ProcessOrder'); + // // Get all files from uploads/temp + // $files = Storage::disk('local')->files('uploads/ProcessOrder'); - // $fileToDelete = null; - // foreach ($files as $file) { - // if (str_contains($file, $equipmentNumber)) { - // $fileToDelete = $file; - // break; - // } - // } + // $fileToDelete = null; + // foreach ($files as $file) { + // if (str_contains($file, $equipmentNumber)) { + // $fileToDelete = $file; + // break; + // } + // } - // if (!$fileToDelete) { - // Notification::make() - // ->title('PDF not found for this process order') - // ->danger() - // ->send(); - // return; - // } + // if (!$fileToDelete) { + // Notification::make() + // ->title('PDF not found for this process order') + // ->danger() + // ->send(); + // return; + // } - // // Delete the matched file - // Storage::disk('local')->delete($fileToDelete); + // // Delete the matched file + // Storage::disk('local')->delete($fileToDelete); - // Notification::make() - // ->title('PDF removed successfully') - // ->body("File for process order {$equipmentNumber} has been deleted.") - // ->success() - // ->send(); - // }), - ]), + // Notification::make() + // ->title('PDF removed successfully') + // ->body("File for process order {$equipmentNumber} has been deleted.") + // ->success() + // ->send(); + // }), + ]), Forms\Components\Hidden::make('created_by') ->label('Created By') ->default(Filament::auth()->user()?->name), @@ -312,6 +318,7 @@ class ProcessOrderResource extends Resource $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') @@ -349,6 +356,16 @@ class ProcessOrderResource extends Resource ->alignCenter() ->searchable() ->sortable(), + Tables\Columns\TextColumn::make('sfg_number') + ->label('SFG Number') + ->alignCenter() + ->searchable() + ->sortable(), + Tables\Columns\TextColumn::make('machine_name') + ->label('Machine ID') + ->alignCenter() + ->searchable() + ->sortable(), Tables\Columns\TextColumn::make('created_at') ->label('Created At') ->alignCenter() @@ -385,7 +402,7 @@ class ProcessOrderResource extends Resource Tables\Actions\EditAction::make(), ]) ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ + Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), Tables\Actions\ForceDeleteBulkAction::make(), Tables\Actions\RestoreBulkAction::make(), @@ -396,14 +413,14 @@ class ProcessOrderResource extends Resource ->label('Import Process Order') ->color('warning') ->importer(ProcessOrderImporter::class) - ->visible(function() { + ->visible(function () { return Filament::auth()->user()->can('view import process order'); }), ExportAction::make() ->label('Export Process Order') ->color('warning') ->exporter(ProcessOrderExporter::class) - ->visible(function() { + ->visible(function () { return Filament::auth()->user()->can('view export process order'); }), ]); diff --git a/app/Models/ProcessOrder.php b/app/Models/ProcessOrder.php index 39ed72e..a3507eb 100644 --- a/app/Models/ProcessOrder.php +++ b/app/Models/ProcessOrder.php @@ -8,19 +8,21 @@ use Illuminate\Database\Eloquent\SoftDeletes; class ProcessOrder extends Model { - use SoftDeletes; + use SoftDeletes; protected $fillable = [ - "plant_id", - "item_id", - "process_order", - "coil_number", - "order_quantity", - "received_quantity", - "created_at", - "created_by", - "updated_by", - "updated_at" + 'plant_id', + 'item_id', + 'process_order', + 'coil_number', + 'order_quantity', + 'received_quantity', + 'sfg_number', + 'machine_name', + 'created_at', + 'created_by', + 'updated_by', + 'updated_at', ]; public function plant(): BelongsTo @@ -32,5 +34,4 @@ class ProcessOrder extends Model { return $this->belongsTo(Item::class, 'item_id'); } - } diff --git a/database/migrations/2025_11_26_160752_add_sfg_number_and_machine_name_columns_to_process_orders.php b/database/migrations/2025_11_26_160752_add_sfg_number_and_machine_name_columns_to_process_orders.php new file mode 100644 index 0000000..4cbca26 --- /dev/null +++ b/database/migrations/2025_11_26_160752_add_sfg_number_and_machine_name_columns_to_process_orders.php @@ -0,0 +1,38 @@ +