diff --git a/app/Filament/Pages/BulkStickerPrinting.php b/app/Filament/Pages/BulkStickerPrinting.php index 37d1e20b..be88c958 100644 --- a/app/Filament/Pages/BulkStickerPrinting.php +++ b/app/Filament/Pages/BulkStickerPrinting.php @@ -25,6 +25,8 @@ use Filament\Forms\Components\Section; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Illuminate\Support\Facades\Log; +use Livewire\Attributes\On; +use Filament\Forms\Set; class BulkStickerPrinting extends Page implements HasForms { @@ -36,12 +38,19 @@ class BulkStickerPrinting extends Page implements HasForms public array $filters = []; + public array $serialNumbers = ['']; + public $serNo; public $ref_number; //public $workCenter; + public function mount(): void + { + $this->form->fill(); + } + public function form(Form $form): Form { return $form @@ -85,8 +94,7 @@ class BulkStickerPrinting extends Page implements HasForms TextInput::make('production_order') ->label('Production Order') ->reactive() - ->readOnly() - ->required(), + ->readOnly(), // ->afterStateUpdated(function ($state, callable $set, $get) { // for ($i = 1; $i <= 8; $i++) { @@ -979,6 +987,7 @@ class BulkStickerPrinting extends Page implements HasForms } } + public function generateStickerId() { $state = $this->form->getState(); @@ -1432,6 +1441,378 @@ class BulkStickerPrinting extends Page implements HasForms } + + #[On('generate-sticker-id')] + public function generateStickerId2(string $serialNumbers) + { + $state = $this->form->getState(); + + $plantId = trim($state['plant_id'] ?? ''); + + $machineId = trim($state['machine_id'] ?? ''); + + $stickerId = $state['sticker_id'] ?? null; + + $pOrder = $state['production_order'] ?? null; + + $fromSno = trim($state['from_serial_number'] ?? ''); + + $toSno = trim($state['to_serial_number'] ?? ''); + + $serialNumbersArray = array_filter(array_map('trim', explode(',', $serialNumbers))); + + if (count($serialNumbersArray) > 50) { + Notification::make() + ->title('Too Many Serial Numbers') + ->body('You can enter a maximum of 50 serial numbers.') + ->danger() + ->send(); + + return; + } + + $plantName = Plant::where('id', $plantId)->value('name'); + + if (!$stickerId) { + + Notification::make() + ->danger() + ->title('Sticker ID Not Selected') + ->body('Please Choose a Sticker ID.') + ->send(); + + return; + } + + $pOrderExist = ClassCharacteristic::where('plant_id',$plantId)->where('aufnr', $pOrder)->first(); + + if(!$pOrderExist){ + Notification::make() + ->danger() + ->title('Unknown Production Order') + ->body("Production Order '$pOrder' not found.") + ->send(); + return; + } + + if($pOrderExist){ + + $existingSerialNumbers = ClassCharacteristic::where('plant_id', $plantId) + ->where('aufnr', $pOrder) + ->whereIn('gernr', $serialNumbersArray) + ->pluck('gernr') + ->map(fn ($value) => trim((string) $value)) + ->unique() + ->toArray(); + + $invalidSerialNumbers = array_values( + array_diff($serialNumbersArray, $existingSerialNumbers) + ); + + if (!empty($invalidSerialNumbers)) { + Notification::make() + ->danger() + ->title('Unknown Serial Numbers') + ->body( + "The following serial numbers do not belong to Production Order '$pOrder' " + . "for plant '$plantName': " + . implode(', ', $invalidSerialNumbers) + ) + ->send(); + + return; + } + } + + $existingStickers = StickerOrder::where('plant_id', $plantId) + ->where('production_order', $pOrder) + ->where('sticker_id', $stickerId) + ->where('print_status', 'Printed') + ->whereIn('serial_number', $serialNumbersArray) + ->pluck('serial_number') + ->unique() + ->values() + ->toArray(); + + if (!empty($existingStickers)) { + Notification::make() + ->danger() + ->title('Duplicate Sticker') + ->body("The following serial numbers already exist in generated stickers for ". "Sticker '$stickerId', Production Order '$pOrder', and plant '$plantName': ". implode(', ', $existingStickers)) + ->send(); + + return; + } + + $structure = StickerStructureDetail::where('sticker_id',$stickerId)->first(); + + if (!$structure) { + + Notification::make() + ->danger() + ->title('Sticker Structure Not Found') + ->body("No sticker structure found for sticker ID '{$stickerId}'.") + ->send(); + return; + } + + //.New Logic + + $stickerMappingMasterItems = StickerMappingMaster::where('plant_id', $plantId)->where('item_id', $pOrderExist->item_id)->get(); + + if ($stickerMappingMasterItems->isEmpty()) { + Notification::make() + ->danger() + ->title('Sticker Mapping Not Found') + ->body("No sticker mapping found for plant ID '{$plantId}'.") + ->send(); + + return; + } + + $structureIds = $stickerMappingMasterItems + ->flatMap(function ($mapping) { + $ids = []; + + for ($i = 1; $i <= 8; $i++) { + $column = "sticker_structure{$i}_id"; + + if (!empty($mapping->{$column})) { + $ids[] = $mapping->{$column}; + } + } + + return $ids; + }) + ->unique() + ->values(); + + $detailsById = StickerStructureDetail::whereIn('id', $structureIds) + ->get() + ->keyBy('id'); + + $structure = null; + $stickerMappingMasterItem = null; + + foreach ($stickerMappingMasterItems as $mapping) { + for ($i = 1; $i <= 8; $i++) { + $column = "sticker_structure{$i}_id"; + $structureId = $mapping->{$column}; + + if (empty($structureId)) { + continue; + } + + $detail = $detailsById->get($structureId); + + if (!$detail) { + continue; + } + + if ((string) $detail->sticker_id === (string) $stickerId) { + $structure = $detail; + $stickerMappingMasterItem = $mapping; + break 2; + } + } + } + + if (!$structure) { + Notification::make() + ->danger() + ->title('Sticker Mapping Not Found') + ->body("No mapping found for sticker ID '{$stickerId}' and plant ID '{$plantId}'.") + ->send(); + + return; + } + + + // $checkItem = StickerMappingMaster::where('plant_id', $plantId)->where('item_id', $pOrderExist->item_id)->where('sticker_structure1_id', $structure->id)->first(); + + $itemCode = Item::where('id', $pOrderExist->item_id)->value('code'); + + $plantCode = Plant::where('id', $plantId)->value('code'); + + // if (!$checkItem) { + + // Notification::make() + // ->danger() + // ->title('Item Not Found') + // ->body("Item code '$itemCode' not found in sticker mapping master for selected sticker ID '{$stickerId}'.") + // ->send(); + // return; + // } + + $itemCharacteristic1 = ClassCharacteristic::where('plant_id', $plantId)->where('aufnr', $pOrder)->where('item_id', $pOrderExist->item_id)->first(); + + if (!$itemCharacteristic1) { + + Notification::make() + ->danger() + ->title('Item Not Found') + ->body("Item code '{$itemCode}' was not found against job number '$pOrder' in class characteristic.") + ->send(); + return; + } + + $matchedMachineId = null; + + for ($i = 1; $i <= 8; $i++) { + + $structureColumn = "sticker_structure{$i}_id"; + $machineColumn = "sticker{$i}_machine_id"; + + $mappedStructureId = $stickerMappingMasterItem->{$structureColumn} ?? null; + + if ( + $mappedStructureId !== null && + (string) $mappedStructureId === (string) $structure->id + ) { + $matchedMachineId = $stickerMappingMasterItem->{$machineColumn} ?? null; + break; + } + } + + $selectedMachineId = trim((string) $machineId); + $mappedMachineId = trim((string) $matchedMachineId); + + if ($mappedMachineId === '' || $mappedMachineId !== $selectedMachineId) { + Notification::make() + ->danger() + ->title('Machine Mapping Mismatch') + ->body("Selected machine '{$selectedMachineId}' does not match the mapped machine '{$mappedMachineId}'.") + ->send(); + + return; + } + + $itemCharacteristic = ClassCharacteristic::where('plant_id', $plantId) + ->where('item_id', $pOrderExist->item_id) + ->where('machine_id', $machineId) + ->where('aufnr', $pOrder) + ->first(); + + if(!$itemCharacteristic){ + Notification::make() + ->danger() + ->title('Record Not Found') + ->body("Record not found in class characteristic against job '$pOrder', item '$itemCode' and plant '$plantCode'.") + ->send(); + + return; + } + + $elements = StickerDetail::where('sticker_structure_detail_id',$structure->id)->get(); + + if ($elements->isEmpty()) { + + Notification::make() + ->danger() + ->title('Sticker Details Not Found') + ->body('No sticker details configured for the selected sticker.') + ->send(); + + return; + } + + $stickerService = new StickerPdfService(); + + $template = $stickerService->generateTemplate( + $structure->sticker_id, + $elements, + $itemCharacteristic, + $itemCode, + $plantId, + $machineId + ); + + $pdfContent = $stickerService->generateMultipleBulkFromTemplate( + $template, + $serialNumbersArray, + $itemCode, + ); + + $fileName = 'bulk_sticker_'. '_'. uniqid(). '.pdf'; + + $tempPdfPath = storage_path('app/' . $fileName); + + file_put_contents( + $tempPdfPath, + $pdfContent + ); + + $pdfUrl = route( + 'sticker.preview', + [ + 'path' => $fileName, + ] + ); + + $this->dispatch('open-sticker-pdf',urls: [$pdfUrl]); + + $totalStickers = count($serialNumbersArray); + + $item = Item::where('id', $pOrderExist->item_id)->where('plant_id', $plantId)->first(); + + foreach ($serialNumbersArray as $serialNumber) { + + $serialNumber = trim($serialNumber); + + $exists = StickerOrder::where('plant_id', $plantId) + ->where('production_order', $pOrder) + ->where('sticker_id', $stickerId) + ->where('serial_number', $serialNumber) + ->first(); + + if (!$exists) { + StickerOrder::create([ + 'plant_id' => $plantId, + 'item_id' => $item->id, + 'production_order' => $pOrder, + 'serial_number' => $serialNumber, + 'sticker_id' => $stickerId, + 'print_status' => 'Printed', + ]); + } + } + + Notification::make() + ->success() + ->title('Sticker Generated') + ->body("{$totalStickers} sticker(s) generated successfully.") + ->seconds(3) + ->send(); + + return; + + } + + + #[On('production-order-updated')] + public function updateProductionOrder(string $productionOrder): void + { + $this->filters['production_order'] = $productionOrder; + } + + #[On('sticker-options')] + public function stickerStructure(array $stickerOptions): void + { + $this->filters['sticker_options'] = $stickerOptions; + } + + #[On('production-order-clear')] + public function updateProductionOrderClear(): void + { + $this->filters['production_order'] = null; + } + + #[On('sticker-options-clear')] + public function stickerStructureClear(): void + { + $this->filters['sticker_options'] = null; + } + public static function canAccess(): bool { return Auth::check() && Auth::user()->can('view sticker bulk print page'); diff --git a/app/Livewire/RandomSerialNumberList.php b/app/Livewire/RandomSerialNumberList.php new file mode 100644 index 00000000..b83b18e7 --- /dev/null +++ b/app/Livewire/RandomSerialNumberList.php @@ -0,0 +1,238 @@ +serialNumbers = collect($this->serialNumbers) + ->filter(fn ($serial) => trim($serial) !== '') + ->values() + ->toArray(); + // Clear all values whenever the checkbox changes + $this->serialNumbers = ['']; + } + + public function splitSerialNumbers(string $text): void + { + $serials = preg_split('/[\r\n\t ,;]+/', trim($text)); + + $this->serialNumbers = collect($serials) + ->filter(fn ($serial) => $serial !== '') + ->values() + ->toArray(); + + if (empty($this->serialNumbers)) { + $this->serialNumbers = ['']; + } + + $plantId = $this->plantId; + $machineId = $this->machineId; + + if (!$plantId) { + Notification::make() + ->danger() + ->title('Plant Not Selected') + ->body('Please select a plant before pasting serial numbers.') + ->send(); + $this->dispatch('sticker-options-clear', stickerOptions: ''); + $this->dispatch('production-order-clear', productionOrder: ''); + return; + } + + $serialNumbersArray = array_values( + array_filter( + array_map('trim', $this->serialNumbers), + fn ($serial) => $serial !== '' + ) + ); + + if (count($serialNumbersArray) > 50) { + Notification::make() + ->title('Too Many Serial Numbers') + ->body('You can enter a maximum of 50 serial numbers.') + ->danger() + ->send(); + $this->dispatch('sticker-options-clear', stickerOptions: ''); + $this->dispatch('production-order-clear', productionOrder: ''); + $this->serialNumbers = ['']; + return; + } + + $records = ClassCharacteristic::where('plant_id', $plantId)->whereIn('gernr', $serialNumbersArray)->get(); + + $foundSerialNumbers = $records->pluck('gernr') + ->map(fn ($serial) => trim((string) $serial)) + ->unique() + ->toArray(); + + $missingSerialNumbers = array_values( + array_diff($serialNumbersArray, $foundSerialNumbers) + ); + + if (!empty($missingSerialNumbers)) { + Notification::make() + ->danger() + ->title('Serial Numbers Not Found') + ->body('The following serial numbers do not exist for the selected plant: '. implode(', ', $missingSerialNumbers)) + ->send(); + return; + } + + $productionOrder = $records->first()->aufnr; + + $invalidSerialNumbers = $productionOrder + ? $records->filter( + fn ($record) => $record->aufnr != $productionOrder + )->pluck('gernr')->unique()->values()->toArray() + : []; + + if (!empty($invalidSerialNumbers)) { + Notification::make() + ->danger() + ->title('Invalid Serial Numbers') + ->body('The following serial numbers belong to a different production order: '. implode(', ', $invalidSerialNumbers)) + ->send(); + return; + } + + + $record = $records->first(); + $itemId = $record->item_id; + + $item = Item::find($itemId); + + if (! $item) { + Notification::make() + ->title('Item not found') + ->body("Item code '{$itemId}' was not found in item master.") + ->danger() + ->send(); + $this->dispatch('sticker-options-clear', stickerOptions: ''); + $this->dispatch('production-order-clear', productionOrder: ''); + return; + } + + $itemCode = $item->code; + + $item = Item::where('code', $itemCode)->where('plant_id', $plantId)->first(); + + if (! $item) { + Notification::make() + ->title('Item not found') + ->body("Item '{$itemCode}' was not found for the selected plant.") + ->danger() + ->send(); + $this->dispatch('sticker-options-clear', stickerOptions: ''); + $this->dispatch('production-order-clear', productionOrder: ''); + return; + } + + $itemCharacteristic = ClassCharacteristic::where('plant_id', $plantId)->where('item_id', $item->id)->first(); + + if (! $itemCharacteristic) { + Notification::make() + ->title('Class characteristic not found') + ->body("No class characteristic found for item '{$itemCode}'.") + ->danger() + ->send(); + return; + } + + // $itemCharacteristicId = $itemCharacteristic->id; + + $stickerMappings = StickerMappingMaster::where('plant_id', $plantId) + ->where('item_id', $item->id) + ->get(); + + if (! $stickerMappings) { + Notification::make() + ->title('Sticker mapping not found') + ->body("No sticker mapping found for this plant and item '$itemCode'.") + ->danger() + ->send(); + return; + } + + $stickerOptions = []; + + foreach ($stickerMappings as $stickerMapping) { + + for ($i = 1; $i <= 8; $i++) { + + $machineColumn = "sticker{$i}_machine_id"; + + $stickerMachineId = $stickerMapping->$machineColumn; + + if ((string) $stickerMachineId != (string) $machineId) { + continue; + } + + $structureColumn = "sticker_structure{$i}_id"; + + $stickerStructureId = $stickerMapping->$structureColumn; + + if (empty($stickerStructureId)) { + continue; + } + + $detail = StickerStructureDetail::find($stickerStructureId); + + if ($detail && $detail->sticker_id) { + + $stickerOptions[$detail->sticker_id] = + $detail->sticker_id; + } + + $this->dispatch('sticker-structure-updated', stickerStructureId: $stickerStructureId); + + } + } + + $this->dispatch('sticker-options', stickerOptions: $stickerOptions); + + $this->dispatch('production-order-updated', productionOrder: $productionOrder); + } + + public function generate(): void + { + $serialNumbersString = implode(',', array_filter( + $this->serialNumbers, + fn ($serial) => trim($serial) !== '' + )); + + $this->dispatch('generate-sticker-id', serialNumbers: $serialNumbersString); + + } + + public function clear(){ + $this->serialNumbers = ['']; + $this->dispatch('sticker-options-clear', stickerOptions: ''); + $this->dispatch('production-order-clear', productionOrder: ''); + } + + public function render() + { + return view('livewire.random-serial-number-list'); + } +} diff --git a/resources/views/filament/pages/bulk-sticker-printing.blade.php b/resources/views/filament/pages/bulk-sticker-printing.blade.php index 6404ab18..6f242721 100644 --- a/resources/views/filament/pages/bulk-sticker-printing.blade.php +++ b/resources/views/filament/pages/bulk-sticker-printing.blade.php @@ -18,7 +18,25 @@ > Generate Sticker - + + {{-- --}} + {{--