line_no)) { Log::debug("Skipping Construction Paint Logs sync - missing line number"); return ['skipped' => true, 'reason' => 'line_no_empty']; } // Skip processing if painting_cycle is empty // Construction Paint Logs should only exist when there is a painting cycle if (empty($lineList->painting_cycle)) { Log::debug("Skipping Construction Paint Logs sync - painting_cycle is empty", [ 'line_no' => $lineList->line_no ]); return ['skipped' => true, 'reason' => 'painting_cycle_empty']; } // Check if matching weld_logs record exists with same unit + line + fluid_code // Construction paint logs should only be created if there's a corresponding weld log $matchingWeldLogExists = db("weld_logs") ->where("line_number", $lineList->line_no) ->where("design_area", $lineList->unit) ->where("fluid_code", $lineList->fluid_code) ->exists(); if (!$matchingWeldLogExists) { Log::debug("Skipping Construction Paint Logs sync - no matching weld_logs record found", [ 'line_no' => $lineList->line_no, 'unit' => $lineList->unit, 'fluid_code' => $lineList->fluid_code ]); return ['skipped' => true, 'reason' => 'no_matching_weld_log']; } // Retrieve all weld logs with the same line number, unit and fluid_code $allWeldLogs = db("weld_logs") ->where("line_number", $lineList->line_no) ->where("design_area", $lineList->unit) ->where("fluid_code", $lineList->fluid_code) ->orderBy('id', 'ASC') // Deadlock prevention ->get(); Log::debug("Syncing Construction Paint Logs for line: " . $lineList->line_no, [ 'weld_log_count' => count($allWeldLogs), 'painting_cycle' => $lineList->painting_cycle ]); $createdCount = 0; $updatedCount = 0; // Track processed spools to avoid duplicates $processedSpools = []; // Process weld logs in chunks with TransactionHelper TransactionHelper::chunkTransaction( $allWeldLogs, function ($weldLogChunk) use ($lineList, &$updatedCount, &$createdCount, &$processedSpools) { foreach ($weldLogChunk as $weldLogData) { // Skip if spool is empty if (empty($weldLogData->spool_number)) { Log::debug("Skipping weld log - empty spool_number", ['weld_log_id' => $weldLogData->id]); continue; } // Skip if already processed this spool if (in_array($weldLogData->spool_number, $processedSpools)) { Log::debug("Skipping weld log - spool already processed", [ 'weld_log_id' => $weldLogData->id, 'spool' => $weldLogData->spool_number ]); continue; } // Shop joint check - only process spools with shop joints $hasShopJoint = db("weld_logs") ->where('line_number', $lineList->line_no) ->where('spool_number', $weldLogData->spool_number) ->where('type_of_joint', 'S') ->exists(); if (!$hasShopJoint) { Log::debug("Skipping spool - no shop joint found", [ 'line' => $lineList->line_no, 'spool' => $weldLogData->spool_number ]); continue; } Log::debug("Processing spool for Construction Paint Log", [ 'line' => $lineList->line_no, 'spool' => $weldLogData->spool_number, 'weld_log_id' => $weldLogData->id ]); // Process this spool $this->processWeldLogRecord($weldLogData, $lineList, $updatedCount, $createdCount); // Mark this spool as processed $processedSpools[] = $weldLogData->spool_number; } return $weldLogChunk->count(); }, 1, // Chunk size 10000 // 10ms delay ); Log::debug("Construction Paint Logs sync completed", [ 'line_no' => $lineList->line_no, 'created' => $createdCount, 'updated' => $updatedCount ]); return [ 'success' => true, 'created' => $createdCount, 'updated' => $updatedCount ]; } /** * Process a single weld log record for construction paint logs * Same structure as WeldLog trigger */ protected function processWeldLogRecord($currentWeldLog, $lineList, &$updatedCount, &$createdCount) { Log::debug("Starting processWeldLogRecord", [ 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'painting_cycle' => $lineList->painting_cycle, 'fluid_code' => $lineList->fluid_code ]); // Get paint matrix data for paint system information $paintMatrix = PaintMatrix::where('line', $lineList->line_no) ->where('fluid_code', $lineList->fluid_code) ->first(); Log::debug("Paint Matrix lookup result", [ 'found' => $paintMatrix !== null, 'line' => $lineList->line_no, 'fluid_code' => $lineList->fluid_code ]); // Base data for construction paint log $baseConstructionPaintLogData = [ // Report Information 'construction_report_no' => $currentWeldLog->weld_map_no ?? '', 'test_package' => $currentWeldLog->test_package_no ?? '', 'rev' => $lineList->rev ?? '', // Project Information 'engineering' => $lineList->engineering ?? '', 'area' => $currentWeldLog->project ?? '', 'unit' => $currentWeldLog->design_area ?? '', // Line Details 'line' => $lineList->line_no, 'iso_drawings' => $currentWeldLog->iso_number ?? '', 'fluid_code' => $lineList->fluid_code ?? '', 'fluid_code_description' => $lineList->fluid_ru ?? '', 'isolation_info' => $lineList->external_finish_type ?? '', ]; // Add paint system data if available if ($paintMatrix) { $paintSystemData = [ 'painting_system_type_1' => $paintMatrix->paint_cycle ?? '', 'painting_system_type_2' => $paintMatrix->paint_cycle ?? '', // First coat (Primer) 'brend_name_1' => $paintMatrix->brend_name_1 ?? '', 'ral_1' => $paintMatrix->ral_code_1 ?? '', 'color_1' => $paintMatrix->colour_1 ?? '', // Russian color description 'thickness_1' => $paintMatrix->thickness_1 ?? '', // Second coat (Intermediate) 'brend_name_2' => $paintMatrix->brend_name_2 ?? '', 'ral_2' => $paintMatrix->ral_code_2 ?? '', 'color_2' => $paintMatrix->colour_2 ?? '', // Russian color description 'thickness_2' => $paintMatrix->thickness_2 ?? '', // Third coat (Final) 'brend_name_3' => $paintMatrix->brend_name_3 ?? '', 'ral_3' => $paintMatrix->ral_code_3 ?? '', 'color_3' => $paintMatrix->colour_3 ?? '', // Russian color description 'thickness_3' => $paintMatrix->thickness_3 ?? '', ]; $baseConstructionPaintLogData = array_merge($baseConstructionPaintLogData, $paintSystemData); } // Add timestamp $baseConstructionPaintLogData['updated_at'] = now(); // Process only the specific spool $constructionPaintLogData = $baseConstructionPaintLogData; // Add spool-specific data $constructionPaintLogData['test_package'] = $currentWeldLog->test_package_no ?? ''; $constructionPaintLogData['spool'] = $currentWeldLog->spool_number ?? ''; $constructionPaintLogData['spool_status'] = $currentWeldLog->spool_status ?? 'Waiting'; // Generate unique report number for the spool $constructionPaintLogData['report_no'] = ''; // Add dimensions $constructionPaintLogData['dn_1'] = $currentWeldLog->nps_1 ?? ''; $constructionPaintLogData['dn_2'] = $currentWeldLog->nps_2 ?? ''; $constructionPaintLogData['dn_3'] = ''; // UNIQUE CONSTRAINT: line + spool + painting_system_type_1 (paint cycle) // This allows multiple records for same spool with different paint cycles $uniqueConstraintCondition = [ 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'painting_system_type_1' => $paintMatrix->paint_cycle ?? '' ]; // WHERE condition without cycle (to find records with different cycles) $whereCondition = [ 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number ]; // Find existing record with SAME painting cycle $existingRecordSameCycle = db("construction_paint_logs") ->where($uniqueConstraintCondition) ->first(); // Find records with DIFFERENT painting cycle $recordsWithDifferentPaintCycle = db("construction_paint_logs") ->where($whereCondition) ->where('painting_system_type_1', '!=', $paintMatrix->paint_cycle ?? '') ->get(); Log::debug('LineList ConstructionPaintLogsTrigger: Record check', [ 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'currentPaintCycle' => $paintMatrix->paint_cycle ?? '', 'existingSameCycle' => (bool) $existingRecordSameCycle, 'differentCycleCount' => $recordsWithDifferentPaintCycle->count() ]); try { if ($existingRecordSameCycle) { // Record with same paint cycle exists $hasAllEmptyDates = $this->hasAllEmptyDates($existingRecordSameCycle); if ($hasAllEmptyDates) { // All dates are empty - safe to update completely Log::debug('LineList ConstructionPaintLogsTrigger: Updating record (all dates empty)', [ 'recordId' => $existingRecordSameCycle->id, 'paintCycle' => $paintMatrix->paint_cycle ?? '' ]); db("construction_paint_logs") ->where('id', $existingRecordSameCycle->id) ->update($constructionPaintLogData); $updatedCount++; Log::info("✓ Updated Construction Paint Log (same cycle)", [ 'record_id' => $existingRecordSameCycle->id, 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'painting_cycle' => $lineList->painting_cycle ]); } else { // Some dates are filled - preserve completed work Log::debug('LineList ConstructionPaintLogsTrigger: Skipping update (dates filled)', [ 'recordId' => $existingRecordSameCycle->id, 'paintCycle' => $paintMatrix->paint_cycle ?? '' ]); } } else { // No record with same paint cycle exists // Handle records with different paint cycles if ($recordsWithDifferentPaintCycle->count() > 0) { foreach ($recordsWithDifferentPaintCycle as $oldRecord) { $hasAnyDateFilled = !$this->hasAllEmptyDates($oldRecord); if ($hasAnyDateFilled) { // Dates are filled - keep old record, will create new one Log::debug('LineList ConstructionPaintLogsTrigger: Old paint cycle record has dates, keeping it', [ 'oldRecordId' => $oldRecord->id, 'oldPaintCycle' => $oldRecord->painting_system_type_1, 'newPaintCycle' => $paintMatrix->paint_cycle ?? '' ]); } else { // Dates are empty - update to new paint cycle instead of creating new Log::debug('LineList ConstructionPaintLogsTrigger: Updating old record to new paint cycle', [ 'oldRecordId' => $oldRecord->id, 'oldPaintCycle' => $oldRecord->painting_system_type_1, 'newPaintCycle' => $paintMatrix->paint_cycle ?? '' ]); db("construction_paint_logs") ->where('id', $oldRecord->id) ->update($constructionPaintLogData); $updatedCount++; Log::info("✓ Updated Construction Paint Log (cycle changed, no dates)", [ 'record_id' => $oldRecord->id, 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'old_cycle' => $oldRecord->painting_system_type_1, 'new_cycle' => $lineList->painting_cycle ]); return; // Don't create new record } } } // Create new record (either no record exists, or old one has dates) Log::debug('LineList ConstructionPaintLogsTrigger: Creating new record', [ 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'paintCycle' => $paintMatrix->paint_cycle ?? '', 'reason' => $recordsWithDifferentPaintCycle->count() > 0 ? 'different_cycle_with_dates' : 'no_existing_record' ]); $constructionPaintLogData['created_at'] = now(); $insertedId = db("construction_paint_logs")->insertGetId($constructionPaintLogData); $createdCount++; Log::info("✓ Created Construction Paint Log", [ 'record_id' => $insertedId, 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'painting_cycle' => $lineList->painting_cycle, 'reason' => $recordsWithDifferentPaintCycle->count() > 0 ? 'different_cycle_with_dates' : 'no_existing_record' ]); } } catch (\Exception $e) { Log::error("✗ Failed to save Construction Paint Log", [ 'error' => $e->getMessage(), 'line' => $lineList->line_no, 'spool' => $currentWeldLog->spool_number, 'file' => $e->getFile(), 'line_number' => $e->getLine() ]); throw $e; } } /** * Check if all date fields are empty in a construction paint log record * * @param object $record Construction paint log record * @return bool True if all date fields are empty */ protected function hasAllEmptyDates($record): bool { $dateFields = [ 'blasting_date', 'blasting_finish_date', 'painting_date_1', 'painting_finish_date_1', 'rfi_date_1', 'painting_date_2', 'painting_finish_date_2', 'rfi_date_2', 'painting_date_3', 'painting_finish_date_3', 'rfi_date_3' ]; foreach ($dateFields as $field) { if (!empty($record->$field)) { return false; // Found a filled date } } return true; // All dates are empty } }