Added livewire page for serial validation

This commit is contained in:
dhanabalan
2025-10-03 16:06:41 +05:30
parent b9aa549705
commit c3e0429421
2 changed files with 580 additions and 0 deletions

View File

@@ -0,0 +1,371 @@
<?php
namespace App\Livewire;
use App\Models\StickerMaster;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Livewire\Component;
use App\Models\SerialValidation;
class SerialValidationData extends Component
{
public $invoiceData = [];
public $plantId = 0;
public string $invoiceNumber = '';
public string $serialNumber = '';
public bool $completedInvoice = false;
public bool $isSerial = false;
public bool $emptyInvoice = false;
public bool $hasSearched = false;
public bool $materialInvoice = false;
public bool $showCapacitorInput = false;
// protected $listeners = ['refreshInvoiceData' => 'loadData',];
protected $listeners = [
'refreshCompletedInvoice' => 'loadCompletedData',
'refreshEmptyInvoice' => 'loadEmptyData',
'refreshInvoiceData' => 'loadData',
'refreshMaterialInvoiceData' => 'loadMaterialData',
'openCapacitorModal' => 'showCapacitorInputBox',
];
public $capacitorInput = '';
public $panel_box_supplier;
public $panel_box_item_code;
public $panel_box_serial_number;
public string $currentItemCode = '';
public string $currentSerialNumber = '';
// public function loadCompletedData($invoiceNumber, $plantId, $isSerial)
// {
// $this->plantId = $plantId;
// $this->invoiceNumber = $invoiceNumber;
// $this->completedInvoice = true;
// $this->isSerial = $isSerial;
// $this->emptyInvoice = false;
// $this->hasSearched = false;
// $this->materialInvoice = false;
// // $this->showCapacitorInput = false;
// }
public function loadCompletedData($invoiceNumber, $plantId, $isSerial)
{
$this->plantId = $plantId;
$this->invoiceNumber = $invoiceNumber;
$this->completedInvoice = true;
$this->isSerial = $isSerial;
$this->emptyInvoice = false;
$this->hasSearched = false;
$this->materialInvoice = false;
// $this->showCapacitorInput = false;
}
public function loadEmptyData($invoiceNumber, $plantId)
{
$this->plantId = $plantId;
$this->invoiceNumber = $invoiceNumber;
$this->completedInvoice = false;
$this->emptyInvoice = true;
$this->hasSearched = false;
$this->materialInvoice = false;
// $this->showCapacitorInput = false;
}
public function loadData($invoiceNumber, $plantId)
{
$this->plantId = $plantId;
$this->invoiceNumber = $invoiceNumber;
$this->completedInvoice = false;
$this->isSerial = true;
$this->emptyInvoice = false;
$this->hasSearched = true;
$this->materialInvoice = false;
// $this->showCapacitorInput = false;
//->where('serial_number', '!=', '')
$this->invoiceData = SerialValidation::where('invoice_number', $this->invoiceNumber)
->where('plant_id', $plantId)->where('scanned_status', null)
->get()
->map(function ($record) {
return [
'sticker_master_id' => $record->sticker_master_id,
'serial_number' => $record->serial_number,
'motor_scanned_status' => $record->motor_scanned_status ?? '',
'pump_scanned_status' => $record->pump_scanned_status ?? '',
'capacitor_scanned_status' => $record->capacitor_scanned_status ?? '',
'scanned_status_set' => $record->scanned_status_set ?? '',
'scanned_status' => $record->scanned_status ?? '',
'panel_box_supplier' => $record->panel_box_supplier ?? '',
'panel_box_serial_number' => $record->panel_box_serial_number ?? '',
'created_at' => $record->created_at,
'operator_id' => $record->operator_id,
];
})
->toArray();
//Loop through and replace 'code' using related StickerMaster > Item > code
foreach ($this->invoiceData as &$row) {
// $stickerMaster = \App\Models\StickerMaster::with('item')->find($row['sticker_master_id'] ?? null);
$row['code'] = StickerMaster::with('item')->find($row['sticker_master_id'] ?? null)?->item?->code ?? 'N/A';
}
}
public function loadMaterialData($invoiceNumber, $plantId)
{
$this->plantId = $plantId;
$this->invoiceNumber = $invoiceNumber;
$this->completedInvoice = false;
$this->isSerial = false;
$this->emptyInvoice = false;
$this->hasSearched = false;
$this->materialInvoice = true;
// $this->showCapacitorInput = false;
//->where('serial_number', '!=', '')
$this->invoiceData = SerialValidation::where('invoice_number', $this->invoiceNumber)->where('plant_id', $plantId)->where('serial_number', null)
->get()
->map(function ($record) {
return [
'sticker_master_id' => $record->sticker_master_id,
// 'material_type' => StickerMaster::where('id', $record->sticker_master_id)->first()->material_type ?? '',
'quantity' => $record->quantity ?? '',
'serial_number' => $record->serial_number ?? '',
'batch_number' => $record->batch_number ?? '',
'created_at' => $record->created_at,
'operator_id' => $record->operator_id,
];
})
->toArray();
//Loop through and replace 'code' using related StickerMaster > Item > code
foreach ($this->invoiceData as &$row) {
// $stickerMaster = \App\Models\StickerMaster::with('item')->find($row['sticker_master_id'] ?? null);
$row['code'] = StickerMaster::with('item')->find($row['sticker_master_id'] ?? null)?->item?->code ?? 'N/A';
$matType = StickerMaster::where('id', $row['sticker_master_id'] ?? null)->first()->material_type ?? '';
if($matType === 1)
{
$row['material_type'] = 'Individual';
}
else if($matType === 2)
{
$row['material_type'] = 'Bundle';
}
else if($matType === 3)
{
$row['material_type'] = 'Quantity';
}
else
{
$row['material_type'] = 'N/A';
}
}
}
// public function showCapacitorInputBox()
// {
// $this->showCapacitorInput = true;
// }
public function showCapacitorInputBox($itemCode, $serialNumber, $plantId)
{
$this->plantId = $plantId;
$this->currentItemCode = $itemCode;
$this->currentSerialNumber = $serialNumber;
$this->showCapacitorInput = true;
// $this->capacitorInput = '';
$this->completedInvoice = false;
$this->isSerial = true;
$this->emptyInvoice = false;
$this->hasSearched = false;
$this->materialInvoice = false;
$this->dispatch('focus-capacitor-input');
}
public function cancelCapacitorInput()
{
$this->showCapacitorInput = false;
}
public function processCapacitorInput()
{
$user = Filament::auth()->user();
$operatorName = $user->name;
if (!$this->capacitorInput) {
return;
}
if (!preg_match('/^[^\/]+\/[^\/]+\/.+$/', $this->capacitorInput)) {
Notification::make()
->title('Invalid Panel Box QR Format:')
->body('Scan the valid panel box QR code to proceed!')
->danger()
// ->duration(3000)
->seconds(2)
->send();
return;
}
$parts = explode('/', $this->capacitorInput);
$supplier = $parts[0];
$itemCode = $parts[1];
$serialNumber = implode('/', array_slice($parts, 2)); // Keep rest of the string
$existsInStickerMaster = StickerMaster::where('panel_box_code', $itemCode)->where('plant_id', $this->plantId)->whereHas('item', function ($query) {
$query->where('code', $this->currentItemCode);
})
->exists();
if (!$existsInStickerMaster) {
Notification::make()
->title('Unknown: Panel Box Code')
->body("Unknown panel box code: $itemCode found for item code: $this->currentItemCode")
->danger()
// ->duration(4000)
->seconds(2)
->send();
$this->capacitorInput = '';
return;
}
foreach ($this->invoiceData as &$row) {
if (
($row['code'] ?? '') === $this->currentItemCode &&
($row['serial_number'] ?? '') === $this->currentSerialNumber
) {
$row['panel_box_supplier'] = $supplier;
$row['panel_box_item_code'] = $itemCode;
$row['panel_box_serial_number'] = $serialNumber;
$row['capacitor_scanned_status'] = 1;
// $row['scanned_status_set'] = true;
$matchingValidation = SerialValidation::with('stickerMaster.item')
->where('serial_number', $this->currentSerialNumber)
->where('plant_id', $this->plantId)
->get()
->first(function ($validation) {
return $validation->stickerMaster?->item?->code === $this->currentItemCode;
});
if ($matchingValidation) {
$hasMotorQr = $matchingValidation->stickerMasterRelation->tube_sticker_motor ?? null;
$hasPumpQr = $matchingValidation->stickerMasterRelation->tube_sticker_pump ?? null;
$hasPumpSetQr = $matchingValidation->stickerMasterRelation->tube_sticker_pumpset ?? null;
// $hasCapacitorQr = $matchingValidation->stickerMasterRelation->panel_box_code ?? null;
$hadMotorQr = $matchingValidation->motor_scanned_status ?? null;
$hadPumpQr = $matchingValidation->pump_scanned_status ?? null;
$hadPumpSetQr = $matchingValidation->scanned_status_set ?? null;
// $hadCapacitorQr = $matchingValidation->capacitor_scanned_status ?? null;
$packCnt = 1;
$scanCnt = 1;
// if($hadMotorQr === $hasMotorQr && $hadPumpQr === $hasPumpQr && $hadPumpSetQr === $hasPumpSetQr)
if($hasMotorQr || $hasPumpQr || $hasPumpSetQr)
{
$packCnt = $hasMotorQr ? $packCnt + 1 : $packCnt;
$packCnt = $hasPumpQr ? $packCnt + 1 : $packCnt;
$packCnt = $hasPumpSetQr ? $packCnt + 1 : $packCnt;
$scanCnt = $hadMotorQr ? $scanCnt + 1: $scanCnt;
$scanCnt = $hadPumpQr ? $scanCnt + 1: $scanCnt;
$scanCnt = $hadPumpSetQr ? $scanCnt + 1: $scanCnt;
if($packCnt === $scanCnt)
{
$matchingValidation->update([
'panel_box_supplier' => $supplier,
'panel_box_item_code' => $itemCode,
'panel_box_serial_number' => $serialNumber,
'capacitor_scanned_status' => 1,
'scanned_status' => 'Scanned',
'operator_id'=> $operatorName,
]);
}
else
{
$matchingValidation->update([
'panel_box_supplier' => $supplier,
'panel_box_item_code' => $itemCode,
'panel_box_serial_number' => $serialNumber,
'capacitor_scanned_status' => 1,
'operator_id'=> $operatorName,
]);
}
}
else
{
$matchingValidation->update([
'panel_box_supplier' => $supplier,
'panel_box_item_code' => $itemCode,
'panel_box_serial_number' => $serialNumber,
'capacitor_scanned_status' => 1,
'scanned_status' => 'Scanned',
'operator_id'=> $operatorName,
]);
}
// Notification::make()
// ->title('Success: Capacitor QR')
// // ->title("Panel box code scanned: $itemCode")
// ->body("'Capacitor' QR scanned status updated, Scan next QR.")
// ->success() // commented
// ->seconds(2)
// ->send();
$totalQuantity = SerialValidation::where('invoice_number', $matchingValidation->invoice_number)->where('plant_id', $this->plantId)->count();
$scannedQuantity = SerialValidation::where('invoice_number', $matchingValidation->invoice_number)->where('plant_id', $this->plantId)->where('scanned_status', 'Scanned')->count();
// $this->form->fill([
// 'plant_id' => $matchingValidation->plant_id,
// 'invoice_number' => $matchingValidation->invoice_number,
// 'serial_number' => null,
// 'total_quantity' => $totalQuantity,
// 'scanned_quantity'=> $scannedQuantity,
// ]);
if($totalQuantity === $scannedQuantity)
{
Notification::make()
->title('Completed: Serial Invoice')
->body("Serial invoice '$matchingValidation->invoice_number' completed the scanning process.<br>Scan the next 'Serial Invoice' to proceed!")
->success()
->seconds(2)
->send();
$this->loadCompletedData($matchingValidation->invoice_number, $matchingValidation->plant_id, true);
}
else
{
$this->loadData($matchingValidation->invoice_number, $matchingValidation->plant_id);
}
}
break;
}
}
$this->showCapacitorInput = false;
$this->capacitorInput = '';
$this->dispatch('focus-serial-number');
}
public function render()
{
return view('livewire.serial-validation-data');
}
}

View File

@@ -0,0 +1,209 @@
<div>
<div class="mb-4">
<h2 class="text-lg font-bold text-gray-800">
@if ($hasSearched)
SERIAL INVOICE DATA TABLE
@elseif ($materialInvoice)
MATERIAL INVOICE DATA TABLE
@else
@if ($completedInvoice)
@if ($isSerial)
SERIAL INVOICE DATA TABLE
@else
MATERIAL INVOICE DATA TABLE
@endif
@else
INVOICE DATA TABLE
@endif
@endif
</h2>
<div class="mt-2">
<hr class="border-t-2 border-gray-300">
</div>
</div>
{{-- Modal for completed invoice--}}
@if ($completedInvoice)
<div class="text-center text-red-500">
<p>
@if ($isSerial)
Completed the scanning process for serial invoice number <strong>{{ $invoiceNumber }}</strong>.
@else
Completed the scanning process for material invoice number <strong>{{ $invoiceNumber }}</strong>.
@endif
</p>
</div>
@endif
{{-- Modal for empty invoice--}}
@if ($emptyInvoice)
<div class="text-center text-red-500">
<p>No data found for invoice number <strong>{{ $invoiceNumber }}</strong>.</p>
</div>
@endif
{{-- Modal for serial invoice--}}
@if ($hasSearched)
<div class="overflow-x-auto overflow-y-visible" style="height: 385px;">
{{-- <table class="min-w-[1500px] text-sm text-center border border-gray-300"> --}}
{{-- <table class="table-fixed min-w-[1500px] text-sm text-center border border-gray-300"> --}}
<table class="min-w-full text-sm text-center border border-gray-300">
<thead class="bg-gray-100 font-bold">
<tr>
<th class="border px-4 py-2">No</th>
<th class="border px-4 py-2">Material Code</th>
<th class="border px-4 py-2">Serial Number</th>
<th class="border px-4 py-2">Motor Scanned Status</th>
<th class="border px-4 py-2">Pump Scanned Status</th>
<th class="border px-4 py-2">Capacitor Scanned Status</th>
<th class="border px-4 py-2">Scanned Status Set</th>
<th class="border px-4 py-2">Scanned Status</th>
<th class="border px-4 py-2 w-[300px] whitespace-nowrap">Time Stamp</th>
<th class="border px-4 py-2">Operator ID</th>
<th class="border px-4 py-2">Panel Box Supplier</th>
<th class="border px-4 py-2">Panel Box Serial Number</th>
</tr>
</thead>
<tbody>
@forelse ($invoiceData as $index => $row)
<tr class="border-t">
<td class="border px-4 py-2">{{ $index + 1 }}</td>
<td class="border px-4 py-2">{{ $row['code'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['serial_number'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['motor_scanned_status'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['pump_scanned_status'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['capacitor_scanned_status'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['scanned_status_set'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['scanned_status'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['created_at'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['operator_id'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['panel_box_supplier'] ?? '' }}</td>
<td class="border px-4 py-2">{{ $row['panel_box_serial_number'] ?? '' }}</td>
</tr>
@empty
<tr>
<td colspan="12" class="text-center py-4 text-gray-500">
No data found for invoice number <strong>{{ $invoiceNumber }}</strong>.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@endif
{{-- Modal for Capacitor Input --}}
<div>
<button wire:click="$set('showCapacitorInput', true)"></button>
@if($showCapacitorInput)
<div class="fixed inset-0 z-[9999] bg-black bg-opacity-50 flex items-center justify-center">
<div style="background:white; border:4px solid orange;" class="p-6 rounded-xl shadow-2xl w-[450px]">
<h3 class="text-xl font-semibold text-orange-700 mb-4">
Scan the Panel Box Supplier/Item Code/Serial Number
</h3>
<input
type="text"
id="capacitorInput"
autocomplete="off"
wire:model.defer="capacitorInput"
wire:keydown.enter.prevent="processCapacitorInput"
class="w-full border border-orange-300 rounded px-3 py-2 focus:outline-none focus:ring-0 focus:border-orange-300"
placeholder="Scan the panel box QR code"
{{-- autofocus --}}
onload="this.focus(); this.select();"
{{-- onfocus="this.select();" --}}
/>
<div class="flex justify-end gap-2 mt-4">
<button type="button" wire:click="cancelCapacitorInput"
class="mt-6 ml-10 bg-gray-300 hover:bg-gray-400 px-4 py-2 rounded transition">
Cancel
</button>
</div>
</div>
</div>
{{-- Add this script to focus on the input --}}
<script>
document.getElementById('capacitorInput').focus();
</script>
@endif
</div>
{{-- Modal for material invoice--}}
@if($materialInvoice)
<div class="overflow-x-auto overflow-y-visible" style="height: 385px;">
{{-- <table class="min-w-[1500px] text-sm text-center border border-gray-300"> --}}
{{-- <table class="table-fixed min-w-[1500px] text-sm text-center border border-gray-300"> --}}
<table class="min-w-full text-sm text-center border border-gray-300">
<thead class="bg-gray-100 font-bold">
<tr>
<th class="border px-4 py-2">No</th>
<th class="border px-4 py-2">Material Code</th>
<th class="border px-4 py-2">Material Type</th>
<th class="border px-4 py-2">Material Quantity</th>
<th class="border px-4 py-2">Serial Number</th>
<th class="border px-4 py-2">Batch Number</th>
<th class="border px-4 py-2">TimeStamp</th>
<th class="border px-4 py-2">Operator ID</th>
</tr>
</thead>
<tbody>
@forelse ($invoiceData as $index => $row)
<tr class="border-t">
<td class="border px-4 py-2">{{ $index + 1 }}</td>
<td class="border px-4 py-2">{{ $row['code'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['material_type'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['quantity'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['serial_number'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['batch_number'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['created_at'] ?? 'N/A' }}</td>
<td class="border px-4 py-2">{{ $row['operator_id'] ?? 'N/A' }}</td>
</tr>
@empty
<tr>
<td colspan="10" class="text-center py-4 text-gray-500">
No data found for invoice number <strong>{{ $invoiceNumber }}</strong>.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@endif
</div>
{{-- <script>
// Clear input and set focus on form load
document.addEventListener('DOMContentLoaded', function () {
const input = document.getElementById('capacitorInput');
input.value = ''; // Clear the input field
input.focus(); // Set focus to the input field
});
</script> --}}
<script>
window.addEventListener('focus-capacitor-input', () => {
setTimeout(() => {
const input = document.getElementById('capacitorInput');
if (input) {
input.focus();
input.select();
}
}, 50);
});
window.addEventListener('focus-serial-number', () => {
setTimeout(() => {
const container = document.getElementById('serial_number_input');
const input = container?.querySelector('input'); // gets the actual input inside
if (input) {
input.focus();
input.select();
}
}, 100);
});
</script>