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:
@@ -212,60 +212,8 @@ class DashboardController extends Controller
|
||||
$isContractorUser = $user && ($user->user_type === 'contractor' || $user->contractor_id !== null || $user->hasRole('Main Contractor Admin') || $user->hasRole('Contractor Admin'));
|
||||
|
||||
if ($isContractorUser && $user->contractor_id) {
|
||||
// 1. Bid Invitations
|
||||
$invitations = \Modules\BiddingManagement\Models\BidInvitation::with(['package:id,project_id,title', 'package.project:id,code,name'])
|
||||
->where('contractor_id', $user->contractor_id)
|
||||
->whereHas('package', function ($q) use ($project, $visibleProjectIds) {
|
||||
if ($project) {
|
||||
$q->where('project_id', $project->id);
|
||||
} elseif (!empty($visibleProjectIds)) {
|
||||
$q->whereIn('project_id', $visibleProjectIds);
|
||||
}
|
||||
})
|
||||
->orderByDesc('created_at')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
foreach ($invitations as $inv) {
|
||||
$pkgTitle = $inv->package->title ?? 'Tender Package';
|
||||
$projCode = $inv->package->project->code ?? '';
|
||||
$activitiesList[] = [
|
||||
'id' => 'bid_inv_' . $inv->id,
|
||||
'time' => $inv->created_at?->diffForHumans() ?? 'Recently',
|
||||
'timestamp' => $inv->created_at?->timestamp ?? 0,
|
||||
'title' => sprintf('Received tender invitation for %s (%s)', $pkgTitle, $projCode),
|
||||
'status' => 'info',
|
||||
];
|
||||
}
|
||||
|
||||
// 2. Bid Submissions
|
||||
$submissions = \Modules\BiddingManagement\Models\BidSubmission::with(['invitation:id,bid_package_id,contractor_id', 'invitation.package:id,project_id,title', 'invitation.package.project:id,code,name'])
|
||||
->whereHas('invitation', function ($q) use ($user, $project, $visibleProjectIds) {
|
||||
$q->where('contractor_id', $user->contractor_id);
|
||||
if ($project) {
|
||||
$q->whereHas('package', fn($pq) => $pq->where('project_id', $project->id));
|
||||
} elseif (!empty($visibleProjectIds)) {
|
||||
$q->whereHas('package', fn($pq) => $pq->whereIn('project_id', $visibleProjectIds));
|
||||
}
|
||||
})
|
||||
->orderByDesc('submitted_at')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
foreach ($submissions as $sub) {
|
||||
$pkgTitle = $sub->invitation->package->title ?? 'Bid Package';
|
||||
$price = number_format((float) $sub->submitted_price, 2);
|
||||
$activitiesList[] = [
|
||||
'id' => 'bid_sub_' . $sub->id,
|
||||
'time' => $sub->submitted_at ? \Carbon\Carbon::parse($sub->submitted_at)->diffForHumans() : 'Recently',
|
||||
'timestamp' => $sub->submitted_at ? \Carbon\Carbon::parse($sub->submitted_at)->timestamp : 0,
|
||||
'title' => sprintf('Submitted bid proposal for %s: ₱%s (%s)', $pkgTitle, $price, ucfirst($sub->status ?? 'submitted')),
|
||||
'status' => $sub->status === 'awarded' ? 'completed' : 'in_progress',
|
||||
];
|
||||
}
|
||||
|
||||
// 3. Financial Invoices
|
||||
$invoices = \Modules\FinancialManagement\Models\FinancialInvoice::with('project')
|
||||
// 1. Contractor Invoices
|
||||
$invoices = \Modules\ContractorManagement\Models\ContractorInvoice::with('project')
|
||||
->where('contractor_id', $user->contractor_id)
|
||||
->where(function ($q) use ($project, $visibleProjectIds) {
|
||||
if ($project) {
|
||||
@@ -280,12 +228,15 @@ class DashboardController extends Controller
|
||||
|
||||
foreach ($invoices as $inv) {
|
||||
$projCode = $inv->project->code ?? '';
|
||||
$statusVal = $inv->status instanceof \Modules\ContractorManagement\Enums\InvoiceStatus
|
||||
? $inv->status->value
|
||||
: (string) ($inv->status ?? '');
|
||||
$activitiesList[] = [
|
||||
'id' => 'inv_act_' . $inv->id,
|
||||
'time' => $inv->updated_at?->diffForHumans() ?? 'Recently',
|
||||
'timestamp' => $inv->updated_at?->timestamp ?? 0,
|
||||
'title' => sprintf('Invoice %s status: %s (%s)', $inv->invoice_number, str_replace('_', ' ', $inv->status), $projCode),
|
||||
'status' => $inv->status === 'paid' ? 'completed' : 'info',
|
||||
'title' => sprintf('Invoice %s status: %s (%s)', $inv->invoice_number, str_replace('_', ' ', $statusVal), $projCode),
|
||||
'status' => $statusVal === 'paid' ? 'completed' : 'info',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -513,8 +464,8 @@ class DashboardController extends Controller
|
||||
$pendingApprovalsQuery = \Modules\ApprovalWorkflow\Models\ApprovalChain::whereIn('status', ['in_review', 'pending']);
|
||||
if ($user->hasRole('Project Manager') && !($user->user_type === 'admin' || $user->hasRole(['Super Admin', 'admin', 'Main Contractor Admin']))) {
|
||||
$pendingApprovalsQuery->where(function ($q) {
|
||||
$q->whereNull('chain_type')
|
||||
->orWhere('chain_type', '!=', 'project_estimation');
|
||||
$q->whereNull('type')
|
||||
->orWhere('type', '!=', 'project_estimation');
|
||||
})->where('approvable_type', '!=', Project::class);
|
||||
}
|
||||
$pendingApprovalsCount = $pendingApprovalsQuery->count();
|
||||
@@ -532,7 +483,7 @@ class DashboardController extends Controller
|
||||
$activeProjectsCount = (int) ($projectStats->active_count ?? 0);
|
||||
|
||||
// 2. PM Milestone & Progress Analytics (Scoped Relation Columns)
|
||||
$milestonesQuery = \Modules\ProjectManagement\Models\ProjectMilestone::with('tasks:id,project_milestone_id,status');
|
||||
$milestonesQuery = \Modules\ProjectManagement\Models\ProjectMilestone::with('tasks:id,milestone_id,status');
|
||||
if ($project) {
|
||||
$milestonesQuery->where('project_id', $project->id);
|
||||
} else {
|
||||
@@ -565,43 +516,7 @@ class DashboardController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Subcontractor / Bidding Analytics
|
||||
$bidsQuery = \Modules\BiddingManagement\Models\BidPackage::query();
|
||||
if ($project) {
|
||||
$bidsQuery->where('project_id', $project->id);
|
||||
} else {
|
||||
$bidsQuery->whereIn('project_id', $visibleProjectIds);
|
||||
}
|
||||
$activeBids = $bidsQuery->count();
|
||||
|
||||
$openInvitationsQuery = \Modules\BiddingManagement\Models\BidInvitation::query()
|
||||
->whereIn('status', ['invited', 'accepted'])
|
||||
->whereDoesntHave('submission');
|
||||
|
||||
if ($user?->contractor_id) {
|
||||
$openInvitationsQuery->where('contractor_id', $user->contractor_id);
|
||||
$openInvitations = $openInvitationsQuery
|
||||
->whereHas('package', function ($query) use ($project) {
|
||||
$query->where('status', 'open');
|
||||
if ($project) {
|
||||
$query->where('project_id', $project->id);
|
||||
}
|
||||
})
|
||||
->count();
|
||||
} else {
|
||||
$openInvitations = $openInvitationsQuery
|
||||
->whereHas('package', function ($query) use ($visibleProjectIds, $project) {
|
||||
$query->where('status', 'open');
|
||||
if ($project) {
|
||||
$query->where('project_id', $project->id);
|
||||
} elseif (!empty($visibleProjectIds)) {
|
||||
$query->whereIn('project_id', $visibleProjectIds);
|
||||
}
|
||||
})
|
||||
->count();
|
||||
}
|
||||
|
||||
// 4. Warehouse & Technical Inventory (Cached Short TTL)
|
||||
// 3. Warehouse & Technical Inventory (Cached Short TTL)
|
||||
$totalItems = Cache::remember('master_materials_count', 300, fn () => \Modules\MasterData\Models\Material::count());
|
||||
$totalWarehouses = Cache::remember('master_warehouses_count', 300, fn () => \Modules\MaterialLogistics\Models\Warehouse::count());
|
||||
$totalDocuments = \Modules\DocumentManagement\Models\Document::whereIn('project_id', $project ? [$project->id] : $visibleProjectIds)->count();
|
||||
@@ -635,7 +550,7 @@ class DashboardController extends Controller
|
||||
'project_name' => $ret->project?->name ?? 'Project',
|
||||
'amount' => (float) $ret->amount,
|
||||
'type' => 'retention',
|
||||
'status' => $ret->status,
|
||||
'status' => is_object($ret->status) ? ($ret->status->value ?? (string) $ret->status) : (string) $ret->status,
|
||||
'confirm_url' => route('retention.confirm', $ret->ulid),
|
||||
'view_url' => route('retention.index'),
|
||||
]);
|
||||
@@ -681,10 +596,6 @@ class DashboardController extends Controller
|
||||
'in_progress' => $inProgressMilestones,
|
||||
'completion_rate' => $totalMilestones > 0 ? round(($completedMilestones / $totalMilestones) * 100, 1) : 0,
|
||||
],
|
||||
'bidding' => [
|
||||
'active_packages' => $activeBids,
|
||||
'open_invitations' => $openInvitations,
|
||||
],
|
||||
'logistics' => [
|
||||
'catalog_items' => $totalItems,
|
||||
'warehouses' => $totalWarehouses,
|
||||
|
||||
Reference in New Issue
Block a user