diff --git a/app/Filament/Resources/InvoiceDataValidationResource.php b/app/Filament/Resources/InvoiceDataValidationResource.php index b4f76ac..8f0f71c 100644 --- a/app/Filament/Resources/InvoiceDataValidationResource.php +++ b/app/Filament/Resources/InvoiceDataValidationResource.php @@ -23,6 +23,7 @@ use Illuminate\Support\Facades\Storage; use Maatwebsite\Excel\Facades\Excel; use App\Models\StickerMaster; use App\Models\User; +use DB; use Filament\Tables\Actions\ExportAction; class InvoiceDataValidationResource extends Resource @@ -213,16 +214,13 @@ class InvoiceDataValidationResource extends Resource $invalidPlantType = []; $seenPlantDoc = []; - $duplicateEntries = []; + //$duplicateEntries = []; $duplicateEntriesExcel = []; - $duplicateGroupedByPlant = []; - $duplicateGroupedByPlantExcel = []; foreach ($rows as $index => $row) { if ($index == 0) continue; // Skip header - $DisChaDesc = trim($row[3]); $plantCode = trim($row[4]); $CustomerCode = trim($row[5]); @@ -231,7 +229,7 @@ class InvoiceDataValidationResource extends Resource $CusTradeName = trim($row[9]); $CusLocation = trim($row[10]); - // if (empty($plantCode)) $invalidPlantCode[] = "Row {$index}"; + // if (empty($plantCode)) $invalidPlantCode[] = "Row {$index}"; if (empty($DisChaDesc)){ $invalidDisChaDesc[] = "Row {$index}"; } @@ -250,7 +248,7 @@ class InvoiceDataValidationResource extends Resource { $invalidCusLocation[] = "Row {$index}"; } - // if (empty($createdBy)) $invalidUser[] = "Row {$index}"; + // if (empty($createdBy)) $invalidUser[] = "Row {$index}"; if (strlen($plantCode) < 4) { $invalidPlantCode[] = $plantCode; @@ -258,31 +256,30 @@ class InvoiceDataValidationResource extends Resource if (!is_numeric($plantCode)) { $invalidPlantType[] = $plantCode; } - else if(!Plant::where('code', $plantCode)->first()) + else if (!Plant::where('code', $plantCode)->first()) { $invalidPlaCoFound[] = $plantCode; } - // --- Find Plant by code --- + // --- Find Plant by code --- $plant = Plant::where('code', $plantCode)->first(); - //Duplicate Check in DB --- - $exists = InvoiceDataValidation::where('plant_id', $plant->id) - ->where('document_number', $DocNo) - ->first(); + // //Duplicate Check in DB --- + // $exists = InvoiceDataValidation::where('plant_id', $plant->id) + // ->where('document_number', $DocNo) + // ->first(); - if ($exists) - { - $duplicateEntries[] = "Duplicate record: Document Number '{$DocNo}' already exists for Plant {$plant->name}"; - } + // if ($exists) + // { + // $duplicateEntries[] = "Duplicate record: Document Number '{$DocNo}' already exists for Plant '{$plant->name}'"; + // } //Also check duplicates within the same file --- $uniqueKey = $plantCode . '_' . $DocNo; if (in_array($uniqueKey, $seenPlantDoc)) { - $duplicateEntriesExcel[] = "Duplicate in file at Row {$index}: Document Number '{$DocNo}' already exist for Plant {$plant->name}"; + $duplicateEntriesExcel[] = "Duplicate in file at Row {$index}: Document Number '{$DocNo}' already exists for Plant '{$plant->name}'"; } $seenPlantDoc[] = $uniqueKey; - } if (!empty($invalidCustomerCode) || !empty($invalidDocNo) || !empty($invalidDocDate) || !empty($invalidCusTradeName) || !empty($invalidCusLocation)) @@ -307,96 +304,101 @@ class InvoiceDataValidationResource extends Resource } return; } - - - if (!empty($invalidPlantCode)) { + else 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(); + ->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; } - else if(!empty($invalidPlantType)) + else if (!empty($invalidPlantType)) { $invalidPlantType = array_unique($invalidPlantType); Notification::make() - ->title('Invalid Plant Codes') - ->body('The following plant codes should contain numeric values:
' . implode(', ', $invalidPlantType)) - ->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; - } - - foreach ($duplicateEntries as $message) - { - if (preg_match("/Document Number '([^']+)' already exists for Plant (.+)/", $message, $matches)) { - $docNo = $matches[1]; - $plantName = trim($matches[2]); - $duplicateGroupedByPlant[$plantName][] = $docNo; - } - } - - foreach ($duplicateEntriesExcel as $message) { - if (preg_match("/Document Number '([^']+)' already exist(?:s)?(?: for Plant (.+))?/", $message, $matches)) { - $docNo = $matches[1]; - $plantName = $matches[2] ?? 'Unknown'; - $duplicateGroupedByPlantExcel[$plantName][] = $docNo; - } - } - - if (!empty($duplicateGroupedByPlant)) { - $errorMsg = 'Duplicate Entries in Database:
'; - - foreach ($duplicateGroupedByPlant as $plant => $docNumbers) { - $count = count($docNumbers); - - if ($count > 10) - { - $errorMsg .= "Duplicate record(s) for Plant {$plant}: {$count} document numbers already exist in DB
"; - } - else - { - $errorMsg .= "Duplicate record(s) for Plant {$plant}: " - . implode(', ', $docNumbers) - . " already exist
"; - } - } - - Notification::make() - //->title('Duplicate Entries in Database') - ->body($errorMsg) + ->title('Invalid Plant Codes') + ->body('The following plant codes should contain numeric values:
' . implode(', ', $invalidPlantType)) ->danger() ->send(); - if ($disk->exists($path)) { $disk->delete($path); } return; } - if (!empty($duplicateGroupedByPlantExcel)) + else 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; + } - $errorMsg = 'Duplicate Entries found in Uploaded File:
'; + // if (!empty($duplicateEntries)) + // { + // $duplicateGroupedByPlant = []; + + // foreach ($duplicateEntries as $message) + // { + // if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) { + // $docNo = $matches[1]; + // $plantName = trim($matches[2]); + // $duplicateGroupedByPlant[$plantName][] = $docNo; + // } + // } + + // $errorMsg = 'Duplicate Document Number found in Database :
'; + + // foreach ($duplicateGroupedByPlant as $plant => $docNumbers) { + // $count = count($docNumbers); + + // if ($count > 10) + // { + // $errorMsg .= "Duplicate record(s) for Plant {$plant} : {$count} document numbers already exist in DB
"; + // } + // else + // { + // $errorMsg .= "Duplicate record(s) for Plant {$plant} : " + // . implode(', ', $docNumbers) + // . " already exist
"; + // } + // } + + // Notification::make() + // //->title('Duplicate Entries in Database') + // ->body($errorMsg) + // ->danger() + // ->send(); + + // if ($disk->exists($path)) { + // $disk->delete($path); + // } + // return; + // } + + if (!empty($duplicateEntriesExcel)) + { + $duplicateGroupedByPlantExcel = []; + + foreach ($duplicateEntriesExcel as $message) {//"/Document Number '([^']+)' already exist(?:s)?(?: for Plant (.+))?/" + if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) { + $docNo = $matches[1]; + $plantName = $matches[2] ?? 'Unknown'; + $duplicateGroupedByPlantExcel[$plantName][] = $docNo; + } + } + + $errorMsg = 'Duplicate Document Number found in Uploaded File :
'; foreach ($duplicateGroupedByPlantExcel as $plant => $docNumbers) { @@ -405,16 +407,16 @@ class InvoiceDataValidationResource extends Resource $count = count($uniqueDocNumbers); if ($count > 10) { - $errorMsg .= "Duplicate record(s) for Plant {$plant}: {$count} document numbers already exist in uploaded file
"; + $errorMsg .= "Duplicate Document Numbers for Plant {$plant} : {$count} Document Numbers already exist in uploaded file
"; } else { - $errorMsg .= "Duplicate record(s) for Plant {$plant}: " + $errorMsg .= "Duplicate Document Numbers for Plant {$plant} : '" . implode(', ', $uniqueDocNumbers) - . " already exist
"; + . "' already exist in uploaded file
"; } } Notification::make() - //->title('Duplicate Entries in Uploaded File') + //->title('Duplicate Document Number in Uploaded File') ->body($errorMsg) ->danger() ->send(); @@ -425,79 +427,138 @@ class InvoiceDataValidationResource extends Resource return; } - // if(!empty($duplicateEntriesExcel)) + // if (!empty($duplicateEntriesExcel)) // { - // //$errorMsg = 'Duplicate Entries found in the uploaded file:
' . implode('
', $duplicateEntriesExcel); - // $errorMsg = buildDuplicateMessage($duplicateEntriesExcel, 'Duplicate Entries found in Uploaded File'); + // //$errorMsg = 'Duplicate Document Number found in the uploaded file:
' . implode('
', $duplicateEntriesExcel); + // $errorMsg = buildDuplicateMessage($duplicateEntriesExcel, 'Duplicate Document Number found in Uploaded File'); // Notification::make() - // ->title('Duplicate Entries in Uploaded File') + // ->title('Duplicate Document Number in Uploaded File') // ->body($errorMsg) - $successCount = 0; - $failCount = 0; + $failedRecords = []; - foreach ($rows as $index => $row) { - if ($index == 0) continue; + DB::beginTransaction(); - $DisChaDesc = trim($row[3]); - $plantCode = trim($row[4]); - $CustomerCode = trim($row[5]); - $DocNo = trim($row[6]); - $DocDate = trim($row[7]); - $CusTradeName = trim($row[9]); - $CusLocation = trim($row[10]); + try + { + foreach ($rows as $index => $row) { + if ($index == 0) continue; - try - { - $plant = Plant::where('code', $plantCode)->first(); + $rowNumber = $index + 1; - 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)); + try { + $DisChaDesc = trim($row[3]); + $plantCode = trim($row[4]); + $CustomerCode = trim($row[5]); + $DocNo = trim($row[6]); + $DocDate = trim($row[7]); + $CusTradeName = trim($row[9]); + $CusLocation = trim($row[10]); + + if (empty($DocNo)) { + throw new \Exception("Row '{$rowNumber}' Missing QR Code"); } - } 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, - ]); + $plant = Plant::where('code', $plantCode)->first(); + if (!$plant) { + throw new \Exception("Invalid plant code : '{$plantCode}'"); + } + + 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; + } + + $record = InvoiceDataValidation::where('plant_id', $plant->id) + ->where('document_number', $DocNo) + ->first(); + + $curStat = $record ? 'Updation' : 'Insertion'; + + if ($record) { + $record->update([ + 'distribution_channel_desc' => $DisChaDesc, + 'customer_code' => $CustomerCode, + 'document_date' => $formattedDate, + 'customer_trade_name' => $CusTradeName, + 'customer_location' => $CusLocation, + 'updated_by' => $operatorName + ]); + $inserted = $record; + } else { + // Record does not exist, create with 'created_by' + $inserted = InvoiceDataValidation::create([ + 'plant_id' => $plant->id, + 'document_number' => $DocNo, + 'distribution_channel_desc' => $DisChaDesc, + 'customer_code' => $CustomerCode, + 'document_date' => $formattedDate, + 'customer_trade_name' => $CusTradeName, + 'customer_location' => $CusLocation, + 'created_by' => $operatorName + ]); + } + // $inserted = InvoiceDataValidation::create([ + // 'plant_id' => $plant->id, + // 'document_number' => $DocNo, + // 'distribution_channel_desc' => $DisChaDesc, + // 'customer_code' => $CustomerCode, + // 'document_date' => $formattedDate, + // 'customer_trade_name' => $CusTradeName, + // 'customer_location' => $CusLocation, + // 'created_by' => $operatorName + // ]); + + if (!$inserted) { + throw new \Exception("{$curStat} failed for Document Number : {$DocNo}"); + } - if ($inserted) { $successCount++; - } else { - $failCount++; + } catch (\Exception $e) { + $failedRecords[] = [ + 'row' => $rowNumber, + 'document_number' => $DocNo ?? null, + 'error' => $e->getMessage() + ]; } - } catch (\Exception $e) { - $failCount++; + } + + DB::commit(); + + if (count($failedRecords) > 0) { + $failedSummary = collect($failedRecords) + ->map(fn($f) => "Row {$f['row']} ({$f['document_number']}) : {$f['error']}") + ->take(5) // limit preview to first 5 errors + ->implode("\n"); + + Notification::make() + ->title('Partial Import Warning') + ->body("'{$successCount}' records inserted. " . count($failedRecords) . " failed.\n\n{$failedSummary}") + ->warning() + ->send(); + } else { + Notification::make() + ->title('Import Success') + ->body("Successfully imported '{$successCount}' records.") + ->success() + ->send(); } } - if($successCount > 0) + catch (\Exception $e) { + DB::rollBack(); Notification::make() - ->title('Import Summary') - ->body("Successfully inserted: {$successCount} records") - ->success() - ->send(); - } - else - { - Notification::make() - ->title('Import Summary') - ->body("Failed to insert any records.") + ->title('Import Failed') + ->body("No records were inserted. Error : {$e->getMessage()}") ->danger() ->send(); } @@ -506,10 +567,10 @@ class InvoiceDataValidationResource extends Resource ->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'); + ExportAction::make() + ->exporter(InvoiceDataValidationExporter::class) + ->visible(function() { + return Filament::auth()->user()->can('view export invoice data validation'); }), ]); }