Merge pull request 'Added production checklist livewire pages' (#507) from ranjith-dev into master
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Has been cancelled

Reviewed-on: #507
This commit was merged in pull request #507.
This commit is contained in:
2026-04-07 12:06:04 +00:00
2 changed files with 333 additions and 0 deletions

View File

@@ -0,0 +1,268 @@
<?php
namespace App\Livewire;
use App\Mail\InvalidQualityMail;
use App\Models\AlertMailRule;
use App\Models\Item;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductCharacteristicsMaster;
use App\Models\ProductionCharacteristic;
use App\Models\QualityValidation;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Livewire\Component;
use Livewire\Attributes\On;
class ProductionCheckList extends Component
{
public $records = [];
public $existingRecords = [];
public bool $shouldSkipChecklist = false;
public array $checklist = [];
public $showChecklist = false;
public $skipChecklistValidation = false;
protected $listeners = ['focus-item-id' => 'handleFocus', 'trigger-create' => 'doCreate',];
public $data =
[
'item_id' => '',
'plant_id' => '',
];
public $data1 = [
'checklist' => [],
];
#[On('focus-item-id')]
public function handleFocus()
{
$this->dispatch('focus-input');
}
public function doCreate()
{
$this->create();
$this->shouldSkipChecklist = false;
}
public function mount($records = [])
{
$this->records = collect($records);
}
public function cancel()
{
$this->dispatch('checklist-cancelled');
}
public function saveChecklist()
{
if (empty($this->checklist) || count($this->checklist) != count($this->records)) {
Notification::make()
->title('Incomplete Checklist')
->body('Please complete all checklist fields before submitting.')
->danger()
->send();
return;
}
$item = Item::where('code', $this->data['item_id'])->first();
if (! $item) {
Notification::make()
->title('Invalid Item Code')
->body('Item not found for given code.')
->danger()
->send();
return;
}
$itemAgaPlant = Item::where('code', $this->data['item_id'])->where('plant_id', $this->data['plant_id'])->first();
$plant = Plant::find($this->data['plant_id']);
if (! $itemAgaPlant) {
Notification::make()
->title('Invalid Item Code')
->body("Item code '$this->data['item_id']' not found for given plant code '{$plant?->code}'.")
->danger()
->send();
return;
}
$itemId = $itemAgaPlant->id;
$exists = QualityValidation::where('plant_id', $this->data['plant_id'] ?? null)
->where('serial_number', $this->data['serial_number'] ?? null)
->first();
$plan = Plant::find($this->data['plant_id']);
if ($exists) {
Notification::make()
->title('Duplicate Serial Number')
->body("serial number {$this->data['serial_number']} already exists for the selected plant $plan->code.")
->danger()
->send();
return;
}
$qualityValidation = QualityValidation::create([
'plant_id' => $this->data['plant_id'] ?? null,
'line_id' => $this->data['line_id'] ?? null,
'sticker_master_id' => $this->data['sticker_master_id'] ?? null,
'production_order' => $this->data['production_order'] ?? null,
'serial_number_motor' => $this->data['serial_number_motor'] ?? null,
'serial_number_pump' => $this->data['serial_number_pump'] ?? null,
'serial_number_pumpset' => $this->data['serial_number_pumpset'] ?? null,
'pack_slip_motor' => $this->data['pack_slip_motor'] ?? null,
'pack_slip_pump' => $this->data['pack_slip_pump'] ?? null,
'pack_slip_pumpset' => $this->data['pack_slip_pumpset'] ?? null,
'name_plate_motor' => $this->data['name_plate_motor'] ?? null,
'name_plate_pump' => $this->data['name_plate_pump'] ?? null,
'name_plate_pumpset' => $this->data['name_plate_pumpset'] ?? null,
'tube_sticker_motor' => $this->data['tube_sticker_motor'] ?? null,
'tube_sticker_pump' => $this->data['tube_sticker_pump'] ?? null,
'tube_sticker_pumpset' => $this->data['tube_sticker_pumpset'] ?? null,
'warranty_card' => $this->data['warranty_card'] ?? null,
'part_validation1' => $this->data['part_validation1'] ?? null,
'part_validation2' => $this->data['part_validation2'] ?? null,
'part_validation3' => $this->data['part_validation3'] ?? null,
'part_validation4' => $this->data['part_validation4'] ?? null,
'part_validation5' => $this->data['part_validation5'] ?? null,
'operator_id' => $this->data['operator_id'] ?? null,
'uom' => $this->data['uom'] ?? null,
'serial_number' => $this->data['serial_number'] ?? null,
]);
if (! $qualityValidation || ! $qualityValidation->exists) {
Notification::make()
->title('Failed to save Quality Validation')
->body('Something went wrong while inserting data.')
->danger()
->send();
return;
}
$hasNotOk = collect($this->checklist)->contains(function ($val) {
return $val != 'ok';
});
$finalInspectionStatus = $hasNotOk ? 'NotOk' : 'Ok';
foreach ($this->checklist as $characteristicId => $value) {
$characteristic = ProductCharacteristicsMaster::find($characteristicId);
ProductionCharacteristic::create([
'plant_id' => $this->data['plant_id'] ?? null,
'item_id' => $itemId ?? null,
'line_id' => $this->data['line_id'] ?? null,
'machine_id' => $characteristic?->machine_id ?? null,
'production_order' => $this->data['production_order'] ?? null,
'serial_number' => $this->data['serial_number'] ?? null,
'characteristic_name' => $characteristic?->name ?? null,
'observed_value' => $this->data['observed_value'] ?? null,
'status' => $value == 'ok' ? 'Ok' : 'NotOk',
'inspection_status' => $finalInspectionStatus ?? null,
'created_by' => $this->data['operator_id'] ?? null,
]);
}
if ($finalInspectionStatus == 'NotOk') {
$mailData = \App\Filament\Resources\QualityValidationResource::getMailData($this->data['plant_id']);
$mPlantName = $mailData['plant_name'];
$emails = $mailData['emails'];
$mUserName = Filament::auth()->user()->name;
$itemCode = $this->data['item_id'] ?? null;
$sNo = $this->data['serial_number'] ?? null;
$mPorder = $this->data['production_order'] ?? null;
$mLinePart = Line::where('id', $this->data['line_id'] ?? null)
->value('name');
$mExpectedValue = null; // optional
$state = $itemCode . '|' . $sNo;
if (!empty($emails)) {
Mail::to($emails)->queue(
new InvalidQualityMail(
$state,
$mPorder,
$mPlantName,
$mLinePart,
$mUserName,
$mExpectedValue,
'FinalInspectionNotOk'
)
);
}
else {
\Log::warning("No emails configured for plant: {$mPlantName}");
}
}
$this->showChecklist = false;
$this->dispatch('checklist-saved');
}
public static function getMailData($plantId)
{
$globalEmails = AlertMailRule::where('plant', 0)
->where('module', 'QualityValidation')
->where('rule_name', 'QualityMail')
->where(fn ($q) => $q->whereNull('schedule_type')->orWhere('schedule_type', ''))
->pluck('email')
->toArray();
if (! empty($globalEmails)) {
return [
'plant_id' => 0,
'plant_name' => 'All Plants',
'emails' => $globalEmails,
];
}
$mPlantName = Plant::where('id', $plantId)->value('name');
$emails = AlertMailRule::where('plant', $plantId)
->where('module', 'QualityValidation')
->where('rule_name', 'QualityMail')
->where(fn ($q) => $q->whereNull('schedule_type')->orWhere('schedule_type', ''))
->pluck('email')
->toArray();
return [
'plant_id' => $plantId,
'plant_name' => $mPlantName,
'emails' => $emails,
];
}
public function updatedDataChecklist()
{
$this->dispatch('checklistUpdated', $this->data['checklist']);
}
public function render()
{
return view('livewire.production-check-list');
}
}

View File

@@ -0,0 +1,65 @@
<div class="fixed inset-0 flex items-center justify-center z-50">
<div class="bg-white max-h-[80vh] overflow-hidden p-6 rounded-lg shadow-lg pointer-events-auto"
style="width:30vw !important; max-width:none !important;">
@if($records && $records->count())
<div style="max-height:250px; overflow-y:auto; border:1px solid #ccc;">
{{-- <table class="min-w-full border"> --}}
<table class="w-full table-fixed border text-sm">
<thead>
<tr class="bg-gray-100">
<th class="border px-2 py-1 w-2/3">Characteristics</th>
<th class="border px-2 py-1 w-1/6">OK</th>
<th class="border px-2 py-1 w-1/6">Not OK</th>
</tr>
</thead>
<tbody>
@foreach($records as $record)
<tr>
<td class="border p-2">
{{ $record['name'] }}
</td>
<td class="border text-center">
<input type="radio"
wire:model="checklist.{{ $record['id'] }}"
value="ok">
</td>
<td class="border text-center">
<input type="radio"
wire:model="checklist.{{ $record['id'] }}"
value="not_ok">
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<p>No records found.</p>
@endif
<div class="border-t mt-6 pt-4 flex justify-end gap-3">
<button
type="button"
wire:click="cancel"
style="background-color:#dc2626; color:white;"
class="px-6 py-2 rounded-lg shadow-md"
>
Cancel
</button>
<button
type="button"
wire:click="saveChecklist"
style="background-color:#16a34a; color:white;"
class="px-6 py-2 rounded-lg shadow-md"
>
Save
</button>
</div>
</div>
</div>