feat: implement core ERP modules, multi-tenant architecture, and comprehensive system workflow documentation.
This commit is contained in:
@@ -6,10 +6,10 @@ use Inertia\Inertia;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\ProjectManagement\Models\Project;
|
||||
use Modules\ProjectManagement\Models\Task;
|
||||
use Modules\DailyReports\Models\DailyReportLabor;
|
||||
use Modules\ProjectManagement\Models\TaskActivity;
|
||||
use Modules\ProjectManagement\Models\TaskDelay;
|
||||
use Modules\DailyReports\Models\DailyReport;
|
||||
use Modules\DailyReports\Models\DailyReportLabor;
|
||||
use Modules\DailyReports\Models\DailyReportEquipment;
|
||||
use Modules\DailyReports\Models\DailyReportIssue;
|
||||
use App\Services\WeatherService;
|
||||
@@ -274,7 +274,7 @@ class DashboardController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile resource logs (Labor & Equipment) from latest Daily Reports.
|
||||
* Compile deployed labor and current equipment from active project data.
|
||||
*/
|
||||
private function getResourcesData(?Project $project): array
|
||||
{
|
||||
@@ -286,31 +286,35 @@ class DashboardController extends Controller
|
||||
$equipmentIdle = 0;
|
||||
$equipmentList = [];
|
||||
|
||||
// Resolve which projects we care about
|
||||
$projectIds = $project ? [$project->id] : Project::pluck('id')->toArray();
|
||||
// Global resource roll-ups should represent active execution only.
|
||||
// A selected project intentionally narrows the dashboard to that project.
|
||||
$projectIds = $project
|
||||
? [$project->id]
|
||||
: Project::whereIn('status', ['active', 'planning', 'in_progress'])
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
// Fetch latest reports for the selected project or across all active projects
|
||||
$latestReports = DailyReport::whereIn('project_id', $projectIds)
|
||||
->whereIn('id', function ($query) use ($projectIds) {
|
||||
$query->selectRaw('MAX(id)')
|
||||
->from('daily_reports')
|
||||
->whereIn('project_id', $projectIds)
|
||||
->groupBy('project_id');
|
||||
})
|
||||
// Labor totals come from every Daily Report labor entry for the active
|
||||
// project set. This intentionally includes all stored report records.
|
||||
$laborLogs = DailyReportLabor::whereHas('dailyReport', function ($query) use ($projectIds) {
|
||||
$query->whereIn('project_id', $projectIds);
|
||||
})->get();
|
||||
|
||||
foreach ($laborLogs as $log) {
|
||||
$laborActual += (int) $log->workers_count;
|
||||
$tradeName = $log->trade ?? 'General Labor';
|
||||
$trades[$tradeName] = ($trades[$tradeName] ?? 0) + (int) $log->workers_count;
|
||||
}
|
||||
|
||||
// Read equipment entries from every daily report in the project set.
|
||||
// ResourceSummary must represent all stored daily-report records, not
|
||||
// only the latest report for each project.
|
||||
$reports = DailyReport::whereIn('project_id', $projectIds)
|
||||
->with('equipment')
|
||||
->get();
|
||||
|
||||
foreach ($latestReports as $report) {
|
||||
// Compile Labor
|
||||
$laborLogs = DailyReportLabor::where('daily_report_id', $report->id)->get();
|
||||
foreach ($laborLogs as $log) {
|
||||
$laborActual += (int) $log->workers_count;
|
||||
$tradeName = $log->trade ?? 'General Labor';
|
||||
$trades[$tradeName] = ($trades[$tradeName] ?? 0) + (int) $log->workers_count;
|
||||
}
|
||||
|
||||
// Compile Equipment
|
||||
$equipLogs = DailyReportEquipment::where('daily_report_id', $report->id)->get();
|
||||
foreach ($equipLogs as $log) {
|
||||
foreach ($reports as $report) {
|
||||
foreach ($report->equipment as $log) {
|
||||
$status = strtolower($log->status ?? 'active');
|
||||
if (str_contains($status, 'active') || str_contains($status, 'use') || str_contains($status, 'operat')) {
|
||||
$equipmentActive++;
|
||||
@@ -330,9 +334,8 @@ class DashboardController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Expected labor calculation: calculate expected labor from project allocation if present, otherwise dynamically from actual logs
|
||||
if ($laborActual > 0) {
|
||||
$laborExpected = max($laborActual, (int)ceil($laborActual * 1.15));
|
||||
$laborExpected = max($laborActual, (int) ceil($laborActual * 1.15));
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -345,7 +348,7 @@ class DashboardController extends Controller
|
||||
'active' => $equipmentActive,
|
||||
'maintenance' => $equipmentMaintenance,
|
||||
'idle' => $equipmentIdle,
|
||||
'list' => array_slice($equipmentList, 0, 5) // Cap list at 5
|
||||
'list' => $equipmentList
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -374,8 +377,14 @@ class DashboardController extends Controller
|
||||
$totalRetention = (float) $invoicesQuery->sum('retention_amount');
|
||||
|
||||
$pendingApprovalsCount = \Modules\ApprovalWorkflow\Models\ApprovalChain::where('status', 'in_review')->count();
|
||||
$totalProjectsCount = Project::count();
|
||||
$activeProjectsCount = Project::where('status', 'active')->count();
|
||||
$projectsAnalyticsQuery = Project::query();
|
||||
if ($project) {
|
||||
$projectsAnalyticsQuery->whereKey($project->id);
|
||||
}
|
||||
$totalProjectsCount = (clone $projectsAnalyticsQuery)->count();
|
||||
$activeProjectsCount = (clone $projectsAnalyticsQuery)
|
||||
->whereIn('status', ['planning', 'in_progress'])
|
||||
->count();
|
||||
|
||||
// 2. PM Milestone & Progress Analytics
|
||||
$milestonesQuery = \Modules\TimelineScheduling\Models\Milestone::query();
|
||||
@@ -402,6 +411,7 @@ class DashboardController extends Controller
|
||||
|
||||
return [
|
||||
'role' => $roleName,
|
||||
'roles' => $user?->getRoleNames()->values()->all() ?? [],
|
||||
'user_type' => $userType,
|
||||
'financials' => [
|
||||
'total_billed' => $totalBilled,
|
||||
|
||||
Reference in New Issue
Block a user