From 72da3c5b8db6c8774287327279fcd27bdb246ced Mon Sep 17 00:00:00 2001 From: mohanmd Date: Tue, 23 Jun 2026 18:27:14 +0530 Subject: [PATCH] employer profile api issue fixed --- .../Api/EmployerProfileController.php | 132 ++++++++++-- public/swagger.json | 189 +++++++++++++++--- tests/Feature/EmployerProfileApiTest.php | 112 +++++++---- 3 files changed, 348 insertions(+), 85 deletions(-) diff --git a/app/Http/Controllers/Api/EmployerProfileController.php b/app/Http/Controllers/Api/EmployerProfileController.php index d41b9ca..ce4980d 100644 --- a/app/Http/Controllers/Api/EmployerProfileController.php +++ b/app/Http/Controllers/Api/EmployerProfileController.php @@ -43,6 +43,17 @@ public function getProfile(Request $request) 'verification_status' => $profile->verification_status ?? 'approved', 'emirates_id_number' => $profile->emirates_id_number, 'emirates_id_expiry' => $profile->emirates_id_expiry, + 'id_number' => $profile->emirates_id_number, + 'card_number' => $profile->emirates_id_card_number, + 'full_name' => $profile->emirates_id_name, + 'date_of_birth' => $profile->emirates_id_dob, + 'nationality' => $profile->nationality, + 'gender' => $profile->emirates_id_gender, + 'issue_date' => $profile->emirates_id_issue_date, + 'expiry_date' => $profile->emirates_id_expiry, + 'occupation' => $profile->emirates_id_occupation, + 'employer' => $profile->emirates_id_employer, + 'issuing_place' => $profile->emirates_id_issue_place, ]; return response()->json([ @@ -94,10 +105,21 @@ public function updateProfile(Request $request) $sponsor ? 'unique:sponsors,mobile,' . $sponsor->id : 'unique:sponsors,mobile', ], 'address' => 'required|string|max:255', - 'notifications' => 'required|boolean', - 'current_password' => 'nullable|required_with:new_password|string', - 'new_password' => 'nullable|string|min:8|confirmed', + 'notifications' => 'nullable|boolean', 'fcm_token' => 'nullable|string|max:255', + + // Emirates ID optional fields + 'id_number' => 'nullable|string|max:255', + 'card_number' => 'nullable|string|max:255', + 'full_name' => 'nullable|string|max:255', + 'date_of_birth' => 'nullable|string|max:255', + 'nationality' => 'nullable|string|max:255', + 'gender' => 'nullable|string|max:255', + 'issue_date' => 'nullable|string|max:255', + 'expiry_date' => 'nullable|string|max:255', + 'occupation' => 'nullable|string|max:255', + 'employer' => 'nullable|string|max:255', + 'issuing_place' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -109,14 +131,15 @@ public function updateProfile(Request $request) } try { - // Check current password if new password is provided - if ($request->filled('new_password')) { - if (!Hash::check($request->current_password, $employer->password)) { + // Validate Emirates ID immutability — once set, it cannot be changed + if ($request->filled('id_number')) { + $existingProfile = $employer->employerProfile; + if ($existingProfile && $existingProfile->emirates_id_number && $existingProfile->emirates_id_number !== $request->id_number) { return response()->json([ 'success' => false, - 'message' => 'The provided current password does not match.', + 'message' => 'Emirates ID mismatch. You cannot change your registered Emirates ID number.', 'errors' => [ - 'current_password' => ['The provided password does not match your current password.'] + 'id_number' => ['Emirates ID mismatch.'] ] ], 422); } @@ -138,12 +161,48 @@ public function updateProfile(Request $request) // Sync with corresponding sponsor record if found $matchingSponsor = \App\Models\Sponsor::where('email', $oldEmail)->first(); if ($matchingSponsor) { - $matchingSponsor->update([ + $sponsorData = [ 'full_name' => $request->name, 'email' => $request->email, 'mobile' => $request->phone, 'address' => $request->address, - ]); + ]; + + if ($request->has('id_number')) { + $sponsorData['emirates_id'] = $request->id_number; + } + if ($request->has('card_number')) { + $sponsorData['emirates_id_card_number'] = $request->card_number; + } + if ($request->has('full_name')) { + $sponsorData['emirates_id_name'] = $request->full_name; + } + if ($request->has('date_of_birth')) { + $sponsorData['emirates_id_dob'] = $request->date_of_birth; + } + if ($request->has('nationality')) { + $sponsorData['nationality'] = $request->nationality; + } + if ($request->has('gender')) { + $sponsorData['emirates_id_gender'] = $request->gender; + } + if ($request->has('issue_date')) { + $sponsorData['emirates_id_issue_date'] = $request->issue_date; + } + if ($request->has('expiry_date')) { + $sponsorData['emirates_id_expiry'] = $request->expiry_date; + } + if ($request->has('occupation')) { + $sponsorData['emirates_id_occupation'] = $request->occupation; + } + if ($request->has('employer')) { + $sponsorData['emirates_id_employer'] = $request->employer; + } + if ($request->has('issuing_place')) { + $sponsorData['emirates_id_issue_place'] = $request->issuing_place; + } + + $matchingSponsor->update($sponsorData); } // Update employer_profiles table @@ -153,15 +212,43 @@ public function updateProfile(Request $request) } $profile->address = $request->address; $profile->phone = $request->phone; - $profile->notifications = $request->notifications; - $profile->save(); + $profile->notifications = $request->has('notifications') ? $request->notifications : ($profile->notifications ?? true); - // Update password if present - if ($request->filled('new_password')) { - $employer->update([ - 'password' => Hash::make($request->new_password), - ]); + if ($request->has('id_number')) { + $profile->emirates_id_number = $request->id_number; } + if ($request->has('card_number')) { + $profile->emirates_id_card_number = $request->card_number; + } + if ($request->has('full_name')) { + $profile->emirates_id_name = $request->full_name; + } + if ($request->has('date_of_birth')) { + $profile->emirates_id_dob = $request->date_of_birth; + } + if ($request->has('nationality')) { + $profile->nationality = $request->nationality; + } + if ($request->has('gender')) { + $profile->emirates_id_gender = $request->gender; + } + if ($request->has('issue_date')) { + $profile->emirates_id_issue_date = $request->issue_date; + } + if ($request->has('expiry_date')) { + $profile->emirates_id_expiry = $request->expiry_date; + } + if ($request->has('occupation')) { + $profile->emirates_id_occupation = $request->occupation; + } + if ($request->has('employer')) { + $profile->emirates_id_employer = $request->employer; + } + if ($request->has('issuing_place')) { + $profile->emirates_id_issue_place = $request->issuing_place; + } + + $profile->save(); $employerProfile = [ 'name' => $employer->name, @@ -172,6 +259,17 @@ public function updateProfile(Request $request) 'verification_status' => $profile->verification_status ?? 'approved', 'emirates_id_number' => $profile->emirates_id_number, 'emirates_id_expiry' => $profile->emirates_id_expiry, + 'id_number' => $profile->emirates_id_number, + 'card_number' => $profile->emirates_id_card_number, + 'full_name' => $profile->emirates_id_name, + 'date_of_birth' => $profile->emirates_id_dob, + 'nationality' => $profile->nationality, + 'gender' => $profile->emirates_id_gender, + 'issue_date' => $profile->emirates_id_issue_date, + 'expiry_date' => $profile->emirates_id_expiry, + 'occupation' => $profile->emirates_id_occupation, + 'employer' => $profile->emirates_id_employer, + 'issuing_place' => $profile->emirates_id_issue_place, ]; return response()->json([ diff --git a/public/swagger.json b/public/swagger.json index fae42c6..0a6834f 100644 --- a/public/swagger.json +++ b/public/swagger.json @@ -23,7 +23,7 @@ "Sponsor/Auth" ], "summary": "Register Sponsor Account", - "description": "Registers a new sponsor with basic information and uploads their organization/trade license. Sponsors have restricted access — dashboard and charity events only. No payment required.", + "description": "Registers a new sponsor with basic information and uploads their organization/trade license. Sponsors have restricted access \u2014 dashboard and charity events only. No payment required.", "security": [], "requestBody": { "required": true, @@ -51,7 +51,7 @@ "mobile": { "type": "string", "example": "+971501112233", - "description": "Mobile phone number — must be unique. (REQUIRED)" + "description": "Mobile phone number \u00e2\u20ac\u201d must be unique. (REQUIRED)" }, "password": { "type": "string", @@ -600,7 +600,7 @@ "Worker/Auth" ], "summary": "Register Worker Account (Step 1)", - "description": "Creates the worker account and returns a secure Bearer token.\n\nDocument upload is a **separate step** after registration:\n- `POST /workers/register/passport` — upload passport (OCR-processed)\n- `POST /workers/register/visa` — upload visa (OCR-processed)\n\nBoth document endpoints require the Bearer token returned here.", + "description": "Creates the worker account and returns a secure Bearer token.\n\nDocument upload is a **separate step** after registration:\n- `POST /workers/register/passport` \u2014 upload passport (OCR-processed)\n- `POST /workers/register/visa` \u2014 upload visa (OCR-processed)\n\nBoth document endpoints require the Bearer token returned here.", "security": [], "requestBody": { "required": true, @@ -746,7 +746,7 @@ "ocr_accuracy": { "type": "number", "format": "float", - "example": 99.0 + "example": 99 }, "passport_number": { "type": "string" @@ -816,7 +816,7 @@ "ocr_accuracy": { "type": "number", "format": "float", - "example": 99.0 + "example": 99 }, "passport_no": { "type": "string", @@ -895,7 +895,7 @@ } }, "422": { - "description": "Validation error — field validation failed or Passport OCR extraction failed.", + "description": "Validation error \u2014 field validation failed or Passport OCR extraction failed.", "content": { "application/json": { "schema": { @@ -1182,7 +1182,7 @@ }, "name": { "type": "string", - "example": "Hindi (हिन्दी)" + "example": "Hindi (\u0939\u093f\u0928\u094d\u0926\u0940)" } } } @@ -3689,6 +3689,50 @@ "emirates_id_expiry": { "type": "string", "example": "2028-04-11" + }, + "id_number": { + "type": "string", + "example": "784-1987-5493842-5" + }, + "card_number": { + "type": "string", + "example": "151023946" + }, + "full_name": { + "type": "string", + "example": "Mohammad Jobaier Mohammad Abul Kalam" + }, + "date_of_birth": { + "type": "string", + "example": "14/04/1987" + }, + "nationality": { + "type": "string", + "example": "Bangladesh" + }, + "gender": { + "type": "string", + "example": "M" + }, + "issue_date": { + "type": "string", + "example": "12/12/2025" + }, + "expiry_date": { + "type": "string", + "example": "11/12/2027" + }, + "occupation": { + "type": "string", + "example": "Electrician" + }, + "employer": { + "type": "string", + "example": "Msj International Technical Services L.L.C UAE" + }, + "issuing_place": { + "type": "string", + "example": "Dubai" } } } @@ -3708,7 +3752,7 @@ "Employer/Profile" ], "summary": "Update Employer Profile Details", - "description": "Updates the authenticated employer's profile details.", + "description": "Updates the authenticated employer's profile details including optional Emirates ID metadata. Password changes are not supported via this endpoint.", "requestBody": { "required": true, "content": { @@ -3719,8 +3763,7 @@ "name", "email", "phone", - "address", - "notifications" + "address" ], "properties": { "name": { @@ -3741,24 +3784,69 @@ }, "notifications": { "type": "boolean", - "example": true - }, - "current_password": { - "type": "string", - "example": "Password@123" - }, - "new_password": { - "type": "string", - "example": "NewSecurePassword@123" - }, - "new_password_confirmation": { - "type": "string", - "example": "NewSecurePassword@123" + "example": true, + "description": "Optional. Enable/disable push notifications. Defaults to true if not provided.", + "default": true }, "fcm_token": { "type": "string", "example": "fcm_token_example", "description": "Firebase Cloud Messaging token for push notifications." + }, + "id_number": { + "type": "string", + "example": "784-1987-5493842-5", + "description": "Emirates ID card number/ID number (optional)" + }, + "card_number": { + "type": "string", + "example": "151023946", + "description": "Emirates ID card physical serial number (optional)" + }, + "full_name": { + "type": "string", + "example": "Mohammad Jobaier Mohammad Abul Kalam", + "description": "Emirates ID full name (optional)" + }, + "date_of_birth": { + "type": "string", + "example": "14/04/1987", + "description": "Emirates ID date of birth (optional)" + }, + "nationality": { + "type": "string", + "example": "Bangladesh", + "description": "Emirates ID nationality (optional)" + }, + "gender": { + "type": "string", + "example": "M", + "description": "Emirates ID gender (optional)" + }, + "issue_date": { + "type": "string", + "example": "12/12/2025", + "description": "Emirates ID card issue date (optional)" + }, + "expiry_date": { + "type": "string", + "example": "11/12/2027", + "description": "Emirates ID card expiry date (optional)" + }, + "occupation": { + "type": "string", + "example": "Electrician", + "description": "Emirates ID card holder occupation (optional)" + }, + "employer": { + "type": "string", + "example": "Msj International Technical Services L.L.C UAE", + "description": "Emirates ID card holder sponsor/employer name (optional)" + }, + "issuing_place": { + "type": "string", + "example": "Dubai", + "description": "Emirates ID card place of issue (optional)" } } } @@ -3818,6 +3906,50 @@ "emirates_id_expiry": { "type": "string", "example": "2028-04-11" + }, + "id_number": { + "type": "string", + "example": "784-1987-5493842-5" + }, + "card_number": { + "type": "string", + "example": "151023946" + }, + "full_name": { + "type": "string", + "example": "Mohammad Jobaier Mohammad Abul Kalam" + }, + "date_of_birth": { + "type": "string", + "example": "14/04/1987" + }, + "nationality": { + "type": "string", + "example": "Bangladesh" + }, + "gender": { + "type": "string", + "example": "M" + }, + "issue_date": { + "type": "string", + "example": "12/12/2025" + }, + "expiry_date": { + "type": "string", + "example": "11/12/2027" + }, + "occupation": { + "type": "string", + "example": "Electrician" + }, + "employer": { + "type": "string", + "example": "Msj International Technical Services L.L.C UAE" + }, + "issuing_place": { + "type": "string", + "example": "Dubai" } } } @@ -5124,7 +5256,7 @@ "Workers - Auth" ], "summary": "Forgot Password (Send OTP)", - "description": "Sends a 6-digit OTP to verify the worker's identity using their registered mobile number. Workers do not use email — mobile/phone is the primary identifier. OTP is valid for 10 minutes.", + "description": "Sends a 6-digit OTP to verify the worker's identity using their registered mobile number. Workers do not use email \u2014 mobile/phone is the primary identifier. OTP is valid for 10 minutes.", "operationId": "workerForgotPassword", "requestBody": { "required": true, @@ -5188,7 +5320,7 @@ } }, "422": { - "description": "Validation error — phone is required" + "description": "Validation error \u2014 phone is required" } } } @@ -5416,7 +5548,7 @@ } }, "422": { - "description": "Validation error — email or mobile required" + "description": "Validation error \u2014 email or mobile required" } } } @@ -5577,7 +5709,10 @@ "items": { "type": "string" }, - "example": ["English", "Arabic"] + "example": [ + "English", + "Arabic" + ] }, "fcm_token": { "type": "string", diff --git a/tests/Feature/EmployerProfileApiTest.php b/tests/Feature/EmployerProfileApiTest.php index 6ef9490..106906c 100644 --- a/tests/Feature/EmployerProfileApiTest.php +++ b/tests/Feature/EmployerProfileApiTest.php @@ -109,58 +109,88 @@ public function test_employer_can_update_profile() } /** - * Test employer can update password when providing correct current password. + * Test employer can update profile with optional Emirates ID fields. */ - public function test_employer_can_update_password() + public function test_employer_can_update_profile_with_emirates_id_fields() { $response = $this->withHeaders([ 'Authorization' => 'Bearer ' . $this->token, ])->postJson('/api/employers/profile/update', [ - 'name' => 'Original Name', - 'email' => 'employer@example.com', - 'phone' => '+971501112222', - 'address' => 'Original Address', + 'name' => 'Ahmad', + 'email' => 'ahmad@example.com', + 'phone' => '+971509990001', + 'address' => 'Villa 12, Jumeirah 2', 'notifications' => true, - 'current_password' => 'Password@123', - 'new_password' => 'NewSecurePassword@123', - 'new_password_confirmation' => 'NewSecurePassword@123', + 'id_number' => '784-1987-5493842-5', + 'card_number' => '151023946', + 'full_name' => 'Mohammad Jobaier Mohammad Abul Kalam', + 'date_of_birth' => '14/04/1987', + 'nationality' => 'Bangladesh', + 'gender' => 'M', + 'issue_date' => '12/12/2025', + 'expiry_date' => '11/12/2027', + 'occupation' => 'Electrician', + 'employer' => 'Msj International Technical Services L.L.C UAE', + 'issuing_place' => 'Dubai', ]); - $response->assertStatus(200); - - // Verify password hash updated - $this->assertTrue(Hash::check('NewSecurePassword@123', $this->employer->fresh()->password)); - } - - /** - * Test employer password update fails with incorrect current password. - */ - public function test_employer_password_update_fails_with_incorrect_current_password() - { - $response = $this->withHeaders([ - 'Authorization' => 'Bearer ' . $this->token, - ])->postJson('/api/employers/profile/update', [ - 'name' => 'Original Name', - 'email' => 'employer@example.com', - 'phone' => '+971501112222', - 'address' => 'Original Address', - 'notifications' => true, - 'current_password' => 'WrongCurrentPassword', - 'new_password' => 'NewSecurePassword@123', - 'new_password_confirmation' => 'NewSecurePassword@123', - ]); - - $response->assertStatus(422) - ->assertJsonStructure([ - 'success', - 'message', - 'errors' => [ - 'current_password' + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'data' => [ + 'profile' => [ + 'name' => 'Ahmad', + 'email' => 'ahmad@example.com', + 'phone' => '+971509990001', + 'address' => 'Villa 12, Jumeirah 2', + 'id_number' => '784-1987-5493842-5', + 'card_number' => '151023946', + 'full_name' => 'Mohammad Jobaier Mohammad Abul Kalam', + 'gender' => 'M', + ] ] ]); - // Verify password was NOT changed - $this->assertTrue(Hash::check('Password@123', $this->employer->fresh()->password)); + $this->assertDatabaseHas('employer_profiles', [ + 'user_id' => $this->employer->id, + 'emirates_id_number' => '784-1987-5493842-5', + 'emirates_id_card_number' => '151023946', + 'emirates_id_name' => 'Mohammad Jobaier Mohammad Abul Kalam', + 'emirates_id_gender' => 'M', + ]); + } + + /** + * Test employer cannot change an existing Emirates ID number. + */ + public function test_employer_cannot_change_existing_emirates_id_number() + { + // First, set the Emirates ID + $profile = $this->employer->employerProfile; + $profile->emirates_id_number = '784-1987-5493842-5'; + $profile->save(); + + // Attempt to change to a different ID + $response = $this->withHeaders([ + 'Authorization' => 'Bearer ' . $this->token, + ])->postJson('/api/employers/profile/update', [ + 'name' => 'Original Name', + 'email' => 'employer@example.com', + 'phone' => '+971501112222', + 'address' => 'Original Address', + 'id_number' => '784-9999-0000000-0', + ]); + + $response->assertStatus(422) + ->assertJson([ + 'success' => false, + 'errors' => [ + 'id_number' => ['Emirates ID mismatch.'] + ] + ]); + + // Verify ID was NOT changed + $this->assertEquals('784-1987-5493842-5', $profile->fresh()->emirates_id_number); } /**