diff --git a/Modules/BiddingManagement/app/Http/Controllers/BidPackageController.php b/Modules/BiddingManagement/app/Http/Controllers/BidPackageController.php index 6d2ce39..6f4b34a 100644 --- a/Modules/BiddingManagement/app/Http/Controllers/BidPackageController.php +++ b/Modules/BiddingManagement/app/Http/Controllers/BidPackageController.php @@ -16,7 +16,7 @@ class BidPackageController extends Controller { public function index(Request $request) { - $query = BidPackage::with(['project:id,name,code', 'creator:id,name']) + $query = BidPackage::with(['project:id,name,code', 'creator:id,name', 'invitations:id,bid_package_id,ulid,contractor_id,status']) ->withCount(['invitations', 'submissions']); if ($search = $request->search) { @@ -36,6 +36,15 @@ class BidPackageController extends Controller $query->where('project_id', $projectId); } + // Contractor Admin users should ONLY see published (non-draft) bid packages where their company is invited + $user = Auth::user(); + if ($user && $user->contractor_id) { + $query->where('status', '!=', BidPackageStatus::Draft->value) + ->whereHas('invitations', function ($q) use ($user) { + $q->where('contractor_id', $user->contractor_id); + }); + } + $packages = $query->latest()->paginate(15)->withQueryString(); return Inertia::render('BiddingManagement::Bids/Index', [ @@ -97,6 +106,12 @@ class BidPackageController extends Controller public function show(BidPackage $bid) { + $user = Auth::user(); + if ($user && $user->contractor_id) { + abort_if($bid->status === BidPackageStatus::Draft, 403, 'This bid package is currently in draft state.'); + abort_unless($bid->invitations()->where('contractor_id', $user->contractor_id)->exists(), 403, 'Your company has not been invited to this bid package.'); + } + $bid->load([ 'project:id,ulid,name,code', 'creator:id,name', diff --git a/Modules/BiddingManagement/app/Http/Controllers/BidSubmissionController.php b/Modules/BiddingManagement/app/Http/Controllers/BidSubmissionController.php index 87520cf..2b2bdb9 100644 --- a/Modules/BiddingManagement/app/Http/Controllers/BidSubmissionController.php +++ b/Modules/BiddingManagement/app/Http/Controllers/BidSubmissionController.php @@ -124,6 +124,9 @@ class BidSubmissionController extends Controller abort_unless($contractor, 403, 'No contractor profile found for your account.'); $invitations = $contractor->bidInvitations() + ->whereHas('package', function ($query) { + $query->where('status', '!=', BidPackageStatus::Draft->value); + }) ->with([ 'package:id,ulid,project_id,title,submission_deadline,status,evaluation_mode', 'package.project:id,name,code', diff --git a/Modules/BiddingManagement/resources/js/Pages/Bids/Form.tsx b/Modules/BiddingManagement/resources/js/Pages/Bids/Form.tsx index 819d39b..3e81abe 100644 --- a/Modules/BiddingManagement/resources/js/Pages/Bids/Form.tsx +++ b/Modules/BiddingManagement/resources/js/Pages/Bids/Form.tsx @@ -83,18 +83,23 @@ export default function Form({ projects, package: pkg }: Props) { > -
-
+
+
- {/* Basic Info */} - - Bid Package Details - + {/* Basic Info Card */} + + + + Bid Package Details + +
- + - {errors.project_id &&

{errors.project_id}

} + {errors.project_id &&

{errors.project_id}

}
- - setData('title', e.target.value)} className={errors.title ? 'border-red-500' : ''} placeholder="e.g., Civil Works Package A" /> - {errors.title &&

{errors.title}

} + + setData('title', e.target.value)} + className={`h-10 text-sm border-slate-200 ${errors.title ? 'border-rose-400 focus:ring-rose-500' : ''}`} + placeholder="e.g., Architectural Glass & Structural Steel Fabrication Tender" + /> + {errors.title &&

{errors.title}

}
- -