diff --git a/app/Filament/Resources/InvoiceValidationResource.php b/app/Filament/Resources/InvoiceValidationResource.php
index eec47a3..f98bff0 100644
--- a/app/Filament/Resources/InvoiceValidationResource.php
+++ b/app/Filament/Resources/InvoiceValidationResource.php
@@ -3,13 +3,21 @@
namespace App\Filament\Resources;
use App\Filament\Resources\InvoiceValidationResource\Pages;
+use App\Imports\ExcelImport;
use App\Models\InvoiceValidation;
+use App\Models\Plant;
use App\Models\StickerMaster;
+use Filament\Actions\Action as FilamentActionsAction;
use Filament\Actions\CreateAction;
use Filament\Forms;
+use Filament\Forms\Components\Actions\Action as ActionsAction;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Section;
+use Filament\Forms\Components\Select;
+use Filament\Forms\Components\TextInput;
+use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form;
+use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
@@ -20,7 +28,11 @@ use Filament\Notifications\Notification;
use Filament\Tables\Actions\Action;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;
-use Livewire\Livewire; // Ensure this is imported
+use Livewire\Livewire;
+use Str;
+
+
+
class InvoiceValidationResource extends Resource
{
@@ -45,117 +57,842 @@ class InvoiceValidationResource extends Resource
Section::make('')
->schema([
- Forms\Components\Select::make('plant_id')
- ->relationship('plant', 'name')
- ->required(),
-
- Forms\Components\TextInput::make('invoice_number')
+ Forms\Components\Select::make('plant_id')
+ ->relationship('plant', 'name')
->required()
- ->label('Invoice Number')
+ // ->preload()
+ // ->nullable(),
+ ->reactive()
->columnSpan(1)
+ ->default(function () {
+ return optional(InvoiceValidation::latest()->first())->plant_id;
+ })
+ ->disabled(fn (Get $get) => !empty($get('id')))
+ // ->afterStateUpdated(fn ($set) => $set('block_id', null) & $set('name', null) & $set('start_time', null) & $set('duration', null) & $set('end_time', null))
+ ->afterStateUpdated(function ($state, callable $set, callable $get) {
+ $plantId = $get('plant_id');
+ $set('update_invoice', null);
+ // Ensure `linestop_id` is not cleared
+ if (!$plantId) {
+ $set('ivPlantError', 'Please select a plant first.');
+ return;
+ }
+ else
+ {
+ $set('ivPlantError', null);
+ }
+ })
+ ->extraAttributes(fn ($get) => [
+ 'class' => $get('ivPlantError') ? 'border-red-500' : '',
+ ])
+ ->hint(fn ($get) => $get('ivPlantError') ? $get('ivPlantError') : null)
+ ->hintColor('danger'),
+
+ Forms\Components\TextInput::make('invoice_number')
+ ->label('Invoice Number')
+ ->required()
+ ->reactive()
+ ->columnSpan(1)
+ ->readOnly(fn (callable $get) => !empty($get('serial_number')))
+ //->disabled(fn (Get $get) => !empty($get('serial_number')))
->extraAttributes([
'x-data' => '{ value: "" }',
'x-model' => 'value',
'x-on:keydown.enter.prevent' => '$wire.processInvoice(value)',
- ]),
+ ])
+ // ->afterStateHydrated(function (TextInput $component, string $state) {
+ // $component->state(ucwords($state));
+ // })
+ ->afterStateUpdated(function ($state, callable $set, callable $get) {
+ $invNo = $get('invoice_number');
+ $set('serial_number', null);
+ $set('update_invoice', null);
+ // if (!$invNo) { return; } else { }
+ }),
- Forms\Components\TextInput::make('serial_number')
+ Forms\Components\TextInput::make('serial_number')
+ ->label('Serial Number')
+ ->reactive()
+ ->readOnly(fn (callable $get) => empty($get('invoice_number')))
+ //->disabled(fn (Get $get) => empty($get('invoice_number')))
->extraAttributes([
'x-data' => '{ value: "" }',
'x-model' => 'value',
'wire:keydown.enter.prevent' => 'processSerialNumber(value)', // Using wire:keydown
])
-
->columnSpan(1),
-
Forms\Components\TextInput::make('total_quantity')
->label('Total Quantity')
+ ->readOnly(true)
->columnSpan(1),
Forms\Components\TextInput::make('scanned_quantity')
->label('Scanned Quantity')
+ ->readOnly(true)
->columnSpan(1),
+ ToggleButtons::make('update_invoice')
+ ->label('Update Invoice?')
+ ->boolean()
+ ->grouped()
+ ->reactive()
+ ->hidden(fn (callable $get) => ($get('invoice_number') == null || $get('update_invoice') === '0') || !empty($get('serial_number')))
+ ->afterStateUpdated(function ($state, callable $set, callable $get) {
+ if(!$get('plant_id'))
+ {
+ $set('update_invoice', null);
+ return;
+ }
+ if($get('update_invoice') === "1")
+ {
+ $totQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->where('plant_id', $get('plant_id'))->count();
+ if($totQuan <= 0)
+ {
+ $set('update_invoice', null);
+ return;
+ }
+
+ $totMQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->whereNotNull('quantity')->where('plant_id', $get('plant_id'))->count();
+ $scanMQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->whereNotNull('serial_number')->where('serial_number', '!=', '')->where('plant_id', $get('plant_id'))->count();
+ $scanSQuan = InvoiceValidation::where('invoice_number', $get('invoice_number'))->where('scanned_status', 'Scanned')->where('plant_id', $get('plant_id'))->count();
+
+ if($totMQuan > 0)
+ {
+ if ($totQuan === $scanMQuan)
+ {
+ $set('update_invoice', null);
+ return;
+ }
+ }
+ else
+ {
+ if ($totQuan === $scanSQuan)
+ {
+ $set('update_invoice', null);
+ return;
+ }
+ }
+ }
+ })
+ ->disabled(fn (Get $get) => empty($get('invoice_number'))),
+ Forms\Components\TextInput::make('id')
+ ->hidden()
+ ->readOnly(true),
])
->columns(5),
]);
}
+
+
public static function table(Table $table): Table
{
+
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
- Tables\Columns\TextColumn::make('stickerMaster.id')
- ->numeric()
+ Tables\Columns\TextColumn::make('invoice_number')
+ ->label('Invoice Number')
->sortable(),
- Tables\Columns\TextColumn::make('plant.name')
- ->numeric()
+ Tables\Columns\TextColumn::make('stickerMaster.item.code')
+ ->label('Material Code')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('serial_number')
+ ->label('Serial Number')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('motor_scanned_status')
+ ->label('Motor Scanned Status')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('pump_scanned_status')
+ ->label('Pump Scanned Status')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('scanned_status_set')
+ ->label('Pump Set Scanned Status')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('capacitor_scanned_status')
+ ->label('Capacitor Scanned Status')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('scanned_status')
+ ->label('Scanned Status')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('panel_box_supplier')
+ ->label('Panel Box Supplier')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('panel_box_serial_number')
+ ->label('Panel Box Serial Number')
->sortable(),
Tables\Columns\TextColumn::make('load_rate')
+ ->label('Load Rate')
->numeric()
->sortable(),
+ Tables\Columns\TextColumn::make('upload_status')
+ ->label('Upload Status')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('batch_number')
+ ->label('Batch Number')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('quantity')
+ ->label('Quantity')
+ ->numeric()
+ ->sortable(),
+ Tables\Columns\TextColumn::make('operator_id')
+ ->label('Operator ID')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('plant.name')
+ ->label('Plant')
+ ->sortable(),
+ Tables\Columns\TextColumn::make('created_at')
+ ->label('Created At')
+ ->dateTime()
+ ->sortable(),
+ Tables\Columns\TextColumn::make('updated_at')
+ ->label('Updated At')
+ ->dateTime()
+ ->sortable()
+ ->toggleable(isToggledHiddenByDefault: true),
+ Tables\Columns\TextColumn::make('deleted_at')
+ ->label('Deleted At')
+ ->dateTime()
+ ->sortable()
+ ->toggleable(isToggledHiddenByDefault: true),
])
+
->headerActions([
+
+ // Action::make('plant_id')
+ // ->label('Select Plant')
+ // ->form([
+ // Select::make('plant_id')
+ // ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs
+ // ->label('Select Plant')
+ // ->required()
+ // ->reactive()
+ // ]),
+
Tables\Actions\Action::make('Import Serial Number')
- ->label('Import Serial Number')
+ ->label('Import Serial Invoice')
->form([
+ Select::make('plant_id')
+ ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs
+ ->label('Select Plant')
+ ->required()
+ ->default(function () {
+ return optional(InvoiceValidation::latest()->first())->plant_id;
+ })
+ ->afterStateUpdated(function ($state, callable $set, callable $get) {
+ $set('invoice_serial_number', null);
+ })
+ ->reactive(),
+
FileUpload::make('invoice_serial_number')
->label('Invoice Serial Number')
+ // ->required()
->preserveFilenames() // <- this keeps the original filename
->storeFiles(false) // prevent auto-storing, we will store manually
+ ->reactive()
+ ->required()
->disk('local') //'local' refers to the local storage disk defined in config/filesystems.php, typically pointing to storage/app.
- ->directory('uploads/temp'), //storage/app/uploads/temp
+ ->visible(fn (Get $get) => !empty($get('plant_id')))
+ ->directory('uploads/temp'),
])
->action(function (array $data) {
$uploadedFile = $data['invoice_serial_number'];
+ $disk = Storage::disk('local');
+
+ $plantId = $data['plant_id'];
+
// Get original filename
$originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx
// Store manually using storeAs to keep original name
$path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local'); // returns relative path
+ // uploads/temp/3RA0018735.xlsx
+
+ $fullPath = Storage::disk('local')->path($path);
+ // /home/iot-dev/projects/pds/storage/app/private/uploads/temp/3RA0018735.xlsx
+
+ $totQuan = InvoiceValidation::where('invoice_number', $originalName)->where('plant_id', $plantId)->count();
+ $scanSQuan = InvoiceValidation::where('invoice_number', $originalName)->where('scanned_status', 'Scanned')->where('plant_id', $plantId)->count();
+
+ if($totQuan == $scanSQuan && $totQuan > 0)
+ {
+ Notification::make()
+ ->title('Serial invoice already completed the scanning process for selected plant.')
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path))
+ {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ 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 'Serial Invoice' file to proceed..!")
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ $invalidMatCodes = [];
+ $invalidSerialCodes=[];
+ $materialCodes = [];
+ $missingSerials = [];
+ $duplicateSerials = [];
+ $seenSerialNumbers = [];
+ $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;
+
+ }
+ else
+ {
+
+ if (empty($serialNumber)) {
+ $missingSerials[] = $materialCode;
+
+ }
+ else if(Str::length($serialNumber) < 9 || !ctype_alnum($serialNumber))
+ {
+ $invalidSerialCodes[] = $serialNumber;
+ }
+ else
+ {
+ if (in_array($serialNumber, $seenSerialNumbers)) {
+ $duplicateSerials[] = $serialNumber;
+ } else {
+ $seenSerialNumbers[] = $serialNumber;
+ $materialCodes[] = $materialCode;
+ $validRowsFound = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ $uniqueInvalidCodes = array_unique($invalidMatCodes);
+
+ $uniqueMissingSerials = array_unique($missingSerials);
+
+ $uniqueSerialCodes = array_unique($invalidSerialCodes);
+
+ $duplicateSerialCodes = array_unique($duplicateSerials);
+
+
+ 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($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ else 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($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ else if (!empty($uniqueSerialCodes)) {
+ Notification::make()
+ ->title('Invalid Serial Number')
+ ->body('The following serial numbers should contain minimum 9 digit alpha numeric values:
' . implode(', ', $uniqueSerialCodes))
+ ->danger()
+ ->send();
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ else if (!empty($duplicateSerialCodes)) {
+ Notification::make()
+ ->title('Duplicate Serial Numbers')
+ ->body('The following serial numbers are already exist in database:
' . implode(', ', $duplicateSerialCodes))
+ ->danger()
+ ->send();
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ 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($path)) {
+ $disk->delete($path);
+ }
+ 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($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ // Check which codes have a material_type set (not null)
+ $invalidCodes = $matchedItems
+ ->filter(fn ($sticker) => !empty($sticker->material_type)) //filter invalid
+ ->pluck('item.code')
+ ->toArray();
+
+ if (count($invalidCodes) > 10)
+ {
+ Notification::make()
+ ->title('Invalid item codes found')
+ ->body('' . count($invalidCodes) . 'item codes found have material type.')
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ else if(count($invalidCodes) > 0)
+ {
+ Notification::make()
+ ->title('Invalid item codes found')
+ ->body('Material invoice Item Codes found : ' . implode(', ', $invalidCodes))
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ else
+ {
+ // Save full file path to session
+ session(['uploaded_invoice_path' => $fullPath]);
+ Notification::make()
+ ->title('Serial invoice imported successfully.')
+ ->success()
+ ->send();
+ }
+ }
+ }),
+
+ Tables\Actions\Action::make('Import Invoice Material')
+ ->label('Import Material Invoice')
+ ->form([
+
+ Select::make('plant_id')
+ ->options(Plant::pluck('name', 'id')->toArray()) // Fetch plant names and IDs
+ ->label('Select Plant')
+ ->required()
+ ->reactive()
+ ->default(function () {
+ return optional(InvoiceValidation::latest()->first())->plant_id;
+ })
+ ->afterStateUpdated(function ($state, callable $set, callable $get) {
+ $set('invoice_material', null);
+ }),
+
+
+ FileUpload::make('invoice_material')
+ ->label('Invoice Material')
+ ->required()
+ ->preserveFilenames()
+ ->reactive() // <- this keeps the original filename
+ ->storeFiles(false) // prevent auto-storing
+ ->disk('local')
+ ->visible(fn (Get $get) => !empty($get('plant_id')))
+ ->directory('uploads/temp')
+
+ ])
+
+ ->action(function (array $data) {
+ $uploadedFile = $data['invoice_material'];
+
+ $plantId = $data['plant_id']; // Access the selected plant_id
+
+ $disk = Storage::disk('local');
+
+ // Get original filename
+ $originalName = $uploadedFile->getClientOriginalName();
+
+ $path = $uploadedFile->storeAs('uploads/temp', $originalName, 'local');
$fullPath = Storage::disk('local')->path($path);
- // Save full file path to session
- session(['uploaded_invoice_path' => $fullPath]);
+ $totQuan = InvoiceValidation::where('invoice_number', $originalName)->where('plant_id', $plantId)->count();
+ $scanMQuan = InvoiceValidation::where('invoice_number', $originalName)->whereNotNull('serial_number')->where('serial_number', '!=', '')->where('plant_id', $plantId)->count();
- // session()->flash('just_uploaded_invoice', true); // 👈 add this
+ if($totQuan == $scanMQuan && $totQuan > 0)
+ {
+ Notification::make()
+ ->title('Material invoice already completed the scanning process for selected plant.')
+ ->danger()
+ ->send();
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
- Notification::make()
- ->title('File Uploaded. Continue in Create Page.')
- ->success()
- ->send();
+ 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 'Material Invoice' file to proceed..!")
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ $invalidMatCodes = [];
+ $materialCodes = [];
+ $missingQuantities = [];
+ $invalidMatQuan = [];
+ $invalidMaterialQuan = [];
+ $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($materialQuantity == 0)
+ {
+ $invalidMaterialQuan[] = $materialCode;
+ }
+ else if (empty($materialQuantity))
+ {
+ $missingQuantities[] = $materialCode;
+ }
+ else if(!is_numeric($materialQuantity))
+ {
+ $invalidMatQuan[] = $materialCode;
+ }
+ else
+ {
+ $materialCodes[] = $materialCode;
+ $validRowsFound = true;
+ }
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ $uniqueInvalidCodes = array_unique($invalidMatCodes);
+ $uniqueaplhaMat = array_unique($invalidMatQuan);
+ $uniqueZeroMat = array_unique($invalidMaterialQuan);
+ $uniqueEmptyMat = array_unique($missingQuantities);
+
+ 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($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ if (!empty($uniqueaplhaMat)) {
+ Notification::make()
+ ->title('Invalid Material Quantity')
+ ->body("The following item codes material quantity must be a numeric values :
" . implode(', ', $uniqueaplhaMat))
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ if (!empty($uniqueZeroMat)) {
+ Notification::make()
+ ->title('Invalid Material Quantity')
+ ->body("The following item codes material quantity should be greater than 0:
" . implode(', ', $uniqueZeroMat))
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ if (!empty($uniqueEmptyMat)) {
+ Notification::make()
+ ->title('Missing Material Quantity')
+ ->body("The following item codes doesn't have valid material quantity:
" . implode(', ', $uniqueEmptyMat))
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ 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($path)) {
+ $disk->delete($path);
+ }
+ 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 sticker master."
+ : 'Item Codes are not found in sticker master:
' . implode(', ', $missingCodes);
+
+ Notification::make()
+ ->title('Unknown Item Codes')
+ ->body($message)
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+
+ $invalidCodes = $matchedItems
+ ->filter(fn ($sticker) => empty($sticker->material_type)) //filter invalid
+ ->pluck('item.code')
+ ->toArray();
+
+ if (count($invalidCodes) > 10)
+ {
+ Notification::make()
+ ->title('Invalid item codes found')
+ ->body('' . count($invalidCodes) . 'invalid item codes found have serial number.')
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ return;
+ }
+ else if(count($invalidCodes) > 0)
+ {
+ Notification::make()
+ ->title('Invalid item codes found')
+ ->body('Serial invoice Item Codes found : ' . implode(', ', $invalidCodes))
+ ->danger()
+ ->send();
+
+ if ($disk->exists($path)) {
+ $disk->delete($path);
+ }
+ 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($path))
+ {
+ $disk->delete($path);
+ }
+ return;
+ }
+ else
+ {
+ // Save full file path to session
+ session(['uploaded_material_invoice' => $fullPath]);
+ Notification::make()
+ ->title('Material invoice imported successfully.')
+ ->success()
+ ->send();
+ }
+
+ }
}),
+ ])
- Tables\Actions\Action::make('Import Invoice Material')
- ->label('Import Invoice Material')
- ->form([
- FileUpload::make('invoice_material')
- ->label('Invoice Material')
- ->required(),
- ])
+ ->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(),
+ ]),
]);
-
- // ->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(),
- // ]),
- // ]);
}
public static function getRelations(): array