Implement revised retention workflow, overdue late penalty calculation, payment proof verification, and dynamic ledger reconciliation

This commit is contained in:
Ajjj
2026-08-14 15:29:55 +08:00
parent ccbd23d474
commit 1ca1d286cd
39 changed files with 4103 additions and 573 deletions

View File

@@ -180,6 +180,8 @@ class ProjectController extends Controller
];
$estimationTotals = $this->getWizardTotals($project);
$progressService = new \Modules\ProjectProgress\Services\ProjectProgressService();
$evmData = $progressService->getEvmAnalysisData($project);
return Inertia::render('ProjectManagement::Projects/Overview', [
'project' => $project,
@@ -189,6 +191,7 @@ class ProjectController extends Controller
'label' => $s->label(),
]),
'estimationTotals' => $estimationTotals,
'evmData' => $evmData,
'tab' => request()->query('tab', 'overview'),
]);
}
@@ -683,6 +686,11 @@ class ProjectController extends Controller
'labor.*.task_ulid' => 'required|string',
'labor.*.labor_ulid' => 'required|string',
'labor.*.estimated_hours' => 'required|numeric|min:0',
'labor.*.allocation_type' => 'nullable|string|in:trade,bundle',
'labor.*.bundle_name' => 'nullable|string|max:255',
'labor.*.bundle_unit' => 'nullable|string|max:50',
'labor.*.bundle_quantity' => 'nullable|numeric|min:0',
'labor.*.bundle_unit_rate' => 'nullable|numeric|min:0',
'team_ulids' => 'nullable|array',
'team_ulids.*' => 'string|exists:teams,ulid',
'user_ulids' => 'nullable|array',
@@ -690,26 +698,34 @@ class ProjectController extends Controller
]);
\DB::transaction(function () use ($project, $validated) {
$existingLaborIds = [];
$taskIds = $project->tasks()->pluck('id');
\Modules\ProjectManagement\Models\TaskLabor::whereIn('task_id', $taskIds)->delete();
if (isset($validated['labor'])) {
if (!empty($validated['labor'])) {
foreach ($validated['labor'] as $lb) {
$task = $project->tasks()->where('ulid', $lb['task_ulid'])->firstOrFail();
$laborRecord = \Modules\Labors\Models\Labor::where('ulid', $lb['labor_ulid'])->firstOrFail();
$task = $project->tasks()->where('ulid', $lb['task_ulid'])->first() ?? $project->tasks()->first();
if (!$task) {
continue;
}
$taskLabor = $task->taskLabors()->updateOrCreate(
['labor_id' => $laborRecord->id],
['estimated_hours' => $lb['estimated_hours']]
);
$existingLaborIds[] = $taskLabor->id;
$laborRecord = \Modules\Labors\Models\Labor::where('ulid', $lb['labor_ulid'])->first();
if (!$laborRecord) {
continue;
}
\Modules\ProjectManagement\Models\TaskLabor::create([
'task_id' => $task->id,
'labor_id' => $laborRecord->id,
'allocation_type' => $lb['allocation_type'] ?? 'trade',
'bundle_name' => $lb['bundle_name'] ?? null,
'bundle_unit' => $lb['bundle_unit'] ?? null,
'bundle_quantity' => isset($lb['bundle_quantity']) ? (float) $lb['bundle_quantity'] : null,
'bundle_unit_rate' => isset($lb['bundle_unit_rate']) ? (float) $lb['bundle_unit_rate'] : null,
'estimated_hours' => round((float) $lb['estimated_hours'], 2),
]);
}
}
$taskIds = $project->tasks()->pluck('id');
\Modules\ProjectManagement\Models\TaskLabor::whereIn('task_id', $taskIds)
->whereNotIn('id', $existingLaborIds)
->delete();
// Synchronize project personnel pool
$userIds = [];