İlk temizlik tamamlandı bir önceki projeden
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Base;
|
||||
|
||||
use App\Services\WeldLogTriggers\Contracts\WeldLogTriggerInterface;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Base class for all WeldLog triggers
|
||||
*
|
||||
* Provides common functionality like timing, logging, and shouldRun logic
|
||||
*/
|
||||
abstract class BaseTrigger implements WeldLogTriggerInterface
|
||||
{
|
||||
/**
|
||||
* @var float Start time for performance tracking
|
||||
*/
|
||||
protected $startTime;
|
||||
|
||||
/**
|
||||
* @var array Execution context
|
||||
*/
|
||||
protected $context = [];
|
||||
|
||||
/**
|
||||
* Get trigger name - must be implemented by child classes
|
||||
*/
|
||||
abstract public function getName(): string;
|
||||
|
||||
/**
|
||||
* Get trigger order - must be implemented by child classes
|
||||
*/
|
||||
abstract public function getOrder(): int;
|
||||
|
||||
/**
|
||||
* Get dependent fields - must be implemented by child classes
|
||||
*/
|
||||
abstract public function getDependentFields(): array;
|
||||
|
||||
/**
|
||||
* Process trigger logic - must be implemented by child classes
|
||||
*
|
||||
* @param object $weldLogData Current weld log data
|
||||
* @param object|null $beforeData Previous weld log data
|
||||
* @param array $context Execution context
|
||||
* @return array Result data
|
||||
*/
|
||||
abstract protected function process($weldLogData, $beforeData, array $context): array;
|
||||
|
||||
/**
|
||||
* Execute the trigger with logging and error handling
|
||||
*
|
||||
* @param object $weldLogData Current weld log data
|
||||
* @param object|null $beforeData Previous weld log data
|
||||
* @param array $context Execution context
|
||||
* @return array Result data
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function execute($weldLogData, $beforeData = null, array $context = []): array
|
||||
{
|
||||
$this->startTime = microtime(true);
|
||||
$this->context = $context;
|
||||
|
||||
Log::info("WeldLog Trigger [{$this->getOrder()}/14] {$this->getName()} - STARTED", [
|
||||
'weld_log_id' => $weldLogData->id,
|
||||
'process' => $this->getName()
|
||||
]);
|
||||
|
||||
try {
|
||||
$result = $this->process($weldLogData, $beforeData, $context);
|
||||
$this->logCompletion($weldLogData->id, 'success', $result);
|
||||
return $result;
|
||||
} catch (\Throwable $th) {
|
||||
$this->logCompletion($weldLogData->id, 'error', [
|
||||
'error' => $th->getMessage(),
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine()
|
||||
]);
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if trigger should run based on changed fields
|
||||
*
|
||||
* @param array $changedFields List of changed field names
|
||||
* @param bool $isNewRecord Whether this is a new record
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRun(array $changedFields, bool $isNewRecord): bool
|
||||
{
|
||||
if ($isNewRecord) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$dependentFields = $this->getDependentFields();
|
||||
|
||||
// If no dependent fields defined, always run
|
||||
if (empty($dependentFields)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if any changed field is in dependent fields
|
||||
return !empty(array_intersect($changedFields, $dependentFields));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if trigger is async (default: false)
|
||||
* Override in child classes if needed
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAsync(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log trigger completion with performance metrics
|
||||
*
|
||||
* @param int $weldLogId Weld log ID
|
||||
* @param string $status Execution status (success/error)
|
||||
* @param array $additionalData Additional log data
|
||||
*/
|
||||
protected function logCompletion($weldLogId, string $status, array $additionalData = [])
|
||||
{
|
||||
$duration = round((microtime(true) - $this->startTime) * 1000, 2);
|
||||
|
||||
$logLevel = $status === 'error' ? 'error' : 'info';
|
||||
|
||||
Log::$logLevel("WeldLog Trigger [{$this->getOrder()}/14] {$this->getName()} - COMPLETED", array_merge([
|
||||
'weld_log_id' => $weldLogId,
|
||||
'process' => $this->getName(),
|
||||
'status' => $status,
|
||||
'duration_ms' => $duration,
|
||||
'duration_sec' => round($duration / 1000, 3)
|
||||
], $additionalData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Contracts;
|
||||
|
||||
/**
|
||||
* Interface for WeldLog triggers
|
||||
*
|
||||
* Each trigger must implement this interface to be registered
|
||||
* in the WeldLogTriggerRegistry and managed by WeldLogTriggerManager
|
||||
*/
|
||||
interface WeldLogTriggerInterface
|
||||
{
|
||||
/**
|
||||
* Get trigger name for logging purposes
|
||||
*
|
||||
* @return string The human-readable name of the trigger
|
||||
*/
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* Get trigger execution order/priority (1-13)
|
||||
* Lower numbers execute first
|
||||
*
|
||||
* @return int The execution order
|
||||
*/
|
||||
public function getOrder(): int;
|
||||
|
||||
/**
|
||||
* Check if trigger should run based on changed fields
|
||||
*
|
||||
* @param array $changedFields List of field names that changed
|
||||
* @param bool $isNewRecord Whether this is a new record
|
||||
* @return bool True if trigger should execute
|
||||
*/
|
||||
public function shouldRun(array $changedFields, bool $isNewRecord): bool;
|
||||
|
||||
/**
|
||||
* Get fields that this trigger depends on
|
||||
* Used to determine if trigger should run when fields change
|
||||
*
|
||||
* @return array List of field names this trigger depends on
|
||||
*/
|
||||
public function getDependentFields(): array;
|
||||
|
||||
/**
|
||||
* Execute the trigger logic
|
||||
*
|
||||
* @param object $weldLogData Current weld log data
|
||||
* @param object|null $beforeData Previous weld log data (null for new records)
|
||||
* @param array $context Additional context (changed_fields, is_new_record, etc)
|
||||
* @return array Result data from trigger execution
|
||||
*/
|
||||
public function execute($weldLogData, $beforeData = null, array $context = []): array;
|
||||
|
||||
/**
|
||||
* Check if trigger can be executed asynchronously (queued)
|
||||
*
|
||||
* @return bool True if can be queued, false for synchronous execution
|
||||
*/
|
||||
public function isAsync(): bool;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
# WeldLog Triggers System
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
Modular, service-based trigger system for WeldLog save operations. Replaces the monolithic 2,435-line trigger file with 12 separate, maintainable trigger classes.
|
||||
|
||||
## 📊 Quick Stats
|
||||
|
||||
- **Original**: 1 file, 2,435 lines
|
||||
- **New System**: 16 files, ~3,600 lines (better organized)
|
||||
- **Triggers**: 12 independent operations
|
||||
- **Execution Order**: 1-12 (explicit ordering)
|
||||
- **Test Coverage**: Ready for unit testing
|
||||
|
||||
## 🗂️ Structure
|
||||
|
||||
```
|
||||
app/Services/WeldLogTriggers/
|
||||
├── Contracts/
|
||||
│ └── WeldLogTriggerInterface.php # Interface
|
||||
├── Base/
|
||||
│ └── BaseTrigger.php # Base class
|
||||
├── Triggers/
|
||||
│ ├── SpoolStatusChangerTrigger.php # Order 1
|
||||
│ ├── LineListsUpdateTrigger.php # Order 2
|
||||
│ ├── NdeMatrixUpdateTrigger.php # Order 3
|
||||
│ ├── RequestDateOperationsTrigger.php # Order 4
|
||||
│ ├── RepairLogsUpdateTrigger.php # Order 5
|
||||
│ ├── NdeProjectUpdateTrigger.php # Order 6
|
||||
│ ├── TestPackageOperationsTrigger.php # Order 7
|
||||
│ ├── ConstructionPaintLogsTrigger.php # Order 8
|
||||
│ ├── TestPackBaseStatusChangerTrigger.php # Order 9
|
||||
│ ├── PaintFollowUpsSyncTrigger.php # Order 10
|
||||
│ ├── HandoversSyncTrigger.php # Order 11
|
||||
│ └── TestPackCleanupTrigger.php # Order 12
|
||||
├── WeldLogTriggerRegistry.php # Central registry
|
||||
├── WeldLogTriggerManager.php # Execution manager
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```php
|
||||
use App\Services\WeldLogTriggers\WeldLogTriggerManager;
|
||||
use App\Services\WeldLogTriggers\WeldLogTriggerRegistry;
|
||||
|
||||
// Initialize
|
||||
$registry = new WeldLogTriggerRegistry();
|
||||
$manager = new WeldLogTriggerManager($registry);
|
||||
|
||||
// Execute all triggers
|
||||
$results = $manager->executeTriggers(
|
||||
$weldLogData, // Current data
|
||||
$beforeData, // Previous data (null for new)
|
||||
$changedFields, // Array of changed field names
|
||||
$isNewRecord // Boolean
|
||||
);
|
||||
```
|
||||
|
||||
### Adding a New Trigger
|
||||
|
||||
1. Create trigger class in `Triggers/` directory
|
||||
2. Extend `BaseTrigger`
|
||||
3. Implement required methods
|
||||
4. Register in `WeldLogTriggerRegistry.php`
|
||||
|
||||
```php
|
||||
class MyNewTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string { return 'My New Trigger'; }
|
||||
public function getOrder(): int { return 14; }
|
||||
public function getDependentFields(): array { return ['field1', 'field2']; }
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
// Your logic here
|
||||
return ['success' => true];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
### 1. Modular Design
|
||||
Each trigger is a separate, focused class with single responsibility.
|
||||
|
||||
### 2. Automatic Change Detection
|
||||
System automatically detects which fields changed and runs only relevant triggers.
|
||||
|
||||
### 3. Standardized Logging
|
||||
All triggers use consistent log format with timing information.
|
||||
|
||||
### 4. Error Isolation
|
||||
One trigger's error doesn't affect others (except critical triggers).
|
||||
|
||||
### 5. Performance Tracking
|
||||
Each trigger's execution time is measured and logged separately.
|
||||
|
||||
### 6. Future-Ready
|
||||
Built-in support for async execution (to be implemented).
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
### Complete Documentation
|
||||
See [resources/views/guide/weld-log-triggers-system.md](../../../resources/views/guide/weld-log-triggers-system.md) for:
|
||||
- Detailed architecture
|
||||
- Complete trigger descriptions
|
||||
- API documentation
|
||||
- Best practices
|
||||
- Troubleshooting guide
|
||||
|
||||
### Migration Guide
|
||||
See [resources/views/guide/weld-log-triggers-migration.md](../../../resources/views/guide/weld-log-triggers-migration.md) for:
|
||||
- Step-by-step migration
|
||||
- Rollback procedures
|
||||
- Validation checklist
|
||||
- Common issues and solutions
|
||||
|
||||
## 🔍 How It Works
|
||||
|
||||
```
|
||||
1. WeldLog saved in database
|
||||
↓
|
||||
2. SaveTrigger called (weld_logs.php)
|
||||
↓
|
||||
3. Detect changed fields
|
||||
↓
|
||||
4. Initialize Registry & Manager
|
||||
↓
|
||||
5. For each trigger (1-12):
|
||||
- Check if should run (based on changed fields)
|
||||
- Execute if needed
|
||||
- Log results
|
||||
↓
|
||||
6. Return consolidated results
|
||||
```
|
||||
|
||||
## 🎨 Design Patterns
|
||||
|
||||
- **Strategy Pattern**: Each trigger is a strategy
|
||||
- **Registry Pattern**: Central trigger registry
|
||||
- **Template Method**: BaseTrigger defines execution template
|
||||
- **Chain of Responsibility**: Triggers execute in sequence
|
||||
|
||||
## 📋 Trigger List
|
||||
|
||||
| # | Trigger | Purpose | Avg Time |
|
||||
|---|---------|---------|----------|
|
||||
| 1 | Spool Status Changer | Updates spool statuses | 50-100ms |
|
||||
| 2 | Line Lists Update | Syncs line lists data | 100-200ms |
|
||||
| 3 | NDE Matrix Update | Manages NDE matrices | 200-500ms |
|
||||
| 4 | Request Date Operations | Generates request numbers | 100-300ms |
|
||||
| 5 | Repair Logs Update | Updates repair statuses | 50-100ms |
|
||||
| 6 | NDE Project Update | Updates project fields | 50-100ms |
|
||||
| 7 | Test Package Operations | Complex test package logic | 500-2000ms |
|
||||
| 8 | Construction Paint Logs | Construction paint sync | 200-400ms |
|
||||
| 9 | Test Pack Base Status | Updates base statuses | 300-600ms |
|
||||
| 10 | Paint Follow Ups Sync | Comprehensive paint sync | 250-450ms |
|
||||
| 11 | Handovers Sync | Syncs handover data | 100-200ms |
|
||||
| 12 | Test Pack Cleanup | Cleans orphaned records | 50-100ms |
|
||||
|
||||
**Total**: 2-4 seconds average
|
||||
|
||||
## ⚡ Performance
|
||||
|
||||
### Optimization Features
|
||||
- Chunk processing for large datasets
|
||||
- Transaction retry logic for deadlocks
|
||||
- Configurable delays between chunks
|
||||
- Memory management
|
||||
- Database timeout settings
|
||||
|
||||
### Monitoring
|
||||
Check logs for performance metrics:
|
||||
```bash
|
||||
tail -f storage/logs/laravel.log | grep "WeldLog Trigger"
|
||||
```
|
||||
|
||||
Look for:
|
||||
- `duration_ms`: Execution time per trigger
|
||||
- `total_execution_time_sec`: Overall time
|
||||
- `peak_memory_usage_mb`: Memory usage
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Manual Testing
|
||||
```php
|
||||
// Test with real weld log
|
||||
$weldLog = WeldLog::find(1);
|
||||
$beforeData = clone $weldLog;
|
||||
$weldLog->spool_number = 'NEW-SPOOL';
|
||||
$weldLog->save();
|
||||
|
||||
// Check logs for trigger execution
|
||||
```
|
||||
|
||||
### Unit Testing (Future)
|
||||
Each trigger can be unit tested independently:
|
||||
```php
|
||||
$trigger = new SpoolStatusChangerTrigger();
|
||||
$result = $trigger->execute($data, $beforeData, []);
|
||||
$this->assertTrue($result['success']);
|
||||
```
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Trigger not executing?**
|
||||
- Check `getDependentFields()` includes changed field
|
||||
- Check logs for "Skipping trigger" messages
|
||||
- Verify trigger is registered in Registry
|
||||
|
||||
**Performance slow?**
|
||||
- Check chunk sizes in TransactionHelper calls
|
||||
- Add database indexes
|
||||
- Monitor slow query log
|
||||
|
||||
**Deadlock errors?**
|
||||
- Ensure queries ordered by 'id ASC'
|
||||
- Use TransactionHelper with retry logic
|
||||
- Increase delays between chunks
|
||||
|
||||
### Debug Mode
|
||||
Enable detailed logging:
|
||||
```php
|
||||
Log::setDefaultDriver('daily');
|
||||
Log::info("Debug info", ['data' => $data]);
|
||||
```
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
### Version 1.1.0 (2025-11-15)
|
||||
- ✅ Consolidated paint follow-up logic (LineList parity)
|
||||
- ✅ Removed legacy PaintFollowUpTrigger
|
||||
- ✅ Added cleanup + protection to construction paint sync
|
||||
- ✅ Updated docs and registry ordering
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
### Adding New Triggers
|
||||
1. Create class in `Triggers/` directory
|
||||
2. Extend `BaseTrigger`
|
||||
3. Implement all required methods
|
||||
4. Add to Registry
|
||||
5. Update documentation
|
||||
6. Test thoroughly
|
||||
|
||||
### Code Style
|
||||
- Follow PSR-12 standards
|
||||
- Use type hints
|
||||
- Add PHPDoc comments
|
||||
- Keep methods focused (single responsibility)
|
||||
- Log important operations
|
||||
|
||||
## 📖 Additional Resources
|
||||
|
||||
- [Main Documentation](../../../resources/views/guide/weld-log-triggers-system.md)
|
||||
- [Migration Guide](../../../resources/views/guide/weld-log-triggers-migration.md)
|
||||
- [DevQMS Documentation](../../../resources/views/guide/)
|
||||
|
||||
## 🔐 Security
|
||||
|
||||
- All triggers use prepared statements
|
||||
- Transaction safety ensured
|
||||
- Input validation in place
|
||||
- Error messages don't expose sensitive data
|
||||
|
||||
## 📞 Support
|
||||
|
||||
For issues or questions:
|
||||
1. Check documentation
|
||||
2. Review logs
|
||||
3. Contact development team
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Status**: Production Ready ✅
|
||||
**Last Updated**: October 30, 2025
|
||||
**Maintainer**: DevQMS Development Team
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use App\Models\PaintMatrix;
|
||||
use App\Helpers\TransactionHelper;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Construction Paint Logs Trigger
|
||||
*
|
||||
* Aligns weld log driven construction paint sync with LineList trigger behaviour.
|
||||
* - Requires matching Line List + painting cycle
|
||||
* - Processes each spool once, only when shop joints exist
|
||||
* - Protects finished records and cleans up orphan entries
|
||||
*/
|
||||
class ConstructionPaintLogsTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Construction Paint Logs Sync';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'line_number',
|
||||
'spool_number',
|
||||
'type_of_joint',
|
||||
'project',
|
||||
'design_area',
|
||||
'iso_number',
|
||||
'fluid_code',
|
||||
'painting_cycle',
|
||||
'test_package_no',
|
||||
'nps_1',
|
||||
'nps_2',
|
||||
'spool_status',
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
$constructionPaintLogUpdatedCount = 0;
|
||||
$constructionPaintLogCreatedCount = 0;
|
||||
$deletedCleanupCount = 0;
|
||||
|
||||
try {
|
||||
Log::debug('ConstructionPaintLogsTrigger: Starting process', [
|
||||
'weldLogId' => $data->id
|
||||
]);
|
||||
|
||||
$weldLog = db("weld_logs")->where("id", $data->id)->first();
|
||||
|
||||
if (!$weldLog) {
|
||||
return ['success' => false, 'reason' => 'weld_log_not_found'];
|
||||
}
|
||||
|
||||
if (empty($weldLog->line_number)) {
|
||||
return ['success' => false, 'reason' => 'line_number_empty'];
|
||||
}
|
||||
|
||||
$lineList = db("line_lists")
|
||||
->where('line_no', $weldLog->line_number)
|
||||
->first();
|
||||
|
||||
if (!$lineList) {
|
||||
return ['success' => false, 'reason' => 'line_list_not_found'];
|
||||
}
|
||||
|
||||
if (empty($lineList->painting_cycle)) {
|
||||
return ['skipped' => true, 'reason' => 'painting_cycle_empty'];
|
||||
}
|
||||
|
||||
$allWeldLogs = db("weld_logs")
|
||||
->where("line_number", $lineList->line_no)
|
||||
->where("design_area", $lineList->unit)
|
||||
->where("fluid_code", $lineList->fluid_code)
|
||||
->orderBy('id', 'ASC')
|
||||
->get();
|
||||
|
||||
if ($allWeldLogs->isEmpty()) {
|
||||
return ['skipped' => true, 'reason' => 'no_matching_weld_logs'];
|
||||
}
|
||||
|
||||
$processedSpools = [];
|
||||
$validShopSpools = $this->getValidShopSpools($lineList->line_no, $lineList->unit, $lineList->fluid_code);
|
||||
|
||||
TransactionHelper::chunkTransaction(
|
||||
$allWeldLogs,
|
||||
function ($weldLogChunk) use (
|
||||
$lineList,
|
||||
&$constructionPaintLogUpdatedCount,
|
||||
&$constructionPaintLogCreatedCount,
|
||||
&$processedSpools
|
||||
) {
|
||||
foreach ($weldLogChunk as $currentWeldLog) {
|
||||
if (empty($currentWeldLog->spool_number)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($currentWeldLog->spool_number, $processedSpools, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->hasShopJoint($lineList->line_no, $currentWeldLog->spool_number)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->processWeldLogRecord(
|
||||
$currentWeldLog,
|
||||
$lineList,
|
||||
$constructionPaintLogUpdatedCount,
|
||||
$constructionPaintLogCreatedCount
|
||||
);
|
||||
|
||||
$processedSpools[] = $currentWeldLog->spool_number;
|
||||
}
|
||||
return $weldLogChunk->count();
|
||||
},
|
||||
1,
|
||||
10000
|
||||
);
|
||||
|
||||
$deletedCleanupCount = $this->cleanupConstructionRecords($lineList->line_no, $validShopSpools);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Construction Paint Logs sync error: " . $th->getMessage(), [
|
||||
'weld_log_id' => $data->id
|
||||
]);
|
||||
throw $th;
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'created' => $constructionPaintLogCreatedCount,
|
||||
'updated' => $constructionPaintLogUpdatedCount,
|
||||
'deleted_cleanup' => $deletedCleanupCount
|
||||
];
|
||||
}
|
||||
|
||||
protected function processWeldLogRecord($currentWeldLog, $lineList, &$updatedCount, &$createdCount)
|
||||
{
|
||||
$paintMatrix = PaintMatrix::where('line', $lineList->line_no)
|
||||
->where('fluid_code', $lineList->fluid_code)
|
||||
->first();
|
||||
|
||||
$baseConstructionPaintLogData = [
|
||||
'construction_report_no' => $currentWeldLog->weld_map_no ?? '',
|
||||
'test_package' => $currentWeldLog->test_package_no ?? '',
|
||||
'rev' => $lineList->rev ?? '',
|
||||
'engineering' => $lineList->engineering ?? '',
|
||||
'area' => $currentWeldLog->project ?? '',
|
||||
'unit' => $currentWeldLog->design_area ?? '',
|
||||
'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 ?? '',
|
||||
'updated_at' => now()
|
||||
];
|
||||
|
||||
if ($paintMatrix) {
|
||||
$baseConstructionPaintLogData = array_merge($baseConstructionPaintLogData, [
|
||||
'painting_system_type_1' => $paintMatrix->paint_cycle ?? '',
|
||||
'painting_system_type_2' => $paintMatrix->paint_cycle ?? '',
|
||||
'brend_name_1' => $paintMatrix->brend_name_1 ?? '',
|
||||
'ral_1' => $paintMatrix->ral_code_1 ?? '',
|
||||
'color_1' => $paintMatrix->colour_1 ?? '',
|
||||
'thickness_1' => $paintMatrix->thickness_1 ?? '',
|
||||
'brend_name_2' => $paintMatrix->brend_name_2 ?? '',
|
||||
'ral_2' => $paintMatrix->ral_code_2 ?? '',
|
||||
'color_2' => $paintMatrix->colour_2 ?? '',
|
||||
'thickness_2' => $paintMatrix->thickness_2 ?? '',
|
||||
'brend_name_3' => $paintMatrix->brend_name_3 ?? '',
|
||||
'ral_3' => $paintMatrix->ral_code_3 ?? '',
|
||||
'color_3' => $paintMatrix->colour_3 ?? '',
|
||||
'thickness_3' => $paintMatrix->thickness_3 ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
$constructionPaintLogData = $baseConstructionPaintLogData;
|
||||
$constructionPaintLogData['test_package'] = $currentWeldLog->test_package_no ?? '';
|
||||
$constructionPaintLogData['spool'] = $currentWeldLog->spool_number ?? '';
|
||||
$constructionPaintLogData['spool_status'] = $currentWeldLog->spool_status ?? 'Waiting';
|
||||
$constructionPaintLogData['report_no'] = '';
|
||||
$constructionPaintLogData['dn_1'] = $currentWeldLog->nps_1 ?? '';
|
||||
$constructionPaintLogData['dn_2'] = $currentWeldLog->nps_2 ?? '';
|
||||
$constructionPaintLogData['dn_3'] = '';
|
||||
|
||||
$uniqueConstraintCondition = [
|
||||
'line' => $lineList->line_no,
|
||||
'spool' => $currentWeldLog->spool_number,
|
||||
'painting_system_type_1' => $paintMatrix->paint_cycle ?? ''
|
||||
];
|
||||
|
||||
$whereCondition = [
|
||||
'line' => $lineList->line_no,
|
||||
'spool' => $currentWeldLog->spool_number
|
||||
];
|
||||
|
||||
$existingRecordSameCycle = db("construction_paint_logs")
|
||||
->where($uniqueConstraintCondition)
|
||||
->first();
|
||||
|
||||
$recordsWithDifferentPaintCycle = db("construction_paint_logs")
|
||||
->where($whereCondition)
|
||||
->where('painting_system_type_1', '!=', $paintMatrix->paint_cycle ?? '')
|
||||
->get();
|
||||
|
||||
if ($existingRecordSameCycle) {
|
||||
$hasAllEmptyDates = $this->hasAllEmptyDates($existingRecordSameCycle);
|
||||
|
||||
if ($hasAllEmptyDates) {
|
||||
db("construction_paint_logs")
|
||||
->where('id', $existingRecordSameCycle->id)
|
||||
->update($constructionPaintLogData);
|
||||
$updatedCount++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($recordsWithDifferentPaintCycle->count() > 0) {
|
||||
foreach ($recordsWithDifferentPaintCycle as $oldRecord) {
|
||||
$hasAnyDateFilled = !$this->hasAllEmptyDates($oldRecord);
|
||||
|
||||
if (!$hasAnyDateFilled) {
|
||||
db("construction_paint_logs")
|
||||
->where('id', $oldRecord->id)
|
||||
->update($constructionPaintLogData);
|
||||
$updatedCount++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$constructionPaintLogData['created_at'] = now();
|
||||
db("construction_paint_logs")->insert($constructionPaintLogData);
|
||||
$createdCount++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function hasShopJoint(string $lineNumber, string $spoolNumber): bool
|
||||
{
|
||||
return db("weld_logs")
|
||||
->where('line_number', $lineNumber)
|
||||
->where('spool_number', $spoolNumber)
|
||||
->where('type_of_joint', 'S')
|
||||
->exists();
|
||||
}
|
||||
|
||||
protected function getValidShopSpools(string $lineNumber, ?string $unit, ?string $fluidCode): array
|
||||
{
|
||||
return db("weld_logs")
|
||||
->where('line_number', $lineNumber)
|
||||
->when($unit, function ($query, $unit) {
|
||||
return $query->where('design_area', $unit);
|
||||
})
|
||||
->when($fluidCode, function ($query, $fluidCode) {
|
||||
return $query->where('fluid_code', $fluidCode);
|
||||
})
|
||||
->where('type_of_joint', 'S')
|
||||
->whereNotNull('spool_number')
|
||||
->pluck('spool_number')
|
||||
->unique()
|
||||
->values()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
protected function cleanupConstructionRecords(string $lineNumber, array $validShopSpools): int
|
||||
{
|
||||
$query = db("construction_paint_logs")
|
||||
->where('line', $lineNumber);
|
||||
|
||||
if (!empty($validShopSpools)) {
|
||||
$recordsToEvaluate = $query
|
||||
->whereNotIn('spool', $validShopSpools)
|
||||
->get();
|
||||
} else {
|
||||
$recordsToEvaluate = $query->get();
|
||||
}
|
||||
|
||||
if ($recordsToEvaluate->isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$deletableIds = $recordsToEvaluate
|
||||
->filter(function ($record) {
|
||||
return $this->hasAllEmptyDates($record);
|
||||
})
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
if (empty($deletableIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return db("construction_paint_logs")
|
||||
->whereIn('id', $deletableIds)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use App\Helpers\TransactionHelper;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Handovers Sync Trigger
|
||||
*
|
||||
* Syncs data from WeldLogs to Handovers table
|
||||
* Groups by line_number and creates/updates handover records
|
||||
*/
|
||||
class HandoversSyncTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Handovers Sync';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
try {
|
||||
// Get current weld log data
|
||||
$weldLog = db("weld_logs")->where("id", $data->id)->first();
|
||||
|
||||
if (!$weldLog) {
|
||||
return ['success' => false, 'reason' => 'weld_log_not_found'];
|
||||
}
|
||||
|
||||
// Skip processing if essential fields are missing
|
||||
if (empty($weldLog->line_number)) {
|
||||
return ['success' => false, 'reason' => 'line_number_empty'];
|
||||
}
|
||||
|
||||
// Get all weld logs with the same line_number
|
||||
$allWeldLogs = db("weld_logs")
|
||||
->where("line_number", $weldLog->line_number)
|
||||
->orderBy('id', 'ASC') // Deadlock prevention
|
||||
->get();
|
||||
|
||||
// Process each weld log
|
||||
$handoversCreated = 0;
|
||||
$handoversUpdated = 0;
|
||||
|
||||
// Group by line - handovers are stored by line
|
||||
$uniqueLines = [];
|
||||
foreach ($allWeldLogs as $currentWeldLog) {
|
||||
$lineKey = $currentWeldLog->line_number;
|
||||
if (!isset($uniqueLines[$lineKey])) {
|
||||
$uniqueLines[$lineKey] = $currentWeldLog;
|
||||
}
|
||||
}
|
||||
|
||||
// Process Handovers in chunks with TransactionHelper
|
||||
TransactionHelper::chunkTransaction(
|
||||
collect($uniqueLines),
|
||||
function ($handoverChunk) use (&$handoversCreated, &$handoversUpdated) {
|
||||
foreach ($handoverChunk as $currentWeldLog) {
|
||||
$this->processHandoverRecord($currentWeldLog, $handoversCreated, $handoversUpdated);
|
||||
}
|
||||
return $handoverChunk->count();
|
||||
},
|
||||
10, // Chunk size
|
||||
10000 // 10ms delay
|
||||
);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Handovers sync error: " . $th->getMessage());
|
||||
|
||||
// Log detailed error for debugging
|
||||
Log::error("Error details: ", [
|
||||
'weldLogId' => $data->id,
|
||||
'exception' => get_class($th),
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
'trace' => $th->getTraceAsString()
|
||||
]);
|
||||
|
||||
throw $th;
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'created' => $handoversCreated,
|
||||
'updated' => $handoversUpdated
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single handover record
|
||||
*/
|
||||
protected function processHandoverRecord($currentWeldLog, &$createdCount, &$updatedCount)
|
||||
{
|
||||
// Check for required field
|
||||
if (empty($currentWeldLog->line_number)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get line list data (for additional information)
|
||||
$lineList = db("line_lists")
|
||||
->where('line_no', $currentWeldLog->line_number)
|
||||
->first();
|
||||
|
||||
// Handover data
|
||||
$handoverData = [
|
||||
// Mapping: weld_logs -> handovers
|
||||
'project' => $currentWeldLog->line_number, // line_number -> location (zone instead)
|
||||
'work_type' => 'ТРУБКА', // piping_type -> work_type
|
||||
'object' => $currentWeldLog->project ?? '', // project -> object
|
||||
'location' => $currentWeldLog->design_area ?? '', // design_area -> project
|
||||
|
||||
// Status information
|
||||
'status1' => 'In Progress',
|
||||
'updated_at' => now()
|
||||
];
|
||||
|
||||
// Where condition - location (line_number) and object (project) for unique record
|
||||
$whereCondition = [
|
||||
'project' => $currentWeldLog->line_number,
|
||||
];
|
||||
|
||||
// Check if existing record exists
|
||||
$existingRecord = db("handovers")
|
||||
->where($whereCondition)
|
||||
->first();
|
||||
|
||||
// Calculate volumes logic (mirrors hand-over.blade.php)
|
||||
$collected = 0;
|
||||
$notCollected = 1;
|
||||
|
||||
if ($existingRecord) {
|
||||
$collected = (float) $existingRecord->collected_volumes;
|
||||
// If existing record has specific value, use it, but check the "default to 1 if 0" rule
|
||||
$notCollected = (float) $existingRecord->not_collected_volumes;
|
||||
}
|
||||
|
||||
// Logic: if not_collected is 0 or empty, make it 1
|
||||
if (empty($notCollected) || $notCollected == 0) {
|
||||
$notCollected = 1;
|
||||
}
|
||||
|
||||
$totalVolumes = $collected + $notCollected;
|
||||
|
||||
$handoverData['not_collected_volumes'] = $notCollected;
|
||||
$handoverData['total_volumes'] = $totalVolumes;
|
||||
|
||||
// Calculate id_status logic
|
||||
$handoverControlCount = (int) setting('handover_control_count', 3);
|
||||
$idStatus = '';
|
||||
$allAgreed = true;
|
||||
$hasController = false;
|
||||
|
||||
for ($i = 1; $i <= $handoverControlCount; $i++) {
|
||||
$statusField = "control{$i}_id_status";
|
||||
$controllerField = "control{$i}_controller";
|
||||
|
||||
$statusValue = $existingRecord ? $existingRecord->$statusField : null;
|
||||
$controllerValue = $existingRecord ? $existingRecord->$controllerField : null;
|
||||
|
||||
if ($controllerValue) {
|
||||
$hasController = true;
|
||||
|
||||
if ($statusValue == 'Comment / замечание') {
|
||||
$idStatus = 'Comment / замечание';
|
||||
$allAgreed = false;
|
||||
break;
|
||||
}
|
||||
if ($statusValue == 'Revision / Редакция') {
|
||||
$idStatus = 'Revision / Редакция';
|
||||
$allAgreed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($statusValue != 'Agreed / подписано') {
|
||||
$allAgreed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($idStatus === '') {
|
||||
if ($allAgreed && $hasController) {
|
||||
$archiveValue = $existingRecord ? $existingRecord->archive : null;
|
||||
$idStatus = $archiveValue ? $archiveValue : 'Agreed / подписано';
|
||||
} else {
|
||||
$idStatus = 'Wait - Not Prepared';
|
||||
}
|
||||
}
|
||||
|
||||
$handoverData['id_status'] = $idStatus;
|
||||
|
||||
if ($existingRecord) {
|
||||
// Update existing record
|
||||
db("handovers")
|
||||
->where('id', $existingRecord->id)
|
||||
->update($handoverData);
|
||||
$updatedCount++;
|
||||
} else {
|
||||
// Create new record
|
||||
$handoverData['created_at'] = now();
|
||||
db("handovers")->insert($handoverData);
|
||||
$createdCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Line Lists Update Trigger
|
||||
*
|
||||
* Updates line_lists table and syncs data from line_lists to weld_logs
|
||||
* Triggers when line_number or design_area changes
|
||||
*/
|
||||
class LineListsUpdateTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Line Lists Update';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'line_number',
|
||||
'design_area',
|
||||
'fluid_code',
|
||||
'type_of_welds'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
try {
|
||||
// Line lists updated_at trigger for cron
|
||||
db("line_lists")
|
||||
->where(['line_no'=> $data->line_number])
|
||||
->where(['unit'=> $data->design_area])
|
||||
->update(["updated_at" => simdi()]);
|
||||
|
||||
// Sync data from Line Lists to WeldLog via view render
|
||||
$lineListsToWeldLogView = view('cron.line_lists-sync-from-linelists-to-weldlog', [
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area,
|
||||
'commitSize' => 3, // Chunk size for transaction batching
|
||||
'triggerMode' => true // Called from SaveTrigger
|
||||
])->render();
|
||||
|
||||
|
||||
Log::info("Line Lists to WeldLog sync completed via view render", [
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area
|
||||
];
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Line Lists sync error: " . $th->getMessage(), [
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area
|
||||
]);
|
||||
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use App\Models\NdeMatrix;
|
||||
use App\Helpers\TransactionHelper;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* NDE Matrix Update Trigger
|
||||
*
|
||||
* Syncs data between Line Lists, NDE Matrix, and WeldLogs
|
||||
* Handles type_of_welds changes and updates NDE test scope percentages
|
||||
*/
|
||||
class NdeMatrixUpdateTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'NDE Matrix Update';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'type_of_welds',
|
||||
'fluid_code',
|
||||
'type_of_joint',
|
||||
'line_number',
|
||||
'design_area',
|
||||
'project'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
try {
|
||||
// Sync data from Line Lists to NDE Matrix via view render
|
||||
$ndeMatrixView = view('cron.line_lists-sync-from-linelists-nde-matrix', [
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area,
|
||||
'commitSize' => 5, // Chunk size for transaction batching
|
||||
'triggerMode' => true // Called from SaveTrigger
|
||||
])->render();
|
||||
|
||||
Log::info("Line Lists to NDE Matrix sync completed via view render", [
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area
|
||||
]);
|
||||
|
||||
// Special handling for type_of_welds change
|
||||
if (!is_null($beforeData) && $beforeData->type_of_welds !== $data->type_of_welds) {
|
||||
TransactionHelper::retryTransaction(function () use ($data, $beforeData) {
|
||||
// Where condition for old type
|
||||
$oldTypeWhereData = [
|
||||
'line' => $data->line_number,
|
||||
'type_of_joint' => $beforeData->type_of_welds,
|
||||
'fluid' => $data->fluid_code,
|
||||
];
|
||||
|
||||
// Check if old type is still used by other WeldLog records
|
||||
$otherRecordsUsingOldType = db("weld_logs")
|
||||
->where('line_number', $data->line_number)
|
||||
->where('type_of_welds', $beforeData->type_of_welds)
|
||||
->where('fluid_code', $data->fluid_code)
|
||||
->where('id', '!=', $data->id)
|
||||
->orderBy('id', 'ASC') // Deadlock prevention
|
||||
->exists();
|
||||
|
||||
// Delete from NDE Matrix only if old type is not used elsewhere
|
||||
if (!$otherRecordsUsingOldType) {
|
||||
$deleteResult = db("nde_matrices")
|
||||
->where($oldTypeWhereData)
|
||||
->delete();
|
||||
|
||||
Log::info("NDE Matrix old type cleaned up - no other weld logs using it", [
|
||||
'line' => $data->line_number,
|
||||
'old_type_of_joint' => $beforeData->type_of_welds,
|
||||
'new_type_of_joint' => $data->type_of_welds,
|
||||
'fluid' => $data->fluid_code,
|
||||
'delete_result' => $deleteResult
|
||||
]);
|
||||
} else {
|
||||
Log::info("NDE Matrix old type preserved - still used by other weld logs", [
|
||||
'line' => $data->line_number,
|
||||
'old_type_of_joint' => $beforeData->type_of_welds,
|
||||
'new_type_of_joint' => $data->type_of_welds,
|
||||
'fluid' => $data->fluid_code
|
||||
]);
|
||||
}
|
||||
}, 5); // 5 attempts with exponential backoff
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("NDE Matrix sync error: " . $th->getMessage(), [
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area
|
||||
]);
|
||||
throw $th;
|
||||
}
|
||||
|
||||
// Sync from NDE Matrix to WeldLog
|
||||
return $this->syncNdeMatrixToWeldLog($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync NDE Matrix data to WeldLog
|
||||
* Updates scope percentages and other NDE-related fields
|
||||
*/
|
||||
protected function syncNdeMatrixToWeldLog($data): array
|
||||
{
|
||||
// fluid_code null check - get from line_lists if needed
|
||||
$currentFluidCode = $data->fluid_code ?? '';
|
||||
if(empty($currentFluidCode)) {
|
||||
$lineListForFluid = db("line_lists")->where('line_no', $data->line_number)->first();
|
||||
if($lineListForFluid) {
|
||||
$currentFluidCode = $lineListForFluid->fluid_code ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
Log::info("NDE Matrix to WeldLog sync started", [
|
||||
'weld_log_id' => $data->id,
|
||||
'line_number' => $data->line_number,
|
||||
'type_of_welds' => $data->type_of_welds,
|
||||
'fluid_code' => $currentFluidCode
|
||||
]);
|
||||
|
||||
// Skip if fluid_code is null
|
||||
if(empty($currentFluidCode)) {
|
||||
Log::info("NDE Matrix to WeldLog sync skipped - fluid_code is null", [
|
||||
'weld_log_id' => $data->id,
|
||||
'line_number' => $data->line_number
|
||||
]);
|
||||
return ['skipped' => true, 'reason' => 'fluid_code_null'];
|
||||
}
|
||||
|
||||
// Get NDE Matrix records
|
||||
$ndeMatrices = NdeMatrix::where("line", $data->line_number)
|
||||
->where("type_of_joint", $data->type_of_welds)
|
||||
->where("fluid", $currentFluidCode)
|
||||
->get();
|
||||
|
||||
Log::debug("NDE Matrix records retrieved", [
|
||||
'matrix_count' => $ndeMatrices->count(),
|
||||
'matrix_examples' => $ndeMatrices->take(2)->toArray()
|
||||
]);
|
||||
|
||||
$ndeToWeldLogUpdateCount = 0;
|
||||
|
||||
// Process NDE Matrix in chunks with TransactionHelper
|
||||
Log::debug("NDE Matrix to WeldLog sync starting", [
|
||||
'total_records' => $ndeMatrices->count()
|
||||
]);
|
||||
|
||||
TransactionHelper::chunkTransaction(
|
||||
$ndeMatrices,
|
||||
function ($ndeMatrixChunk) use (&$ndeToWeldLogUpdateCount) {
|
||||
foreach($ndeMatrixChunk as $ndeMatrix) {
|
||||
$weldLogUpdateData = [
|
||||
'vt_scope' => 100,
|
||||
'rt_scope' => $ndeMatrix->rt,
|
||||
'ut_scope' => $ndeMatrix->ut,
|
||||
'mt_scope' => $ndeMatrix->mt,
|
||||
'pt_scope' => $ndeMatrix->pt,
|
||||
'pmi_scope' => $ndeMatrix->pmi,
|
||||
'ht_scope' => $ndeMatrix->ht,
|
||||
'pwht' => $ndeMatrix->pwht_field,
|
||||
'ferrite_scope' => $ndeMatrix->fn,
|
||||
'ndt_percent' => $ndeMatrix->ndt,
|
||||
'operating_temperature_s' => $ndeMatrix->operation_temp,
|
||||
'operating_pressure_mpa' => $ndeMatrix->operations_pressure_kg,
|
||||
'fluid_group' => $ndeMatrix->piping_group,
|
||||
'main_material' => $ndeMatrix->material,
|
||||
'updated_at' => simdi()
|
||||
];
|
||||
|
||||
$result = db("weld_logs")
|
||||
->where("line_number", $ndeMatrix->line)
|
||||
->where("type_of_welds", $ndeMatrix->type_of_joint)
|
||||
->orderBy('id', 'ASC') // Deadlock prevention
|
||||
->update($weldLogUpdateData);
|
||||
|
||||
$ndeToWeldLogUpdateCount += $result;
|
||||
}
|
||||
return $ndeMatrixChunk->count();
|
||||
},
|
||||
10, // Chunk size increased from 3 to 10 for better performance
|
||||
10000 // 10ms delay (reduced from 150ms) - sufficient for deadlock prevention
|
||||
);
|
||||
|
||||
Log::info("NDE Matrix to WeldLog sync completed", [
|
||||
'total_updated_records' => $ndeToWeldLogUpdateCount
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'updated_records' => $ndeToWeldLogUpdateCount
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* NDE Project Update Trigger
|
||||
*
|
||||
* Updates NDE Matrix project field from weld_logs when it's null
|
||||
* Syncs project information between tables
|
||||
*/
|
||||
class NdeProjectUpdateTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'NDE Project Update';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'line_number',
|
||||
'project'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
// Update NDE matrices where project is null
|
||||
$updatedCount = DB::table('nde_matrices')
|
||||
->join('weld_logs', function($join) {
|
||||
$join->on('nde_matrices.line', '=', 'weld_logs.line_number')
|
||||
->on('nde_matrices.design_area', '=', 'weld_logs.design_area');
|
||||
})
|
||||
->whereNull('nde_matrices.project') // Find records where project column is empty
|
||||
->where("weld_logs.id", $data->id)
|
||||
->update([
|
||||
'nde_matrices.project' => DB::raw('weld_logs.project') // Update with project value from weld_logs
|
||||
]);
|
||||
|
||||
Log::info("NDE Matrix project field updated", [
|
||||
'weld_log_id' => $data->id,
|
||||
'line_number' => $data->line_number,
|
||||
'design_area' => $data->design_area,
|
||||
'project' => $data->project,
|
||||
'updated_records' => $updatedCount
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'updated_records' => $updatedCount
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* NDT Calculation Cache Trigger
|
||||
*
|
||||
* Updates the NDT calculation cache when relevant fields are modified.
|
||||
* This ensures the frontend displays up-to-date NDT backlog and status information
|
||||
* without needing to run heavy calculations on every page load.
|
||||
*/
|
||||
class NdtCalculationCacheTrigger extends BaseTrigger
|
||||
{
|
||||
/**
|
||||
* Get trigger name
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'NdtCalculationCacheTrigger';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get trigger execution order
|
||||
* Running as #14 (after all other updates)
|
||||
*/
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 14;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fields that this trigger depends on
|
||||
* Includes all fields used in ndt-calculation-no-cache.blade.php
|
||||
*/
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
// Identifiers
|
||||
'iso_number',
|
||||
'test_package_no',
|
||||
'welder_1',
|
||||
'welder_2',
|
||||
'type_of_welds',
|
||||
'welding_date',
|
||||
|
||||
// Scopes and Results
|
||||
'rt_scope', 'rt_result', 'rt_test_date', 'rt_request_date',
|
||||
'ut_scope', 'ut_result', 'ut_test_date', 'ut_request_date',
|
||||
'pt_scope', 'pt_result', 'pt_test_date', 'pt_request_date',
|
||||
'mt_scope', 'mt_result', 'mt_test_date', 'mt_request_date',
|
||||
'pmi_scope', 'pmi_result', 'pmi_test_date', 'pmi_request_date',
|
||||
'ferrite_scope', 'ferrite_result', 'ferrite_test_date', 'ferrite_request_date',
|
||||
'ht_scope', 'ht_result', 'ht_test_date', 'ht_request_date',
|
||||
'test_laboratory_ht',
|
||||
'test_laboratory_rt',
|
||||
'test_laboratory_ut',
|
||||
'test_laboratory_pt',
|
||||
'test_laboratory_mt',
|
||||
'test_laboratory_pmi',
|
||||
'test_laboratory_ferrite',
|
||||
'test_laboratory_pwht',
|
||||
'test_laboratory_vt',
|
||||
'ut_request_date',
|
||||
'pt_request_date',
|
||||
'mt_request_date',
|
||||
'pmi_request_date',
|
||||
'ferrite_request_date',
|
||||
'ht_request_date',
|
||||
'rt_request_date',
|
||||
'vt_request_date',
|
||||
'pwht_request_date',
|
||||
|
||||
// PWHT
|
||||
'pwht', 'pwht_date', 'pwht_result'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process trigger logic
|
||||
* Dispatches cache update job for NDT calculation
|
||||
*/
|
||||
protected function process($weldLogData, $beforeData, array $context): array
|
||||
{
|
||||
// Clone işleminde cache hesaplaması yapma
|
||||
if (isset($context['action']) && $context['action'] === 'clone') {
|
||||
Log::info('NdtCalculationCacheTrigger: Skipped due to clone action');
|
||||
return ['skipped' => true, 'reason' => 'clone_action'];
|
||||
}
|
||||
|
||||
$dispatched = false;
|
||||
|
||||
// Using the global helper function to dispatch the cache update
|
||||
// This matches the usage in test2.blade.php provided by the user
|
||||
if (function_exists('dispatchCacheBladeViews')) {
|
||||
dispatchCacheBladeViews([
|
||||
[
|
||||
'view' => 'admin-ajax.request-ndt-no-cache',
|
||||
'cache' => 'request-ndt'
|
||||
],
|
||||
[
|
||||
'view' => 'admin-ajax.ndt-order.order-list-no-cache',
|
||||
'cache' => 'ndt-order-list'
|
||||
],
|
||||
[
|
||||
'view' => 'admin-ajax.repair-log-no-cache',
|
||||
'cache' => 'repair-log'
|
||||
],
|
||||
[
|
||||
'view' => 'admin-ajax.ndt-calculation-no-cache',
|
||||
'cache' => 'ndt-calculation'
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
]);
|
||||
|
||||
$dispatched = true;
|
||||
|
||||
Log::info('NdtCalculationCacheTrigger: Cache update dispatched', [
|
||||
'weld_log_id' => $weldLogData->id,
|
||||
'iso' => $weldLogData->iso_number ?? 'unknown'
|
||||
]);
|
||||
} else {
|
||||
Log::warning('NdtCalculationCacheTrigger: dispatchCacheBladeViews function not found');
|
||||
}
|
||||
|
||||
return [
|
||||
'cache_dispatched' => $dispatched
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow async execution since this is just dispatching another job
|
||||
*/
|
||||
public function isAsync(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,758 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use App\Models\PaintMatrix;
|
||||
use App\Helpers\TransactionHelper;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Paint Follow Ups Sync Trigger
|
||||
*
|
||||
* Mirrors the LineList trigger logic while running during WeldLog saves:
|
||||
* - Requires matching Line List + painting cycle
|
||||
* - Generates SHOP + FIELD entries with temperature/volume data
|
||||
* - Protects finished records, manages cycle changes, cleans up orphans
|
||||
*/
|
||||
class PaintFollowUpsSyncTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Paint Follow Ups Sync';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 11;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'line_number',
|
||||
'spool_number',
|
||||
'no_of_the_joint_as_per_as_built_survey',
|
||||
'fluid_code',
|
||||
'iso_number',
|
||||
'project',
|
||||
'design_area',
|
||||
'type_of_joint'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
$paintFollowUpCreated = 0;
|
||||
$paintFollowUpUpdated = 0;
|
||||
$deletedOrphanedCount = 0;
|
||||
$finalCleanupCount = 0;
|
||||
|
||||
try {
|
||||
$weldLog = db("weld_logs")->where("id", $data->id)->first();
|
||||
|
||||
if (!$weldLog) {
|
||||
return ['success' => false, 'reason' => 'weld_log_not_found'];
|
||||
}
|
||||
|
||||
if (empty($weldLog->line_number)) {
|
||||
return ['success' => false, 'reason' => 'line_number_empty'];
|
||||
}
|
||||
|
||||
$lineList = db("line_lists")
|
||||
->where('line_no', $weldLog->line_number)
|
||||
->first();
|
||||
|
||||
if (!$lineList) {
|
||||
return ['success' => false, 'reason' => 'line_list_not_found'];
|
||||
}
|
||||
|
||||
if (empty($lineList->painting_cycle)) {
|
||||
return ['skipped' => true, 'reason' => 'painting_cycle_empty'];
|
||||
}
|
||||
|
||||
$matchingWeldLogExists = db("weld_logs")
|
||||
->where("line_number", $lineList->line_no)
|
||||
->where("design_area", $lineList->unit)
|
||||
->where("fluid_code", $lineList->fluid_code)
|
||||
->exists();
|
||||
|
||||
if (!$matchingWeldLogExists) {
|
||||
return ['skipped' => true, 'reason' => 'no_matching_weld_log'];
|
||||
}
|
||||
|
||||
$deletedOrphanedCount = $this->cleanupOrphanedRecords($weldLog, $beforeData);
|
||||
|
||||
$resultFields = [
|
||||
'vt_result',
|
||||
'rt_result',
|
||||
'ut_result',
|
||||
'pt_result',
|
||||
'mt_result',
|
||||
'pmi_result',
|
||||
'ht_result',
|
||||
'ferrite_result'
|
||||
];
|
||||
|
||||
$allWeldLogs = db("weld_logs")
|
||||
->where("line_number", $lineList->line_no)
|
||||
->where("design_area", $lineList->unit)
|
||||
->where("fluid_code", $lineList->fluid_code)
|
||||
->where(function ($query) {
|
||||
$query->where("no_of_the_joint_as_per_as_built_survey", "not like", "%clone%");
|
||||
})
|
||||
->where(function ($query) use ($resultFields) {
|
||||
foreach ($resultFields as $field) {
|
||||
$query->where(function ($subQuery) use ($field) {
|
||||
$subQuery->whereNull($field)
|
||||
->orWhere($field, '')
|
||||
->orWhere($field, 'Accept / Годен');
|
||||
});
|
||||
}
|
||||
})
|
||||
->orderBy('id', 'ASC')
|
||||
->get();
|
||||
|
||||
if ($allWeldLogs->isEmpty()) {
|
||||
return ['skipped' => true, 'reason' => 'no_weld_logs_for_line'];
|
||||
}
|
||||
|
||||
$paintMatrix = PaintMatrix::where('line', $lineList->line_no)
|
||||
->where('fluid_code', $lineList->fluid_code)
|
||||
->where('area', $lineList->unit)
|
||||
->where('paint_cycle', $lineList->painting_cycle)
|
||||
->first();
|
||||
|
||||
if (!$paintMatrix) {
|
||||
$paintMatrix = PaintMatrix::create([
|
||||
'project' => $allWeldLogs->first()->project ?? '',
|
||||
'area' => $lineList->unit,
|
||||
'description' => "PIPE",
|
||||
'line' => $lineList->line_no,
|
||||
'fluid_code_description' => $lineList->fluid_ru,
|
||||
'fluid_code' => $lineList->fluid_code,
|
||||
'paint_cycle' => $lineList->painting_cycle,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now()
|
||||
]);
|
||||
}
|
||||
|
||||
$temperatures = j(setting("temperatures"));
|
||||
$todayTempData = null;
|
||||
|
||||
$blastingDateRecord = db('construction_paint_logs')
|
||||
->where('line', $lineList->line_no)
|
||||
->whereNotNull('blasting_date')
|
||||
->first();
|
||||
|
||||
if (!is_null($temperatures) && $blastingDateRecord && !empty($blastingDateRecord->blasting_date)) {
|
||||
$blastingDate = Carbon::parse($blastingDateRecord->blasting_date);
|
||||
$dayOfYear = $blastingDate->format('z');
|
||||
$todayTempData = $temperatures[$dayOfYear] ?? null;
|
||||
}
|
||||
|
||||
$fAvgNps = $allWeldLogs->where("type_of_joint", "F")->avg("nps_1");
|
||||
$sAvgNps = $allWeldLogs->where("type_of_joint", "S")->avg("nps_1");
|
||||
|
||||
$mtoTotal = db("m_t_o_s")
|
||||
->where("description_en", "like", "%pipe%")
|
||||
->where("line", $lineList->line_no)
|
||||
->selectRaw("SUM(quantity * POWER(odmm_1/2000, 2) * PI()) AS total")
|
||||
->first()->total ?? 0;
|
||||
|
||||
$fVolume = round(pi() * pow($fAvgNps, 2) * 200, 2);
|
||||
$sVolume = round($mtoTotal, 2);
|
||||
|
||||
$processedPaintFollowUpIds = [];
|
||||
$processedShopSpools = [];
|
||||
$replacedJointNumbers = $this->determineReplacedJointNumbers($allWeldLogs);
|
||||
|
||||
TransactionHelper::chunkTransaction(
|
||||
$allWeldLogs,
|
||||
function ($paintWeldLogChunk) use (
|
||||
$lineList,
|
||||
$paintMatrix,
|
||||
$todayTempData,
|
||||
$fVolume,
|
||||
$sVolume,
|
||||
&$paintFollowUpCreated,
|
||||
&$paintFollowUpUpdated,
|
||||
&$processedPaintFollowUpIds,
|
||||
&$processedShopSpools,
|
||||
$replacedJointNumbers
|
||||
) {
|
||||
foreach ($paintWeldLogChunk as $currentWeldLog) {
|
||||
if (empty($currentWeldLog->fluid_code)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipJoint($currentWeldLog, $replacedJointNumbers)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$basePaintFollowUpData = [
|
||||
'project' => $currentWeldLog->project ?? '',
|
||||
'description' => "PIPE",
|
||||
'area' => $lineList->unit ?? '',
|
||||
'line' => $lineList->line_no,
|
||||
'iso_number' => $currentWeldLog->iso_number ?? '',
|
||||
'fluid_code' => $lineList->fluid_code,
|
||||
'fluid_code_description' => $lineList->fluid_ru ?? '',
|
||||
'cycle' => $lineList->painting_cycle ?? '',
|
||||
'primer_coat_name_1' => $paintMatrix->primer_coat ?? '',
|
||||
'brend_name_1' => $paintMatrix->brend_name_1 ?? '',
|
||||
'colour_1' => $paintMatrix->colour_1 ?? '',
|
||||
'ral_code_1' => $paintMatrix->ral_code_1 ?? '',
|
||||
'thickness_1' => $paintMatrix->thickness_1 ?? '',
|
||||
'intermediate_coat_name_2' => $paintMatrix->intermediate_coat ?? '',
|
||||
'brend_name_2' => $paintMatrix->brend_name_2 ?? '',
|
||||
'colour_2' => $paintMatrix->colour_2 ?? '',
|
||||
'ral_code_2' => $paintMatrix->ral_code_2 ?? '',
|
||||
'thickness_2' => $paintMatrix->thickness_2 ?? '',
|
||||
'final_coat_name_3' => $paintMatrix->final_coat ?? '',
|
||||
'brend_name_3' => $paintMatrix->brend_name_3 ?? '',
|
||||
'colour_3' => $paintMatrix->colour_3 ?? '',
|
||||
'ral_code_3' => $paintMatrix->ral_code_3 ?? '',
|
||||
'thickness_3' => $paintMatrix->thickness_3 ?? '',
|
||||
'status' => 'In Progress',
|
||||
'updated_at' => now()
|
||||
];
|
||||
|
||||
$result = $this->processShopRecord(
|
||||
$lineList,
|
||||
$currentWeldLog,
|
||||
$basePaintFollowUpData,
|
||||
$paintMatrix,
|
||||
$todayTempData,
|
||||
$sVolume,
|
||||
$paintFollowUpCreated,
|
||||
$paintFollowUpUpdated,
|
||||
$processedShopSpools
|
||||
);
|
||||
$paintFollowUpCreated = $result['created'];
|
||||
$paintFollowUpUpdated = $result['updated'];
|
||||
$processedShopSpools = $result['processed_spools'];
|
||||
|
||||
$fieldResult = $this->processFieldRecord(
|
||||
$lineList,
|
||||
$currentWeldLog,
|
||||
$basePaintFollowUpData,
|
||||
$paintMatrix,
|
||||
$todayTempData,
|
||||
$fVolume,
|
||||
$paintFollowUpCreated,
|
||||
$paintFollowUpUpdated,
|
||||
$processedPaintFollowUpIds
|
||||
);
|
||||
$paintFollowUpCreated = $fieldResult['created'];
|
||||
$paintFollowUpUpdated = $fieldResult['updated'];
|
||||
$processedPaintFollowUpIds = $fieldResult['processed_ids'];
|
||||
}
|
||||
return $paintWeldLogChunk->count();
|
||||
},
|
||||
1,
|
||||
10000
|
||||
);
|
||||
|
||||
$finalCleanupCount = $this->cleanupNonMatchingRecords($lineList->line_no);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Paint Follow Ups sync error: " . $th->getMessage(), [
|
||||
'weld_log_id' => $data->id
|
||||
]);
|
||||
throw $th;
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'deleted_orphaned' => $deletedOrphanedCount,
|
||||
'deleted_final_cleanup' => $finalCleanupCount
|
||||
];
|
||||
}
|
||||
|
||||
protected function processShopRecord(
|
||||
$lineList,
|
||||
$weldLog,
|
||||
$basePaintFollowUpData,
|
||||
$paintMatrix,
|
||||
$todayTempData,
|
||||
$sVolume,
|
||||
$paintFollowUpCreated,
|
||||
$paintFollowUpUpdated,
|
||||
$processedShopSpools
|
||||
): array {
|
||||
$hasShopJoint = db("weld_logs")
|
||||
->where('line_number', $lineList->line_no)
|
||||
->where('spool_number', $weldLog->spool_number)
|
||||
->where('type_of_joint', 'S')
|
||||
->exists();
|
||||
|
||||
if (!$hasShopJoint || empty($weldLog->spool_number)) {
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_spools' => $processedShopSpools
|
||||
];
|
||||
}
|
||||
|
||||
if (in_array($weldLog->spool_number, $processedShopSpools, true)) {
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_spools' => $processedShopSpools
|
||||
];
|
||||
}
|
||||
|
||||
$processedShopSpools[] = $weldLog->spool_number;
|
||||
|
||||
$shopData = $basePaintFollowUpData;
|
||||
$shopData['location'] = 'SHOP';
|
||||
$shopData['spool_no_joint_no'] = $weldLog->spool_number;
|
||||
$shopData['surface_roughness'] = $paintMatrix->surface_preparation ?? '';
|
||||
|
||||
if ($todayTempData) {
|
||||
$shopData['substrate_temprature'] = $todayTempData['temp_material_shop'] ?? null;
|
||||
$shopData['ambient_temprature'] = $todayTempData['shop_ambient'] ?? null;
|
||||
}
|
||||
$shopData['volume_1'] = $sVolume;
|
||||
$shopData['volume_2'] = $sVolume;
|
||||
$shopData['volume_3'] = $sVolume;
|
||||
$shopData['total_volume'] = $sVolume * 3;
|
||||
|
||||
$shopUniqueConstraintCondition = [
|
||||
'line' => $lineList->line_no,
|
||||
'spool_no_joint_no' => $weldLog->spool_number,
|
||||
'cycle' => $lineList->painting_cycle,
|
||||
'location' => 'SHOP'
|
||||
];
|
||||
|
||||
$shopWhereCondition = [
|
||||
'line' => $lineList->line_no,
|
||||
'spool_no_joint_no' => $weldLog->spool_number,
|
||||
'location' => 'SHOP'
|
||||
];
|
||||
|
||||
$existingShopRecord = db("paint_follow_ups")
|
||||
->where($shopUniqueConstraintCondition)
|
||||
->first();
|
||||
|
||||
$recordsWithDifferentPaintCycle = db("paint_follow_ups")
|
||||
->where($shopWhereCondition)
|
||||
->where('cycle', '!=', $lineList->painting_cycle)
|
||||
->get();
|
||||
|
||||
if ($existingShopRecord) {
|
||||
$hasAllEmptyDates = $this->hasAllEmptyDates($existingShopRecord);
|
||||
|
||||
if ($hasAllEmptyDates) {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $existingShopRecord->id)
|
||||
->update($shopData);
|
||||
$paintFollowUpUpdated++;
|
||||
} else {
|
||||
$tempVolumeData = $this->getTempVolumeUpdateData(
|
||||
$existingShopRecord,
|
||||
$todayTempData,
|
||||
$sVolume,
|
||||
'SHOP'
|
||||
);
|
||||
|
||||
if (!empty($tempVolumeData)) {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $existingShopRecord->id)
|
||||
->update($tempVolumeData);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($recordsWithDifferentPaintCycle->count() > 0) {
|
||||
foreach ($recordsWithDifferentPaintCycle as $oldRecord) {
|
||||
$hasAnyDateFilled = !$this->hasAllEmptyDates($oldRecord);
|
||||
|
||||
if ($hasAnyDateFilled) {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $oldRecord->id)
|
||||
->update([
|
||||
'status' => 'HOLD',
|
||||
'updated_at' => now()
|
||||
]);
|
||||
} else {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $oldRecord->id)
|
||||
->update([
|
||||
'cycle' => $lineList->painting_cycle,
|
||||
'updated_at' => now()
|
||||
]);
|
||||
$paintFollowUpUpdated++;
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_spools' => $processedShopSpools
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$shopData['primer_coating_start_date'] = null;
|
||||
$shopData['primer_coating_finish_date'] = null;
|
||||
$shopData['start_intermediate_date2'] = null;
|
||||
$shopData['finish_intermediate_date2'] = null;
|
||||
$shopData['final_coat_start_date3'] = null;
|
||||
$shopData['final_coat_finish_date3'] = null;
|
||||
$shopData['created_at'] = now();
|
||||
$shopData['updated_at'] = now();
|
||||
|
||||
db("paint_follow_ups")->insert($shopData);
|
||||
$paintFollowUpCreated++;
|
||||
}
|
||||
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_spools' => $processedShopSpools
|
||||
];
|
||||
}
|
||||
|
||||
protected function processFieldRecord(
|
||||
$lineList,
|
||||
$weldLog,
|
||||
$basePaintFollowUpData,
|
||||
$paintMatrix,
|
||||
$todayTempData,
|
||||
$fVolume,
|
||||
$paintFollowUpCreated,
|
||||
$paintFollowUpUpdated,
|
||||
$processedPaintFollowUpIds
|
||||
): array {
|
||||
if (empty($weldLog->no_of_the_joint_as_per_as_built_survey)) {
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_ids' => $processedPaintFollowUpIds
|
||||
];
|
||||
}
|
||||
|
||||
$jointNo = $weldLog->no_of_the_joint_as_per_as_built_survey;
|
||||
|
||||
$fieldData = $basePaintFollowUpData;
|
||||
$fieldData['location'] = 'FIELD';
|
||||
$fieldData['spool_no_joint_no'] = $jointNo;
|
||||
$fieldData['surface_roughness'] = $paintMatrix->touch_up_of_damaged_parts ?? '';
|
||||
|
||||
if ($todayTempData) {
|
||||
$fieldData['substrate_temprature'] = $todayTempData['temp_material_field'] ?? null;
|
||||
$fieldData['ambient_temprature'] = $todayTempData['field_ambient'] ?? null;
|
||||
}
|
||||
$fieldData['volume_1'] = $fVolume;
|
||||
$fieldData['volume_2'] = $fVolume;
|
||||
$fieldData['volume_3'] = $fVolume;
|
||||
$fieldData['total_volume'] = $fVolume * 3;
|
||||
|
||||
$fieldUniqueConstraintCondition = [
|
||||
'line' => $lineList->line_no,
|
||||
'spool_no_joint_no' => $jointNo,
|
||||
'cycle' => $lineList->painting_cycle,
|
||||
'location' => 'FIELD'
|
||||
];
|
||||
|
||||
$fieldWhereCondition = [
|
||||
'line' => $lineList->line_no,
|
||||
'spool_no_joint_no' => $jointNo,
|
||||
'location' => 'FIELD'
|
||||
];
|
||||
|
||||
$existingFieldRecord = db("paint_follow_ups")
|
||||
->where($fieldUniqueConstraintCondition)
|
||||
->first();
|
||||
|
||||
$recordsWithDifferentPaintCycle = db("paint_follow_ups")
|
||||
->where($fieldWhereCondition)
|
||||
->where('cycle', '!=', $lineList->painting_cycle)
|
||||
->get();
|
||||
|
||||
if ($existingFieldRecord) {
|
||||
if (in_array($existingFieldRecord->id, $processedPaintFollowUpIds)) {
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_ids' => $processedPaintFollowUpIds
|
||||
];
|
||||
}
|
||||
|
||||
$processedPaintFollowUpIds[] = $existingFieldRecord->id;
|
||||
|
||||
$hasAllEmptyDates = $this->hasAllEmptyDates($existingFieldRecord);
|
||||
|
||||
if ($hasAllEmptyDates) {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $existingFieldRecord->id)
|
||||
->update($fieldData);
|
||||
$paintFollowUpUpdated++;
|
||||
} else {
|
||||
$tempVolumeData = $this->getTempVolumeUpdateData(
|
||||
$existingFieldRecord,
|
||||
$todayTempData,
|
||||
$fVolume,
|
||||
'FIELD'
|
||||
);
|
||||
|
||||
if (!empty($tempVolumeData)) {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $existingFieldRecord->id)
|
||||
->update($tempVolumeData);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($recordsWithDifferentPaintCycle->count() > 0) {
|
||||
foreach ($recordsWithDifferentPaintCycle as $oldRecord) {
|
||||
$hasAnyDateFilled = !$this->hasAllEmptyDates($oldRecord);
|
||||
|
||||
if ($hasAnyDateFilled) {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $oldRecord->id)
|
||||
->update([
|
||||
'status' => 'HOLD',
|
||||
'updated_at' => now()
|
||||
]);
|
||||
} else {
|
||||
db("paint_follow_ups")
|
||||
->where('id', $oldRecord->id)
|
||||
->update([
|
||||
'cycle' => $lineList->painting_cycle,
|
||||
'updated_at' => now()
|
||||
]);
|
||||
$paintFollowUpUpdated++;
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_ids' => $processedPaintFollowUpIds
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fieldData['primer_coating_start_date'] = null;
|
||||
$fieldData['primer_coating_finish_date'] = null;
|
||||
$fieldData['start_intermediate_date2'] = null;
|
||||
$fieldData['finish_intermediate_date2'] = null;
|
||||
$fieldData['final_coat_start_date3'] = null;
|
||||
$fieldData['final_coat_finish_date3'] = null;
|
||||
$fieldData['created_at'] = now();
|
||||
$fieldData['updated_at'] = now();
|
||||
|
||||
db("paint_follow_ups")->insert($fieldData);
|
||||
$paintFollowUpCreated++;
|
||||
}
|
||||
|
||||
return [
|
||||
'created' => $paintFollowUpCreated,
|
||||
'updated' => $paintFollowUpUpdated,
|
||||
'processed_ids' => $processedPaintFollowUpIds
|
||||
];
|
||||
}
|
||||
|
||||
protected function cleanupOrphanedRecords($weldLog, $beforeData): int
|
||||
{
|
||||
if (!$beforeData) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$deletedCount = 0;
|
||||
|
||||
try {
|
||||
if (isset($beforeData->no_of_the_joint_as_per_as_built_survey) &&
|
||||
$beforeData->no_of_the_joint_as_per_as_built_survey != $weldLog->no_of_the_joint_as_per_as_built_survey &&
|
||||
!empty($beforeData->no_of_the_joint_as_per_as_built_survey)) {
|
||||
|
||||
$oldJointNo = $beforeData->no_of_the_joint_as_per_as_built_survey;
|
||||
|
||||
$deleted = db("paint_follow_ups")
|
||||
->where('line', $weldLog->line_number)
|
||||
->where('spool_no_joint_no', $oldJointNo)
|
||||
->where('location', 'FIELD')
|
||||
->delete();
|
||||
|
||||
$deletedCount += $deleted;
|
||||
}
|
||||
|
||||
if (isset($beforeData->spool_number) &&
|
||||
$beforeData->spool_number != $weldLog->spool_number &&
|
||||
!empty($beforeData->spool_number)) {
|
||||
|
||||
$oldSpoolNumber = $beforeData->spool_number;
|
||||
|
||||
$deleted = db("paint_follow_ups")
|
||||
->where('line', $weldLog->line_number)
|
||||
->where('spool_no_joint_no', $oldSpoolNumber)
|
||||
->where('location', 'SHOP')
|
||||
->delete();
|
||||
|
||||
$deletedCount += $deleted;
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::warning("Failed to cleanup orphaned records", [
|
||||
'error' => $th->getMessage(),
|
||||
'weld_log_id' => $weldLog->id
|
||||
]);
|
||||
}
|
||||
|
||||
return $deletedCount;
|
||||
}
|
||||
|
||||
protected function cleanupNonMatchingRecords(string $lineNumber): int
|
||||
{
|
||||
$deletedCount = 0;
|
||||
|
||||
try {
|
||||
$validFieldJointNos = db("weld_logs")
|
||||
->where("line_number", $lineNumber)
|
||||
->whereNotNull("no_of_the_joint_as_per_as_built_survey")
|
||||
->where("no_of_the_joint_as_per_as_built_survey", "!=", "")
|
||||
->pluck("no_of_the_joint_as_per_as_built_survey")
|
||||
->toArray();
|
||||
|
||||
$validShopSpoolNos = db("weld_logs")
|
||||
->where("line_number", $lineNumber)
|
||||
->where("type_of_joint", "S")
|
||||
->whereNotNull("spool_number")
|
||||
->where("spool_number", "!=", "")
|
||||
->pluck("spool_number")
|
||||
->toArray();
|
||||
|
||||
if (!empty($validFieldJointNos)) {
|
||||
$deletedField = db("paint_follow_ups")
|
||||
->where('line', $lineNumber)
|
||||
->where('location', 'FIELD')
|
||||
->whereNotIn('spool_no_joint_no', $validFieldJointNos)
|
||||
->delete();
|
||||
|
||||
$deletedCount += $deletedField;
|
||||
} else {
|
||||
$deletedField = db("paint_follow_ups")
|
||||
->where('line', $lineNumber)
|
||||
->where('location', 'FIELD')
|
||||
->delete();
|
||||
|
||||
$deletedCount += $deletedField;
|
||||
}
|
||||
|
||||
if (!empty($validShopSpoolNos)) {
|
||||
$deletedShop = db("paint_follow_ups")
|
||||
->where('line', $lineNumber)
|
||||
->where('location', 'SHOP')
|
||||
->whereNotIn('spool_no_joint_no', $validShopSpoolNos)
|
||||
->delete();
|
||||
|
||||
$deletedCount += $deletedShop;
|
||||
} else {
|
||||
$deletedShop = db("paint_follow_ups")
|
||||
->where('line', $lineNumber)
|
||||
->where('location', 'SHOP')
|
||||
->delete();
|
||||
|
||||
$deletedCount += $deletedShop;
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::warning("Failed to cleanup non-matching records", [
|
||||
'error' => $th->getMessage(),
|
||||
'line_number' => $lineNumber
|
||||
]);
|
||||
}
|
||||
|
||||
return $deletedCount;
|
||||
}
|
||||
|
||||
protected function hasAllEmptyDates($record): bool
|
||||
{
|
||||
return empty($record->primer_coating_start_date) &&
|
||||
empty($record->primer_coating_finish_date) &&
|
||||
empty($record->start_intermediate_date2) &&
|
||||
empty($record->finish_intermediate_date2) &&
|
||||
empty($record->final_coat_start_date3) &&
|
||||
empty($record->final_coat_finish_date3);
|
||||
}
|
||||
|
||||
protected function getTempVolumeUpdateData($record, $todayTempData, $volume, $location): array
|
||||
{
|
||||
$updateData = [];
|
||||
|
||||
if ($todayTempData) {
|
||||
$tempField = $location === 'SHOP' ? 'temp_material_shop' : 'temp_material_field';
|
||||
$ambientField = $location === 'SHOP' ? 'shop_ambient' : 'field_ambient';
|
||||
|
||||
if (empty($record->substrate_temprature) && isset($todayTempData[$tempField])) {
|
||||
$updateData['substrate_temprature'] = $todayTempData[$tempField];
|
||||
}
|
||||
if (empty($record->ambient_temprature) && isset($todayTempData[$ambientField])) {
|
||||
$updateData['ambient_temprature'] = $todayTempData[$ambientField];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($record->volume_1)) {
|
||||
$updateData['volume_1'] = $volume;
|
||||
}
|
||||
if (empty($record->volume_2)) {
|
||||
$updateData['volume_2'] = $volume;
|
||||
}
|
||||
if (empty($record->volume_3)) {
|
||||
$updateData['volume_3'] = $volume;
|
||||
}
|
||||
if (empty($record->total_volume)) {
|
||||
$updateData['total_volume'] = $volume * 3;
|
||||
}
|
||||
|
||||
return $updateData;
|
||||
}
|
||||
|
||||
protected function determineReplacedJointNumbers($weldLogs): array
|
||||
{
|
||||
$toSkip = [];
|
||||
|
||||
foreach ($weldLogs as $log) {
|
||||
$jointNo = $log->no_of_the_joint_as_per_as_built_survey;
|
||||
if ($this->isRepairJoint($jointNo)) {
|
||||
$baseJoint = $this->stripRepairSuffix($jointNo);
|
||||
if (!empty($baseJoint)) {
|
||||
$toSkip[] = $baseJoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($toSkip);
|
||||
}
|
||||
|
||||
protected function shouldSkipJoint($weldLog, array $replacedJointNumbers): bool
|
||||
{
|
||||
$jointNo = $weldLog->no_of_the_joint_as_per_as_built_survey;
|
||||
|
||||
if (empty($jointNo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($jointNo, $replacedJointNumbers, true);
|
||||
}
|
||||
|
||||
protected function isRepairJoint(?string $jointNo): bool
|
||||
{
|
||||
return !empty($jointNo) && strpos($jointNo, 'R') !== false;
|
||||
}
|
||||
|
||||
protected function stripRepairSuffix(?string $jointNo): ?string
|
||||
{
|
||||
if (empty($jointNo)) {
|
||||
return $jointNo;
|
||||
}
|
||||
|
||||
$pos = strpos($jointNo, 'R');
|
||||
if ($pos === false) {
|
||||
return $jointNo;
|
||||
}
|
||||
|
||||
return substr($jointNo, 0, $pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Register Creator Cache Trigger
|
||||
*
|
||||
* Updates the Register Creator cache when relevant fields are modified.
|
||||
* This ensures the frontend displays up-to-date information in the register creator view.
|
||||
*/
|
||||
class RegisterCreatorCacheTrigger extends BaseTrigger
|
||||
{
|
||||
/**
|
||||
* Get trigger name
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'RegisterCreatorCacheTrigger';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get trigger execution order
|
||||
* Running as #15 (after all other updates)
|
||||
*/
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fields that this trigger depends on
|
||||
*/
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'nps_1',
|
||||
'welding_date',
|
||||
'test_package_no',
|
||||
'date_test',
|
||||
'line_number',
|
||||
'iso_number'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process trigger logic
|
||||
* Dispatches cache update job for Register Creator
|
||||
*/
|
||||
protected function process($weldLogData, $beforeData, array $context): array
|
||||
{
|
||||
// Skip for clone action
|
||||
if (isset($context['action']) && $context['action'] === 'clone') {
|
||||
Log::info('RegisterCreatorCacheTrigger: Skipped due to clone action');
|
||||
return ['skipped' => true, 'reason' => 'clone_action'];
|
||||
}
|
||||
|
||||
$dispatched = false;
|
||||
|
||||
if (function_exists('dispatchCacheBladeViews')) {
|
||||
dispatchCacheBladeViews([
|
||||
[
|
||||
'view' => 'admin-ajax.register-no-cache',
|
||||
'cache' => 'register-creator'
|
||||
]
|
||||
]);
|
||||
|
||||
$dispatched = true;
|
||||
|
||||
Log::info('RegisterCreatorCacheTrigger: Cache update dispatched', [
|
||||
'weld_log_id' => $weldLogData->id,
|
||||
'iso' => $weldLogData->iso_number ?? 'unknown'
|
||||
]);
|
||||
} else {
|
||||
Log::warning('RegisterCreatorCacheTrigger: dispatchCacheBladeViews function not found');
|
||||
}
|
||||
|
||||
return [
|
||||
'cache_dispatched' => $dispatched
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow async execution since this is just dispatching another job
|
||||
*/
|
||||
public function isAsync(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Repair Logs Update Trigger
|
||||
*
|
||||
* Updates repair logs based on test results
|
||||
* Determines repair status: "Not Done", "Done", or "Repair"
|
||||
*/
|
||||
class RepairLogsUpdateTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Repair Logs Update';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'iso_number',
|
||||
'no_of_the_joint_as_per_as_built_survey',
|
||||
'welding_date',
|
||||
'vt_result',
|
||||
'rt_result',
|
||||
'ut_result',
|
||||
'pt_result',
|
||||
'mt_result',
|
||||
'pmi_result',
|
||||
'ht_result',
|
||||
'ferrite_result',
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
// Test result fields to check
|
||||
$testResultFields = [
|
||||
'vt_result',
|
||||
'rt_result',
|
||||
'ut_result',
|
||||
'pt_result',
|
||||
'mt_result',
|
||||
'pmi_result',
|
||||
'ht_result',
|
||||
'ferrite_result'
|
||||
];
|
||||
|
||||
$hasRepairOrCut = false;
|
||||
$allFieldsEmpty = true;
|
||||
$rtAndUtEmpty = false;
|
||||
|
||||
// Check if RT or UT results are empty
|
||||
if(empty($data->rt_result) && empty($data->ut_result)) {
|
||||
$rtAndUtEmpty = true;
|
||||
}
|
||||
|
||||
// Check all test result fields
|
||||
foreach($testResultFields as $field) {
|
||||
if(isset($data->$field) && !empty($data->$field)) {
|
||||
$allFieldsEmpty = false;
|
||||
if(in_array($data->$field, ['Repair / Ремонт', 'Cut / Резать'])) {
|
||||
$hasRepairOrCut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine repair status based on test results
|
||||
if($allFieldsEmpty || $rtAndUtEmpty) {
|
||||
$repairStatus = "Not Done";
|
||||
} elseif(!$hasRepairOrCut) {
|
||||
$repairStatus = "Done";
|
||||
} else {
|
||||
$repairStatus = "Repair";
|
||||
}
|
||||
|
||||
// Update repair logs
|
||||
$updateResult = db("repair_logs")
|
||||
->where([
|
||||
'iso_number' => $data->iso_number,
|
||||
'new_joint_no' => $data->no_of_the_joint_as_per_as_built_survey,
|
||||
])
|
||||
->update([
|
||||
'repair_date' => $data->welding_date,
|
||||
'repair_status' => $repairStatus,
|
||||
]);
|
||||
|
||||
Log::info("Repair logs updated", [
|
||||
'iso_number' => $data->iso_number,
|
||||
'joint_no' => $data->no_of_the_joint_as_per_as_built_survey,
|
||||
'repair_status' => $repairStatus,
|
||||
'updated_records' => $updateResult,
|
||||
'has_repair_or_cut' => $hasRepairOrCut,
|
||||
'all_fields_empty' => $allFieldsEmpty,
|
||||
'rt_and_ut_empty' => $rtAndUtEmpty
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'repair_status' => $repairStatus,
|
||||
'updated_records' => $updateResult
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Request Date Operations Trigger
|
||||
*
|
||||
* Handles request number generation for all test types (RT, UT, MT, PT, VT, PWHT, Ferrite, PMI)
|
||||
* Updates request numbers in both weld_logs and test-specific tables
|
||||
*/
|
||||
class RequestDateOperationsTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Request Date Operations';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'iso_number',
|
||||
'no_of_the_joint_as_per_as_built_survey',
|
||||
'rt_request_date', 'rt_request_no', 'test_laboratory_rt',
|
||||
'ht_request_date', 'ht_request_no', 'test_laboratory_ht',
|
||||
'ut_request_date', 'ut_request_no', 'test_laboratory_ut',
|
||||
'mt_request_date', 'mt_request_no', 'test_laboratory_mt',
|
||||
'pt_request_date', 'pt_request_no', 'test_laboratory_pt',
|
||||
'vt_request_date', 'vt_request_no', 'test_laboratory_vt',
|
||||
'pwht_request_date', 'pwht_request_no', 'test_laboratory_pwht',
|
||||
'ferrite_request_date', 'ferrite_request_no', 'test_laboratory_ferrite',
|
||||
'pmi_request_date', 'pmi_request_no', 'test_laboratory_pmi',
|
||||
'rt_test_date',
|
||||
'ut_test_date',
|
||||
'mt_test_date',
|
||||
'pt_test_date',
|
||||
'vt_test_date',
|
||||
'pwht_test_date',
|
||||
'pmi_test_date',
|
||||
'ferrite_test_date',
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
$logs_request_number_pattern = setting("logs_request_number_pattern");
|
||||
$logTestTypes = log_test_types();
|
||||
|
||||
Log::info("Available test types for request date processing", [
|
||||
'test_types' => array_keys($logTestTypes),
|
||||
'iso_number' => $data->iso_number,
|
||||
'joint_no' => $data->no_of_the_joint_as_per_as_built_survey
|
||||
]);
|
||||
|
||||
$testNames = array_keys($logTestTypes);
|
||||
$processedTests = [];
|
||||
|
||||
foreach($testNames AS $testName) {
|
||||
$result = $this->processTestType(
|
||||
$testName,
|
||||
$logTestTypes[$testName],
|
||||
$data,
|
||||
$beforeData,
|
||||
$logs_request_number_pattern
|
||||
);
|
||||
|
||||
if ($result['processed']) {
|
||||
$processedTests[] = $testName;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'processed_test_types' => $processedTests,
|
||||
'total_processed' => count($processedTests)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single test type for request number generation
|
||||
*/
|
||||
protected function processTestType(
|
||||
string $testName,
|
||||
string $testTableName,
|
||||
$data,
|
||||
$beforeData,
|
||||
string $logs_request_number_pattern
|
||||
): array {
|
||||
$requestDate = $testName . "_request_date";
|
||||
$run = false;
|
||||
|
||||
Log::info("Processing test type", [
|
||||
'test_name' => $testName,
|
||||
'request_date_field' => $requestDate,
|
||||
'current_request_date' => $data->$requestDate ?? 'null',
|
||||
'before_request_date' => $beforeData->$requestDate ?? 'null'
|
||||
]);
|
||||
|
||||
// Check if request date is not empty
|
||||
if($data->$requestDate != "") {
|
||||
$requestNo = $testName . "_request_no";
|
||||
$laboratoryCompany = "test_laboratory_" . $testName;
|
||||
|
||||
Log::info("Request date is not empty, checking conditions", [
|
||||
'test_name' => $testName,
|
||||
'request_date' => $data->$requestDate,
|
||||
'current_request_no' => $data->$requestNo ?? 'null',
|
||||
'current_laboratory' => $data->$laboratoryCompany ?? 'null',
|
||||
'before_laboratory' => $beforeData->$laboratoryCompany ?? 'null'
|
||||
]);
|
||||
|
||||
// Check conditions to run
|
||||
if($data->$requestNo == "") {
|
||||
// Request no not assigned yet
|
||||
$run = true;
|
||||
Log::info("Run condition met: Request number is empty", [
|
||||
'test_name' => $testName,
|
||||
'reason' => 'request_no_empty'
|
||||
]);
|
||||
}
|
||||
|
||||
if($data->$laboratoryCompany != $beforeData->$laboratoryCompany) {
|
||||
// Laboratory changed
|
||||
$run = true;
|
||||
Log::info("Run condition met: Laboratory changed", [
|
||||
'test_name' => $testName,
|
||||
'reason' => 'laboratory_changed',
|
||||
'old_laboratory' => $beforeData->$laboratoryCompany ?? 'null',
|
||||
'new_laboratory' => $data->$laboratoryCompany ?? 'null'
|
||||
]);
|
||||
}
|
||||
|
||||
$requestDateChange = false;
|
||||
if($data->$requestDate != $beforeData->$requestDate) {
|
||||
// Request date changed
|
||||
$run = true;
|
||||
Log::info("Run condition met: Request date changed", [
|
||||
'test_name' => $testName,
|
||||
'reason' => 'request_date_changed',
|
||||
'old_date' => $beforeData->$requestDate ?? 'null',
|
||||
'new_date' => $data->$requestDate
|
||||
]);
|
||||
|
||||
// Check if this date was already used
|
||||
$isOldSignReqDate = db("weld_logs")
|
||||
->where([
|
||||
$requestDate => $data->$requestDate,
|
||||
$laboratoryCompany => $data->$laboratoryCompany,
|
||||
])
|
||||
->where("id", "<>", $data->id)
|
||||
->first();
|
||||
|
||||
if(!$isOldSignReqDate) {
|
||||
$requestDateChange = true;
|
||||
Log::info("Request date is unique, will generate new request number", [
|
||||
'test_name' => $testName,
|
||||
'request_date' => $data->$requestDate,
|
||||
'laboratory' => $data->$laboratoryCompany ?? 'null'
|
||||
]);
|
||||
} else {
|
||||
Log::info("Request date already exists, will reuse existing request number", [
|
||||
'test_name' => $testName,
|
||||
'request_date' => $data->$requestDate,
|
||||
'laboratory' => $data->$laboratoryCompany ?? 'null',
|
||||
'existing_record_id' => $isOldSignReqDate->id ?? 'null'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if($run) {
|
||||
$this->generateAndUpdateRequestNumber(
|
||||
$testName,
|
||||
$testTableName,
|
||||
$data,
|
||||
$requestDate,
|
||||
$requestNo,
|
||||
$laboratoryCompany,
|
||||
$requestDateChange,
|
||||
$logs_request_number_pattern
|
||||
);
|
||||
|
||||
return ['processed' => true, 'test_name' => $testName];
|
||||
} else {
|
||||
Log::info("Request number generation skipped", [
|
||||
'test_name' => $testName,
|
||||
'reason' => 'run_condition_false',
|
||||
'current_request_date' => $data->$requestDate ?? 'null',
|
||||
'current_request_no' => $data->$requestNo ?? 'null'
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
Log::info("Test processing skipped", [
|
||||
'test_name' => $testName,
|
||||
'reason' => 'request_date_empty',
|
||||
'request_date_field' => $requestDate
|
||||
]);
|
||||
}
|
||||
|
||||
return ['processed' => false];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and update request number for a test type
|
||||
*/
|
||||
protected function generateAndUpdateRequestNumber(
|
||||
string $testName,
|
||||
string $testTableName,
|
||||
$data,
|
||||
string $requestDate,
|
||||
string $requestNo,
|
||||
string $laboratoryCompany,
|
||||
bool $requestDateChange,
|
||||
string $logs_request_number_pattern
|
||||
) {
|
||||
Log::info("Starting request number generation process", [
|
||||
'test_name' => $testName,
|
||||
'request_date_changed' => $requestDateChange,
|
||||
'current_request_no' => $data->$requestNo ?? 'null',
|
||||
'laboratory' => $data->$laboratoryCompany ?? 'null'
|
||||
]);
|
||||
|
||||
$thisRequestNumberPattern = $logs_request_number_pattern;
|
||||
|
||||
// Get company code
|
||||
$companyCode = db("subcontractors")
|
||||
->where("company_name_en", $data->$laboratoryCompany)
|
||||
->first();
|
||||
|
||||
if(!is_null($companyCode)) {
|
||||
$companyCode = $companyCode->company_code;
|
||||
} else {
|
||||
$companyCode = "";
|
||||
}
|
||||
|
||||
Log::info("Company code resolved", [
|
||||
'test_name' => $testName,
|
||||
'laboratory_name' => $data->$laboratoryCompany ?? 'null',
|
||||
'company_code' => $companyCode
|
||||
]);
|
||||
|
||||
$thisRequestNumberPattern = str_replace("{company_code}", $companyCode, $thisRequestNumberPattern);
|
||||
|
||||
// Get counter
|
||||
if($requestDateChange) {
|
||||
// Different date, get new counter
|
||||
$lastRequestNumber = get_counter($companyCode . $testName);
|
||||
Log::info("Getting new counter for date change", [
|
||||
'test_name' => $testName,
|
||||
'counter_key' => $companyCode . $testName,
|
||||
'new_counter' => $lastRequestNumber
|
||||
]);
|
||||
} else {
|
||||
// Same date, get existing or new counter
|
||||
$lastRequestNumber = get_counter($companyCode . $testName, "");
|
||||
Log::info("Getting existing or new counter for same date", [
|
||||
'test_name' => $testName,
|
||||
'counter_key' => $companyCode . $testName,
|
||||
'counter' => $lastRequestNumber
|
||||
]);
|
||||
}
|
||||
|
||||
$thisRequestNumberPattern = str_replace("{number}", $lastRequestNumber, $thisRequestNumberPattern);
|
||||
$thisRequestNumberPattern = str_replace("{log_name}", strtoupper($testName), $thisRequestNumberPattern);
|
||||
|
||||
Log::info("Request number pattern generated", [
|
||||
'test_name' => $testName,
|
||||
'pattern' => $thisRequestNumberPattern,
|
||||
'counter' => $lastRequestNumber
|
||||
]);
|
||||
|
||||
// Check if same company/date already has a request number today
|
||||
$todayDataThisCompanyThisTest = db("weld_logs")->where([
|
||||
$requestDate => $data->$requestDate,
|
||||
$laboratoryCompany => $data->$laboratoryCompany,
|
||||
])->first();
|
||||
|
||||
if($todayDataThisCompanyThisTest) {
|
||||
if($todayDataThisCompanyThisTest->$requestNo !="") {
|
||||
$thisRequestNumberPattern = $todayDataThisCompanyThisTest->$requestNo;
|
||||
Log::info("Reusing existing request number for same date/company", [
|
||||
'test_name' => $testName,
|
||||
'existing_request_no' => $thisRequestNumberPattern,
|
||||
'existing_record_id' => $todayDataThisCompanyThisTest->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update weld_logs
|
||||
$whereData = [
|
||||
'iso_number' => $data->iso_number,
|
||||
'no_of_the_joint_as_per_as_built_survey' => $data->no_of_the_joint_as_per_as_built_survey,
|
||||
];
|
||||
|
||||
$updateData = [
|
||||
$requestNo => $thisRequestNumberPattern,
|
||||
"updated_at" => simdi()
|
||||
];
|
||||
|
||||
Log::info("Updating weld_logs with request number", [
|
||||
'test_name' => $testName,
|
||||
'where_data' => $whereData,
|
||||
'update_data' => $updateData,
|
||||
'final_request_number' => $thisRequestNumberPattern
|
||||
]);
|
||||
|
||||
$weldLogUpdateResult = db("weld_logs")
|
||||
->where($whereData)
|
||||
->update($updateData);
|
||||
|
||||
Log::info("Weld_logs update completed", [
|
||||
'test_name' => $testName,
|
||||
'affected_rows' => $weldLogUpdateResult,
|
||||
'request_number' => $thisRequestNumberPattern
|
||||
]);
|
||||
|
||||
// Update test table
|
||||
$weldLogData = db("weld_logs")->where($whereData)->first();
|
||||
|
||||
$testTableUpdateData = [];
|
||||
$testTableColumns = table_columns($testTableName);
|
||||
|
||||
foreach($weldLogData AS $weldLogColumn => $weldLogValue)
|
||||
{
|
||||
if(in_array($weldLogColumn, $testTableColumns))
|
||||
{
|
||||
$testTableUpdateData[$weldLogColumn] = $weldLogValue;
|
||||
}
|
||||
}
|
||||
|
||||
unset($testTableUpdateData['id']);
|
||||
|
||||
// Check if control_standart exists in test table columns
|
||||
if(in_array('control_standart', $testTableColumns)) {
|
||||
$ndeMatrixInfo = db("nde_matrices")
|
||||
->where("line", $weldLogData->line_number)
|
||||
->where("type_of_joint", $weldLogData->type_of_welds)
|
||||
->first();
|
||||
|
||||
if ($ndeMatrixInfo) {
|
||||
$testTableUpdateData['control_standart'] = $ndeMatrixInfo->control_standart;
|
||||
|
||||
Log::info("Added control_standart from NDE Matrix", [
|
||||
'test_name' => $testName,
|
||||
'control_standart' => $ndeMatrixInfo->control_standart
|
||||
]);
|
||||
} else {
|
||||
Log::warning("Control standart not found in NDE Matrix", [
|
||||
'test_name' => $testName,
|
||||
'line' => $weldLogData->line_number,
|
||||
'type_of_joint' => $weldLogData->type_of_welds
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
Log::warning("Control standart column not found in test table", [
|
||||
'test_name' => $testName,
|
||||
'test_table' => $testTableName
|
||||
]);
|
||||
}
|
||||
|
||||
Log::info("Updating test table with weld log data", [
|
||||
'test_name' => $testName,
|
||||
'test_table' => $testTableName,
|
||||
'where_data' => $whereData,
|
||||
'update_fields_count' => count($testTableUpdateData)
|
||||
]);
|
||||
|
||||
$testTableUpdateResult = db($testTableName)
|
||||
->updateOrInsert($whereData, $testTableUpdateData);
|
||||
|
||||
Log::info("Test table update completed", [
|
||||
'test_name' => $testName,
|
||||
'test_table' => $testTableName,
|
||||
'operation_result' => $testTableUpdateResult ? 'success' : 'failed'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Spool Status Changer Trigger
|
||||
*
|
||||
* Handles spool status updates when spool_number, iso_number, or type_of_joint changes
|
||||
* Also triggers the spool-status-changer cron view for both new and old values
|
||||
*/
|
||||
class SpoolStatusChangerTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Spool Status Changer';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 14;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'spool_number',
|
||||
'no_of_the_joint_as_per_as_built_survey',
|
||||
'iso_number',
|
||||
'type_of_joint',
|
||||
'line_number',
|
||||
'project',
|
||||
'welding_date',
|
||||
'welder_1',
|
||||
'welder_2',
|
||||
'real_welder_1',
|
||||
'real_welder_2',
|
||||
'design_area'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
$triggerSpoolStatusChanger = false;
|
||||
$spoolStatusChangerParams = [];
|
||||
|
||||
// spool_number change check
|
||||
if (isset($data->spool_number)) {
|
||||
if(isset($data->iso_number)) {
|
||||
$triggerSpoolStatusChanger = true;
|
||||
spoolStatusChanger($data->iso_number, $data->spool_number);
|
||||
Log::info("Spool Status Changer triggered", [
|
||||
'iso_number' => $data->iso_number,
|
||||
'spool_number' => $data->spool_number
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'triggered' => $triggerSpoolStatusChanger
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use App\Models\TestPackage;
|
||||
use App\Models\TestPackBaseStatus;
|
||||
use App\Helpers\TransactionHelper;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Test Pack Base Status Changer Trigger
|
||||
*
|
||||
* Updates test package base statuses including:
|
||||
* - WDI (Weld Diameter Inch) calculations
|
||||
* - Welding progress
|
||||
* - Repair statistics
|
||||
* - Shop/Field weld tracking
|
||||
*/
|
||||
class TestPackBaseStatusChangerTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Test Pack Base Status Changer';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'test_package_no',
|
||||
'iso_number',
|
||||
'line_number',
|
||||
'welding_date',
|
||||
'type_of_joint',
|
||||
'nps_1'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
$testPackageNo = $data->test_package_no;
|
||||
$lineNumber = $data->line_number;
|
||||
|
||||
$testPackages = TestPackage::where("test_package_number", $testPackageNo)->get();
|
||||
$testPackagesIso = TestPackBaseStatus::where("test_package_no", $testPackageNo)->get();
|
||||
|
||||
$weldLogs = db("weld_logs")
|
||||
->where("test_package_no", $testPackageNo)
|
||||
->get();
|
||||
|
||||
$repairLogs = db("repair_logs")
|
||||
->where("test_package_no", $testPackageNo)
|
||||
->get();
|
||||
|
||||
$testPackagesSummary = [];
|
||||
$testPackagesIsoSummary = [];
|
||||
|
||||
$totalFields = [
|
||||
'total_wdi',
|
||||
'total_complated_wdi',
|
||||
'welding_progress',
|
||||
'total_shop_wdi',
|
||||
'total_complated_shop_wdi',
|
||||
'total_field_wdi',
|
||||
'total_complated_field_wdi',
|
||||
];
|
||||
|
||||
// Calculate repair log summaries
|
||||
$repairSummaries = $this->calculateRepairSummaries($repairLogs);
|
||||
|
||||
// Calculate weld log summaries
|
||||
foreach($weldLogs AS $weldLog) {
|
||||
foreach($totalFields AS $field) {
|
||||
if(!isset($testPackagesSummary[$weldLog->test_package_no][$field]))
|
||||
$testPackagesSummary[$weldLog->test_package_no][$field] = 0;
|
||||
|
||||
if(!isset($testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no][$field]))
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no][$field] = 0;
|
||||
}
|
||||
|
||||
$wdi = (float) $weldLog->nps_1;
|
||||
|
||||
$testPackagesSummary[$weldLog->test_package_no]['total_wdi'] += $wdi ;
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no]['total_wdi'] += $wdi;
|
||||
|
||||
if($weldLog->type_of_joint == "F") {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['total_field_wdi'] += $wdi;
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no]['total_field_wdi'] += $wdi ;
|
||||
|
||||
if(!rejected_date($weldLog->welding_date)) {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['total_complated_field_wdi'] += $wdi;
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_field_wdi'] += $wdi;
|
||||
}
|
||||
}
|
||||
|
||||
if($weldLog->type_of_joint == "S") {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['total_shop_wdi'] += $wdi;
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no]['total_shop_wdi'] += $wdi;
|
||||
|
||||
if(!rejected_date($weldLog->welding_date)) {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['total_complated_shop_wdi'] += $wdi;
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_shop_wdi'] += $wdi;
|
||||
}
|
||||
}
|
||||
|
||||
if(!rejected_date($weldLog->welding_date)) {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['total_complated_wdi'] += $wdi;
|
||||
$testPackagesIsoSummary[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_wdi'] += $wdi;
|
||||
}
|
||||
|
||||
// Welding progress calculation
|
||||
$totalWdi = $testPackagesSummary[$weldLog->test_package_no]['total_wdi'];
|
||||
$totalComplatedWdi = $testPackagesSummary[$weldLog->test_package_no]['total_complated_wdi'];
|
||||
|
||||
if ($totalWdi > 0) {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['welding_progress'] =
|
||||
round(($totalComplatedWdi * 100) / $totalWdi, 2);
|
||||
} else {
|
||||
$testPackagesSummary[$weldLog->test_package_no]['welding_progress'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update test pack base statuses
|
||||
$this->updateTestPackBaseStatuses($testPackagesIsoSummary, $repairSummaries);
|
||||
|
||||
// Update test packages summary
|
||||
$this->updateTestPackagesSummary($testPackagesSummary, $repairSummaries['repairLogsSummary2']);
|
||||
|
||||
// Update test packages with WDI fields and status
|
||||
$processedCount = $this->updateTestPackagesWDI($testPackages, $testPackagesSummary, $totalFields);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'processed_records' => $processedCount
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate repair log summaries
|
||||
*/
|
||||
protected function calculateRepairSummaries($repairLogs): array
|
||||
{
|
||||
$repairLogsSummary = [];
|
||||
$repairLogsSummary2 = [];
|
||||
$repairLogsSummaryCompleted = [];
|
||||
$repairLogsSummaryCompleted2 = [];
|
||||
$repairLogsSummaryRemaining = [];
|
||||
$repairLogsSummaryRemaining2 = [];
|
||||
|
||||
foreach($repairLogs AS $repairLog) {
|
||||
if(!isset($repairLogsSummary[$repairLog->iso_number][$repairLog->test_package_no]))
|
||||
$repairLogsSummary[$repairLog->iso_number][$repairLog->test_package_no] = 0;
|
||||
|
||||
if(!isset($repairLogsSummary2[$repairLog->test_package_no]))
|
||||
$repairLogsSummary2[$repairLog->test_package_no] = 0;
|
||||
|
||||
if(!isset($repairLogsSummaryCompleted[$repairLog->iso_number][$repairLog->test_package_no]))
|
||||
$repairLogsSummaryCompleted[$repairLog->iso_number][$repairLog->test_package_no] = 0;
|
||||
|
||||
if(!isset($repairLogsSummaryRemaining[$repairLog->iso_number][$repairLog->test_package_no]))
|
||||
$repairLogsSummaryRemaining[$repairLog->iso_number][$repairLog->test_package_no] = 0;
|
||||
|
||||
if(!isset($repairLogsSummaryCompleted2[$repairLog->test_package_no]))
|
||||
$repairLogsSummaryCompleted2[$repairLog->test_package_no] = 0;
|
||||
|
||||
if(!isset($repairLogsSummaryRemaining2[$repairLog->test_package_no]))
|
||||
$repairLogsSummaryRemaining2[$repairLog->test_package_no] = 0;
|
||||
|
||||
if($repairLog->repair_status == "Not Done") {
|
||||
$repairLogsSummary[$repairLog->iso_number][$repairLog->test_package_no]++;
|
||||
$repairLogsSummary2[$repairLog->test_package_no]++;
|
||||
}
|
||||
|
||||
if(!rejected_date($repairLog->repair_date)) {
|
||||
$repairLogsSummaryCompleted[$repairLog->iso_number][$repairLog->test_package_no]++;
|
||||
$repairLogsSummaryCompleted2[$repairLog->test_package_no]++;
|
||||
} else {
|
||||
$repairLogsSummaryRemaining[$repairLog->iso_number][$repairLog->test_package_no]++;
|
||||
$repairLogsSummaryRemaining2[$repairLog->test_package_no]++;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'repairLogsSummary' => $repairLogsSummary,
|
||||
'repairLogsSummary2' => $repairLogsSummary2,
|
||||
'repairLogsSummaryCompleted' => $repairLogsSummaryCompleted,
|
||||
'repairLogsSummaryCompleted2' => $repairLogsSummaryCompleted2,
|
||||
'repairLogsSummaryRemaining' => $repairLogsSummaryRemaining,
|
||||
'repairLogsSummaryRemaining2' => $repairLogsSummaryRemaining2,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update test pack base statuses
|
||||
*/
|
||||
protected function updateTestPackBaseStatuses($testPackagesIsoSummary, $repairSummaries)
|
||||
{
|
||||
TransactionHelper::retryTransaction(function () use ($testPackagesIsoSummary, $repairSummaries) {
|
||||
foreach($testPackagesIsoSummary AS $isoNumber => $data) {
|
||||
foreach($data AS $tpNo => $data2) {
|
||||
|
||||
if($data2['total_complated_wdi'] == $data2['total_wdi']) {
|
||||
$status = "Completed";
|
||||
}
|
||||
|
||||
if($data2['total_complated_wdi'] < $data2['total_wdi']) {
|
||||
$status = "On Going";
|
||||
}
|
||||
|
||||
if($data2['total_complated_wdi'] == 0) {
|
||||
$status = "Waiting";
|
||||
}
|
||||
|
||||
$updateData = [
|
||||
'welding_status' => $status,
|
||||
'repair_qty' => @$repairSummaries['repairLogsSummary'][$isoNumber][$tpNo],
|
||||
'repair_completed' => @$repairSummaries['repairLogsSummaryCompleted'][$isoNumber][$tpNo],
|
||||
'repair_remaining' => @$repairSummaries['repairLogsSummaryRemaining'][$isoNumber][$tpNo],
|
||||
];
|
||||
|
||||
db("test_pack_base_statuses")
|
||||
->where("drawing_no", $isoNumber)
|
||||
->where("test_package_no", $tpNo)
|
||||
->update($updateData);
|
||||
|
||||
$updateData = [
|
||||
'welding_status' => $status,
|
||||
'repair_qty' => @$repairSummaries['repairLogsSummary2'][$tpNo],
|
||||
'repair_completed' => @$repairSummaries['repairLogsSummaryCompleted2'][$tpNo],
|
||||
'repair_remaining' => @$repairSummaries['repairLogsSummaryRemaining2'][$tpNo],
|
||||
];
|
||||
|
||||
db("test_packages")
|
||||
->where("test_package_number", $tpNo)
|
||||
->update($updateData);
|
||||
}
|
||||
}
|
||||
}, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update test packages summary
|
||||
*/
|
||||
protected function updateTestPackagesSummary($testPackagesSummary, $repairLogsSummary2)
|
||||
{
|
||||
TransactionHelper::retryTransaction(function () use ($testPackagesSummary, $repairLogsSummary2) {
|
||||
foreach($testPackagesSummary AS $tpNo => $data2) {
|
||||
if($data2['total_complated_wdi'] == $data2['total_wdi']) {
|
||||
$status = "Completed";
|
||||
}
|
||||
|
||||
if($data2['total_complated_wdi'] < $data2['total_wdi']) {
|
||||
$status = "On Going";
|
||||
}
|
||||
|
||||
if($data2['total_complated_wdi'] == 0) {
|
||||
$status = "Waiting";
|
||||
}
|
||||
|
||||
db("test_packages")
|
||||
->where("test_package_number", $tpNo)
|
||||
->update([
|
||||
'welding_status' => $status,
|
||||
'repair_status_total' => @$repairLogsSummary2[$tpNo]
|
||||
]);
|
||||
}
|
||||
}, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update test packages with WDI fields and status
|
||||
*/
|
||||
protected function updateTestPackagesWDI($testPackages, $testPackagesSummary, $totalFields): int
|
||||
{
|
||||
$k = 0;
|
||||
|
||||
TransactionHelper::retryTransaction(function () use ($testPackages, $testPackagesSummary, $totalFields, &$k) {
|
||||
foreach($testPackages AS $testPackage) {
|
||||
$updateData = [];
|
||||
|
||||
if(isset($testPackagesSummary[$testPackage->test_package_number])) {
|
||||
foreach($totalFields AS $field) {
|
||||
$testPackage->$field = $testPackagesSummary[$testPackage->test_package_number][$field];
|
||||
$updateData[$field] = $testPackagesSummary[$testPackage->test_package_number][$field];
|
||||
}
|
||||
}
|
||||
|
||||
$updateData = array_merge($updateData, updateTestPackageStatus($testPackage));
|
||||
|
||||
db("test_packages")->where("id", $testPackage->id)
|
||||
->update($updateData);
|
||||
|
||||
db("test_pack_base_statuses")->where("test_package_no", $testPackage->test_package_number)
|
||||
->update([
|
||||
'tp_status' => $updateData['status'] ?? 'Waiting',
|
||||
'priority' => $testPackage->priority,
|
||||
'priority_info' => $testPackage->priority_info,
|
||||
'responsible_person' => $testPackage->responsible_test,
|
||||
'target_test_date' => $testPackage->planned_test_date,
|
||||
]);
|
||||
|
||||
$k++;
|
||||
}
|
||||
|
||||
return $k;
|
||||
}, 5);
|
||||
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Test Pack Cleanup Trigger
|
||||
*
|
||||
* Deletes non-matching test pack statuses
|
||||
* Cleans up orphaned test package records
|
||||
*/
|
||||
class TestPackCleanupTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Test Pack Cleanup';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 13;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'test_package_no',
|
||||
'iso_number'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
try {
|
||||
// Call the cleanup view to delete non-matching test pack statuses
|
||||
$result = view('cron.weld_logs-delete-non-matching-test-pack-statuses')->render();
|
||||
|
||||
Log::info("Test Pack Cleanup completed successfully", [
|
||||
'weld_log_id' => $data->id
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'result' => 'cleanup_completed'
|
||||
];
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Test Pack Cleanup failed (non-critical)", [
|
||||
'weld_log_id' => $data->id,
|
||||
'error' => $th->getMessage(),
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine()
|
||||
]);
|
||||
|
||||
// This is a non-critical operation, don't throw exception
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $th->getMessage(),
|
||||
'note' => 'non_critical_operation'
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Test Pack Sync Trigger
|
||||
*
|
||||
* Syncs weld log data to test packages when test_package_no changes or new record is inserted.
|
||||
* This trigger calls the sync view with specific test_package_no filter.
|
||||
*/
|
||||
class TestPackSyncTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Test Pack Sync from WeldLog';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 8; // Run before TestPackBaseStatusChangerTrigger (order 9)
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'test_package_no',
|
||||
'iso_number',
|
||||
'welding_date',
|
||||
'type_of_joint',
|
||||
'nps_1',
|
||||
'design_area',
|
||||
'piping_type',
|
||||
'circuit_number',
|
||||
'p_id',
|
||||
'type_of_test',
|
||||
'test_pressure',
|
||||
'no_of_the_joint_as_per_as_built_survey', // golden joints
|
||||
'quantity_of_iso',
|
||||
// NDT test dates
|
||||
'rt_test_date',
|
||||
'ut_test_date',
|
||||
'pwht_test_date',
|
||||
'pmi_test_date',
|
||||
'ferrite_test_date',
|
||||
'pt_test_date',
|
||||
'mt_test_date',
|
||||
'vt_test_date',
|
||||
// NDT Request Dates and Numbers
|
||||
'rt_request_date', 'rt_request_no',
|
||||
'ut_request_date', 'ut_request_no',
|
||||
'mt_request_no', 'mt_request_date',
|
||||
'pt_request_no', 'pt_request_date',
|
||||
'vt_request_no', 'vt_request_date',
|
||||
'pwht_request_no', 'pwht_request_date',
|
||||
'ferrite_request_no', 'ferrite_request_date',
|
||||
'pmi_request_no', 'pmi_request_date',
|
||||
'ht_request_no', 'ht_request_date',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Static registry to track already synced test packages in the current process
|
||||
* to avoid redundant heavy sync calls.
|
||||
*/
|
||||
protected static $isSynced = [];
|
||||
protected static $lastJobId = null;
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
// Get current job ID if running in queue
|
||||
$currentJobId = 'manual';
|
||||
if (\Illuminate\Support\Facades\Request::header('X-Laravel-Job-Id')) {
|
||||
$currentJobId = \Illuminate\Support\Facades\Request::header('X-Laravel-Job-Id');
|
||||
} elseif (function_exists('app') && app()->bound(\Illuminate\Contracts\Queue\Job::class)) {
|
||||
try {
|
||||
$currentJobId = resolve(\Illuminate\Contracts\Queue\Job::class)->getJobId();
|
||||
} catch (\Throwable $e) {
|
||||
// Fallback if resolution fails despite being bound
|
||||
}
|
||||
}
|
||||
|
||||
// Reset registry if this is a new job
|
||||
if (self::$lastJobId !== $currentJobId) {
|
||||
self::$isSynced = [];
|
||||
self::$lastJobId = $currentJobId;
|
||||
}
|
||||
|
||||
$changedFields = $context['changed_fields'] ?? [];
|
||||
$isNewRecord = $context['is_new_record'] ?? false;
|
||||
|
||||
// Collect all test package numbers that need to be synced
|
||||
$testPackageNosToSync = [];
|
||||
|
||||
// Current test package
|
||||
$currentTestPackageNo = $data->test_package_no;
|
||||
if (!empty($currentTestPackageNo)) {
|
||||
// Check if already synced in this process
|
||||
if (!isset(self::$isSynced[$currentTestPackageNo])) {
|
||||
$testPackageNosToSync[] = $currentTestPackageNo;
|
||||
}
|
||||
}
|
||||
|
||||
// If test_package_no changed, also sync the old test package
|
||||
if (in_array('test_package_no', $changedFields) && $beforeData && !empty($beforeData->test_package_no)) {
|
||||
$oldTestPackageNo = $beforeData->test_package_no;
|
||||
if ($oldTestPackageNo !== $currentTestPackageNo && !in_array($oldTestPackageNo, $testPackageNosToSync)) {
|
||||
if (!isset(self::$isSynced[$oldTestPackageNo])) {
|
||||
$testPackageNosToSync[] = $oldTestPackageNo;
|
||||
}
|
||||
Log::info("TestPackSync: test_package_no changed, will sync both old and new", [
|
||||
'old_test_package_no' => $oldTestPackageNo,
|
||||
'new_test_package_no' => $currentTestPackageNo,
|
||||
'weld_log_id' => $data->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// If no test packages to sync, return early
|
||||
if (empty($testPackageNosToSync)) {
|
||||
Log::info("TestPackSync: No test packages to sync", [
|
||||
'weld_log_id' => $data->id,
|
||||
'test_package_no' => $currentTestPackageNo
|
||||
]);
|
||||
return [
|
||||
'success' => true,
|
||||
'synced' => 0,
|
||||
'reason' => 'no_test_package'
|
||||
];
|
||||
}
|
||||
|
||||
$syncedCount = 0;
|
||||
$errors = [];
|
||||
|
||||
// Sync each test package
|
||||
foreach ($testPackageNosToSync as $testPackageNo) {
|
||||
try {
|
||||
// Mark as synced before calling the view to prevent re-entry/collision
|
||||
self::$isSynced[$testPackageNo] = true;
|
||||
|
||||
// Call the sync view with specific test_package_no
|
||||
$result = view('cron.weld_logs-sync-from-weldlog-to-test-pack', [
|
||||
'test_package_no' => $testPackageNo
|
||||
])->render();
|
||||
|
||||
Log::info("TestPackSync: Sync completed for test package", [
|
||||
'test_package_no' => $testPackageNo,
|
||||
'weld_log_id' => $data->id
|
||||
]);
|
||||
|
||||
$syncedCount++;
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("TestPackSync: Sync failed for test package (non-critical)", [
|
||||
'test_package_no' => $testPackageNo,
|
||||
'weld_log_id' => $data->id,
|
||||
'error' => $th->getMessage(),
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine()
|
||||
]);
|
||||
|
||||
$errors[] = [
|
||||
'test_package_no' => $testPackageNo,
|
||||
'error' => $th->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => empty($errors),
|
||||
'synced' => $syncedCount,
|
||||
'test_packages_synced' => $testPackageNosToSync,
|
||||
'errors' => $errors
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,613 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers\Triggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Base\BaseTrigger;
|
||||
use App\Models\TestPackage;
|
||||
use App\Models\PunchList;
|
||||
use App\Models\TestPackBaseStatus;
|
||||
use App\Helpers\TransactionHelper;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Test Package Operations Trigger
|
||||
*
|
||||
* Comprehensive test package management including:
|
||||
* - Supports updates
|
||||
* - Punch list tracking
|
||||
* - WDI calculations
|
||||
* - Golden joints tracking
|
||||
* - NDT calculations
|
||||
* - Test package status updates
|
||||
*/
|
||||
class TestPackageOperationsTrigger extends BaseTrigger
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Test Package Operations';
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
public function getDependentFields(): array
|
||||
{
|
||||
return [
|
||||
'test_package_no',
|
||||
'iso_number',
|
||||
'nps_1',
|
||||
'nps_2',
|
||||
'outside_diameter_1',
|
||||
'outside_diameter_2',
|
||||
'line_number',
|
||||
'project',
|
||||
'design_area',
|
||||
'piping_type',
|
||||
'circuit_number',
|
||||
'p_id',
|
||||
'type_of_test',
|
||||
'test_pressure',
|
||||
'quantity_of_iso',
|
||||
'welding_date',
|
||||
'rt_test_date',
|
||||
'ut_test_date',
|
||||
'mt_test_date',
|
||||
'pt_test_date',
|
||||
'vt_test_date',
|
||||
'pwht_test_date',
|
||||
'pmi_test_date',
|
||||
'ferrite_test_date',
|
||||
'no_of_the_joint_as_per_as_built_survey'
|
||||
];
|
||||
}
|
||||
|
||||
protected function process($data, $beforeData, array $context): array
|
||||
{
|
||||
$weldLogs = db("weld_logs")->orderBy("test_package_no", "DESC")
|
||||
->where("iso_number", $data->iso_number)
|
||||
->where("test_package_no", $data->test_package_no)
|
||||
->get();
|
||||
|
||||
$repairLogs = db("repair_logs")
|
||||
->where("iso_number", $data->iso_number)
|
||||
->where("test_package_no", $data->test_package_no)
|
||||
->get();
|
||||
|
||||
$supports = db("supports")
|
||||
->where("line_number", $data->line_number)
|
||||
->get();
|
||||
|
||||
// Update supports weld_or_assembled_date when welding_date is available
|
||||
if (!empty($data->welding_date) && !empty($data->line_number)) {
|
||||
db("supports")
|
||||
->where("line_number", $data->line_number)
|
||||
->where(function($query) use ($data) {
|
||||
$query->where("support_code", $data->element_code_1)
|
||||
->orWhere("support_code", $data->element_code_2);
|
||||
})
|
||||
->update([
|
||||
"weld_or_assembled_date" => $data->welding_date
|
||||
]);
|
||||
}
|
||||
|
||||
$punchLists = PunchList::where("line_isometric_no", $data->line_number)
|
||||
->where("test_package", $data->test_package_no)
|
||||
->get();
|
||||
|
||||
$logTypes = array_keys(log_test_types());
|
||||
|
||||
$testTypeToMedium = [
|
||||
'PNEUMATIC' => 'Air',
|
||||
'HYDRAULIC' => 'Water',
|
||||
'VISUAL' => '-',
|
||||
'ACUISTIC' => '-',
|
||||
];
|
||||
|
||||
// Delete empty test packages
|
||||
TestPackage::orWhere("test_package_number", "")->orWhereNull("test_package_number")->delete();
|
||||
TestPackBaseStatus::orWhere("test_package_no", "")->orWhereNull("test_package_no")->delete();
|
||||
|
||||
$weldLogTestPackCount = 0;
|
||||
|
||||
// Calculate support statistics
|
||||
$supportStats = $this->calculateSupportStats($supports);
|
||||
|
||||
// Calculate punch list statistics
|
||||
$punchListStats = $this->calculatePunchListStats($punchLists);
|
||||
|
||||
// Calculate weld log statistics
|
||||
$weldLogStats = $this->calculateWeldLogStats($weldLogs, $logTypes);
|
||||
|
||||
// Get NDT calculations
|
||||
// Temporarily set $_GET['type'] for the view's getEsit() helper
|
||||
$originalGetType = $_GET['type'] ?? null;
|
||||
$_GET['type'] = 'test_packs';
|
||||
|
||||
try {
|
||||
$ndtCalculation = j(view('admin-ajax.ndt-calculation-no-cache', [
|
||||
'test_package_no' => $data->test_package_no,
|
||||
'iso_number2' => $data->iso_number,
|
||||
'type' => 'test_packs',
|
||||
])->render());
|
||||
} finally {
|
||||
// Restore original $_GET['type']
|
||||
if ($originalGetType !== null) {
|
||||
$_GET['type'] = $originalGetType;
|
||||
} else {
|
||||
unset($_GET['type']);
|
||||
}
|
||||
}
|
||||
|
||||
$tpStats = $ndtCalculation['tpStats'] ?? [];
|
||||
$tpIsoStats = $ndtCalculation['tpISOStats'] ?? [];
|
||||
|
||||
// Process Test Package data in chunks
|
||||
$this->processTestPackageData(
|
||||
$weldLogs,
|
||||
$punchListStats,
|
||||
$weldLogStats,
|
||||
$tpStats,
|
||||
$tpIsoStats,
|
||||
$supportStats,
|
||||
$testTypeToMedium,
|
||||
$weldLogTestPackCount
|
||||
);
|
||||
|
||||
// Sync weld logs to test packages for this specific test package
|
||||
try {
|
||||
if(isset($data->test_package_no) && $data->test_package_no != "") {
|
||||
$syncParams = [
|
||||
'test_package_no' => $data->test_package_no
|
||||
];
|
||||
|
||||
$syncResult = view('cron.weld_logs-sync-from-weldlog-to-test-pack', $syncParams)->render();
|
||||
Log::debug("Weld logs sync completed for test package: " . $data->test_package_no);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Weld logs sync failed for test package: " . $data->test_package_no . " - " . $th->getMessage());
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'processed_records' => $weldLogTestPackCount
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate support statistics
|
||||
*/
|
||||
protected function calculateSupportStats($supports): array
|
||||
{
|
||||
$supportStats = [];
|
||||
$supportStatsTP = [];
|
||||
$isoToTP = [];
|
||||
|
||||
foreach($supports AS $support) {
|
||||
$tpNo = @$isoToTP[$support->line_number];
|
||||
|
||||
if(!isset($supportStatsTP[$tpNo]['support_remaining'])) {
|
||||
$supportStatsTP[$tpNo]['support_remaining'] = 0;
|
||||
$supportStatsTP[$tpNo]['welded_support_quantity'] = 0;
|
||||
$supportStatsTP[$tpNo]['support_progress'] = 0;
|
||||
}
|
||||
|
||||
if(!isset($supportStats[$support->line_number]['support_remaining']))
|
||||
$supportStats[$support->line_number]['support_remaining'] = 0;
|
||||
|
||||
if(!isset($supportStats[$support->line_number]['welded_support_quantity']))
|
||||
$supportStats[$support->line_number]['welded_support_quantity'] = 0;
|
||||
|
||||
if(!isset($supportStats[$support->line_number]['support_progress']))
|
||||
$supportStats[$support->line_number]['support_progress'] = 0;
|
||||
|
||||
if(!rejected_date($support->weld_or_assembled_date) && $support->erection_type == "Weld") {
|
||||
$supportStats[$support->line_number]['welded_support_quantity']+= $support->quantity;
|
||||
$supportStatsTP[$tpNo]['welded_support_quantity']+= $support->quantity;
|
||||
} else {
|
||||
$supportStats[$support->line_number]['support_remaining']+= $support->quantity;
|
||||
$supportStatsTP[$tpNo]['support_remaining']+= $support->quantity;
|
||||
}
|
||||
|
||||
if($supportStats[$support->line_number]['welded_support_quantity'] > 0) {
|
||||
$supportStats[$support->line_number]['support_progress'] =
|
||||
100 - ($supportStats[$support->line_number]['support_remaining'] * 100) /
|
||||
($supportStats[$support->line_number]['welded_support_quantity'] + $supportStats[$support->line_number]['support_remaining']);
|
||||
} else {
|
||||
$supportStats[$support->line_number]['support_progress'] = 0;
|
||||
}
|
||||
|
||||
if($supportStatsTP[$tpNo]['welded_support_quantity'] > 0) {
|
||||
$supportStatsTP[$tpNo]['support_progress'] =
|
||||
100 - ($supportStatsTP[$tpNo]['support_remaining'] * 100) /
|
||||
($supportStatsTP[$tpNo]['welded_support_quantity'] + $supportStatsTP[$tpNo]['support_remaining']);
|
||||
} else {
|
||||
$supportStatsTP[$tpNo]['support_progress'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ['supportStats' => $supportStats, 'supportStatsTP' => $supportStatsTP];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate punch list statistics
|
||||
*/
|
||||
protected function calculatePunchListStats($punchLists): array
|
||||
{
|
||||
$stats = [];
|
||||
$punchListNumbers = [];
|
||||
|
||||
foreach($punchLists AS $punchList) {
|
||||
$drawingNo = $punchList->line_isometric_no;
|
||||
|
||||
if(!isset($stats[$drawingNo][$punchList->test_package]['punch_a_quantity']))
|
||||
$stats[$drawingNo][$punchList->test_package]['punch_a_quantity'] = 0;
|
||||
|
||||
if(!isset($stats[$drawingNo][$punchList->test_package]['punch_b_quantity']))
|
||||
$stats[$drawingNo][$punchList->test_package]['punch_b_quantity'] = 0;
|
||||
|
||||
if(!isset($stats[$drawingNo][$punchList->test_package]['punch_c_quantity']))
|
||||
$stats[$drawingNo][$punchList->test_package]['punch_c_quantity'] = 0;
|
||||
|
||||
if(!isset($punchListNumbers[$punchList->test_package]))
|
||||
$punchListNumbers[$punchList->test_package] = [];
|
||||
|
||||
if(!in_array($punchList->punch_list_no, $punchListNumbers[$punchList->test_package]))
|
||||
$punchListNumbers[$punchList->test_package][] = $punchList->punch_list_no;
|
||||
|
||||
if(!isset($stats[$punchList->test_package]['punch_a_open_quantity']))
|
||||
$stats[$punchList->test_package]['punch_a_open_quantity'] = 0;
|
||||
|
||||
if(!isset($stats[$punchList->test_package]['punch_b_open_quantity']))
|
||||
$stats[$punchList->test_package]['punch_b_open_quantity'] = 0;
|
||||
|
||||
if(!isset($stats[$punchList->test_package]['punch_c_open_quantity']))
|
||||
$stats[$punchList->test_package]['punch_c_open_quantity'] = 0;
|
||||
|
||||
if($punchList->category == "A") {
|
||||
if($punchList->status == "Open") {
|
||||
$stats[$punchList->test_package]['punch_a_open_quantity']++;
|
||||
}
|
||||
$stats[$drawingNo][$punchList->test_package]['punch_a_quantity']++;
|
||||
}
|
||||
|
||||
if($punchList->category == "B") {
|
||||
if($punchList->status == "Open") {
|
||||
$stats[$punchList->test_package]['punch_b_open_quantity']++;
|
||||
}
|
||||
$stats[$drawingNo][$punchList->test_package]['punch_b_quantity']++;
|
||||
}
|
||||
|
||||
if($punchList->category == "C") {
|
||||
if($punchList->status == "Open") {
|
||||
$stats[$punchList->test_package]['punch_c_open_quantity']++;
|
||||
}
|
||||
$stats[$drawingNo][$punchList->test_package]['punch_c_quantity']++;
|
||||
}
|
||||
|
||||
$stats[$punchList->test_package]['found_date'] = $punchList->found_date;
|
||||
$stats[$punchList->test_package]['punch_list'] = $punchList->punch_list;
|
||||
}
|
||||
|
||||
return ['stats' => $stats, 'punchListNumbers' => $punchListNumbers];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate weld log statistics including golden joints, WDI, and backlogs
|
||||
*/
|
||||
protected function calculateWeldLogStats($weldLogs, $logTypes): array
|
||||
{
|
||||
$stats = [];
|
||||
$quantity_of_iso = [];
|
||||
$addedSheet = [];
|
||||
|
||||
foreach($weldLogs AS $weldLog) {
|
||||
$jointNo = $weldLog->no_of_the_joint_as_per_as_built_survey;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['goldenJoints']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['goldenJoints'] = 0;
|
||||
|
||||
if(!isset($quantity_of_iso[$weldLog->test_package_no]['total_qty']))
|
||||
$quantity_of_iso[$weldLog->test_package_no]['total_qty'] = 0;
|
||||
|
||||
if(!isset($addedSheet[$weldLog->test_package_no]))
|
||||
$addedSheet[$weldLog->test_package_no] = [];
|
||||
|
||||
if(!in_array($weldLog->quantity_of_iso, $addedSheet[$weldLog->test_package_no])) {
|
||||
$quantity_of_iso[$weldLog->test_package_no]['total_qty']++;
|
||||
$addedSheet[$weldLog->test_package_no][] = $weldLog->quantity_of_iso;
|
||||
}
|
||||
|
||||
if(!isset($quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_qty']))
|
||||
$quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_qty'] = 0;
|
||||
|
||||
if(!isset($addedSheet[$weldLog->iso_number][$weldLog->test_package_no]))
|
||||
$addedSheet[$weldLog->iso_number][$weldLog->test_package_no] = [];
|
||||
|
||||
if(!in_array($weldLog->quantity_of_iso, $addedSheet[$weldLog->iso_number][$weldLog->test_package_no])) {
|
||||
$quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_qty']++;
|
||||
$addedSheet[$weldLog->iso_number][$weldLog->test_package_no][] = $weldLog->quantity_of_iso;
|
||||
}
|
||||
|
||||
if(!isset($stats[$weldLog->test_package_no]['goldenJoints']))
|
||||
$stats[$weldLog->test_package_no]['goldenJoints'] = 0;
|
||||
|
||||
if(strpos(strtoupper($jointNo), "GJ") !== false) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['goldenJoints']++;
|
||||
$stats[$weldLog->test_package_no]['goldenJoints']++;
|
||||
}
|
||||
|
||||
if(!isset($quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_iso_quantity']))
|
||||
$quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_iso_quantity'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['rt_ut_status']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['rt_ut_status'] = 0;
|
||||
|
||||
$backlogs = [
|
||||
'rt_backlog', 'ut_backlog', 'mt_backlog', 'pmi_backlog',
|
||||
'vt_backlog', 'pt_backlog', 'ferrit_backlog', 'pwht_backlog', 'total_backlog',
|
||||
];
|
||||
|
||||
foreach($backlogs AS $backlog) {
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no][$backlog]))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no][$backlog] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->test_package_no][$backlog]))
|
||||
$stats[$weldLog->test_package_no][$backlog] = 0;
|
||||
}
|
||||
|
||||
if(!isset($stats[$weldLog->test_package_no]['total_backlog']))
|
||||
$stats[$weldLog->test_package_no]['total_backlog'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['rt_ut_done']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['rt_ut_done'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['mt_pt_backlog']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['mt_pt_backlog'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['mt_pt_done']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['mt_pt_done'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['remaining_wdi']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['remaining_wdi'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['total_wdi']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_wdi'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_wdi']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_wdi'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['total_joint_qty']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_joint_qty'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['total_welded_joint_qty']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_welded_joint_qty'] = 0;
|
||||
|
||||
if(!isset($stats[$weldLog->iso_number][$weldLog->test_package_no]['welded_support_quantity']))
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['welded_support_quantity'] = 0;
|
||||
|
||||
foreach($logTypes AS $logType) {
|
||||
$weldLogArray = (Array) $weldLog;
|
||||
$stats[$weldLog->test_package_no]['total_backlog'] += (float) $weldLogArray[$logType . "_scope"];
|
||||
}
|
||||
|
||||
if(!isset($addedSheet[$weldLog->iso_number][$weldLog->test_package_no]['total_iso']))
|
||||
$addedSheet[$weldLog->iso_number][$weldLog->test_package_no]['total_iso'] = [];
|
||||
|
||||
if(!in_array($weldLog->quantity_of_iso, $addedSheet[$weldLog->iso_number][$weldLog->test_package_no]['total_iso'])) {
|
||||
$quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_iso_quantity']++;
|
||||
$addedSheet[$weldLog->iso_number][$weldLog->test_package_no]['total_iso'][] = $weldLog->quantity_of_iso;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->welding_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['remaining_wdi'] += (float) $weldLog->nps_1;
|
||||
}
|
||||
|
||||
// Backlog calculations for each test type
|
||||
if(rejected_date($weldLog->rt_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['rt_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['rt_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->ut_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['ut_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['ut_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->pwht_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['pwht_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['pwht_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->pmi_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['pmi_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['pmi_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->ferrite_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['ferrit_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['ferrit_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->pt_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['pt_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['pt_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->mt_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['mt_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['mt_backlog']++;
|
||||
}
|
||||
|
||||
if(rejected_date($weldLog->vt_test_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['vt_backlog']++;
|
||||
$stats[$weldLog->test_package_no]['vt_backlog']++;
|
||||
}
|
||||
|
||||
if(!rejected_date($weldLog->welding_date)) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_wdi'] += (float) $weldLog->nps_1;
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_welded_joint_qty']++;
|
||||
}
|
||||
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_wdi'] += (float) $weldLog->nps_1;
|
||||
|
||||
// Welding progress calculation - ISO based stats
|
||||
$totalWdi = $stats[$weldLog->iso_number][$weldLog->test_package_no]['total_wdi'];
|
||||
$totalComplatedWdi = $stats[$weldLog->iso_number][$weldLog->test_package_no]['total_complated_wdi'];
|
||||
|
||||
if ($totalWdi > 0) {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['welding_progress'] =
|
||||
round(($totalComplatedWdi * 100) / $totalWdi, 2);
|
||||
} else {
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['welding_progress'] = 0;
|
||||
}
|
||||
|
||||
$stats[$weldLog->iso_number][$weldLog->test_package_no]['total_joint_qty']++;
|
||||
}
|
||||
|
||||
return ['stats' => $stats, 'quantity_of_iso' => $quantity_of_iso];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process and update test package data
|
||||
*/
|
||||
protected function processTestPackageData(
|
||||
$weldLogs,
|
||||
$punchListStats,
|
||||
$weldLogStats,
|
||||
$tpStats,
|
||||
$tpIsoStats,
|
||||
$supportStats,
|
||||
$testTypeToMedium,
|
||||
&$weldLogTestPackCount
|
||||
) {
|
||||
$punchListNumbers = $punchListStats['punchListNumbers'];
|
||||
$stats = array_merge_recursive($punchListStats['stats'], $weldLogStats['stats']);
|
||||
$quantity_of_iso = $weldLogStats['quantity_of_iso'];
|
||||
$supportStatsData = $supportStats['supportStats'];
|
||||
$supportStatsTP = $supportStats['supportStatsTP'];
|
||||
|
||||
// Process Test Package in chunks with TransactionHelper
|
||||
TransactionHelper::chunkTransaction(
|
||||
$weldLogs,
|
||||
function ($weldLogChunk) use ($punchListNumbers, $stats, $tpStats, $tpIsoStats, $supportStatsTP, $quantity_of_iso, $testTypeToMedium, $supportStatsData, &$weldLogTestPackCount) {
|
||||
foreach($weldLogChunk as $weldLog) {
|
||||
try {
|
||||
$punchListData = implode(",", $punchListNumbers[$weldLog->test_package_no] ?? []);
|
||||
} catch (\Throwable $th) {
|
||||
$punchListData = "";
|
||||
}
|
||||
|
||||
$thisStats = @$stats[$weldLog->test_package_no];
|
||||
$thisTpStats = @$tpStats[$weldLog->test_package_no];
|
||||
$thisTpISOStats = @$tpIsoStats[$weldLog->test_package_no][$weldLog->iso_number];
|
||||
$thisSupportStats = @$supportStatsTP[$weldLog->test_package_no];
|
||||
|
||||
$thisTotalBacklog =
|
||||
(@$thisTpStats['vt'] ?? 0) +
|
||||
(@$thisTpStats['ut'] ?? 0) +
|
||||
(@$thisTpStats['mt'] ?? 0) +
|
||||
(@$thisTpStats['pmi'] ?? 0) +
|
||||
(@$thisTpStats['pt'] ?? 0) +
|
||||
(@$thisTpStats['rt'] ?? 0) +
|
||||
(@$thisTpStats['pwht'] ?? 0) +
|
||||
(@$thisTpStats['ferrite'] ?? 0);
|
||||
|
||||
$testPackageData = [
|
||||
'unit' => $weldLog->design_area,
|
||||
'test_package_number' => $weldLog->test_package_no,
|
||||
'discipline' => $weldLog->piping_type,
|
||||
'circuit_number' => $weldLog->circuit_number,
|
||||
'p_id' => $weldLog->p_id,
|
||||
'iso_quantity' => $quantity_of_iso[$weldLog->test_package_no]['total_qty'],
|
||||
'test_type' => $weldLog->type_of_test,
|
||||
'test_medium' => @$testTypeToMedium[strtoupper($weldLog->type_of_test)],
|
||||
'test_pressure' => $weldLog->test_pressure,
|
||||
'golden_joints' => @$stats[$weldLog->iso_number][$weldLog->test_package_no]['goldenJoints'],
|
||||
'walkdown_date' => @$stats[$weldLog->iso_number][$weldLog->test_package_no]['found_date'],
|
||||
'punch_list' => $punchListData,
|
||||
'welded_support_quantity' => @$thisSupportStats['welded_support_quantity'],
|
||||
'support_remaining' => @$thisSupportStats['support_remaining'],
|
||||
'support_progress' => @$thisSupportStats['support_progress'],
|
||||
'a_punch_point_open' => @$stats[$weldLog->iso_number][$weldLog->test_package_no]['punch_a_open_quantity'],
|
||||
'b_punch_point_open' => @$stats[$weldLog->iso_number][$weldLog->test_package_no]['punch_b_open_quantity'],
|
||||
'c_punch_point_open' => @$stats[$weldLog->iso_number][$weldLog->test_package_no]['punch_c_open_quantity'],
|
||||
'vt_backlog' => @$thisTpStats['vt'],
|
||||
'ut_backlog' => @$thisTpStats['ut'],
|
||||
'mt_backlog' => @$thisTpStats['mt'],
|
||||
'pmi_backlog' => @$thisTpStats['pmi'],
|
||||
'pt_backlog' => @$thisTpStats['pt'],
|
||||
'rt_backlog' => @$thisTpStats['rt'],
|
||||
'pwht_backlog' => @$thisTpStats['pwht'],
|
||||
'ferrit_backlog' => @$thisTpStats['ferrite'],
|
||||
'ndt_status' => @$thisTotalBacklog == 0 ? "Completed" : "Not Completed",
|
||||
'welding_progress' => @$stats[$weldLog->iso_number][$weldLog->test_package_no]['welding_progress'],
|
||||
];
|
||||
|
||||
$thisStats = @$stats[$weldLog->iso_number][$weldLog->test_package_no];
|
||||
$thisSupportStats = @$supportStatsData[$weldLog->iso_number];
|
||||
|
||||
try {
|
||||
$pipeProgress = round($thisStats['total_complated_wdi'] * 100 / $thisStats['total_wdi'], 2);
|
||||
} catch (\Throwable $th) {
|
||||
$pipeProgress = 0;
|
||||
}
|
||||
|
||||
$testPackBaseStatusData = [
|
||||
'area' => $weldLog->project,
|
||||
'drawing_no' => $weldLog->iso_number,
|
||||
'test_package_no' => $weldLog->test_package_no,
|
||||
'discipline' => $weldLog->piping_type,
|
||||
'iso_qty' => $quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_qty'],
|
||||
'test_type' => $weldLog->type_of_test,
|
||||
'test_medium' => @$testTypeToMedium[strtoupper($weldLog->type_of_test)],
|
||||
'test_pressure_mpa' => $weldLog->test_pressure,
|
||||
'tp_status' => '', // Will be filled from test pack base stat
|
||||
'total_iso_quantity' => $quantity_of_iso[$weldLog->iso_number][$weldLog->test_package_no]['total_iso_quantity'],
|
||||
'remaining_wdi' => $thisStats['remaining_wdi'],
|
||||
'total_wdi' => $thisStats['total_wdi'],
|
||||
'total_complated_wdi' => $thisStats['total_complated_wdi'],
|
||||
'pipe_progress' => $pipeProgress,
|
||||
'total_joint_qty' => $thisStats['total_joint_qty'],
|
||||
'total_welded_joint_qty' => $thisStats['total_welded_joint_qty'],
|
||||
'welded_support_quantity' => @$thisSupportStats['welded_support_quantity'],
|
||||
'support_remaining' => @$thisSupportStats['support_remaining'],
|
||||
'support_progress' => @$thisSupportStats['support_progress'],
|
||||
'punch_a_quantity' => @$thisStats['punch_a_quantity'],
|
||||
'punch_b_quantity' => @$thisStats['punch_b_quantity'],
|
||||
'punch_c_quantity' => @$thisStats['punch_c_quantity'],
|
||||
'rt_ut_status' => $thisStats['rt_ut_status'],
|
||||
'rt_backlog' => @$thisTpISOStats['rt'],
|
||||
'ut_backlog' => @$thisTpISOStats['ut'],
|
||||
'mt_backlog' => @$thisTpISOStats['mt'],
|
||||
'pmi_backlog' => @$thisTpISOStats['pmi'],
|
||||
'vt_backlog' => @$thisTpISOStats['vt'],
|
||||
'pt_backlog' => @$thisTpISOStats['pt'],
|
||||
'pwht_backlog' => @$thisTpISOStats['pwht'],
|
||||
'ferrit_backlog' => @$thisTpISOStats['ferrite'],
|
||||
];
|
||||
|
||||
$testPackWhereData = [
|
||||
'test_package_number' => $weldLog->test_package_no
|
||||
];
|
||||
|
||||
$testPackBaseStatusWhereData = [
|
||||
'test_package_no' => $weldLog->test_package_no,
|
||||
'drawing_no' => $weldLog->iso_number,
|
||||
];
|
||||
|
||||
if($weldLog->test_package_no != "" && !is_null($weldLog->test_package_no)) {
|
||||
$testPackResult = TestPackage::updateOrCreate($testPackWhereData, $testPackageData);
|
||||
$testPackBaseResult = TestPackBaseStatus::updateOrCreate($testPackBaseStatusWhereData, $testPackBaseStatusData);
|
||||
$weldLogTestPackCount++;
|
||||
}
|
||||
}
|
||||
return $weldLogChunk->count();
|
||||
},
|
||||
50, // Chunk size
|
||||
1000 // 1ms delay
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Helpers\TransactionHelper;
|
||||
|
||||
/**
|
||||
* WeldLog Trigger Manager
|
||||
*
|
||||
* Manages the execution of all weld log triggers
|
||||
* Handles trigger execution order, timing, and error handling
|
||||
*/
|
||||
class WeldLogTriggerManager
|
||||
{
|
||||
/**
|
||||
* @var WeldLogTriggerRegistry Trigger registry
|
||||
*/
|
||||
protected $registry;
|
||||
|
||||
/**
|
||||
* @var float Overall start time
|
||||
*/
|
||||
protected $overallStartTime;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param WeldLogTriggerRegistry $registry
|
||||
*/
|
||||
public function __construct(WeldLogTriggerRegistry $registry)
|
||||
{
|
||||
$this->registry = $registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all applicable triggers
|
||||
*
|
||||
* @param object $weldLogData Current weld log data
|
||||
* @param object|null $beforeData Previous weld log data (null for new records)
|
||||
* @param array $changedFields List of changed field names
|
||||
* @param bool $isNewRecord Whether this is a new record
|
||||
* @return array Execution results
|
||||
*/
|
||||
public function executeTriggers(
|
||||
$weldLogData,
|
||||
$beforeData = null,
|
||||
array $changedFields = [],
|
||||
bool $isNewRecord = false,
|
||||
?string $action = null
|
||||
): array {
|
||||
$this->overallStartTime = microtime(true);
|
||||
|
||||
Log::info("=== WELD LOG SAVE TRIGGER STARTED ===", [
|
||||
'weld_log_id' => $weldLogData->id,
|
||||
'timestamp' => now()->toDateTimeString(),
|
||||
'is_new_record' => $isNewRecord,
|
||||
'changed_fields_count' => count($changedFields),
|
||||
'changed_fields' => $changedFields,
|
||||
'action' => $action,
|
||||
'memory_usage_start' => round(memory_get_usage(true) / 1024 / 1024, 2) . ' MB'
|
||||
]);
|
||||
|
||||
// Set database timeouts and memory limits
|
||||
TransactionHelper::setDatabaseTimeouts(300, 600, 600);
|
||||
ini_set('memory_limit', '2G');
|
||||
ini_set('max_execution_time', 600); // 10 minutes
|
||||
|
||||
$results = [];
|
||||
$triggers = $this->registry->getTriggersInOrder();
|
||||
|
||||
Log::info("Total triggers registered: " . count($triggers), [
|
||||
'trigger_names' => array_map(function($t) { return $t->getName(); }, $triggers)
|
||||
]);
|
||||
|
||||
foreach ($triggers as $trigger) {
|
||||
// Check if trigger should run
|
||||
if (!$trigger->shouldRun($changedFields, $isNewRecord)) {
|
||||
Log::info("Skipping trigger: {$trigger->getName()}", [
|
||||
'reason' => 'shouldRun returned false',
|
||||
'order' => $trigger->getOrder(),
|
||||
'dependent_fields' => $trigger->getDependentFields()
|
||||
]);
|
||||
|
||||
$results[$trigger->getName()] = [
|
||||
'skipped' => true,
|
||||
'reason' => 'shouldRun returned false'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Execute sync or async
|
||||
if ($trigger->isAsync()) {
|
||||
$this->executeAsync($trigger, $weldLogData, $beforeData, $changedFields);
|
||||
$results[$trigger->getName()] = [
|
||||
'queued' => true,
|
||||
'execution' => 'async'
|
||||
];
|
||||
} else {
|
||||
try {
|
||||
$result = $trigger->execute($weldLogData, $beforeData, [
|
||||
'changed_fields' => $changedFields,
|
||||
'is_new_record' => $isNewRecord,
|
||||
'action' => $action
|
||||
]);
|
||||
$results[$trigger->getName()] = array_merge($result, [
|
||||
'executed' => true,
|
||||
'execution' => 'sync'
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Trigger execution failed: {$trigger->getName()}", [
|
||||
'error' => $th->getMessage(),
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
'trace' => $th->getTraceAsString()
|
||||
]);
|
||||
|
||||
$results[$trigger->getName()] = [
|
||||
'executed' => false,
|
||||
'error' => $th->getMessage(),
|
||||
'execution' => 'sync'
|
||||
];
|
||||
|
||||
// Re-throw critical errors, log others
|
||||
if ($this->isCriticalTrigger($trigger->getName())) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->logOverallCompletion($weldLogData->id, $results);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute trigger asynchronously (via queue)
|
||||
*
|
||||
* @param \App\Services\WeldLogTriggers\Contracts\WeldLogTriggerInterface $trigger
|
||||
* @param object $weldLogData
|
||||
* @param object|null $beforeData
|
||||
* @param array $changedFields
|
||||
*/
|
||||
protected function executeAsync($trigger, $weldLogData, $beforeData, $changedFields)
|
||||
{
|
||||
// Future implementation: Dispatch job to queue
|
||||
// \App\Jobs\WeldLogTriggerJob::dispatch(
|
||||
// get_class($trigger),
|
||||
// $weldLogData->id,
|
||||
// $beforeData,
|
||||
// $changedFields
|
||||
// );
|
||||
|
||||
Log::info("Trigger queued (async execution): {$trigger->getName()}", [
|
||||
'weld_log_id' => $weldLogData->id,
|
||||
'note' => 'Async execution not yet implemented, falling back to sync'
|
||||
]);
|
||||
|
||||
// Fallback to sync execution for now
|
||||
try {
|
||||
$trigger->execute($weldLogData, $beforeData, [
|
||||
'changed_fields' => $changedFields,
|
||||
'is_new_record' => false,
|
||||
// $action is not available here in the current signature, but async isn't used yet anyway
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Async trigger execution failed: {$trigger->getName()}", [
|
||||
'error' => $th->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a trigger is critical (should stop execution on failure)
|
||||
*
|
||||
* @param string $triggerName
|
||||
* @return bool
|
||||
*/
|
||||
protected function isCriticalTrigger(string $triggerName): bool
|
||||
{
|
||||
// Define which triggers are critical
|
||||
$criticalTriggers = [
|
||||
'Spool Status Changer',
|
||||
'Line Lists Update',
|
||||
'NDE Matrix Update',
|
||||
'Construction Paint Logs Sync',
|
||||
'Paint Follow Ups Sync',
|
||||
];
|
||||
|
||||
return in_array($triggerName, $criticalTriggers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log overall execution completion
|
||||
*
|
||||
* @param int $weldLogId
|
||||
* @param array $results
|
||||
*/
|
||||
protected function logOverallCompletion($weldLogId, array $results)
|
||||
{
|
||||
$overallDuration = round((microtime(true) - $this->overallStartTime) * 1000, 2);
|
||||
|
||||
// Count execution statistics
|
||||
$executedCount = 0;
|
||||
$skippedCount = 0;
|
||||
$queuedCount = 0;
|
||||
$failedCount = 0;
|
||||
|
||||
foreach ($results as $triggerName => $result) {
|
||||
if (isset($result['executed']) && $result['executed']) {
|
||||
$executedCount++;
|
||||
} elseif (isset($result['skipped']) && $result['skipped']) {
|
||||
$skippedCount++;
|
||||
} elseif (isset($result['queued']) && $result['queued']) {
|
||||
$queuedCount++;
|
||||
} elseif (isset($result['executed']) && !$result['executed']) {
|
||||
$failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Log::info("=== WELD LOG SAVE TRIGGER COMPLETED ===", [
|
||||
'weld_log_id' => $weldLogId,
|
||||
'timestamp' => now()->toDateTimeString(),
|
||||
'total_execution_time_ms' => $overallDuration,
|
||||
'total_execution_time_sec' => round($overallDuration / 1000, 3),
|
||||
'peak_memory_usage_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
|
||||
'final_memory_usage_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
|
||||
'statistics' => [
|
||||
'total_triggers' => count($results),
|
||||
'executed' => $executedCount,
|
||||
'skipped' => $skippedCount,
|
||||
'queued' => $queuedCount,
|
||||
'failed' => $failedCount
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registry instance
|
||||
*
|
||||
* @return WeldLogTriggerRegistry
|
||||
*/
|
||||
public function getRegistry(): WeldLogTriggerRegistry
|
||||
{
|
||||
return $this->registry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\WeldLogTriggers;
|
||||
|
||||
use App\Services\WeldLogTriggers\Triggers\SpoolStatusChangerTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\LineListsUpdateTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\NdeMatrixUpdateTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\RequestDateOperationsTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\RepairLogsUpdateTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\NdeProjectUpdateTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\TestPackageOperationsTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\ConstructionPaintLogsTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\TestPackSyncTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\TestPackBaseStatusChangerTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\PaintFollowUpsSyncTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\HandoversSyncTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\TestPackCleanupTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\NdtCalculationCacheTrigger;
|
||||
use App\Services\WeldLogTriggers\Triggers\RegisterCreatorCacheTrigger;
|
||||
|
||||
/**
|
||||
* WeldLog Trigger Registry
|
||||
*
|
||||
* Central registry for all weld log triggers
|
||||
* Manages trigger registration and retrieval
|
||||
*/
|
||||
class WeldLogTriggerRegistry
|
||||
{
|
||||
/**
|
||||
* @var array Registered triggers
|
||||
*/
|
||||
protected $triggers = [];
|
||||
|
||||
/**
|
||||
* Constructor - automatically registers all triggers
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->registerTriggers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all trigger instances
|
||||
*/
|
||||
protected function registerTriggers()
|
||||
{
|
||||
// Order 1-12 based on trigger execution order
|
||||
$this->register(new SpoolStatusChangerTrigger()); // Order 1
|
||||
$this->register(new LineListsUpdateTrigger()); // Order 2
|
||||
$this->register(new NdeMatrixUpdateTrigger()); // Order 3
|
||||
$this->register(new RequestDateOperationsTrigger()); // Order 4
|
||||
$this->register(new RepairLogsUpdateTrigger()); // Order 5
|
||||
$this->register(new NdeProjectUpdateTrigger()); // Order 6
|
||||
$this->register(new TestPackageOperationsTrigger()); // Order 7
|
||||
$this->register(new TestPackSyncTrigger()); // Order 8 - Sync from WeldLog to Test Pack
|
||||
$this->register(new ConstructionPaintLogsTrigger()); // Order 9
|
||||
$this->register(new TestPackBaseStatusChangerTrigger()); // Order 10
|
||||
$this->register(new PaintFollowUpsSyncTrigger()); // Order 11
|
||||
$this->register(new HandoversSyncTrigger()); // Order 12
|
||||
$this->register(new TestPackCleanupTrigger()); // Order 13
|
||||
$this->register(new NdtCalculationCacheTrigger()); // Order 14
|
||||
$this->register(new RegisterCreatorCacheTrigger()); // Order 15
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a single trigger
|
||||
*
|
||||
* @param \App\Services\WeldLogTriggers\Contracts\WeldLogTriggerInterface $trigger
|
||||
*/
|
||||
public function register($trigger)
|
||||
{
|
||||
$this->triggers[$trigger->getName()] = $trigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all triggers sorted by execution order
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTriggersInOrder(): array
|
||||
{
|
||||
$triggers = $this->triggers;
|
||||
usort($triggers, function($a, $b) {
|
||||
return $a->getOrder() <=> $b->getOrder();
|
||||
});
|
||||
return $triggers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific trigger by name
|
||||
*
|
||||
* @param string $name Trigger name
|
||||
* @return \App\Services\WeldLogTriggers\Contracts\WeldLogTriggerInterface|null
|
||||
*/
|
||||
public function getTrigger(string $name)
|
||||
{
|
||||
return $this->triggers[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered trigger names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTriggerNames(): array
|
||||
{
|
||||
return array_keys($this->triggers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total count of registered triggers
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->triggers);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user