diff --git a/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php b/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php index 5d18f9a2b..c76dd696c 100644 --- a/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php +++ b/app/Filament/Resources/InvoiceValidationResource/Pages/CreateInvoiceValidation.php @@ -53,7 +53,6 @@ class CreateInvoiceValidation extends CreateRecord public function getFormActions(): array { - // return parent::getFormActions(); //return []; return [ $this->getCancelFormAction(), ]; @@ -61,6 +60,8 @@ class CreateInvoiceValidation extends CreateRecord public function processInvoice($invoiceNumber) { + $invoiceNumber = trim($invoiceNumber); + $this->showCapacitorInput = false; $user = Filament::auth()->user(); @@ -73,7 +74,7 @@ class CreateInvoiceValidation extends CreateRecord $updateStatus = $this->form->getState()['update_invoice'] ?? null; - $this->invoiceNumber = $this->form->getState()['invoice_number'] ?? $invoiceNumber; + $this->invoiceNumber = trim($this->form->getState()['invoice_number']) ?? $invoiceNumber; $invoiceType = null; //$this->invoiceNumber = $this->invoiceNumber ?? $invoiceNumber; @@ -143,7 +144,438 @@ class CreateInvoiceValidation extends CreateRecord if($updateStatus === '1') { - dd('Material invoice update in progress...'); + //dd('Material invoice update in progress...'); + $filename = $invoiceNumber . '.xlsx'; + $directory = 'uploads/temp'; + $disk = Storage::disk('local'); + $filePath = $directory . '/' . $filename; + $fullPath = $disk->path($filePath); + + if ($fullPath && file_exists($fullPath)) + { + // Now you can read/process the file here + $rows = Excel::toArray(null, $fullPath)[0]; + + if((count($rows) - 1) <= 0) + { + Notification::make() + ->title('Records Not Found') + ->body("Import the valid updated 'Material Invoice' file to proceed..!") + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $invalidMatCodes = []; + $materialCodes = []; + $missingQuantities = []; + $invalidMatQuan = []; + $validRowsFound = false; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $materialCode = trim($row[0]); + $materialQuantity = trim($row[1]); + + if (empty($materialCode) && empty($materialQuantity)) { + continue; + } + + if (!empty($materialCode)) { + if(Str::length($materialCode) < 6 || !ctype_alnum($materialCode)) + { + $invalidMatCodes[] = $materialCode; + } + else + { + if (empty($materialQuantity)) { + $missingQuantities[] = $materialCode; + } + else if(!is_numeric($materialQuantity)) + { + $invalidMatQuan[] = $materialCode; + } + else if($materialQuantity == 0) + { + $invalidMatQuan[] = $materialCode; + } + else + { + $materialCodes[] = $materialCode; + $validRowsFound = true; + } + } + } + else + { + continue; + } + } + + if (!$validRowsFound) { + Notification::make() + ->title('Invalid Material Invoice') + ->danger() // This makes the notification red to indicate an error + ->body('Uploaded Excel sheet is empty or
contains no valid data.') + ->send(); + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueInvalidCodes = array_unique($invalidMatCodes); + + if (!empty($uniqueInvalidCodes)) { + Notification::make() + ->title('Invalid Item Codes') + ->body('The following item codes should contain minimum 6 digit alpha numeric values:
' . implode(', ', $uniqueInvalidCodes)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueMissingQuanCodes = array_unique($missingQuantities); + + if (!empty($uniqueMissingQuanCodes)) { + Notification::make() + ->title('Missing Material Quantity') + ->body("The following item codes doesn't have valid material quantity:
" . implode(', ', $uniqueMissingQuanCodes)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueInvalidMatQuan = array_unique($invalidMatQuan); + + if (!empty($uniqueInvalidMatQuan)) { + Notification::make() + ->title('Invalid Material Quantity') + ->body("The following item codes doesn't have valid material quantity:
" . implode(', ', $uniqueInvalidMatQuan)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueCodes = array_unique($materialCodes); + + $matchedItems = StickerMaster::with('item') + ->whereHas('item', function ($query) use ($uniqueCodes) { + $query->whereIn('code', $uniqueCodes); + }) + ->get(); + + $matchedCodes = $matchedItems->pluck('item.code')->toArray(); + + $missingCodes = array_diff($uniqueCodes, $matchedCodes); + + if (!empty($missingCodes)) + { + $missingCount = count($missingCodes); + + $message = $missingCount > 10 ? "'$missingCount' item codes are not found in database." : 'The following item codes are not found in database:
' . implode(', ', $missingCodes); + + Notification::make() + ->title('Unknown Item Codes') + ->body($message) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $invalidCodes = $matchedItems + ->filter(fn ($sticker) => empty($sticker->material_type)) //filter invalid + ->pluck('item.code') + ->toArray(); + + + if (!empty($invalidCodes)) + { + $missingCount = count($invalidCodes); + + $message = $missingCount > 10 ? "'$missingCount' Serial Invoice item codes found." : "'Serial Invoice' item codes found:
" . implode(', ', $invalidCodes); + + Notification::make() + ->title('Invalid Item Codes') + ->body($message) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $nonNumericQtyCodes = []; + $zeroQtyCodes = []; + $notDivisibleCodes = []; + + foreach ($matchedItems as $sticker) + { + $code = $sticker->item->code; + $materialType = $sticker->material_type; + + if ($materialType == 2) + { + $bundleQty = $sticker->bundle_quantity ?? 0; + $totalExcelQty = 0; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $excelCode = trim($row[0]); + $excelMatQty = trim($row[1]); + + + if ($excelCode === $code && is_numeric($excelMatQty)) { + $totalExcelQty += $excelMatQty; // Sum up the quantities + } + } + + if ($totalExcelQty === 0) { + $zeroQtyCodes[] = $code; + } elseif (!is_numeric($totalExcelQty)) { + $nonNumericQtyCodes[] = $code; // Here you may want to check divisibility condition too + } elseif ($bundleQty != 0 && $totalExcelQty % $bundleQty !== 0) { + $notDivisibleCodes[] = $code; + } + } + } + + $showValidationNotification = function(array $codes, string $message) { + if (count($codes) === 0) return; + + $uniqueCodes = array_unique($codes); + $codeList = implode(', ', $uniqueCodes); + + Notification::make() + ->title('Invalid Bundle Quantity') + ->body("$message
$codeList") + ->danger() + ->send(); + }; + + $showValidationNotification($nonNumericQtyCodes, "The following item codes contains invalid bundle quantity:"); + $showValidationNotification($zeroQtyCodes, "The following item codes quantity should be greater than '0':"); + $showValidationNotification($notDivisibleCodes, "The following item codes quantity is not divisible by bundle quantity."); + + + if ($nonNumericQtyCodes || $zeroQtyCodes || $notDivisibleCodes) { + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + else + { + $oldQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + $newQuan = -1; + + $inserted = 0; + foreach ($matchedItems as $sticker) + { + if ($newQuan === -1) + { + InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->where(function($query) { + $query->whereNull('serial_number')->orWhere('serial_number', ''); + }) + ->delete(); + + $newQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + continue; + } + + $code = $sticker->item->code; + $materialType = $sticker->material_type; + // $sticker = StickerMaster::where('plant_id', $plantId)->whereHas('item', function ($query) use ($code) { $query->where('plant_id', $this->plantId)->where('code', $code); })->first(); + + if ($materialType == 1) + { + $totalExcelQty = 0; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $excelCode = trim($row[0]); + $excelMatQty = trim($row[1]); + + if ($excelCode === $code && is_numeric($excelMatQty)) { + $totalExcelQty += $excelMatQty; // Sum up the quantities + } + } + + $existQty = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->where('sticker_master_id', $sticker->id)->count(); + + if ($existQty < $totalExcelQty) + { + $newQty = $totalExcelQty - $existQty; + for ($i = 0; $i < $newQty; $i++) + { + if ($sticker) { + InvoiceValidation::create([ + 'sticker_master_id' => $sticker->id, + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'quantity' => 1, + 'operator_id'=> $operatorName, + ]); + $inserted++; + } + } + } + } + else if ($materialType == 2) + { + $bundleQty = $sticker->bundle_quantity; + $totalExcelQty = 0; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $excelCode = trim($row[0]); + $excelMatQty = trim($row[1]); + + if ($excelCode === $code && is_numeric($excelMatQty)) { + $totalExcelQty += $excelMatQty; // Sum up the quantities + } + } + + $existQty = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->where('sticker_master_id', $sticker->id)->count(); + + //for ($i = 0; $i < ($totalExcelQty/$bundleQty); $i++) + $newTotQty = $totalExcelQty/$bundleQty; + if ($existQty < $newTotQty) + { + $newQty = $newTotQty - $existQty; + for ($i = 0; $i < $newQty; $i++) + { + if ($sticker) { + InvoiceValidation::create([ + 'sticker_master_id' => $sticker->id, + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'quantity' => $bundleQty, + 'operator_id'=> $operatorName, + ]); + $inserted++; + } + } + } + } + } + + if ($inserted > 0 || $oldQuan !== $newQuan) + { + Notification::make() + ->title("Material invoice successfully updatad.") + ->success() + ->send(); + Notification::make() + ->title("Start the scanning process!") + ->body("'$inserted' new material invoice records were inserted.") + ->info() + // ->success() + ->send(); + + // Update total quantity in the form + $totalQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + $scannedQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->whereNotNull('serial_number')->where('serial_number', '!=', '')->where('plant_id', $plantId)->count(); + $this->form->fill([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => null, + 'total_quantity' => $totalQuantity, + 'scanned_quantity'=> $scannedQuantity, + ]); + + if ($totalQuantity === $scannedQuantity) + { + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + + $this->dispatch('refreshCompletedInvoice', invoiceNumber: $invoiceNumber, plantId: $plantId); + } + else + { + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + + $this->dispatch('refreshMaterialInvoiceData', invoiceNumber: $invoiceNumber, plantId: $plantId); + } + } + else + { + Notification::make() + ->title("Update Failed: Material Invoice") + ->body("No new records were inserted for Material Invoice : '$invoiceNumber'.") + ->danger() + ->send(); + + $totalQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + $scannedQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->whereNotNull('serial_number')->where('serial_number', '!=', '')->where('plant_id', $plantId)->count(); + $this->form->fill([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => null, + 'total_quantity' => $totalQuantity, + 'scanned_quantity'=> $scannedQuantity, + ]); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + + $this->dispatch('refreshEmptyInvoice', invoiceNumber: $invoiceNumber, plantId: $plantId); + return; + } + } + } + else + { + Notification::make() + ->title('Updated Invoice Not Found') + ->body("Import the updated 'Material Invoice' file to proceed..!") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => null, + 'total_quantity' => 0, + 'scanned_quantity'=> 0, + ]); + $this->dispatch('refreshEmptyInvoice', invoiceNumber: $invoiceNumber, plantId: $plantId); + return; + } } } return; @@ -189,7 +621,362 @@ class CreateInvoiceValidation extends CreateRecord if($updateStatus === '1') { - dd('Serial invoice update in progress...'); + $filename = $invoiceNumber . '.xlsx'; + $directory = 'uploads/temp'; + $disk = Storage::disk('local'); + $filePath = $directory . '/' . $filename; + $fullPath = $disk->path($filePath); + + // Check if file exists //$disk->exists($filePath) + if ($fullPath && file_exists($fullPath)) + { + // /home/iot-dev/projects/pds/storage/app/private/uploads/temp/3RA0018735.xlsx + // dd('Serial invoice update in progress...'); + + // Now you can read/process the file here + $rows = Excel::toArray(null, $fullPath)[0]; + + if((count($rows) - 1) <= 0) + { + Notification::make() + ->title('Records Not Found') + ->body("Import the valid updated 'Serial Invoice' file to proceed..!") + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $invalidMatCodes = []; + $materialCodes = []; + $missingSerials = []; + $invalidSerCodes = []; + $duplicateSerials = []; + $serialNumbers = []; + $validRowsFound = false; + + foreach ($rows as $index => $row) + { + if ($index === 0) continue; // Skip header + + $materialCode = trim($row[0]); + $serialNumber = trim($row[1]); + + if (empty($materialCode) && empty($serialNumber)) + { + continue; + } + + if (!empty($materialCode)) + { + if(Str::length($materialCode) < 6 || !ctype_alnum($materialCode)) + { + $invalidMatCodes[] = $materialCode; + continue; + } + else + { + if(empty($serialNumber)) { + $missingSerials[] = $materialCode; + } + else if(Str::length($serialNumber) < 9 || !ctype_alnum($serialNumber)) + { + $invalidSerCodes[] = $serialNumber; + } + else + { + if (in_array($serialNumber, $serialNumbers)) + { + $duplicateSerials[] = $serialNumber; + } + else + { + $serialNumbers[] = $serialNumber; + $materialCodes[] = $materialCode; + $validRowsFound = true; + } + } + } + } + else + { + continue; + } + } + + if (!$validRowsFound) { + Notification::make() + ->title('Invalid Serial Invoice') + ->danger() // This makes the notification red to indicate an error + ->body('Uploaded excel sheet is empty or
contains no valid data.') + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueInvalidCodes = array_unique($invalidMatCodes); + + if (!empty($uniqueInvalidCodes)) { + Notification::make() + ->title('Invalid Item Codes') + ->body('The following item codes should contain minimum 6 digit alpha numeric values:
' . implode(', ', $uniqueInvalidCodes)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueCodes = array_unique($materialCodes); + + $matchedItems = StickerMaster::with('item') + ->whereHas('item', function ($query) use ($uniqueCodes) { + $query->whereIn('code', $uniqueCodes); + }) + ->get(); + + $matchedCodes = $matchedItems->pluck('item.code')->toArray(); + + $missingCodes = array_diff($uniqueCodes, $matchedCodes); + + if (!empty($missingCodes)) + { + $missingCount = count($missingCodes); + + $message = $missingCount > 10 ? "'$missingCount' item codes are not found in database." : 'The following item codes are not found in database:
' . implode(', ', $missingCodes); + + Notification::make() + ->title('Unknown Item Codes') + ->body($message) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $invalidCodes = $matchedItems + ->filter(fn ($sticker) => !empty($sticker->material_type)) //filter invalid + ->pluck('item.code') + ->toArray(); + + if (!empty($invalidCodes)) + { + $missingCount = count($invalidCodes); + + $message = $missingCount > 10 ? "'$missingCount' Material Invoice item codes found." : "'Material Invoice' item codes found:
" . implode(', ', $invalidCodes); + + Notification::make() + ->title('Invalid Item Codes') + ->body($message) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueMissingSerials = array_unique($missingSerials); + + if (!empty($uniqueMissingSerials)) { + Notification::make() + ->title('Missing Serial Numbers') + ->body("The following item codes doesn't have valid serial number:
" . implode(', ', $uniqueMissingSerials)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueInvalidSerCodes = array_unique($invalidSerCodes); + + if (!empty($uniqueInvalidSerCodes)) { + Notification::make() + ->title('Invalid Serial Numbers') + ->body('The following serial numbers should contain minimum 9 digit alpha numeric values:
' . implode(', ', $uniqueInvalidSerCodes)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $uniqueDupSerCodes = array_unique($duplicateSerials); + + if (!empty($uniqueDupSerCodes)) { + Notification::make() + ->title('Duplicate Serial Numbers') + ->body('The following serial numbers are already exist in invoice excel:
' . implode(', ', $uniqueDupSerCodes)) + ->danger() + ->send(); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + return; + } + + $oldQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + $newQuan = 0; + + $inserted = 0; + foreach ($rows as $index => $row) + { + if ($index === 0) // Skip header; + { + InvoiceValidation::where('invoice_number', $invoiceNumber) + ->where(function($query) { + $query->whereNull('motor_scanned_status')->orWhere('motor_scanned_status', ''); + }) + ->where(function($query) { + $query->whereNull('pump_scanned_status')->orWhere('pump_scanned_status', ''); + }) + ->where(function($query) { + $query->whereNull('capacitor_scanned_status')->orWhere('capacitor_scanned_status', ''); + }) + ->where(function($query) { + $query->whereNull('scanned_status_set')->orWhere('scanned_status_set', ''); + }) + ->where(function($query) { + $query->whereNull('scanned_status')->orWhere('scanned_status', ''); + }) + ->delete(); + + $newQuan = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + continue; + } + + $materialCode = trim($row[0]); + $serialNumber = trim($row[1]); + + if (empty($materialCode) || empty($serialNumber)) { + continue; + } + + $sNoExist = InvoiceValidation::where('serial_number', $serialNumber)->where('plant_id', $plantId)->pluck('serial_number')->first()->exists(); + + if($sNoExist) { continue; } + + $sticker = StickerMaster::where('plant_id', $plantId)->whereHas('item', function ($query) use ($materialCode) { + $query->where('plant_id', $this->plantId)->where('code', $materialCode); //Check if item.code matches Excel's materialCode + })->first(); + + if ($sticker) { + InvoiceValidation::create([ + 'sticker_master_id' => $sticker->id, + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => $serialNumber, + 'operator_id'=> $operatorName, + ]); + $inserted++; + } + } + + if ($inserted > 0 || $oldQuan !== $newQuan) + { + Notification::make() + ->title("Serial invoice successfully updated.") + ->success() + ->send(); + + Notification::make() + ->title("Start the scanning process!") + ->body("'$inserted' new serial invoice records were inserted.") + ->info() + // ->success() + ->send(); + + // Update total quantity in the form + $totalQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + $scannedQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('scanned_status', 'Scanned')->where('plant_id', $plantId)->count(); + $this->form->fill([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => null, + 'total_quantity' => $totalQuantity, + 'scanned_quantity'=> $scannedQuantity, + ]); + + if ($totalQuantity === $scannedQuantity) + { + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + + $this->dispatch('refreshCompletedInvoice', invoiceNumber: $invoiceNumber, plantId: $plantId); + } + else + { + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + // $hasRecords = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->first()->stickerMasterRelation->material_type ?? null; + // $this->dispatch( (!empty($hasRecords) && $hasRecords) ? 'refreshMaterialInvoiceData' : 'refreshInvoiceData', invoiceNumber: $invoiceNumber, plantId: $plantId); //$this->invoiceNumber + $this->dispatch('refreshInvoiceData', invoiceNumber: $invoiceNumber, plantId: $plantId); + } + } + else + { + Notification::make() + ->title("Update Failed: Serial Invoice") + ->body("No new records were inserted for Serial Invoice : '$invoiceNumber'.") + ->danger() + ->send(); + + $totalQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('plant_id', $plantId)->count(); + $scannedQuantity = InvoiceValidation::where('invoice_number', $invoiceNumber)->where('scanned_status', 'Scanned')->where('plant_id', $plantId)->count(); + $this->form->fill([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => null, + 'total_quantity' => $totalQuantity, + 'scanned_quantity'=> $scannedQuantity, + ]); + + if ($disk->exists($filePath)) { + $disk->delete($filePath); + } + + $this->dispatch('refreshEmptyInvoice', invoiceNumber: $invoiceNumber, plantId: $plantId); + return; + } + } + else + { + Notification::make() + ->title('Updated Invoice Not Found') + ->body("Import the updated 'Serial Invoice' file to proceed..!") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'invoice_number' => $invoiceNumber, + 'serial_number' => null, + 'total_quantity' => 0, + 'scanned_quantity'=> 0, + ]); + $this->dispatch('refreshEmptyInvoice', invoiceNumber: $invoiceNumber, plantId: $plantId); + return; + } } } return;