feat: complete GSB construction ERP implementation with dual-mode MR, capitalization cap engine, single PM rule, and system sign-off documentation
This commit is contained in:
@@ -11,7 +11,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Modules\BiddingManagement\Models\BidPackage;
|
||||
use Modules\ContractorManagement\Models\Contractor;
|
||||
use Modules\MasterData\Models\MaterialGroup;
|
||||
use Modules\MaterialLogistics\Models\ProjectInventory;
|
||||
@@ -47,6 +46,7 @@ class Project extends Model
|
||||
'total_capitalization',
|
||||
'parent_project_id',
|
||||
'project_type',
|
||||
'classifications',
|
||||
'is_unprofitable',
|
||||
'current_wizard_step',
|
||||
];
|
||||
@@ -64,6 +64,7 @@ class Project extends Model
|
||||
'target_end_date' => 'date',
|
||||
'actual_end_date' => 'date',
|
||||
'is_unprofitable' => 'boolean',
|
||||
'classifications' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -145,11 +146,6 @@ class Project extends Model
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function bidPackages(): HasMany
|
||||
{
|
||||
return $this->hasMany(BidPackage::class);
|
||||
}
|
||||
|
||||
public function parentProject(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Project::class, 'parent_project_id');
|
||||
@@ -165,6 +161,11 @@ class Project extends Model
|
||||
return $this->hasMany(ProjectMaterialsEstimate::class);
|
||||
}
|
||||
|
||||
public function projectClassifications(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(ProjectClassification::class, 'project_classification_pivot');
|
||||
}
|
||||
|
||||
// --- State Machine Helpers ---
|
||||
|
||||
public function transitionTo(ProjectStatus $newStatus): void
|
||||
@@ -233,8 +234,20 @@ class Project extends Model
|
||||
|
||||
public function recalculateCapitalization(): void
|
||||
{
|
||||
$total = $this->tasks->sum(fn (Task $task) => $task->total_cost);
|
||||
$this->update(['total_capitalization' => $total]);
|
||||
$tasksTotal = (float) $this->tasks->sum(fn (Task $task) => $task->total_cost);
|
||||
|
||||
$unestimatedMaterialsTotal = 0.0;
|
||||
if (\Illuminate\Support\Facades\Schema::hasTable('material_requisition_items') && \Illuminate\Support\Facades\Schema::hasColumn('material_requisition_items', 'is_unestimated')) {
|
||||
$unestimatedMaterialsTotal = (float) \Modules\MaterialLogistics\Models\MaterialRequisitionItem::whereHas('requisition', function ($q) {
|
||||
$q->where('project_id', $this->id)
|
||||
->whereNotIn('status', ['rejected', 'cancelled']);
|
||||
})
|
||||
->where('is_unestimated', true)
|
||||
->get()
|
||||
->sum(fn ($item) => (float) $item->quantity * (float) $item->unit_cost);
|
||||
}
|
||||
|
||||
$this->update(['total_capitalization' => $tasksTotal + $unestimatedMaterialsTotal]);
|
||||
}
|
||||
|
||||
public function getMilestoneCompletionAttribute(): float
|
||||
|
||||
Reference in New Issue
Block a user