feat: implement core ERP modules, multi-tenant architecture, and comprehensive system workflow documentation.

This commit is contained in:
Ajjj
2026-08-05 01:18:31 +08:00
parent 1fcb468dc1
commit c03de704e2
46 changed files with 1902 additions and 387 deletions

View File

@@ -22,13 +22,17 @@ class PurchaseOrderController extends Controller
public function index(Request $request)
{
$query = PurchaseOrder::with([
'requester:id,ulid,name',
'approver:id,ulid,name',
'requester' => fn ($userQuery) => $userQuery->withoutGlobalScopes()->select('id', 'ulid', 'name'),
'approver' => fn ($userQuery) => $userQuery->withoutGlobalScopes()->select('id', 'ulid', 'name'),
'project:id,ulid,name,code',
'requisitions:id,ulid,document_number',
'items:id,purchase_order_id,quantity,unit_cost'
]);
// Purchase Orders inherit visibility from the projects available to
// the authenticated site or contractor user.
$query->whereIn('project_id', $this->availableProjectsQuery()->select('projects.id'));
if ($request->filled('project_ulid')) {
$project = Project::where('ulid', $request->project_ulid)->first();
if ($project) {
@@ -75,8 +79,25 @@ class PurchaseOrderController extends Controller
$approvedRequisitions = $requisitionsQuery->orderByDesc('created_at')->get();
// Find personnel with approve_po permission across the whole system
$approverIds = \App\Models\User::permission('approve_po')
// Purchase Orders may be approved by an explicit permission or by
// the system's Project Manager/executive roles.
$approverIds = \App\Models\User::withoutGlobalScopes()
->where(function ($query) {
$query->whereHas('roles', function ($roleQuery) {
$roleQuery->whereIn('name', [
'Project Manager',
'project_manager',
'Super Admin',
'admin',
'Main Contractor Admin',
]);
})
->orWhere('user_type', 'admin')
->orWhereHas('permissions', function ($permissionQuery) {
$permissionQuery->where('name', 'approve_po');
});
})
->where('status', 'active')
->pluck('id')
->values()
->toArray();
@@ -311,8 +332,25 @@ class PurchaseOrderController extends Controller
return back()->with('error', 'Only draft purchase orders can be submitted.');
}
// Find personnel with approve_po permission across the whole system
$approverIds = \App\Models\User::permission('approve_po')
// Use the same role-based approval rule during submission as on the
// Purchase Order creation form.
$approverIds = \App\Models\User::withoutGlobalScopes()
->where(function ($query) {
$query->whereHas('roles', function ($roleQuery) {
$roleQuery->whereIn('name', [
'Project Manager',
'project_manager',
'Super Admin',
'admin',
'Main Contractor Admin',
]);
})
->orWhere('user_type', 'admin')
->orWhereHas('permissions', function ($permissionQuery) {
$permissionQuery->where('name', 'approve_po');
});
})
->where('status', 'active')
->pluck('id')
->values()
->toArray();
@@ -545,4 +583,43 @@ class PurchaseOrderController extends Controller
$purchaseOrder->receipt_original_name
);
}
private function availableProjectsQuery()
{
$query = Project::withoutGlobalScope(\App\Scopes\TenantScope::class);
$user = auth()->user();
$siteRoles = [
'Site Technical', 'Construction Supervisor', 'Site Operations',
'Site Engineer', 'Site Supervisor',
];
$isSiteOperationsUser = $user && $user->hasAnyRole($siteRoles);
if ($user?->contractor_id) {
$contractorIds = DB::table('contractors')
->where('id', $user->contractor_id)
->orWhere('parent_id', $user->contractor_id)
->pluck('id')
->all();
$query->where(function ($projectQuery) use ($contractorIds, $user, $isSiteOperationsUser) {
$projectQuery
->whereIn('projects.contractor_id', $contractorIds)
->orWhereHas('contractors', function ($contractorQuery) use ($contractorIds) {
$contractorQuery->whereIn('contractors.id', $contractorIds);
});
if ($isSiteOperationsUser) {
$projectQuery->orWhereHas('personnel', function ($personnelQuery) use ($user) {
$personnelQuery->where('users.id', $user->id);
});
}
});
} elseif ($isSiteOperationsUser) {
$query->whereHas('personnel', function ($personnelQuery) use ($user) {
$personnelQuery->where('users.id', $user->id);
});
}
return $query;
}
}