Files
citrus-cms/app/Services/LineListTriggers/Triggers/ConstructionPaintLogsSyncTrigger.php
2026-04-28 21:14:25 +03:00

414 lines
18 KiB
PHP

<?php
namespace App\Services\LineListTriggers\Triggers;
use App\Services\LineListTriggers\Base\BaseLineListTrigger;
use App\Models\PaintMatrix;
use App\Helpers\TransactionHelper;
use Illuminate\Support\Facades\Log;
/**
* Construction Paint Logs Sync Trigger
*
* Syncs data from Line Lists + Weld Logs + Paint Systems to Construction Paint Logs:
* - Creates/updates construction_paint_logs for each spool with shop joint
* - Handles painting cycle changes
* - Similar approach to WeldLog trigger for consistency
*/
class ConstructionPaintLogsSyncTrigger extends BaseLineListTrigger
{
public function getName(): string
{
return 'Construction Paint Logs Sync';
}
public function getDependentFields(): array
{
return [
];
}
protected function process($lineListData, $beforeData, array $context): array
{
$lineList = $lineListData;
// Skip processing if essential fields are missing
if (empty($lineList->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
}
}