From 6b8c4de98585464c2b51e190b03cf4f79b83f441 Mon Sep 17 00:00:00 2001 From: dhanabalan Date: Fri, 31 Oct 2025 17:37:05 +0530 Subject: [PATCH] Added resource file of invoice data validation --- .../InvoiceDataValidationResource.php | 409 ++++++++++++++++++ .../Pages/CreateInvoiceDataValidation.php | 12 + .../Pages/EditInvoiceDataValidation.php | 22 + .../Pages/ListInvoiceDataValidations.php | 19 + .../Pages/ViewInvoiceDataValidation.php | 19 + 5 files changed, 481 insertions(+) create mode 100644 app/Filament/Resources/InvoiceDataValidationResource.php create mode 100644 app/Filament/Resources/InvoiceDataValidationResource/Pages/CreateInvoiceDataValidation.php create mode 100644 app/Filament/Resources/InvoiceDataValidationResource/Pages/EditInvoiceDataValidation.php create mode 100644 app/Filament/Resources/InvoiceDataValidationResource/Pages/ListInvoiceDataValidations.php create mode 100644 app/Filament/Resources/InvoiceDataValidationResource/Pages/ViewInvoiceDataValidation.php diff --git a/app/Filament/Resources/InvoiceDataValidationResource.php b/app/Filament/Resources/InvoiceDataValidationResource.php new file mode 100644 index 0000000..266e37e --- /dev/null +++ b/app/Filament/Resources/InvoiceDataValidationResource.php @@ -0,0 +1,409 @@ +schema([ + Forms\Components\Select::make('plant_id') + ->label('Plant') + ->relationship('plant', 'name') + ->required(), + Forms\Components\TextInput::make('distribution_channel_desc') + ->label('Distribution Channel Description') + ->required(), + Forms\Components\TextInput::make('customer_code') + ->label('Customer Code') + ->required(), + Forms\Components\TextInput::make('document_number') + ->label('Document Number') + ->required(), + Forms\Components\DatePicker::make('document_date') + ->label('Document Date') + ->required(), + Forms\Components\TextInput::make('customer_trade_name') + ->label('Customer Trade Name') + ->required(), + Forms\Components\TextInput::make('customer_location') + ->label('Customer Location') + ->required(), + Forms\Components\Hidden::make('created_by') + ->label('Created By') + ->default(Filament::auth()->user()?->name), + Forms\Components\Hidden::make('updated_by') + ->default(Filament::auth()->user()?->name), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + 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.code') + ->label('Plant') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('distribution_channel_desc') + ->label('Distribution Channel Description') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('customer_code') + ->label('Customer Code') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('document_number') + ->label('Document Number') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('document_date') + ->label('Document Date') + ->alignCenter() + ->date() + ->sortable(), + Tables\Columns\TextColumn::make('customer_trade_name') + ->label('Customer Trade Name') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('customer_location') + ->label('Customer Location') + ->alignCenter() + ->sortable(), + Tables\Columns\TextColumn::make('created_at') + ->label('Created At') + ->alignCenter() + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->label('Updated At') + ->alignCenter() + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('deleted_at') + ->label('Deleted At') + ->alignCenter() + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + Tables\Filters\TrashedFilter::make(), + ]) + ->actions([ + Tables\Actions\ViewAction::make(), + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + Tables\Actions\ForceDeleteBulkAction::make(), + Tables\Actions\RestoreBulkAction::make(), + ]), + ]) + ->headerActions([ + Tables\Actions\Action::make('Import Invoice Data') + ->label('Import Invoice Data') + ->form([ + FileUpload::make('invoice_data_file') + ->label('Invoice Data File') + // ->required() + ->preserveFilenames() + ->storeFiles(false) + ->reactive() + ->required() + ->disk('local') + //->visible(fn (Get $get) => !empty($get('plant_id'))) + ->directory('uploads/temp'), + ]) + ->action(function (array $data) { + $uploadedFile = $data['invoice_data_file']; + + $disk = Storage::disk('local'); + + $user = Filament::auth()->user(); + + $operatorName = $user->name; + + // Get original filename + $originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx + + $originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME); + + // Store manually using storeAs to keep original name + $path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path + + $fullPath = Storage::disk('local')->path($path); + + if ($fullPath && file_exists($fullPath)) + { + $rows = Excel::toArray(null, $fullPath)[0]; + + if ((count($rows) - 1) <= 0) + { + Notification::make() + ->title('Records Not Found') + ->body("Import the valid 'Invoice Data' file to proceed..!") + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $invalidPlantCode = []; + $invalidPlaCoFound = []; + $invalidDisChaDesc = []; + $invalidCustomerCode = []; + $invalidDocNo = []; + $invalidDocDate = []; + $invalidCusTradeName = []; + $invalidCusLocation = []; + $invalidUser = []; + $userNotFound = []; + + foreach ($rows as $index => $row) + { + if ($index == 0) continue; // Skip header + + $plantCode = trim($row[0]); + $DisChaDesc = trim($row[1]); + $CustomerCode = trim($row[2]); + $DocNo = trim($row[3]); + $DocDate = trim($row[4]); + $CusTradeName = trim($row[5]); + $CusLocation = trim($row[6]); + + if (empty($plantCode)) $invalidPlantCode[] = "Row {$index}"; + //if (empty($DisChaDesc)) $invalidDisChaDesc[] = "Row {$index}"; + if (empty($CustomerCode)) $invalidCustomerCode[] = "Row {$index}"; + if (empty($DocNo)) $invalidDocNo[] = "Row {$index}"; + if (empty($CusTradeName)) $invalidCusTradeName[] = "Row {$index}"; + if (empty($CusLocation)) $invalidCusLocation[] = "Row {$index}"; + // if (empty($createdBy)) $invalidUser[] = "Row {$index}"; + + if (strlen($plantCode) < 4) { + $invalidPlantCode[] = $plantCode; + } + else if(!Plant::where('code', $plantCode)->first()) + { + $invalidPlaCoFound[] = $plantCode; + } + // else if(!User::where('name', $createdBy)->first()) + // { + // $userNotFound[] = $createdBy; + // } + + } + + + //!empty($invalidDisChaDesc) || + + if (!empty($invalidCustomerCode) || !empty($invalidDocNo) || !empty($invalidDocDate) || !empty($invalidCusTradeName) || !empty($invalidCusLocation) || !empty($invalidUser)) + { + $errorMsg = ''; + + //if (!empty($invalidDisChaDesc)) $errorMsg .= 'Missing Distribution Channel Description in rows: ' . implode(', ', $invalidDisChaDesc) . '
'; + if (!empty($invalidCustomerCode)) $errorMsg .= 'Missing Customer Code in rows: ' . implode(', ', $invalidCustomerCode) . '
'; + if (!empty($invalidDocNo)) $errorMsg .= 'Missing Document Number in rows: ' . implode(', ', $invalidDocNo) . '
'; + if (!empty($invalidDocDate)) $errorMsg .= 'Missing Document Date in rows: ' . implode(', ', $invalidDocDate) . '
'; + if (!empty($invalidCusTradeName)) $errorMsg .= 'Missing Customer Trade Name in rows: ' . implode(', ', $invalidCusTradeName) . '
'; + if (!empty($invalidCusLocation)) $errorMsg .= 'Missing Customer Location in rows: ' . implode(', ', $invalidCusLocation) . '
'; + if (!empty($invalidUser)) $errorMsg .= 'Missing User in rows: ' . implode(', ', $invalidUser) . '
'; + + Notification::make() + ->title('Missing Mandatory Fields') + ->body($errorMsg) + ->danger() + ->send(); + + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + if (!empty($invalidPlantCode)) { + $invalidPlantCode = array_unique($invalidPlantCode); + Notification::make() + ->title('Invalid Plant Codes') + ->body('The following plant codes should contain minimum 4 digits:
' . implode(', ', $invalidPlantCode)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + if (!empty($invalidPlaCoFound)) { + $invalidPlaCoFound = array_unique($invalidPlaCoFound); + Notification::make() + ->title('Invalid Plant Codes') + ->body('The following plant codes not found in plants:
' . implode(', ', $invalidPlaCoFound)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + if (!empty($userNotFound)) { + $userNotFound = array_unique($userNotFound); + Notification::make() + ->title('Invalid User') + ->body('The following user not found:
' . implode(', ', $userNotFound)) + ->danger() + ->send(); + if ($disk->exists($path)) { + $disk->delete($path); + } + return; + } + + $successCount = 0; + $failCount = 0; + + foreach ($rows as $index => $row) { + if ($index == 0) continue; + + $plantCode = trim($row[0]); + $DisChaDesc = trim($row[1]); + $CustomerCode = trim($row[2]); + $DocNo = trim($row[3]); + $DocDate = trim($row[4]); + $CusTradeName = trim($row[5]); + $CusLocation = trim($row[6]); + + try + { + $plant = Plant::where('code', $plantCode)->first(); + + if (!empty($DocDate)) { + if (preg_match('/^\d{2}[-\/]\d{2}[-\/]\d{4}$/', $DocDate)) { + [$day, $month, $year] = preg_split('/[-\/]/', $DocDate); + $formattedDate = "{$year}-{$month}-{$day}"; + } elseif (is_numeric($DocDate)) { + $formattedDate = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($DocDate)->format('Y-m-d'); + } else { + $formattedDate = date('Y-m-d', strtotime($DocDate)); + } + } else { + $formattedDate = null; + } + + $inserted = InvoiceDataValidation::create([ + 'plant_id' => $plant->id, + 'distribution_channel_desc' => $DisChaDesc, + 'customer_code' => $CustomerCode, + 'document_number' => $DocNo, + 'document_date' => $formattedDate, + 'customer_trade_name' => $CusTradeName, + 'customer_location' => $CusLocation, + 'created_by' => $operatorName, + ]); + + if ($inserted) { + $successCount++; + } else { + $failCount++; + } + } catch (\Exception $e) { + $failCount++; + } + } + if($successCount > 0) + { + Notification::make() + ->title('Import Summary') + ->body("Successfully inserted: {$successCount} records") + ->success() + ->send(); + } + else + { + Notification::make() + ->title('Import Summary') + ->body("Failed to insert any records.") + ->danger() + ->send(); + } + } + }) + ->visible(function() { + return Filament::auth()->user()->can('view import invoice data validation'); + }), + ExportAction::make() + ->exporter(InvoiceDataValidationExporter::class) + ->visible(function() { + return Filament::auth()->user()->can('view export invoice data validation'); + }), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListInvoiceDataValidations::route('/'), + 'create' => Pages\CreateInvoiceDataValidation::route('/create'), + 'view' => Pages\ViewInvoiceDataValidation::route('/{record}'), + 'edit' => Pages\EditInvoiceDataValidation::route('/{record}/edit'), + ]; + } + + public static function getEloquentQuery(): Builder + { + return parent::getEloquentQuery() + ->withoutGlobalScopes([ + SoftDeletingScope::class, + ]); + } +} diff --git a/app/Filament/Resources/InvoiceDataValidationResource/Pages/CreateInvoiceDataValidation.php b/app/Filament/Resources/InvoiceDataValidationResource/Pages/CreateInvoiceDataValidation.php new file mode 100644 index 0000000..7f28674 --- /dev/null +++ b/app/Filament/Resources/InvoiceDataValidationResource/Pages/CreateInvoiceDataValidation.php @@ -0,0 +1,12 @@ +