Added update invoice toggle button and import invoice validations
This commit is contained in:
@@ -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
|
||||
{
|
||||
@@ -47,115 +59,840 @@ class InvoiceValidationResource extends Resource
|
||||
|
||||
Forms\Components\Select::make('plant_id')
|
||||
->relationship('plant', 'name')
|
||||
->required(),
|
||||
->required()
|
||||
// ->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')
|
||||
->required()
|
||||
->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')
|
||||
->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
|
||||
|
||||
// Save full file path to session
|
||||
session(['uploaded_invoice_path' => $fullPath]);
|
||||
$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();
|
||||
|
||||
// session()->flash('just_uploaded_invoice', true); // 👈 add this
|
||||
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:<br>' . 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:<br>" . 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:<br>' . 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:<br>' . 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<br>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:<br>' . implode(', ', $missingCodes);
|
||||
|
||||
Notification::make()
|
||||
->title('File Uploaded. Continue in Create Page.')
|
||||
->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 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(),
|
||||
])
|
||||
]);
|
||||
->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')
|
||||
|
||||
// ->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(),
|
||||
// ]),
|
||||
// ]);
|
||||
])
|
||||
|
||||
->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);
|
||||
|
||||
$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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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:<br>' . 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 :<br>" . 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:<br>" . 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:<br>" . 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<br>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:<br>' . 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 <br>$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();
|
||||
}
|
||||
|
||||
}
|
||||
}),
|
||||
])
|
||||
|
||||
->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
|
||||
|
||||
Reference in New Issue
Block a user