diff --git a/app/Http/Controllers/Api/EmployerProfileController.php b/app/Http/Controllers/Api/EmployerProfileController.php index ce4980d..322acd0 100644 --- a/app/Http/Controllers/Api/EmployerProfileController.php +++ b/app/Http/Controllers/Api/EmployerProfileController.php @@ -309,6 +309,8 @@ public function getDashboard(Request $request) $savedCandidates = \App\Models\Shortlist::where('employer_id', $employer->id)->count(); + $totalWorkers = \App\Models\Worker::where('status', 'active')->count(); + // Resolve plan $sub = \Illuminate\Support\Facades\DB::table('subscriptions') ->where('user_id', $employer->id) @@ -375,6 +377,7 @@ public function getDashboard(Request $request) 'contacted_workers_count' => $contactedWorkersCount, 'total_hired_workers' => $totalHiredWorkers, 'saved_candidates' => $savedCandidates, + 'total_workers' => $totalWorkers, ], 'current_plan' => $currentPlan, 'recent_announcements' => $recentAnnouncements, diff --git a/app/Http/Controllers/Api/EmployerWorkerController.php b/app/Http/Controllers/Api/EmployerWorkerController.php index 54649e5..4db4198 100644 --- a/app/Http/Controllers/Api/EmployerWorkerController.php +++ b/app/Http/Controllers/Api/EmployerWorkerController.php @@ -44,6 +44,7 @@ private function formatWorker(Worker $w) return [ 'id' => $w->id, 'name' => $w->name, + 'email' => $w->email, 'phone' => $w->phone, 'nationality' => $w->nationality, 'age' => $w->age, @@ -57,6 +58,8 @@ private function formatWorker(Worker $w) 'language' => $w->language, 'languages' => $langs, 'preferred_location' => $w->preferred_location, + 'country' => $w->country, + 'city' => $w->city, 'area' => $w->area, 'live_in_out' => $w->live_in_out, 'gender' => $w->gender, @@ -71,7 +74,6 @@ private function formatWorker(Worker $w) 'visa_expiry_date' => $w->visa_expiry_date, 'bio' => $w->bio, 'photo' => $photo, - 'religion' => $w->religion, 'rating' => $rating, 'reviews_count' => $reviewsCount, 'skills' => $w->skills->map(function ($s) { @@ -88,6 +90,11 @@ private function formatWorker(Worker $w) ]; })->toArray(), 'documents' => $w->documents->map(function ($doc) { + $ocrData = $doc->ocr_data; + if ($doc->type === 'visa' && is_array($ocrData)) { + unset($ocrData['sponsor']); + unset($ocrData['valid_until']); + } return [ 'id' => $doc->id, 'worker_id' => $doc->worker_id, @@ -97,7 +104,7 @@ private function formatWorker(Worker $w) 'expiry_date' => $doc->expiry_date, 'ocr_accuracy' => $doc->ocr_accuracy, 'file_path' => $doc->file_path ? url($doc->file_path) : null, - 'ocr_data' => $doc->ocr_data, + 'ocr_data' => $ocrData, 'created_at' => $doc->created_at?->toISOString(), 'updated_at' => $doc->updated_at?->toISOString(), ]; @@ -976,25 +983,74 @@ public function getWorkerDetail(Request $request, $id) $workerProfile = [ 'id' => $w->id, 'name' => $w->name, + 'email' => $w->email, + 'phone' => $w->phone, 'nationality' => $w->nationality, - 'photo' => $photo, - 'emirates_id_status' => $emiratesIdStatus, - 'skills' => $mappedSkills, - 'visa_status' => $visaStatus, - 'experience' => $w->experience, - 'experience_years' => 5, - 'religion' => $w->religion, - 'languages' => $langs, 'age' => $w->age, - 'gender' => $w->gender, + 'salary' => $w->salary, + 'experience' => $w->experience, 'verified' => (bool)$w->verified, + 'status' => $w->status, + 'created_at' => $w->created_at?->toISOString(), + 'updated_at' => $w->updated_at?->toISOString(), + 'deleted_at' => $w->deleted_at?->toISOString(), + 'language' => $w->language, + 'languages' => $langs, + 'preferred_location' => $w->preferred_location, + 'country' => $w->country, + 'city' => $w->city, + 'area' => $w->area, + 'live_in_out' => $w->live_in_out, + 'gender' => $w->gender, + 'in_country' => (bool)$w->in_country, + 'visa_status' => $visaStatus, 'preferred_job_type' => $preferredJobType, + 'fcm_token' => $w->fcm_token, + 'passport_status' => $w->passport_status, + 'emirates_id_status' => $emiratesIdStatus, + 'document_expiry_days' => $w->document_expiry_days, + 'document_expiry_status' => $w->document_expiry_status, + 'visa_expiry_date' => $w->visa_expiry_date, 'bio' => $w->bio, + 'photo' => $photo, 'rating' => $rating, 'reviews_count' => $reviewsCount, 'reviews' => $reviews, 'similar_workers' => $similarWorkers, 'conversation_id' => $conversation ? $conversation->id : null, + 'skills' => $w->skills->map(function ($s) { + return [ + 'id' => $s->id, + 'name' => $s->name, + 'created_at' => $s->created_at?->toISOString(), + 'updated_at' => $s->updated_at?->toISOString(), + 'image_path' => $s->image_path, + 'pivot' => [ + 'worker_id' => $s->pivot->worker_id, + 'skill_id' => $s->pivot->skill_id, + ] + ]; + })->toArray(), + 'documents' => $w->documents->map(function ($doc) { + $ocrData = $doc->ocr_data; + if ($doc->type === 'visa' && is_array($ocrData)) { + unset($ocrData['sponsor']); + unset($ocrData['valid_until']); + } + return [ + 'id' => $doc->id, + 'worker_id' => $doc->worker_id, + 'type' => $doc->type, + 'number' => $doc->number, + 'issue_date' => $doc->issue_date, + 'expiry_date' => $doc->expiry_date, + 'ocr_accuracy' => $doc->ocr_accuracy, + 'file_path' => $doc->file_path ? url($doc->file_path) : null, + 'ocr_data' => $ocrData, + 'created_at' => $doc->created_at?->toISOString(), + 'updated_at' => $doc->updated_at?->toISOString(), + ]; + })->toArray(), ]; return response()->json([ diff --git a/app/Http/Controllers/Employer/WorkerController.php b/app/Http/Controllers/Employer/WorkerController.php index 2632dc4..e2c0371 100644 --- a/app/Http/Controllers/Employer/WorkerController.php +++ b/app/Http/Controllers/Employer/WorkerController.php @@ -370,7 +370,6 @@ public function show($id) 'skills' => $mappedSkills, 'visa_status' => $visaStatus, 'experience' => $w->experience, - 'experience_years' => 5, 'salary' => (int) $w->salary, 'religion' => $w->religion, 'languages' => $langs, diff --git a/public/swagger.json b/public/swagger.json index 0a6834f..adc1825 100644 --- a/public/swagger.json +++ b/public/swagger.json @@ -4198,123 +4198,33 @@ "type": "object", "properties": { "worker": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "example": 1 + "allOf": [ + { + "$ref": "#/components/schemas/Worker" }, - "name": { - "type": "string", - "example": "Jane Doe" - }, - "nationality": { - "type": "string", - "example": "Filipino" - }, - "photo": { - "type": "string", - "example": "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&q=80&w=200" - }, - "emirates_id_status": { - "type": "string", - "example": "Passport Verified", - "description": "Deprecated - Use passport_status instead" - }, - "passport_status": { - "type": "string", - "example": "Passport Verified" - }, - "category": { - "type": "string", - "example": "Domestic Worker" - }, - "skills": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "childcare", - "cooking" - ] - }, - "availability_status": { - "type": "string", - "example": "Active" - }, - "visa_status": { - "type": "string", - "example": "Residence Visa" - }, - "experience": { - "type": "string", - "example": "5 Years" - }, - "experience_years": { - "type": "integer", - "example": 5 - }, - "salary": { - "type": "integer", - "example": 2500 - }, - "religion": { - "type": "string", - "example": "Christian" - }, - "languages": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "English", - "Tagalog" - ] - }, - "age": { - "type": "integer", - "example": 28 - }, - "verified": { - "type": "boolean", - "example": true - }, - "preferred_job_type": { - "type": "string", - "example": "live-in" - }, - "bio": { - "type": "string", - "example": "Experienced and caring domestic worker specialing in childcare and housekeeping..." - }, - "rating": { - "type": "number", - "example": 4.3 - }, - "reviews_count": { - "type": "integer", - "example": 6 - }, - "reviews": { - "type": "array", - "items": { - "type": "object" + { + "type": "object", + "properties": { + "reviews": { + "type": "array", + "items": { + "type": "object" + } + }, + "similar_workers": { + "type": "array", + "items": { + "type": "object" + } + }, + "conversation_id": { + "type": "integer", + "nullable": true, + "example": 4 + } } - }, - "similar_workers": { - "type": "array", - "items": { - "type": "object" - } - }, - "conversation_id": { - "type": "integer", - "nullable": true, - "example": 4 } - } + ] } } } @@ -5738,10 +5648,6 @@ "type": "string", "example": "4 Years" }, - "religion": { - "type": "string", - "example": "Muslim" - }, "bio": { "type": "string", "example": "Certified infant caregiver and housekeeper with excellent cooking skills." diff --git a/tests/Feature/EmployerProfileApiTest.php b/tests/Feature/EmployerProfileApiTest.php index 106906c..01540d5 100644 --- a/tests/Feature/EmployerProfileApiTest.php +++ b/tests/Feature/EmployerProfileApiTest.php @@ -241,4 +241,51 @@ public function test_employer_dashboard_returns_only_two_charity_drives() $this->assertFalse($titles->contains('Charity Drive 1')); $this->assertFalse($titles->contains('Pending Charity Drive')); } + + public function test_employer_dashboard_returns_total_workers_active() + { + // Delete any existing workers seeded or created to make count precise + \App\Models\Worker::query()->delete(); + + // Create 3 active workers + \App\Models\Worker::create([ + 'name' => 'Active 1', 'email' => 'a1@test.com', 'phone' => '+971501110001', + 'password' => bcrypt('password'), 'status' => 'active', 'nationality' => 'Indian', + 'preferred_location' => 'Dubai', 'age' => 25, 'salary' => 1500, 'experience' => '3 Years', + 'availability' => 'Immediate', 'religion' => 'Christian', 'bio' => 'experienced worker', + ]); + \App\Models\Worker::create([ + 'name' => 'Active 2', 'email' => 'a2@test.com', 'phone' => '+971501110002', + 'password' => bcrypt('password'), 'status' => 'active', 'nationality' => 'Indian', + 'preferred_location' => 'Dubai', 'age' => 26, 'salary' => 1500, 'experience' => '3 Years', + 'availability' => 'Immediate', 'religion' => 'Christian', 'bio' => 'experienced worker', + ]); + \App\Models\Worker::create([ + 'name' => 'Active 3', 'email' => 'a3@test.com', 'phone' => '+971501110003', + 'password' => bcrypt('password'), 'status' => 'active', 'nationality' => 'Indian', + 'preferred_location' => 'Dubai', 'age' => 27, 'salary' => 1500, 'experience' => '3 Years', + 'availability' => 'Immediate', 'religion' => 'Christian', 'bio' => 'experienced worker', + ]); + + // Create 2 inactive/hidden workers + \App\Models\Worker::create([ + 'name' => 'Inactive 1', 'email' => 'i1@test.com', 'phone' => '+971502220001', + 'password' => bcrypt('password'), 'status' => 'hidden', 'nationality' => 'Indian', + 'preferred_location' => 'Dubai', 'age' => 28, 'salary' => 1500, 'experience' => '3 Years', + 'availability' => 'Immediate', 'religion' => 'Christian', 'bio' => 'experienced worker', + ]); + \App\Models\Worker::create([ + 'name' => 'Inactive 2', 'email' => 'i2@test.com', 'phone' => '+971502220002', + 'password' => bcrypt('password'), 'status' => 'Hired', 'nationality' => 'Indian', + 'preferred_location' => 'Dubai', 'age' => 29, 'salary' => 1500, 'experience' => '3 Years', + 'availability' => 'Immediate', 'religion' => 'Christian', 'bio' => 'experienced worker', + ]); + + $response = $this->withHeaders([ + 'Authorization' => 'Bearer ' . $this->token, + ])->getJson('/api/employers/dashboard'); + + $response->assertStatus(200); + $this->assertEquals(3, $response->json('data.stats.total_workers')); + } } diff --git a/tests/Feature/EmployerWorkerFilterApiTest.php b/tests/Feature/EmployerWorkerFilterApiTest.php index 9f07315..433fe79 100644 --- a/tests/Feature/EmployerWorkerFilterApiTest.php +++ b/tests/Feature/EmployerWorkerFilterApiTest.php @@ -532,4 +532,87 @@ public function test_worker_list_api_has_full_details_and_pagination() $this->assertEquals('passport', $matchingWorker['documents'][0]['type']); $this->assertEquals('visa', $matchingWorker['documents'][1]['type']); } + + public function test_worker_detail_api_has_full_details_without_religion_and_cleaned_ocr_data() + { + $worker = Worker::create([ + 'name' => 'Detail Worker Test', + 'email' => 'detail_test@example.com', + 'phone' => '+971509999777', + 'password' => bcrypt('password'), + 'nationality' => 'Indian', + 'verified' => true, + 'status' => 'active', + 'preferred_location' => 'Dubai Marina', + 'live_in_out' => 'live_out', + 'gender' => 'male', + 'in_country' => true, + 'visa_status' => 'Tourist Visa', + 'preferred_job_type' => 'full-time', + 'fcm_token' => 'fcm_token_example', + 'age' => 36, + 'salary' => 1500.00, + 'experience' => '4 Years', + 'language' => 'English, Arabic', + 'availability' => 'Immediate', + 'religion' => 'Christian', + 'bio' => 'Experienced helper', + ]); + + $doc1 = WorkerDocument::create([ + 'worker_id' => $worker->id, + 'type' => 'passport', + 'number' => 'YB98239279327', + 'issue_date' => '2017-07-05', + 'expiry_date' => '2022-07-05', + 'ocr_accuracy' => 99, + 'ocr_data' => ['authority' => 'FMP LLC'], + ]); + + $doc2 = WorkerDocument::create([ + 'worker_id' => $worker->id, + 'type' => 'visa', + 'number' => '343434', + 'issue_date' => '2022-02-16', + 'expiry_date' => '2024-02-15', + 'ocr_accuracy' => 99, + 'ocr_data' => [ + 'sponsor' => 'some sponsor', + 'sponsor_name' => 'some sponsor name', + 'valid_until' => '2024-02-15', + 'expiry_date' => '2024-02-15' + ], + ]); + + $response = $this->withHeaders([ + 'Authorization' => 'Bearer ' . $this->token, + ])->getJson('/api/employers/workers/' . $worker->id); + + $response->assertStatus(200); + $wData = $response->json('data.worker'); + + $this->assertNotNull($wData); + $this->assertEquals('+971509999777', $wData['phone']); + $this->assertEquals('detail_test@example.com', $wData['email']); + $this->assertEquals('1500.00', $wData['salary']); + $this->assertEquals('active', $wData['status']); + $this->assertEquals('English, Arabic', $wData['language']); + $this->assertEquals('fcm_token_example', $wData['fcm_token']); + $this->assertEquals('2024-02-15', $wData['visa_expiry_date']); + + // Assert religion is removed + $this->assertArrayNotHasKey('religion', $wData); + + // Check documents object array + $this->assertIsArray($wData['documents']); + $this->assertCount(2, $wData['documents']); + + // Assert visa ocr_data is cleaned up + $visaDoc = collect($wData['documents'])->firstWhere('type', 'visa'); + $this->assertNotNull($visaDoc); + $this->assertArrayNotHasKey('sponsor', $visaDoc['ocr_data']); + $this->assertArrayNotHasKey('valid_until', $visaDoc['ocr_data']); + $this->assertEquals('some sponsor name', $visaDoc['ocr_data']['sponsor_name']); + $this->assertEquals('2024-02-15', $visaDoc['ocr_data']['expiry_date']); + } }