diff --git a/app/Filament/Pages/BulkStickerPrinting.php b/app/Filament/Pages/BulkStickerPrinting.php new file mode 100644 index 0000000..7103751 --- /dev/null +++ b/app/Filament/Pages/BulkStickerPrinting.php @@ -0,0 +1,1051 @@ +statePath('filters') + ->schema([ + Section::make('') + ->schema([ + Select::make('plant_id') + ->label('Plant') + ->reactive() + ->options(function(){ + + $plantId = Filament::auth()->user()->plant_id; + + return $plantId + ? Plant::where('id',$plantId) + ->pluck('name','id') + : Plant::pluck('name','id'); + + }) + ->required(), + Select::make('machine_id') + ->label('Work Center') + ->reactive() + ->options(function(callable $get){ + + $plantId = $get('plant_id'); + if (empty($plantId)) { + return []; + } + return Machine::where('plant_id', $plantId)->pluck('work_center', 'id'); + + }) + ->afterStateUpdated(function ($state, callable $set) { + $set('production_order', null); + $set('from_serial_number', null); + $set('to_serial_number', null); + $set('sticker_options', []); + }) + ->required(), + TextInput::make('production_order') + ->label('Production Order') + ->reactive() + ->required() + ->afterStateUpdated(function ($state, callable $set, $get) { + + for ($i = 1; $i <= 8; $i++) { + $set("sticker_structure{$i}_id", null); + } + + if (blank($state)) { + return; + } + + $machineId = $get('machine_id'); + + if (empty($machineId)) { + Notification::make() + ->title('Work Center not selected') + ->body('Please select a Work Center first.') + ->warning() + ->send(); + + return; + } + + $productionOrder = ProductionOrder::where('production_order', $state) + ->first(); + + if (! $productionOrder) { + Notification::make() + ->title('Production Order not found') + ->body("Production Order '{$state}' was not found.") + ->danger() + ->send(); + + return; + } + + $plantId = $productionOrder->plant_id; + $itemId = $productionOrder->item_id; + + $item = Item::find($itemId); + + if (! $item) { + Notification::make() + ->title('Item not found') + ->body("Item ID '{$itemId}' was not found in item master.") + ->danger() + ->send(); + + 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(); + + return; + } + + $itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)->where('item_id', $item->id)->first(); + + if (! $itemCharacteristic) { + Notification::make() + ->title('Item characteristic not found') + ->body("No item characteristic found for item '{$itemCode}'.") + ->danger() + ->send(); + + return; + } + + $itemCharacteristicId = $itemCharacteristic->id; + + $stickerMappings = StickerMappingMaster::where('plant_id', $plantId) + ->where('item_characteristic_id', $itemCharacteristicId) + ->get(); + + if (! $stickerMappings) { + Notification::make() + ->title('Sticker mapping not found') + ->body("No sticker mapping found for this plant and item characteristic.") + ->danger() + ->send(); + + return; + } + + $stickerOptions = []; + + // foreach ($stickerMappings as $stickerMapping) { + + // for ($i = 1; $i <= 8; $i++) { + + // $stickerStructureId = $stickerMapping->{"sticker_structure{$i}_id"}; + + // if ($stickerStructureId) { + + // $detail = StickerStructureDetail::where('id', $stickerStructureId) + // ->first(); + + // if ($detail && $detail->sticker_id) { + // $stickerOptions[$detail->sticker_id] = $detail->sticker_id; + // } + // } + // } + // } + + 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; + } + + $set("sticker_structure{$i}_id", $stickerStructureId); + + } + } + + $set('sticker_options', $stickerOptions); + }), + Select::make('sticker_id') + ->label('Sticker ID') + ->options(fn (callable $get) => $get('sticker_options') ?? []) + ->reactive() + ->afterStateUpdated(function ($state, callable $set) { + + if (blank($state)) { + return; + } + + $sticker = StickerStructureDetail::where('sticker_id', $state)->first(); + + if (! $sticker) { + Notification::make() + ->title('Sticker not found') + ->body("Sticker ID '{$state}' was not found.") + ->danger() + ->send(); + + return; + } + + $set('sticker_code', $state); + + }), + Hidden::make('sticker_options') + ->default([]), + TextInput::make('from_serial_number') + ->label('From Serial Number') + ->reactive(), + TextInput::make('to_serial_number') + ->label('To Serial Number') + ->reactive(), + ]) + ->columns(6), + ]); + } + + public function processSnoNo($qrcode) + { + + $parts = explode('|', $qrcode, 2); + + $itemCode = $parts[0] ?? null; + $serialNumber = $parts[1] ?? null; + + $plantId = $this->form->getState()['plant_id']; + + $plantId = trim($plantId) ?? null; + + $workCenter = $this->form->getState()['machine_id']; + + $prodOrderNo= $this->form->getState()['production_order']; + + $prodOrderNo = trim($prodOrderNo) ?? null; + + + if (!$qrcode || !preg_match('/^\d+\|\d+$/', $qrcode)) { + Notification::make() + ->title('Invalid QR Code') + ->body('QR code format should be like: 123456|12456456464') + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + elseif (!preg_match('/^[A-Za-z0-9]+$/', $itemCode)) { + Notification::make() + ->title('Invalid Item Code') + ->body('Item code should contain only alpha-numeric values.') + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + elseif (!preg_match('/^[A-Za-z0-9]+$/', $serialNumber)) { + Notification::make() + ->title('Invalid Serial Number') + ->body('Serial number should contain only alpha-numeric values.') + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + + $plant = Plant::find($plantId); + + $plantName = $plant ? $plant->name : null; + + $pOrderExist = ProductionOrder::where('plant_id', $plantId) + ->where('production_order', $prodOrderNo) + ->first(); + + if(!$pOrderExist){ + Notification::make() + ->title('Unknown Production Order') + ->body("Production Order not found against plant '$plantName'.") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + + $itemExist = Item::where('code', $itemCode)->first(); + + $itemAgaPlant = Item::where('code', $itemCode)->where('plant_id', $plantId)->first(); + + if(!$itemExist){ + Notification::make() + ->title('Unknown Item Code') + ->body("Item code '$itemCode' not found.") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + elseif(!$itemAgaPlant){ + Notification::make() + ->title('Unknown Item Code') + ->body("Item code '$itemCode' not found against the the plant '$plantName'.") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + elseif ($itemAgaPlant->id != $pOrderExist->item_id) { + Notification::make() + ->title('Item Code Mismatch') + ->body("Item code '$itemCode' does not match the item associated with production order '$prodOrderNo'.") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + + $productionOrders = ProductionOrder::where('plant_id', $plantId) + ->where('production_order', $prodOrderNo) + ->where('item_id', $itemAgaPlant->id) + ->get(); + + $serialExist = null; + + foreach ($productionOrders as $productionOrder) { + + for ( + $serial = (int) $productionOrder->from_serial_number; + $serial <= (int) $productionOrder->to_serial_number; + $serial++ + ) { + if ($serial == (int) $serialNumber) { + $serialExist = $productionOrder; + break 2; + } + } + } + + if(!$serialExist){ + Notification::make() + ->title('Serial Number Not Found') + ->body("Serial number '$serialNumber' not found for production order '$prodOrderNo', item '$itemCode' and plant '$plantName'.") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'serial_number' => null, + ]); + + return; + } + + + //..Generate Sticker PDF and download it + + $this->ref_number = $this->form->getState()['production_order']; + + $this->serNo = $serialNumber; + + $user = Filament::auth()->user(); + + $operatorName = $user->name; + + $duplicate = StickerValidation::where('plant_id', $plantId) + ->where('production_order', $this->ref_number) + ->where('serial_number', $serialNumber) + ->first(); + + if ($duplicate) { + Notification::make() + ->danger() + ->title('Duplicate Serial Number') + ->body("Serial number $serialNumber already exists for this plant and production order!") + ->seconds(3) + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $this->ref_number, + 'serial_number' => null, + ]); + return; + } + + $itemC = Item::where('code', $itemCode) + ->where('plant_id',$plantId) + ->first(); + + $itemId = $itemC->id; + + $item = ItemCharacteristic::where('item_id', $itemId) + ->where('plant_id',$plantId) + ->first(); + + $itemI = $item->id; + + $mapping = StickerMappingMaster::where('plant_id', $plantId) + ->where('sticker1_machine_id', $workCenter) + ->where('item_characteristic_id', $itemI) + ->first(); + + if (!$mapping) { + Notification::make() + ->danger() + ->title('Sticker Mapping Not Found') + ->body("No sticker mapping found for this item and plant.") + ->send(); + return; + } + + $stickers = []; + + for ($i = 1; $i <= 8; $i++) { + $machineColumn = "sticker{$i}_machine_id"; + $ipColumn = "sticker{$i}_print_ip"; + $stickerColumn = "sticker_structure{$i}_id"; + $itemColumn = "item_characteristic_id"; + + if ( + !empty($mapping->$machineColumn) && + !empty($mapping->$stickerColumn) + ) { + $stickers[] = [ + 'machine_id' => $mapping->$machineColumn, + 'sticker_id' => $mapping->$stickerColumn, + 'item_characteristic' => $mapping->$itemColumn, + 'print_ip' => $mapping->$ipColumn, + ]; + } + } + + if (empty($stickers)) { + Notification::make() + ->danger() + ->title('No Sticker Configuration Found') + ->body('No sticker and machine mappings configured for this item and plant.') + ->send(); + return; + } + + + StickerValidation::create([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $this->ref_number ?? null, + 'serial_number' => $serialNumber, + 'status' => 'Printed', + // 'sticker_id' => $matchedSticker, + 'created_by' => $operatorName, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + Notification::make() + ->success() + ->title('Sticker Recorded') + ->body("Item: $itemCode, Serial: $serialNumber recorded successfully!") + ->seconds(3) + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $this->ref_number, + 'serial_number' => null, + ]); + + $pdfUrls = []; + + foreach ($stickers as $sticker) + { + + $structure = StickerStructureDetail::findOrFail($sticker['sticker_id']); + + $itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId) + ->where('id', $sticker['item_characteristic']) + ->firstOrFail(); + + $dynamicElements = StickerDetail::where( + 'sticker_structure_detail_id', + $structure->id + )->where('element_type', 'Dynamic')->get(); + + $pdfContent = (new StickerPdfService())->generatePdf1( + $structure->sticker_id, + $dynamicElements, + $itemCharacteristic, + $serialNumber, + $itemCode, + $plantId + ); + + $tempPdfPath = storage_path('app/temp_sticker_' . uniqid() . '.pdf'); + + file_put_contents($tempPdfPath, $pdfContent); + + // $pdfUrl = route('sticker.preview', [ + // 'path' => basename($tempPdfPath), + // ]); + $pdfUrls[] = route('sticker.preview', ['path' => basename($tempPdfPath)]); + } + + $this->dispatch('open-sticker-pdf', urls: $pdfUrls); + + Notification::make() + ->success() + ->title('Sticker Printed') + ->body("Sticker for Serial Number: $serialNumber printed successfully!") + ->seconds(3) + ->send(); + } + + public function generateSticker() + { + $plantId = $this->form->getState()['plant_id']; + + $plantId = trim($plantId) ?? null; + + $workCenter = $this->form->getState()['machine_id']; + + $prodOrderNo= $this->form->getState()['production_order']; + + $prodOrderNo = trim($prodOrderNo) ?? null; + + $fromSno= $this->form->getState()['from_serial_number']; + + $fromSno = trim($fromSno) ?? null; + + $toSno= $this->form->getState()['to_serial_number']; + + $toSno = trim($toSno) ?? null; + + $serialExist = ProductionOrder::where('plant_id', $plantId) + ->where('production_order', $prodOrderNo) + ->where('from_serial_number', '=', $fromSno) + ->where('to_serial_number', '=', $toSno) + ->first(); + + if(!$serialExist){ + Notification::make() + ->title('Serial Number Range Not Found') + ->body("Serial number range '$fromSno' to '$toSno' not found for production order '$prodOrderNo'.") + ->danger() + ->send(); + + $this->form->fill([ + 'plant_id' => $plantId, + 'machine_id' => $workCenter, + 'production_order' => $prodOrderNo, + 'from_serial_number' => null, + 'to_serial_number' => null, + ]); + + return; + } + else + { + + if($serialExist){ + $itemId = $serialExist->item_id; + $itemCode = Item::where('id', $itemId) + ->where('plant_id', $serialExist->plant_id) + ->value('code'); + } + + $this->ref_number = $this->form->getState()['production_order']; + + $fromSerNo = $this->form->getState()['from_serial_number']; + + $toSerNo = $this->form->getState()['to_serial_number']; + + $user = Filament::auth()->user(); + + $operatorName = $user->name; + + $itemC = Item::where('code', $itemCode) + ->where('plant_id',$plantId) + ->first(); + + $itemId = $itemC->id; + + $item = ItemCharacteristic::where('item_id', $itemId) + ->where('plant_id',$plantId) + ->first(); + + $itemI = $item->id; + + $mapping = StickerMappingMaster::where('plant_id', $plantId) + ->where('sticker1_machine_id', $workCenter) + ->where('item_characteristic_id', $itemI) + ->first(); + + if (!$mapping) { + Notification::make() + ->danger() + ->title('Sticker Mapping Not Found') + ->body("No sticker mapping found for this item and plant.") + ->send(); + return; + } + + $stickers = []; + + for ($i = 1; $i <= 8; $i++) { + $machineColumn = "sticker{$i}_machine_id"; + $ipColumn = "sticker{$i}_print_ip"; + $stickerColumn = "sticker_structure{$i}_id"; + $itemColumn = "item_characteristic_id"; + + if ( + !empty($mapping->$machineColumn) && + !empty($mapping->$stickerColumn) + ) { + $stickers[] = [ + 'machine_id' => $mapping->$machineColumn, + 'sticker_id' => $mapping->$stickerColumn, + 'item_characteristic' => $mapping->$itemColumn, + 'print_ip' => $mapping->$ipColumn, + ]; + } + } + + if (empty($stickers)) { + Notification::make() + ->danger() + ->title('No Sticker Configuration Found') + ->body('No sticker and machine mappings configured for this item and plant.') + ->send(); + return; + } + + $fromSerNo = (int) $this->form->getState()['from_serial_number']; + $toSerNo = (int) $this->form->getState()['to_serial_number']; + + if ($fromSerNo > $toSerNo) { + Notification::make() + ->danger() + ->title('Invalid Serial Number Range') + ->body("From Serial Number must be less than or equal to To Serial Number.") + ->send(); + + return; + } + + $pdfUrls = []; + + $stickerService = new StickerPdfService(); + + foreach ($stickers as $sticker) { + + $structure = StickerStructureDetail::findOrFail($sticker['sticker_id']); + + $itemCharacteristic = ItemCharacteristic::where('plant_id',$plantId)->where('id',$sticker['item_characteristic'])->firstOrFail(); + + $elements = StickerDetail::where('sticker_structure_detail_id',$structure->id)->get(); + + $template = $stickerService->generateTemplate( + $structure->sticker_id, + $elements, + $itemCharacteristic, + $itemCode, + $plantId + ); + + $pdfContent = $stickerService->generateBulkFromTemplate( + $template, + $fromSerNo, + $toSerNo, + $itemCode + ); + + $fileName ='bulk_sticker_' .$fromSerNo .'_' .$toSerNo .'_' .uniqid() .'.pdf'; + + $tempPdfPath = storage_path('app/' . $fileName); + + file_put_contents($tempPdfPath,$pdfContent); + + $pdfUrls[] = route('sticker.preview',['path' => $fileName,]); + } + + $this->dispatch('open-sticker-pdf',urls: $pdfUrls); + + Notification::make() + ->success() + ->title('Sticker Printed') + ->body("Sticker printed successfully!") + ->seconds(3) + ->send(); + } + } + + public function generateStickerId() + { + $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'] ?? ''); + + $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; + } + + if ($fromSno == '' || $toSno == '') { + + Notification::make() + ->danger() + ->title('Serial Number Required') + ->body('Please enter both From Serial Number and To Serial Number.') + ->send(); + + return; + } + + $fromSerNo = (int) $fromSno; + + $toSerNo = (int) $toSno; + + if ($fromSerNo > $toSerNo) { + + Notification::make() + ->danger() + ->title('Invalid Serial Number Range') + ->body('From Serial Number must be less than or equal to To Serial Number.') + ->send(); + + return; + } + + $pOrderEx = ProductionOrder::where('production_order', $pOrder)->first(); + + if(!$pOrderEx){ + Notification::make() + ->danger() + ->title('Unknown Production Order') + ->body("Production Order '$pOrder' not found.") + ->send(); + return; + } + + $pOrderExist = ProductionOrder::where('plant_id', $plantId)->where('production_order', $pOrder)->first(); + + if(!$pOrderExist){ + Notification::make() + ->danger() + ->title('Unknown Production Order') + ->body("Production Order '$pOrder' not found against plant $plantName.") + ->send(); + return; + } + if($pOrderExist){ + if((int) $pOrderExist->from_serial_number != $fromSerNo || (int) $pOrderExist->to_serial_number != $toSerNo){ + Notification::make() + ->danger() + ->title('Unknown Serial Number') + ->body("The entered serial number range does not match Production Order '$pOrder' for plant '$plantName'.") + ->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; + } + + $stickerMappingMasterItems = StickerMappingMaster::where('plant_id', $plantId)->get(); + + if (!$stickerMappingMasterItems) { + + Notification::make() + ->danger() + ->title('Sticker Mapping Not Found') + ->body("No sticker mapping found for plant ID '{$plantId}'.") + ->send(); + return; + } + + $structure = null; + $stickerMappingMasterItem = null; + + foreach ($stickerMappingMasterItems as $mapping) { + + // Check sticker_structure1_id to sticker_structure8_id + for ($i = 1; $i <= 8; $i++) { + + $column = "sticker_structure{$i}_id"; + + $structureId = $mapping->{$column}; + + if (empty($structureId)) { + continue; + } + + // Find structure detail + $detail = StickerStructureDetail::find($structureId); + + if (!$detail) { + continue; + } + + // Check whether this structure belongs to selected sticker + if ((string) $detail->sticker_id === (string) $stickerId) { + + $structure = $detail; + + // Keep the mapping record also + $stickerMappingMasterItem = $mapping; + + break 2; + } + } + } + + if (!$structure) { + + Notification::make() + ->danger() + ->title('Sticker Structure Not Found') + ->body("No sticker structure found for selected sticker ID '{$stickerId}'.") + ->send(); + return; + } + + $itemCharacteristicId = $stickerMappingMasterItem->item_characteristic_id; + + if (!$itemCharacteristicId) { + + Notification::make() + ->danger() + ->title('Item Characteristic Not Found') + ->body('No item characteristic is configured in sticker mapping.') + ->send(); + return; + } + + $itemCharacteristic = ItemCharacteristic::where('plant_id', $plantId)->where('id',$itemCharacteristicId)->first(); + + if (!$itemCharacteristic) { + + Notification::make() + ->danger() + ->title('Item Characteristic Not Found') + ->body("Item characteristic '{$itemCharacteristicId}' was not found.") + ->send(); + return; + } + + $itemCode = Item::where('id',$itemCharacteristic->item_id)->where('plant_id',$plantId)->value('code'); + + if (!$itemCode) { + + Notification::make() + ->danger() + ->title('Item Not Found') + ->body('No item code found for the selected item characteristic.') + ->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 + ); + + $pdfContent = $stickerService->generateBulkFromTemplate( + $template, + $fromSerNo, + $toSerNo, + $itemCode, + ); + + $fileName = 'bulk_sticker_'. $fromSerNo. '_'. $toSerNo. '_'. 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 = ($toSerNo - $fromSerNo) + 1; + + + Notification::make() + ->success() + ->title('Sticker Generated') + ->body("{$totalStickers} sticker(s) generated successfully.") + ->seconds(3) + ->send(); + } + + public static function canAccess(): bool + { + return Auth::check() && Auth::user()->can('view sticker bulk print page'); + } +}