sponsor profile api updated
This commit is contained in:
parent
3d97fb2e29
commit
76dbb5cf08
@ -198,6 +198,13 @@ public function register(Request $request)
|
|||||||
'phone.unique' => 'This mobile number is already registered.',
|
'phone.unique' => 'This mobile number is already registered.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$validator->after(function ($validator) use ($request) {
|
||||||
|
$emiratesIdInput = $request->input('emirates_id');
|
||||||
|
if (is_array($emiratesIdInput) && empty($emiratesIdInput['name'])) {
|
||||||
|
$validator->errors()->add('emirates_id.name', 'Failed to extract name from the Emirates ID. Please upload a clearer document.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
@ -232,6 +239,9 @@ public function register(Request $request)
|
|||||||
$emiratesIdNumber = $emiratesIdInput['emirates_id_number'] ?? $emiratesIdInput['id_number'] ?? $emiratesIdInput['id number'] ?? $emiratesIdInput['card_number'] ?? null;
|
$emiratesIdNumber = $emiratesIdInput['emirates_id_number'] ?? $emiratesIdInput['id_number'] ?? $emiratesIdInput['id number'] ?? $emiratesIdInput['card_number'] ?? null;
|
||||||
$emiratesIdExpiry = $emiratesIdInput['expiry_date'] ?? $emiratesIdInput['expiry date'] ?? $emiratesIdInput['emirates_id_expiry'] ?? null;
|
$emiratesIdExpiry = $emiratesIdInput['expiry_date'] ?? $emiratesIdInput['expiry date'] ?? $emiratesIdInput['emirates_id_expiry'] ?? null;
|
||||||
$emiratesIdName = $emiratesIdInput['name'] ?? null;
|
$emiratesIdName = $emiratesIdInput['name'] ?? null;
|
||||||
|
if ($emiratesIdName) {
|
||||||
|
$request->merge(['name' => $emiratesIdName]);
|
||||||
|
}
|
||||||
$emiratesIdDob = $emiratesIdInput['date_of_birth'] ?? $emiratesIdInput['date of birth'] ?? $emiratesIdInput['dob'] ?? null;
|
$emiratesIdDob = $emiratesIdInput['date_of_birth'] ?? $emiratesIdInput['date of birth'] ?? $emiratesIdInput['dob'] ?? null;
|
||||||
$emiratesIdNationality = $emiratesIdInput['nationality'] ?? null;
|
$emiratesIdNationality = $emiratesIdInput['nationality'] ?? null;
|
||||||
$emiratesIdIssueDate = $emiratesIdInput['issue_date'] ?? $emiratesIdInput['issue date'] ?? null;
|
$emiratesIdIssueDate = $emiratesIdInput['issue_date'] ?? $emiratesIdInput['issue date'] ?? null;
|
||||||
|
|||||||
@ -133,6 +133,12 @@ public function updateProfile(Request $request)
|
|||||||
'issuing_place' => 'nullable|string|max:255',
|
'issuing_place' => 'nullable|string|max:255',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$validator->after(function ($validator) use ($request) {
|
||||||
|
if ($request->has('full_name') && !$request->filled('full_name')) {
|
||||||
|
$validator->errors()->add('full_name', 'Failed to extract name from the Emirates ID. Please upload a clearer document.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
@ -142,6 +148,10 @@ public function updateProfile(Request $request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if ($request->filled('full_name')) {
|
||||||
|
$request->merge(['name' => $request->full_name]);
|
||||||
|
}
|
||||||
|
|
||||||
// Validate Emirates ID immutability — once set, it cannot be changed
|
// Validate Emirates ID immutability — once set, it cannot be changed
|
||||||
if ($request->filled('id_number')) {
|
if ($request->filled('id_number')) {
|
||||||
$existingProfile = $employer->employerProfile;
|
$existingProfile = $employer->employerProfile;
|
||||||
|
|||||||
@ -97,6 +97,7 @@ private function formatWorker(Worker $w)
|
|||||||
unset($ocrData['passport_number']);
|
unset($ocrData['passport_number']);
|
||||||
unset($ocrData['accompanied_by']);
|
unset($ocrData['accompanied_by']);
|
||||||
unset($ocrData['valid_until']);
|
unset($ocrData['valid_until']);
|
||||||
|
unset($ocrData['sponsor']);
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
'id' => $doc->id,
|
'id' => $doc->id,
|
||||||
@ -1008,6 +1009,7 @@ public function getWorkerDetail(Request $request, $id)
|
|||||||
unset($ocrData['passport_number']);
|
unset($ocrData['passport_number']);
|
||||||
unset($ocrData['accompanied_by']);
|
unset($ocrData['accompanied_by']);
|
||||||
unset($ocrData['valid_until']);
|
unset($ocrData['valid_until']);
|
||||||
|
unset($ocrData['sponsor']);
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
'id' => $doc->id,
|
'id' => $doc->id,
|
||||||
|
|||||||
@ -41,6 +41,13 @@ public function register(Request $request)
|
|||||||
'email.unique' => 'This email address is already registered.',
|
'email.unique' => 'This email address is already registered.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$validator->after(function ($validator) use ($request) {
|
||||||
|
$emiratesIdInput = $request->input('emirates_id');
|
||||||
|
if (is_array($emiratesIdInput) && empty($emiratesIdInput['name'])) {
|
||||||
|
$validator->errors()->add('emirates_id.name', 'Failed to extract name from the Emirates ID. Please upload a clearer document.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
@ -59,8 +66,48 @@ public function register(Request $request)
|
|||||||
|
|
||||||
$licenseExpiry = $request->license_expiry;
|
$licenseExpiry = $request->license_expiry;
|
||||||
$licenseInput = $request->input('license');
|
$licenseInput = $request->input('license');
|
||||||
|
$licenseData = null;
|
||||||
if (is_array($licenseInput)) {
|
if (is_array($licenseInput)) {
|
||||||
$licenseExpiry = $licenseExpiry ?? ($licenseInput['expiry_date'] ?? $licenseInput['license_expiry'] ?? null);
|
$licenseExpiry = $licenseExpiry ?? ($licenseInput['expiry_date'] ?? $licenseInput['license_expiry'] ?? null);
|
||||||
|
$licenseData = [
|
||||||
|
'document_type' => $licenseInput['document_type'] ?? null,
|
||||||
|
'country' => $licenseInput['country'] ?? null,
|
||||||
|
'authority' => $licenseInput['authority'] ?? null,
|
||||||
|
'license_no' => $licenseInput['license_no'] ?? $licenseInput['license_number'] ?? null,
|
||||||
|
'company_name' => $licenseInput['company_name'] ?? $licenseInput['organization_name'] ?? null,
|
||||||
|
'business_name' => $licenseInput['business_name'] ?? null,
|
||||||
|
'license_category' => $licenseInput['license_category'] ?? null,
|
||||||
|
'legal_type' => $licenseInput['legal_type'] ?? null,
|
||||||
|
'issue_date' => $licenseInput['issue_date'] ?? null,
|
||||||
|
'expiry_date' => $licenseInput['expiry_date'] ?? ($licenseInput['license_expiry'] ?? null),
|
||||||
|
'main_license_no' => $licenseInput['main_license_no'] ?? null,
|
||||||
|
'register_no' => $licenseInput['register_no'] ?? null,
|
||||||
|
'dcci_no' => $licenseInput['dcci_no'] ?? null,
|
||||||
|
'members' => $licenseInput['members'] ?? null,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$licenseData = [
|
||||||
|
'document_type' => $request->document_type,
|
||||||
|
'country' => $request->country,
|
||||||
|
'authority' => $request->authority,
|
||||||
|
'license_no' => $request->license_no,
|
||||||
|
'company_name' => $request->company_name,
|
||||||
|
'business_name' => $request->business_name,
|
||||||
|
'license_category' => $request->license_category,
|
||||||
|
'legal_type' => $request->legal_type,
|
||||||
|
'issue_date' => $request->issue_date,
|
||||||
|
'expiry_date' => $request->expiry_date,
|
||||||
|
'main_license_no' => $request->main_license_no,
|
||||||
|
'register_no' => $request->register_no,
|
||||||
|
'dcci_no' => $request->dcci_no,
|
||||||
|
'members' => $request->members,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($licenseData)) {
|
||||||
|
$licenseData = array_filter($licenseData, function ($val) {
|
||||||
|
return !is_null($val);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$emiratesIdInput = $request->input('emirates_id');
|
$emiratesIdInput = $request->input('emirates_id');
|
||||||
@ -78,6 +125,9 @@ public function register(Request $request)
|
|||||||
$emiratesId = $emiratesIdInput['emirates_id_number'] ?? $emiratesIdInput['id_number'] ?? $emiratesIdInput['id number'] ?? $emiratesIdInput['card_number'] ?? null;
|
$emiratesId = $emiratesIdInput['emirates_id_number'] ?? $emiratesIdInput['id_number'] ?? $emiratesIdInput['id number'] ?? $emiratesIdInput['card_number'] ?? null;
|
||||||
$emiratesIdExpiry = $emiratesIdInput['expiry_date'] ?? $emiratesIdInput['expiry date'] ?? $emiratesIdInput['emirates_id_expiry'] ?? null;
|
$emiratesIdExpiry = $emiratesIdInput['expiry_date'] ?? $emiratesIdInput['expiry date'] ?? $emiratesIdInput['emirates_id_expiry'] ?? null;
|
||||||
$emiratesIdName = $emiratesIdInput['name'] ?? null;
|
$emiratesIdName = $emiratesIdInput['name'] ?? null;
|
||||||
|
if ($emiratesIdName) {
|
||||||
|
$request->merge(['full_name' => $emiratesIdName]);
|
||||||
|
}
|
||||||
$emiratesIdDob = $emiratesIdInput['date_of_birth'] ?? $emiratesIdInput['date of birth'] ?? $emiratesIdInput['dob'] ?? null;
|
$emiratesIdDob = $emiratesIdInput['date_of_birth'] ?? $emiratesIdInput['date of birth'] ?? $emiratesIdInput['dob'] ?? null;
|
||||||
$emiratesIdNationality = $emiratesIdInput['nationality'] ?? null;
|
$emiratesIdNationality = $emiratesIdInput['nationality'] ?? null;
|
||||||
$emiratesIdIssueDate = $emiratesIdInput['issue_date'] ?? $emiratesIdInput['issue date'] ?? null;
|
$emiratesIdIssueDate = $emiratesIdInput['issue_date'] ?? $emiratesIdInput['issue date'] ?? null;
|
||||||
@ -94,7 +144,7 @@ public function register(Request $request)
|
|||||||
$sponsor = DB::transaction(function () use (
|
$sponsor = DB::transaction(function () use (
|
||||||
$request, $email, $licensePath, $emiratesIdPath, $emiratesId, $apiToken, $licenseExpiry,
|
$request, $email, $licensePath, $emiratesIdPath, $emiratesId, $apiToken, $licenseExpiry,
|
||||||
$emiratesIdExpiry, $emiratesIdName, $emiratesIdDob, $emiratesIdIssueDate, $emiratesIdEmployer,
|
$emiratesIdExpiry, $emiratesIdName, $emiratesIdDob, $emiratesIdIssueDate, $emiratesIdEmployer,
|
||||||
$emiratesIdIssuePlace, $emiratesIdOccupation
|
$emiratesIdIssuePlace, $emiratesIdOccupation, $licenseData
|
||||||
) {
|
) {
|
||||||
return Sponsor::create([
|
return Sponsor::create([
|
||||||
'full_name' => $request->full_name,
|
'full_name' => $request->full_name,
|
||||||
@ -122,6 +172,7 @@ public function register(Request $request)
|
|||||||
'emirates_id_employer' => $emiratesIdEmployer,
|
'emirates_id_employer' => $emiratesIdEmployer,
|
||||||
'emirates_id_issue_place' => $emiratesIdIssuePlace,
|
'emirates_id_issue_place' => $emiratesIdIssuePlace,
|
||||||
'emirates_id_occupation' => $emiratesIdOccupation,
|
'emirates_id_occupation' => $emiratesIdOccupation,
|
||||||
|
'license_data' => $licenseData,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -305,7 +305,51 @@ public function getProfile(Request $request)
|
|||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'data' => [
|
'data' => [
|
||||||
'sponsor' => [
|
'sponsor' => $this->buildSponsorResponse($sponsor)
|
||||||
|
]
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the standardized sponsor response array with nested license and emirates_id objects.
|
||||||
|
*/
|
||||||
|
private function buildSponsorResponse(Sponsor $sponsor): array
|
||||||
|
{
|
||||||
|
$licenseData = [
|
||||||
|
'license_number' => $sponsor->license_data['license_no'] ?? $sponsor->license_data['license_number'] ?? null,
|
||||||
|
'organization_name' => $sponsor->organization_name,
|
||||||
|
'expiry_date' => $sponsor->license_expiry ? $sponsor->license_expiry->toDateString() : ($sponsor->license_data['expiry_date'] ?? null),
|
||||||
|
'document_type' => $sponsor->license_data['document_type'] ?? null,
|
||||||
|
'country' => $sponsor->license_data['country'] ?? null,
|
||||||
|
'authority' => $sponsor->license_data['authority'] ?? null,
|
||||||
|
'license_no' => $sponsor->license_data['license_no'] ?? null,
|
||||||
|
'company_name' => $sponsor->license_data['company_name'] ?? null,
|
||||||
|
'business_name' => $sponsor->license_data['business_name'] ?? null,
|
||||||
|
'license_category' => $sponsor->license_data['license_category'] ?? null,
|
||||||
|
'legal_type' => $sponsor->license_data['legal_type'] ?? null,
|
||||||
|
'issue_date' => $sponsor->license_data['issue_date'] ?? null,
|
||||||
|
'main_license_no' => $sponsor->license_data['main_license_no'] ?? null,
|
||||||
|
'register_no' => $sponsor->license_data['register_no'] ?? null,
|
||||||
|
'dcci_no' => $sponsor->license_data['dcci_no'] ?? null,
|
||||||
|
'members' => $sponsor->license_data['members'] ?? [],
|
||||||
|
];
|
||||||
|
|
||||||
|
$emiratesIdData = null;
|
||||||
|
if ($sponsor->emirates_id) {
|
||||||
|
$emiratesIdData = [
|
||||||
|
'emirates_id_number' => $sponsor->emirates_id,
|
||||||
|
'name' => $sponsor->emirates_id_name,
|
||||||
|
'nationality' => $sponsor->nationality,
|
||||||
|
'date_of_birth' => $sponsor->emirates_id_dob,
|
||||||
|
'expiry_date' => $sponsor->emirates_id_expiry,
|
||||||
|
'issue_date' => $sponsor->emirates_id_issue_date,
|
||||||
|
'employer' => $sponsor->emirates_id_employer,
|
||||||
|
'issue_place' => $sponsor->emirates_id_issue_place,
|
||||||
|
'occupation' => $sponsor->emirates_id_occupation,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
'id' => $sponsor->id,
|
'id' => $sponsor->id,
|
||||||
'full_name' => $sponsor->full_name,
|
'full_name' => $sponsor->full_name,
|
||||||
'organization_name' => $sponsor->organization_name,
|
'organization_name' => $sponsor->organization_name,
|
||||||
@ -322,9 +366,10 @@ public function getProfile(Request $request)
|
|||||||
'license_expiry' => $sponsor->license_expiry ? $sponsor->license_expiry->toDateString() : null,
|
'license_expiry' => $sponsor->license_expiry ? $sponsor->license_expiry->toDateString() : null,
|
||||||
'validity' => $sponsor->license_expiry ? ($sponsor->license_expiry->isFuture() ? 'Valid' : 'Expired') : 'Pending Review',
|
'validity' => $sponsor->license_expiry ? ($sponsor->license_expiry->isFuture() ? 'Valid' : 'Expired') : 'Pending Review',
|
||||||
'joined_at' => $sponsor->created_at->toIso8601String(),
|
'joined_at' => $sponsor->created_at->toIso8601String(),
|
||||||
]
|
'fcm_token' => $sponsor->fcm_token,
|
||||||
]
|
'license' => $licenseData,
|
||||||
], 200);
|
'emirates_id' => $emiratesIdData,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -394,4 +439,276 @@ public function changePassword(Request $request)
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/sponsors/profile/update
|
||||||
|
*
|
||||||
|
* Updates the authenticated sponsor's profile.
|
||||||
|
*/
|
||||||
|
public function updateProfile(Request $request)
|
||||||
|
{
|
||||||
|
/** @var Sponsor $sponsor */
|
||||||
|
$sponsor = $request->attributes->get('sponsor');
|
||||||
|
|
||||||
|
if (!$sponsor) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Unauthorized.'
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find matching employer user using sponsor's original email
|
||||||
|
$oldEmail = $sponsor->getOriginal('email') ?? $sponsor->email;
|
||||||
|
$matchingUser = \App\Models\User::where('email', $oldEmail)
|
||||||
|
->where('role', 'employer')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$matchingUserId = $matchingUser ? $matchingUser->id : 'NULL';
|
||||||
|
|
||||||
|
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
|
||||||
|
'name' => 'required_without:full_name|nullable|string|max:255',
|
||||||
|
'full_name' => 'required_without:name|nullable|string|max:255',
|
||||||
|
'email' => 'required|email|max:255|unique:sponsors,email,' . $sponsor->id . '|unique:users,email,' . $matchingUserId,
|
||||||
|
'mobile' => 'required|string|max:255|unique:sponsors,mobile,' . $sponsor->id,
|
||||||
|
'organization_name' => 'required|string|max:255',
|
||||||
|
'city' => 'required|string|max:100',
|
||||||
|
'address' => 'required|string|max:255',
|
||||||
|
'nationality' => 'required|string|max:100',
|
||||||
|
'country_code' => 'required|string|max:10',
|
||||||
|
'fcm_token' => 'nullable|string|max:255',
|
||||||
|
|
||||||
|
// Emirates ID — accepts nested object OR flat fields
|
||||||
|
'emirates_id' => 'nullable|array',
|
||||||
|
'emirates_id.emirates_id_number' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.name' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.nationality' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.date_of_birth' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.expiry_date' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.issue_date' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.employer' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.issue_place' => 'nullable|string|max:255',
|
||||||
|
'emirates_id.occupation' => 'nullable|string|max:255',
|
||||||
|
|
||||||
|
// Flat emirates ID fields (backward compatibility)
|
||||||
|
'id_number' => 'nullable|string|max:255',
|
||||||
|
'card_number' => 'nullable|string|max:255',
|
||||||
|
'date_of_birth' => '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',
|
||||||
|
|
||||||
|
// License — accepts nested object OR flat fields
|
||||||
|
'license' => 'nullable|array',
|
||||||
|
'license.document_type' => 'nullable|string|max:255',
|
||||||
|
'license.country' => 'nullable|string|max:255',
|
||||||
|
'license.authority' => 'nullable|string|max:255',
|
||||||
|
'license.license_no' => 'nullable|string|max:255',
|
||||||
|
'license.company_name' => 'nullable|string|max:255',
|
||||||
|
'license.business_name' => 'nullable|string|max:255',
|
||||||
|
'license.license_category' => 'nullable|string|max:255',
|
||||||
|
'license.legal_type' => 'nullable|string|max:255',
|
||||||
|
'license.main_license_no' => 'nullable|string|max:255',
|
||||||
|
'license.register_no' => 'nullable|string|max:255',
|
||||||
|
'license.dcci_no' => 'nullable|string|max:255',
|
||||||
|
'license.members' => 'nullable|array',
|
||||||
|
|
||||||
|
// Flat license fields (backward compatibility)
|
||||||
|
'document_type' => 'nullable|string|max:255',
|
||||||
|
'country' => 'nullable|string|max:255',
|
||||||
|
'authority' => 'nullable|string|max:255',
|
||||||
|
'license_no' => 'nullable|string|max:255',
|
||||||
|
'company_name' => 'nullable|string|max:255',
|
||||||
|
'business_name' => 'nullable|string|max:255',
|
||||||
|
'license_category' => 'nullable|string|max:255',
|
||||||
|
'legal_type' => 'nullable|string|max:255',
|
||||||
|
'main_license_no' => 'nullable|string|max:255',
|
||||||
|
'register_no' => 'nullable|string|max:255',
|
||||||
|
'dcci_no' => 'nullable|string|max:255',
|
||||||
|
'members' => 'nullable|array',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validator->after(function ($validator) use ($request) {
|
||||||
|
$nameFromEid = $request->input('emirates_id.name') ?? $request->input('full_name');
|
||||||
|
if ($request->has('full_name') && !$request->filled('full_name') && !$nameFromEid) {
|
||||||
|
$validator->errors()->add('full_name', 'Failed to extract name from the Emirates ID. Please upload a clearer document.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Validation error.',
|
||||||
|
'errors' => $validator->errors()
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Resolve nested emirates_id input into flat variables
|
||||||
|
$eidInput = $request->input('emirates_id');
|
||||||
|
$eidNumber = null;
|
||||||
|
$eidName = null;
|
||||||
|
$eidDob = null;
|
||||||
|
$eidExpiry = null;
|
||||||
|
$eidIssueDate = null;
|
||||||
|
$eidEmployer = null;
|
||||||
|
$eidIssuePlace = null;
|
||||||
|
$eidOccupation = null;
|
||||||
|
$eidCardNumber = null;
|
||||||
|
$eidGender = null;
|
||||||
|
|
||||||
|
if (is_array($eidInput)) {
|
||||||
|
$eidNumber = $eidInput['emirates_id_number'] ?? $eidInput['id_number'] ?? null;
|
||||||
|
$eidName = $eidInput['name'] ?? null;
|
||||||
|
$eidDob = $eidInput['date_of_birth'] ?? $eidInput['dob'] ?? null;
|
||||||
|
$eidExpiry = $eidInput['expiry_date'] ?? null;
|
||||||
|
$eidIssueDate = $eidInput['issue_date'] ?? null;
|
||||||
|
$eidEmployer = $eidInput['employer'] ?? null;
|
||||||
|
$eidIssuePlace = $eidInput['issue_place'] ?? $eidInput['issuing_place'] ?? null;
|
||||||
|
$eidOccupation = $eidInput['occupation'] ?? null;
|
||||||
|
$eidCardNumber = $eidInput['card_number'] ?? null;
|
||||||
|
$eidGender = $eidInput['gender'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flat field fallbacks (backward compatibility)
|
||||||
|
$eidNumber = $eidNumber ?? $request->input('id_number');
|
||||||
|
$eidName = $eidName ?? $request->input('full_name');
|
||||||
|
$eidDob = $eidDob ?? $request->input('date_of_birth');
|
||||||
|
$eidExpiry = $eidExpiry ?? $request->input('expiry_date');
|
||||||
|
$eidIssueDate = $eidIssueDate ?? $request->input('issue_date');
|
||||||
|
$eidEmployer = $eidEmployer ?? $request->input('employer');
|
||||||
|
$eidIssuePlace = $eidIssuePlace ?? $request->input('issuing_place');
|
||||||
|
$eidOccupation = $eidOccupation ?? $request->input('occupation');
|
||||||
|
$eidCardNumber = $eidCardNumber ?? $request->input('card_number');
|
||||||
|
$eidGender = $eidGender ?? $request->input('gender');
|
||||||
|
|
||||||
|
$nameToUse = $eidName ?? $request->name ?? $request->full_name;
|
||||||
|
|
||||||
|
// Validate Emirates ID immutability — once set, it cannot be changed
|
||||||
|
if ($eidNumber) {
|
||||||
|
if ($sponsor->emirates_id && $sponsor->emirates_id !== $eidNumber) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Emirates ID mismatch. You cannot change your registered Emirates ID number.',
|
||||||
|
'errors' => [
|
||||||
|
'id_number' => ['Emirates ID mismatch.']
|
||||||
|
]
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync with corresponding employer user and profile records if found
|
||||||
|
if ($matchingUser) {
|
||||||
|
$userData = [
|
||||||
|
'name' => $nameToUse,
|
||||||
|
'email' => $request->email,
|
||||||
|
];
|
||||||
|
if ($request->has('fcm_token')) {
|
||||||
|
$userData['fcm_token'] = $request->fcm_token;
|
||||||
|
}
|
||||||
|
$matchingUser->update($userData);
|
||||||
|
|
||||||
|
$profile = $matchingUser->employerProfile;
|
||||||
|
if (!$profile) {
|
||||||
|
$profile = new \App\Models\EmployerProfile(['user_id' => $matchingUser->id]);
|
||||||
|
}
|
||||||
|
$profile->address = $request->address;
|
||||||
|
$profile->phone = $request->mobile;
|
||||||
|
|
||||||
|
if ($eidNumber) { $profile->emirates_id_number = $eidNumber; }
|
||||||
|
if ($eidCardNumber) { $profile->emirates_id_card_number = $eidCardNumber; }
|
||||||
|
if ($eidName) { $profile->emirates_id_name = $eidName; }
|
||||||
|
if ($eidDob) { $profile->emirates_id_dob = $eidDob; }
|
||||||
|
if ($request->has('nationality')) { $profile->nationality = $request->nationality; }
|
||||||
|
if ($eidGender) { $profile->emirates_id_gender = $eidGender; }
|
||||||
|
if ($eidIssueDate) { $profile->emirates_id_issue_date = $eidIssueDate; }
|
||||||
|
if ($eidExpiry) { $profile->emirates_id_expiry = $eidExpiry; }
|
||||||
|
if ($eidOccupation) { $profile->emirates_id_occupation = $eidOccupation; }
|
||||||
|
if ($eidEmployer) { $profile->emirates_id_employer = $eidEmployer; }
|
||||||
|
if ($eidIssuePlace) { $profile->emirates_id_issue_place = $eidIssuePlace; }
|
||||||
|
|
||||||
|
$profile->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Sponsor profile
|
||||||
|
$sponsorData = [
|
||||||
|
'full_name' => $nameToUse,
|
||||||
|
'email' => $request->email,
|
||||||
|
'mobile' => $request->mobile,
|
||||||
|
'organization_name' => $request->organization_name,
|
||||||
|
'city' => $request->city,
|
||||||
|
'address' => $request->address,
|
||||||
|
'nationality' => $request->nationality,
|
||||||
|
'country_code' => $request->country_code,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($request->has('fcm_token')) {
|
||||||
|
$sponsorData['fcm_token'] = $request->fcm_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($eidNumber) { $sponsorData['emirates_id'] = $eidNumber; }
|
||||||
|
if ($eidCardNumber) { $sponsorData['emirates_id_card_number'] = $eidCardNumber; }
|
||||||
|
if ($eidName) { $sponsorData['emirates_id_name'] = $eidName; }
|
||||||
|
if ($eidDob) { $sponsorData['emirates_id_dob'] = $eidDob; }
|
||||||
|
if ($eidGender) { $sponsorData['emirates_id_gender'] = $eidGender; }
|
||||||
|
if ($eidIssueDate) { $sponsorData['emirates_id_issue_date'] = $eidIssueDate; }
|
||||||
|
if ($eidExpiry) { $sponsorData['emirates_id_expiry'] = $eidExpiry; }
|
||||||
|
if ($eidOccupation) { $sponsorData['emirates_id_occupation'] = $eidOccupation; }
|
||||||
|
if ($eidEmployer) { $sponsorData['emirates_id_employer'] = $eidEmployer; }
|
||||||
|
if ($eidIssuePlace) { $sponsorData['emirates_id_issue_place'] = $eidIssuePlace; }
|
||||||
|
|
||||||
|
// Parse and merge license data — from nested license object or flat fields
|
||||||
|
$currentLicenseData = is_array($sponsor->license_data) ? $sponsor->license_data : [];
|
||||||
|
$licenseInput = $request->input('license');
|
||||||
|
$newLicenseData = [];
|
||||||
|
|
||||||
|
if (is_array($licenseInput)) {
|
||||||
|
foreach ([
|
||||||
|
'document_type', 'country', 'authority', 'license_no', 'company_name',
|
||||||
|
'business_name', 'license_category', 'legal_type', 'issue_date', 'expiry_date',
|
||||||
|
'main_license_no', 'register_no', 'dcci_no', 'members'
|
||||||
|
] as $field) {
|
||||||
|
if (isset($licenseInput[$field])) {
|
||||||
|
$newLicenseData[$field] = $licenseInput[$field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flat field fallbacks (backward compatibility)
|
||||||
|
foreach ([
|
||||||
|
'document_type', 'country', 'authority', 'license_no', 'company_name',
|
||||||
|
'business_name', 'license_category', 'legal_type', 'issue_date', 'expiry_date',
|
||||||
|
'main_license_no', 'register_no', 'dcci_no', 'members'
|
||||||
|
] as $field) {
|
||||||
|
if (!isset($newLicenseData[$field]) && $request->has($field)) {
|
||||||
|
$newLicenseData[$field] = $request->input($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($newLicenseData)) {
|
||||||
|
$sponsorData['license_data'] = array_merge($currentLicenseData, $newLicenseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sponsor->update($sponsorData);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Profile updated successfully.',
|
||||||
|
'data' => [
|
||||||
|
'sponsor' => $this->buildSponsorResponse($sponsor)
|
||||||
|
]
|
||||||
|
], 200);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
logger()->error('Mobile Sponsor Update Profile Failure: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'An error occurred while updating profile.',
|
||||||
|
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -338,6 +338,14 @@ public function uploadEmiratesId(Request $request)
|
|||||||
$extractedIssueDate = $backOcr['issue_date'] ?? null;
|
$extractedIssueDate = $backOcr['issue_date'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($request->hasFile('emirates_id_front') || $request->hasFile('emirates_id_file')) && empty($extractedName)) {
|
||||||
|
return response()->json([
|
||||||
|
'errors' => [
|
||||||
|
'emirates_id_front' => ['Failed to extract name from the Emirates ID. Please upload a clear image.']
|
||||||
|
]
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
$pending = session('pending_employer_registration');
|
$pending = session('pending_employer_registration');
|
||||||
$pending['emirates_id_file'] = null;
|
$pending['emirates_id_file'] = null;
|
||||||
$pending['emirates_id_number'] = $extractedIdNumber;
|
$pending['emirates_id_number'] = $extractedIdNumber;
|
||||||
@ -351,6 +359,14 @@ public function uploadEmiratesId(Request $request)
|
|||||||
$pending['emirates_id_employer'] = $extractedEmployer;
|
$pending['emirates_id_employer'] = $extractedEmployer;
|
||||||
$pending['emirates_id_issue_place'] = $extractedIssuePlace;
|
$pending['emirates_id_issue_place'] = $extractedIssuePlace;
|
||||||
$pending['emirates_id_issue_date'] = $extractedIssueDate;
|
$pending['emirates_id_issue_date'] = $extractedIssueDate;
|
||||||
|
|
||||||
|
if (!empty($extractedName)) {
|
||||||
|
if (isset($pending['company_name']) && (empty($pending['company_name']) || $pending['company_name'] === ($pending['name'] ?? '') . ' Household')) {
|
||||||
|
$pending['company_name'] = $extractedName . ' Household';
|
||||||
|
}
|
||||||
|
$pending['name'] = $extractedName;
|
||||||
|
}
|
||||||
|
|
||||||
session(['pending_employer_registration' => $pending]);
|
session(['pending_employer_registration' => $pending]);
|
||||||
session(['employer_emirates_id_uploaded' => true]);
|
session(['employer_emirates_id_uploaded' => true]);
|
||||||
|
|
||||||
|
|||||||
@ -170,6 +170,62 @@ public function update(Request $request)
|
|||||||
|
|
||||||
$oldEmail = $user->getOriginal('email') ?? $user->email;
|
$oldEmail = $user->getOriginal('email') ?? $user->email;
|
||||||
|
|
||||||
|
// Update EmployerProfile
|
||||||
|
$profile = $user->employerProfile;
|
||||||
|
if (!$profile) {
|
||||||
|
$profile = new EmployerProfile(['user_id' => $user->id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle physical uploads/OCR for Emirates ID first to allow name autofill
|
||||||
|
$uploaded = false;
|
||||||
|
$extractedIdNumber = null;
|
||||||
|
$extractedExpiry = null;
|
||||||
|
$extractedName = null;
|
||||||
|
$extractedDob = null;
|
||||||
|
$extractedNationality = null;
|
||||||
|
$extractedCardNumber = null;
|
||||||
|
$extractedGender = null;
|
||||||
|
$extractedOccupation = null;
|
||||||
|
$extractedEmployer = null;
|
||||||
|
$extractedIssuePlace = null;
|
||||||
|
$extractedIssueDate = null;
|
||||||
|
|
||||||
|
if ($request->hasFile('emirates_id_front')) {
|
||||||
|
$file = $request->file('emirates_id_front');
|
||||||
|
$ocrFront = \App\Services\OcrDocumentService::extractEmiratesIdFrontData($file);
|
||||||
|
$extractedIdNumber = $ocrFront['emirates_id_number'] ?? null;
|
||||||
|
$extractedName = $ocrFront['name'] ?? null;
|
||||||
|
$extractedDob = $ocrFront['date_of_birth'] ?? null;
|
||||||
|
$extractedNationality = $ocrFront['nationality'] ?? null;
|
||||||
|
$extractedCardNumber = $ocrFront['card_number'] ?? null;
|
||||||
|
$extractedGender = $ocrFront['gender'] ?? null;
|
||||||
|
$extractedOccupation = $ocrFront['occupation'] ?? null;
|
||||||
|
$extractedEmployer = $ocrFront['employer'] ?? null;
|
||||||
|
$extractedIssuePlace = $ocrFront['issue_place'] ?? null;
|
||||||
|
$profile->emirates_id_front = '[DELETED_FOR_PDPL_COMPLIANCE]';
|
||||||
|
$uploaded = true;
|
||||||
|
}
|
||||||
|
if ($request->hasFile('emirates_id_back')) {
|
||||||
|
$file = $request->file('emirates_id_back');
|
||||||
|
$ocrBack = \App\Services\OcrDocumentService::extractEmiratesIdBackData($file);
|
||||||
|
$extractedExpiry = $ocrBack['expiry_date'] ?? null;
|
||||||
|
$extractedIssueDate = $ocrBack['issue_date'] ?? null;
|
||||||
|
$profile->emirates_id_back = '[DELETED_FOR_PDPL_COMPLIANCE]';
|
||||||
|
$uploaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($uploaded) {
|
||||||
|
// Validate that name was extracted
|
||||||
|
if ($request->hasFile('emirates_id_front') && empty($extractedName)) {
|
||||||
|
return back()->withErrors(['emirates_id_front' => 'Failed to extract name from the Emirates ID. Please upload a clear image.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autofill user's name
|
||||||
|
if (!empty($extractedName)) {
|
||||||
|
$request->merge(['name' => $extractedName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update User Model
|
// Update User Model
|
||||||
$user->update([
|
$user->update([
|
||||||
'name' => $request->name,
|
'name' => $request->name,
|
||||||
@ -179,18 +235,50 @@ public function update(Request $request)
|
|||||||
// Sync with corresponding sponsor record if found
|
// Sync with corresponding sponsor record if found
|
||||||
$matchingSponsor = \App\Models\Sponsor::where('email', $oldEmail)->first();
|
$matchingSponsor = \App\Models\Sponsor::where('email', $oldEmail)->first();
|
||||||
if ($matchingSponsor) {
|
if ($matchingSponsor) {
|
||||||
$matchingSponsor->update([
|
$sponsorData = [
|
||||||
'full_name' => $request->name,
|
'full_name' => $request->name,
|
||||||
'email' => $request->email,
|
'email' => $request->email,
|
||||||
'mobile' => $request->phone,
|
'mobile' => $request->phone,
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if ($uploaded) {
|
||||||
|
if ($extractedIdNumber) {
|
||||||
|
$sponsorData['emirates_id'] = $extractedIdNumber;
|
||||||
|
}
|
||||||
|
if ($extractedExpiry) {
|
||||||
|
$sponsorData['emirates_id_expiry'] = $extractedExpiry;
|
||||||
|
}
|
||||||
|
if ($extractedName) {
|
||||||
|
$sponsorData['emirates_id_name'] = $extractedName;
|
||||||
|
}
|
||||||
|
if ($extractedDob) {
|
||||||
|
$sponsorData['emirates_id_dob'] = $extractedDob;
|
||||||
|
}
|
||||||
|
if ($extractedNationality) {
|
||||||
|
$sponsorData['nationality'] = $extractedNationality;
|
||||||
|
}
|
||||||
|
if ($extractedGender) {
|
||||||
|
$sponsorData['emirates_id_gender'] = $extractedGender;
|
||||||
|
}
|
||||||
|
if ($extractedOccupation) {
|
||||||
|
$sponsorData['emirates_id_occupation'] = $extractedOccupation;
|
||||||
|
}
|
||||||
|
if ($extractedEmployer) {
|
||||||
|
$sponsorData['emirates_id_employer'] = $extractedEmployer;
|
||||||
|
}
|
||||||
|
if ($extractedIssuePlace) {
|
||||||
|
$sponsorData['emirates_id_issue_place'] = $extractedIssuePlace;
|
||||||
|
}
|
||||||
|
if ($extractedIssueDate) {
|
||||||
|
$sponsorData['emirates_id_issue_date'] = $extractedIssueDate;
|
||||||
|
}
|
||||||
|
if ($extractedCardNumber) {
|
||||||
|
$sponsorData['emirates_id_card_number'] = $extractedCardNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$matchingSponsor->update($sponsorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update EmployerProfile
|
|
||||||
$profile = $user->employerProfile;
|
|
||||||
if (!$profile) {
|
|
||||||
$profile = new EmployerProfile(['user_id' => $user->id]);
|
|
||||||
}
|
|
||||||
$profile->phone = $request->phone;
|
$profile->phone = $request->phone;
|
||||||
|
|
||||||
if ($request->has('company_name')) {
|
if ($request->has('company_name')) {
|
||||||
@ -202,7 +290,7 @@ public function update(Request $request)
|
|||||||
if ($request->has('notifications')) {
|
if ($request->has('notifications')) {
|
||||||
$profile->notifications = $request->notifications;
|
$profile->notifications = $request->notifications;
|
||||||
}
|
}
|
||||||
if ($request->has('nationality')) {
|
if ($request->has('nationality') && !$uploaded) {
|
||||||
$profile->nationality = $request->nationality;
|
$profile->nationality = $request->nationality;
|
||||||
}
|
}
|
||||||
if ($request->has('family_size')) {
|
if ($request->has('family_size')) {
|
||||||
@ -227,35 +315,38 @@ public function update(Request $request)
|
|||||||
$profile->push_notifications = $request->push_notifications;
|
$profile->push_notifications = $request->push_notifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle physical uploads/OCR for Emirates ID
|
|
||||||
$uploaded = false;
|
|
||||||
$extractedIdNumber = null;
|
|
||||||
$extractedExpiry = null;
|
|
||||||
|
|
||||||
if ($request->hasFile('emirates_id_front')) {
|
|
||||||
$file = $request->file('emirates_id_front');
|
|
||||||
$ocrFront = \App\Services\OcrDocumentService::extractData($file);
|
|
||||||
$extractedIdNumber = $ocrFront['document_number'];
|
|
||||||
$extractedExpiry = $ocrFront['expiry_date'];
|
|
||||||
$profile->emirates_id_front = '[DELETED_FOR_PDPL_COMPLIANCE]';
|
|
||||||
$uploaded = true;
|
|
||||||
}
|
|
||||||
if ($request->hasFile('emirates_id_back')) {
|
|
||||||
$file = $request->file('emirates_id_back');
|
|
||||||
$ocrBack = \App\Services\OcrDocumentService::extractData($file);
|
|
||||||
if (empty($extractedIdNumber)) {
|
|
||||||
$extractedIdNumber = $ocrBack['document_number'];
|
|
||||||
}
|
|
||||||
if (empty($extractedExpiry)) {
|
|
||||||
$extractedExpiry = $ocrBack['expiry_date'];
|
|
||||||
}
|
|
||||||
$profile->emirates_id_back = '[DELETED_FOR_PDPL_COMPLIANCE]';
|
|
||||||
$uploaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uploaded) {
|
if ($uploaded) {
|
||||||
$profile->emirates_id_number = $extractedIdNumber ?? ('784-' . rand(1975, 2005) . '-' . rand(1000000, 9999999) . '-' . rand(1, 9));
|
$profile->emirates_id_number = $extractedIdNumber ?? $profile->emirates_id_number ?? ('784-' . rand(1975, 2005) . '-' . rand(1000000, 9999999) . '-' . rand(1, 9));
|
||||||
$profile->emirates_id_expiry = $extractedExpiry ?? now()->addYears(rand(2, 4))->toDateString();
|
$profile->emirates_id_expiry = $extractedExpiry ?? $profile->emirates_id_expiry ?? now()->addYears(rand(2, 4))->toDateString();
|
||||||
|
|
||||||
|
if ($extractedName) {
|
||||||
|
$profile->emirates_id_name = $extractedName;
|
||||||
|
}
|
||||||
|
if ($extractedDob) {
|
||||||
|
$profile->emirates_id_dob = $extractedDob;
|
||||||
|
}
|
||||||
|
if ($extractedNationality) {
|
||||||
|
$profile->nationality = $extractedNationality;
|
||||||
|
}
|
||||||
|
if ($extractedCardNumber) {
|
||||||
|
$profile->emirates_id_card_number = $extractedCardNumber;
|
||||||
|
}
|
||||||
|
if ($extractedGender) {
|
||||||
|
$profile->emirates_id_gender = $extractedGender;
|
||||||
|
}
|
||||||
|
if ($extractedOccupation) {
|
||||||
|
$profile->emirates_id_occupation = $extractedOccupation;
|
||||||
|
}
|
||||||
|
if ($extractedEmployer) {
|
||||||
|
$profile->emirates_id_employer = $extractedEmployer;
|
||||||
|
}
|
||||||
|
if ($extractedIssuePlace) {
|
||||||
|
$profile->emirates_id_issue_place = $extractedIssuePlace;
|
||||||
|
}
|
||||||
|
if ($extractedIssueDate) {
|
||||||
|
$profile->emirates_id_issue_date = $extractedIssueDate;
|
||||||
|
}
|
||||||
|
|
||||||
$profile->verification_status = 'approved';
|
$profile->verification_status = 'approved';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,6 +45,7 @@ class Sponsor extends Authenticatable
|
|||||||
'emirates_id_occupation',
|
'emirates_id_occupation',
|
||||||
'emirates_id_card_number',
|
'emirates_id_card_number',
|
||||||
'emirates_id_gender',
|
'emirates_id_gender',
|
||||||
|
'license_data',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
@ -59,6 +60,7 @@ class Sponsor extends Authenticatable
|
|||||||
'subscription_end_date' => 'datetime',
|
'subscription_end_date' => 'datetime',
|
||||||
'last_login_at' => 'datetime',
|
'last_login_at' => 'datetime',
|
||||||
'license_expiry' => 'datetime',
|
'license_expiry' => 'datetime',
|
||||||
|
'license_data' => 'array',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function hasActiveSubscription(): bool
|
public function hasActiveSubscription(): bool
|
||||||
@ -66,4 +68,58 @@ public function hasActiveSubscription(): bool
|
|||||||
return $this->subscription_status === 'active' &&
|
return $this->subscription_status === 'active' &&
|
||||||
($this->subscription_end_date === null || $this->subscription_end_date->isFuture());
|
($this->subscription_end_date === null || $this->subscription_end_date->isFuture());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the model instance to an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
$array = parent::toArray();
|
||||||
|
|
||||||
|
// Remove any flat properties that should be nested
|
||||||
|
unset($array['license_data']);
|
||||||
|
|
||||||
|
$licenseDataObj = [
|
||||||
|
'license_number' => $this->license_data['license_no'] ?? $this->license_data['license_number'] ?? null,
|
||||||
|
'organization_name' => $this->organization_name,
|
||||||
|
'expiry_date' => $this->license_expiry ? $this->license_expiry->toDateString() : ($this->license_data['expiry_date'] ?? null),
|
||||||
|
'document_type' => $this->license_data['document_type'] ?? null,
|
||||||
|
'country' => $this->license_data['country'] ?? null,
|
||||||
|
'authority' => $this->license_data['authority'] ?? null,
|
||||||
|
'license_no' => $this->license_data['license_no'] ?? null,
|
||||||
|
'company_name' => $this->license_data['company_name'] ?? null,
|
||||||
|
'business_name' => $this->license_data['business_name'] ?? null,
|
||||||
|
'license_category' => $this->license_data['license_category'] ?? null,
|
||||||
|
'legal_type' => $this->license_data['legal_type'] ?? null,
|
||||||
|
'issue_date' => $this->license_data['issue_date'] ?? null,
|
||||||
|
'main_license_no' => $this->license_data['main_license_no'] ?? null,
|
||||||
|
'register_no' => $this->license_data['register_no'] ?? null,
|
||||||
|
'dcci_no' => $this->license_data['dcci_no'] ?? null,
|
||||||
|
'members' => $this->license_data['members'] ?? [],
|
||||||
|
];
|
||||||
|
|
||||||
|
$emiratesIdData = null;
|
||||||
|
if ($this->emirates_id) {
|
||||||
|
$emiratesIdData = [
|
||||||
|
'emirates_id_number' => $this->emirates_id,
|
||||||
|
'name' => $this->emirates_id_name,
|
||||||
|
'nationality' => $this->nationality,
|
||||||
|
'date_of_birth' => $this->emirates_id_dob,
|
||||||
|
'expiry_date' => $this->emirates_id_expiry,
|
||||||
|
'issue_date' => $this->emirates_id_issue_date,
|
||||||
|
'employer' => $this->emirates_id_employer,
|
||||||
|
'issue_place' => $this->emirates_id_issue_place,
|
||||||
|
'occupation' => $this->emirates_id_occupation,
|
||||||
|
'card_number' => $this->emirates_id_card_number,
|
||||||
|
'gender' => $this->emirates_id_gender,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge($array, [
|
||||||
|
'license' => $licenseDataObj,
|
||||||
|
'emirates_id' => $emiratesIdData,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('sponsors', function (Blueprint $table) {
|
||||||
|
if (!Schema::hasColumn('sponsors', 'license_data')) {
|
||||||
|
$table->json('license_data')->nullable()->after('license_expiry');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('sponsors', function (Blueprint $table) {
|
||||||
|
if (Schema::hasColumn('sponsors', 'license_data')) {
|
||||||
|
$table->dropColumn('license_data');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -74,6 +74,78 @@
|
|||||||
"expiry_date": {
|
"expiry_date": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "2028-06-12"
|
"example": "2028-06-12"
|
||||||
|
},
|
||||||
|
"document_type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "dubai_commercial_license"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "United Arab Emirates"
|
||||||
|
},
|
||||||
|
"authority": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Dubai Economy and Tourism"
|
||||||
|
},
|
||||||
|
"license_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"company_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"business_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"license_category": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Dep. of Economic Development"
|
||||||
|
},
|
||||||
|
"legal_type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Limited Liability Company Single Owner(LLC- - SO)"
|
||||||
|
},
|
||||||
|
"issue_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "06/03/2019"
|
||||||
|
},
|
||||||
|
"main_license_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"register_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1656486"
|
||||||
|
},
|
||||||
|
"dcci_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "317412"
|
||||||
|
},
|
||||||
|
"members": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"person_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "752967"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Lo lo wallus issued in"
|
||||||
|
},
|
||||||
|
"nationality": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "India"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Shares Owner Who"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -586,7 +658,28 @@
|
|||||||
"description": "Returns the full profile of the authenticated sponsor.",
|
"description": "Returns the full profile of the authenticated sponsor.",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Profile retrieved successfully."
|
"description": "Profile retrieved successfully.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"success": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"sponsor": {
|
||||||
|
"$ref": "#/components/schemas/Sponsor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthenticated."
|
"description": "Unauthenticated."
|
||||||
@ -594,6 +687,248 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/sponsors/profile/update": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Sponsor"
|
||||||
|
],
|
||||||
|
"summary": "Update Sponsor Profile Details",
|
||||||
|
"description": "Updates the authenticated sponsor's profile details including optional Emirates ID metadata. Password changes are not supported via this endpoint.",
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"email",
|
||||||
|
"mobile",
|
||||||
|
"organization_name",
|
||||||
|
"city",
|
||||||
|
"address",
|
||||||
|
"nationality",
|
||||||
|
"country_code"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Ahmad Bin Ahmed",
|
||||||
|
"description": "Sponsor's full name (required if full_name is not provided)"
|
||||||
|
},
|
||||||
|
"full_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Ahmad Bin Ahmed",
|
||||||
|
"description": "Sponsor's full name (required if name is not provided)"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "email",
|
||||||
|
"example": "test.sponsor@example.com"
|
||||||
|
},
|
||||||
|
"mobile": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "+971509990001"
|
||||||
|
},
|
||||||
|
"organization_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Charity Co"
|
||||||
|
},
|
||||||
|
"city": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Abu Dhabi"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Villa 45, Street 12"
|
||||||
|
},
|
||||||
|
"nationality": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Emirati"
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "+971"
|
||||||
|
},
|
||||||
|
"fcm_token": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "fcm_token_example",
|
||||||
|
"description": "Firebase Cloud Messaging token for push notifications."
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Optional JSON object containing extracted commercial license details.",
|
||||||
|
"properties": {
|
||||||
|
"license_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"organization_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"expiry_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "05/03/2026"
|
||||||
|
},
|
||||||
|
"document_type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "dubai_commercial_license"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "United Arab Emirates"
|
||||||
|
},
|
||||||
|
"authority": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Dubai Economy and Tourism"
|
||||||
|
},
|
||||||
|
"license_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"company_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"business_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"license_category": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Dep. of Economic Development"
|
||||||
|
},
|
||||||
|
"legal_type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Limited Liability Company Single Owner(LLC- - SO)"
|
||||||
|
},
|
||||||
|
"issue_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "06/03/2019"
|
||||||
|
},
|
||||||
|
"main_license_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"register_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1656486"
|
||||||
|
},
|
||||||
|
"dcci_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "317412"
|
||||||
|
},
|
||||||
|
"members": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"person_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "752967"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Lo lo wallus issued in"
|
||||||
|
},
|
||||||
|
"nationality": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "India"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Shares Owner Who"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emirates_id": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Optional JSON object containing extracted Emirates ID details.",
|
||||||
|
"properties": {
|
||||||
|
"emirates_id_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "784-1988-5310327-2"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "KRISHNA PRASAD"
|
||||||
|
},
|
||||||
|
"nationality": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "NPL"
|
||||||
|
},
|
||||||
|
"date_of_birth": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1988-03-22"
|
||||||
|
},
|
||||||
|
"expiry_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "2028-04-11"
|
||||||
|
},
|
||||||
|
"issue_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "2023-04-11"
|
||||||
|
},
|
||||||
|
"employer": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Federal Authority"
|
||||||
|
},
|
||||||
|
"issue_place": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Abu Dhabi"
|
||||||
|
},
|
||||||
|
"occupation": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Manager"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Profile updated successfully.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"success": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Profile updated successfully."
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"sponsor": {
|
||||||
|
"$ref": "#/components/schemas/Sponsor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthenticated."
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "Validation error (duplicate mobile/email, mismatched immutable fields, or name extraction failure)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/workers/register": {
|
"/workers/register": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -6251,6 +6586,131 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "fcm_token_example"
|
"example": "fcm_token_example"
|
||||||
},
|
},
|
||||||
|
"document_type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "dubai_commercial_license"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "United Arab Emirates"
|
||||||
|
},
|
||||||
|
"authority": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Dubai Economy and Tourism"
|
||||||
|
},
|
||||||
|
"license_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"company_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"business_name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C"
|
||||||
|
},
|
||||||
|
"license_category": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Dep. of Economic Development"
|
||||||
|
},
|
||||||
|
"legal_type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Limited Liability Company Single Owner(LLC- - SO)"
|
||||||
|
},
|
||||||
|
"issue_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "06/03/2019"
|
||||||
|
},
|
||||||
|
"expiry_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "05/03/2026"
|
||||||
|
},
|
||||||
|
"main_license_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "828302"
|
||||||
|
},
|
||||||
|
"register_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1656486"
|
||||||
|
},
|
||||||
|
"dcci_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "317412"
|
||||||
|
},
|
||||||
|
"members": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"person_no": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "752967"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Lo lo wallus issued in"
|
||||||
|
},
|
||||||
|
"nationality": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "India"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Shares Owner Who"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emirates_id": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"emirates_id_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "784-1988-5310327-2"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "KRISHNA PRASAD"
|
||||||
|
},
|
||||||
|
"nationality": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "NPL"
|
||||||
|
},
|
||||||
|
"date_of_birth": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "1988-03-22"
|
||||||
|
},
|
||||||
|
"expiry_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "2028-04-11"
|
||||||
|
},
|
||||||
|
"issue_date": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "2023-04-11"
|
||||||
|
},
|
||||||
|
"employer": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Federal Authority"
|
||||||
|
},
|
||||||
|
"issue_place": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Abu Dhabi"
|
||||||
|
},
|
||||||
|
"occupation": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Manager"
|
||||||
|
},
|
||||||
|
"card_number": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "987654321"
|
||||||
|
},
|
||||||
|
"gender": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Male"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
|
|||||||
@ -72,9 +72,10 @@ export default function UploadEmiratesId({ email }) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.response && err.response.data && err.response.data.errors) {
|
if (err.response && err.response.data && err.response.data.errors) {
|
||||||
const errors = err.response.data.errors;
|
const errors = err.response.data.errors;
|
||||||
const errorMsg = errors.emirates_id_front?.[0] || errors.emirates_id_back?.[0] || 'Validation failed.';
|
const firstError = Object.values(errors).flat()[0];
|
||||||
|
const errorMsg = firstError || 'Validation failed.';
|
||||||
setError(errorMsg);
|
setError(errorMsg);
|
||||||
toast.error('Validation failed. Please verify the document.');
|
toast.error(errorMsg);
|
||||||
} else {
|
} else {
|
||||||
toast.error('Scan extraction failed. Please try again.');
|
toast.error('Scan extraction failed. Please try again.');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -159,6 +159,7 @@
|
|||||||
// Sponsors can ONLY access: dashboard and charity events. No payments, no worker browsing.
|
// Sponsors can ONLY access: dashboard and charity events. No payments, no worker browsing.
|
||||||
Route::middleware(['auth.sponsor'])->group(function () {
|
Route::middleware(['auth.sponsor'])->group(function () {
|
||||||
Route::get('/sponsors/profile', [SponsorController::class, 'getProfile']);
|
Route::get('/sponsors/profile', [SponsorController::class, 'getProfile']);
|
||||||
|
Route::post('/sponsors/profile/update', [SponsorController::class, 'updateProfile']);
|
||||||
Route::get('/sponsors/dashboard', [SponsorController::class, 'getDashboard']);
|
Route::get('/sponsors/dashboard', [SponsorController::class, 'getDashboard']);
|
||||||
Route::get('/sponsors/charity-events', [SponsorController::class, 'getCharityEvents']);
|
Route::get('/sponsors/charity-events', [SponsorController::class, 'getCharityEvents']);
|
||||||
Route::post('/sponsors/charity-events', [SponsorController::class, 'postCharityEvent']);
|
Route::post('/sponsors/charity-events', [SponsorController::class, 'postCharityEvent']);
|
||||||
|
|||||||
@ -141,7 +141,7 @@ public function test_employer_can_update_profile_with_emirates_id_fields()
|
|||||||
'success' => true,
|
'success' => true,
|
||||||
'data' => [
|
'data' => [
|
||||||
'profile' => [
|
'profile' => [
|
||||||
'name' => 'Ahmad',
|
'name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
||||||
'email' => 'ahmad@example.com',
|
'email' => 'ahmad@example.com',
|
||||||
'phone' => '+971509990001',
|
'phone' => '+971509990001',
|
||||||
'address' => 'Villa 12, Jumeirah 2',
|
'address' => 'Villa 12, Jumeirah 2',
|
||||||
|
|||||||
@ -54,6 +54,7 @@ public function test_employer_registration_and_login_stores_fcm_token_and_sends_
|
|||||||
'fcm_token' => 'employer_register_fcm_token',
|
'fcm_token' => 'employer_register_fcm_token',
|
||||||
'emirates_id' => [
|
'emirates_id' => [
|
||||||
'emirates_id_number' => '784-1988-5310327-2',
|
'emirates_id_number' => '784-1988-5310327-2',
|
||||||
|
'name' => 'Employer FCM Test',
|
||||||
'expiry_date' => '2028-04-11',
|
'expiry_date' => '2028-04-11',
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
@ -182,6 +183,7 @@ public function test_sponsor_registration_and_login_stores_fcm_token_and_sends_n
|
|||||||
],
|
],
|
||||||
'emirates_id' => [
|
'emirates_id' => [
|
||||||
'emirates_id_number' => '784-1988-5310327-2',
|
'emirates_id_number' => '784-1988-5310327-2',
|
||||||
|
'name' => 'Sponsor FCM Org',
|
||||||
],
|
],
|
||||||
'organization_name' => 'Sponsor FCM Co',
|
'organization_name' => 'Sponsor FCM Co',
|
||||||
'email' => 'sponsor.fcm@example.com',
|
'email' => 'sponsor.fcm@example.com',
|
||||||
|
|||||||
@ -71,7 +71,7 @@ public function test_sponsor_can_register_with_license()
|
|||||||
|
|
||||||
$this->assertDatabaseHas('sponsors', [
|
$this->assertDatabaseHas('sponsors', [
|
||||||
'mobile' => '+971509990001',
|
'mobile' => '+971509990001',
|
||||||
'full_name' => 'Test Sponsor Organization',
|
'full_name' => 'Ahmad Bin Ahmed',
|
||||||
'license_expiry' => '2028-06-12 00:00:00',
|
'license_expiry' => '2028-06-12 00:00:00',
|
||||||
'emirates_id_name' => 'Ahmad Bin Ahmed',
|
'emirates_id_name' => 'Ahmad Bin Ahmed',
|
||||||
'emirates_id_dob' => '1990-01-01',
|
'emirates_id_dob' => '1990-01-01',
|
||||||
@ -537,6 +537,7 @@ public function test_sponsor_registration_with_emirates_id_and_separate_license(
|
|||||||
'country_code' => '+971',
|
'country_code' => '+971',
|
||||||
'emirates_id' => [
|
'emirates_id' => [
|
||||||
'emirates_id_number' => '784-1988-5310327-2',
|
'emirates_id_number' => '784-1988-5310327-2',
|
||||||
|
'name' => 'Test Sponsor Sep',
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -657,4 +658,229 @@ public function test_sponsor_can_change_password()
|
|||||||
$this->assertTrue(Hash::check('NewPassword@123', $sponsor->fresh()->password));
|
$this->assertTrue(Hash::check('NewPassword@123', $sponsor->fresh()->password));
|
||||||
$this->assertTrue(Hash::check('NewPassword@123', $user->fresh()->password));
|
$this->assertTrue(Hash::check('NewPassword@123', $user->fresh()->password));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sponsor can update profile and it correctly syncs with matching user/employer profile.
|
||||||
|
*/
|
||||||
|
public function test_sponsor_can_update_profile_and_syncs_with_matching_user()
|
||||||
|
{
|
||||||
|
$sponsor = Sponsor::create([
|
||||||
|
'full_name' => 'Original Sponsor Name',
|
||||||
|
'email' => 'sync-test@example.com',
|
||||||
|
'mobile' => '+971500000001',
|
||||||
|
'password' => Hash::make('Password@123'),
|
||||||
|
'organization_name' => 'Original Org',
|
||||||
|
'city' => 'Dubai',
|
||||||
|
'address' => 'Old Address',
|
||||||
|
'nationality' => 'Emirati',
|
||||||
|
'country_code' => '+971',
|
||||||
|
'api_token' => 'sync-test-token',
|
||||||
|
'status' => 'active',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = User::create([
|
||||||
|
'name' => 'Original Sponsor Name',
|
||||||
|
'email' => 'sync-test@example.com',
|
||||||
|
'password' => Hash::make('Password@123'),
|
||||||
|
'role' => 'employer',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$profile = EmployerProfile::create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'company_name' => 'Original Org',
|
||||||
|
'phone' => '+971500000001',
|
||||||
|
'address' => 'Old Address',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer sync-test-token',
|
||||||
|
])->postJson('/api/sponsors/profile/update', [
|
||||||
|
'name' => 'Updated Sponsor Name',
|
||||||
|
'email' => 'new-sync-test@example.com',
|
||||||
|
'mobile' => '+971500000002',
|
||||||
|
'organization_name' => 'Updated Org',
|
||||||
|
'city' => 'Abu Dhabi',
|
||||||
|
'address' => 'New Address',
|
||||||
|
'nationality' => 'Jordanian',
|
||||||
|
'country_code' => '+962',
|
||||||
|
'id_number' => '784-2000-1234567-1',
|
||||||
|
'card_number' => '987654321',
|
||||||
|
'full_name' => 'Updated Sponsor Name',
|
||||||
|
'date_of_birth' => '2000-01-01',
|
||||||
|
'gender' => 'Male',
|
||||||
|
'issue_date' => '2023-01-01',
|
||||||
|
'expiry_date' => '2028-01-01',
|
||||||
|
'occupation' => 'Business Owner',
|
||||||
|
'employer' => 'Self',
|
||||||
|
'issuing_place' => 'Abu Dhabi',
|
||||||
|
'document_type' => 'dubai_commercial_license',
|
||||||
|
'country' => 'United Arab Emirates',
|
||||||
|
'authority' => 'Dubai Economy and Tourism',
|
||||||
|
'license_no' => '828302',
|
||||||
|
'company_name' => 'MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C',
|
||||||
|
'business_name' => 'MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C',
|
||||||
|
'license_category' => 'Dep. of Economic Development',
|
||||||
|
'legal_type' => 'Limited Liability Company Single Owner(LLC- - SO)',
|
||||||
|
'main_license_no' => '828302',
|
||||||
|
'register_no' => '1656486',
|
||||||
|
'dcci_no' => '317412',
|
||||||
|
'members' => [
|
||||||
|
[
|
||||||
|
'person_no' => '752967',
|
||||||
|
'name' => 'Lo lo wallus issued in',
|
||||||
|
'nationality' => 'India',
|
||||||
|
'role' => 'Shares Owner Who'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertStatus(200)
|
||||||
|
->assertJson([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Profile updated successfully.',
|
||||||
|
])
|
||||||
|
->assertJsonPath('data.sponsor.full_name', 'Updated Sponsor Name')
|
||||||
|
->assertJsonPath('data.sponsor.email', 'new-sync-test@example.com')
|
||||||
|
->assertJsonPath('data.sponsor.mobile', '+971500000002')
|
||||||
|
->assertJsonPath('data.sponsor.organization_name', 'Updated Org')
|
||||||
|
->assertJsonPath('data.sponsor.city', 'Abu Dhabi')
|
||||||
|
->assertJsonPath('data.sponsor.address', 'New Address')
|
||||||
|
->assertJsonPath('data.sponsor.nationality', 'Jordanian')
|
||||||
|
->assertJsonPath('data.sponsor.country_code', '+962')
|
||||||
|
->assertJsonPath('data.sponsor.license.document_type', 'dubai_commercial_license')
|
||||||
|
->assertJsonPath('data.sponsor.license.license_no', '828302')
|
||||||
|
->assertJsonPath('data.sponsor.license.members.0.name', 'Lo lo wallus issued in')
|
||||||
|
->assertJsonPath('data.sponsor.emirates_id.emirates_id_number', '784-2000-1234567-1')
|
||||||
|
->assertJsonPath('data.sponsor.emirates_id.name', 'Updated Sponsor Name')
|
||||||
|
->assertJsonPath('data.sponsor.emirates_id.occupation', 'Business Owner')
|
||||||
|
->assertJsonPath('data.sponsor.emirates_id.employer', 'Self');
|
||||||
|
|
||||||
|
// Check Sponsor table
|
||||||
|
$this->assertDatabaseHas('sponsors', [
|
||||||
|
'id' => $sponsor->id,
|
||||||
|
'full_name' => 'Updated Sponsor Name',
|
||||||
|
'email' => 'new-sync-test@example.com',
|
||||||
|
'mobile' => '+971500000002',
|
||||||
|
'emirates_id' => '784-2000-1234567-1',
|
||||||
|
'emirates_id_card_number' => '987654321',
|
||||||
|
'emirates_id_name' => 'Updated Sponsor Name',
|
||||||
|
'emirates_id_dob' => '2000-01-01',
|
||||||
|
'emirates_id_gender' => 'Male',
|
||||||
|
'emirates_id_issue_date' => '2023-01-01',
|
||||||
|
'emirates_id_expiry' => '2028-01-01',
|
||||||
|
'emirates_id_occupation' => 'Business Owner',
|
||||||
|
'emirates_id_employer' => 'Self',
|
||||||
|
'emirates_id_issue_place' => 'Abu Dhabi',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$dbSponsor = Sponsor::find($sponsor->id);
|
||||||
|
$this->assertEquals('dubai_commercial_license', $dbSponsor->license_data['document_type']);
|
||||||
|
$this->assertEquals('Lo lo wallus issued in', $dbSponsor->license_data['members'][0]['name']);
|
||||||
|
|
||||||
|
// Check User table
|
||||||
|
$this->assertDatabaseHas('users', [
|
||||||
|
'id' => $user->id,
|
||||||
|
'name' => 'Updated Sponsor Name',
|
||||||
|
'email' => 'new-sync-test@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Check EmployerProfile table
|
||||||
|
$this->assertDatabaseHas('employer_profiles', [
|
||||||
|
'id' => $profile->id,
|
||||||
|
'address' => 'New Address',
|
||||||
|
'phone' => '+971500000002',
|
||||||
|
'emirates_id_number' => '784-2000-1234567-1',
|
||||||
|
'emirates_id_card_number' => '987654321',
|
||||||
|
'emirates_id_name' => 'Updated Sponsor Name',
|
||||||
|
'emirates_id_dob' => '2000-01-01',
|
||||||
|
'emirates_id_gender' => 'Male',
|
||||||
|
'emirates_id_issue_date' => '2023-01-01',
|
||||||
|
'emirates_id_expiry' => '2028-01-01',
|
||||||
|
'emirates_id_occupation' => 'Business Owner',
|
||||||
|
'emirates_id_employer' => 'Self',
|
||||||
|
'emirates_id_issue_place' => 'Abu Dhabi',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sponsor cannot change immutable Emirates ID.
|
||||||
|
*/
|
||||||
|
public function test_sponsor_cannot_change_immutable_emirates_id()
|
||||||
|
{
|
||||||
|
$sponsor = Sponsor::create([
|
||||||
|
'full_name' => 'Sponsor Name',
|
||||||
|
'email' => 'immutable-id-test@example.com',
|
||||||
|
'mobile' => '+971500000003',
|
||||||
|
'password' => Hash::make('Password@123'),
|
||||||
|
'organization_name' => 'Org',
|
||||||
|
'city' => 'Dubai',
|
||||||
|
'address' => 'Address',
|
||||||
|
'nationality' => 'Emirati',
|
||||||
|
'country_code' => '+971',
|
||||||
|
'api_token' => 'immutable-id-token',
|
||||||
|
'status' => 'active',
|
||||||
|
'emirates_id' => '784-2000-1234567-1',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer immutable-id-token',
|
||||||
|
])->postJson('/api/sponsors/profile/update', [
|
||||||
|
'name' => 'Sponsor Name',
|
||||||
|
'email' => 'immutable-id-test@example.com',
|
||||||
|
'mobile' => '+971500000003',
|
||||||
|
'organization_name' => 'Org',
|
||||||
|
'city' => 'Dubai',
|
||||||
|
'address' => 'Address',
|
||||||
|
'nationality' => 'Emirati',
|
||||||
|
'country_code' => '+971',
|
||||||
|
'id_number' => '784-2000-7654321-2', // different EID
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertStatus(422)
|
||||||
|
->assertJson([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Emirates ID mismatch. You cannot change your registered Emirates ID number.',
|
||||||
|
])
|
||||||
|
->assertJsonValidationErrors(['id_number']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sponsor profile update validates Emirates ID name OCR.
|
||||||
|
*/
|
||||||
|
public function test_sponsor_profile_update_validates_emirates_id_name_ocr()
|
||||||
|
{
|
||||||
|
$sponsor = Sponsor::create([
|
||||||
|
'full_name' => 'Sponsor Name',
|
||||||
|
'email' => 'ocr-test@example.com',
|
||||||
|
'mobile' => '+971500000004',
|
||||||
|
'password' => Hash::make('Password@123'),
|
||||||
|
'organization_name' => 'Org',
|
||||||
|
'city' => 'Dubai',
|
||||||
|
'address' => 'Address',
|
||||||
|
'nationality' => 'Emirati',
|
||||||
|
'country_code' => '+971',
|
||||||
|
'api_token' => 'ocr-token',
|
||||||
|
'status' => 'active',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'Authorization' => 'Bearer ocr-token',
|
||||||
|
])->postJson('/api/sponsors/profile/update', [
|
||||||
|
'name' => 'Sponsor Name',
|
||||||
|
'email' => 'ocr-test@example.com',
|
||||||
|
'mobile' => '+971500000004',
|
||||||
|
'organization_name' => 'Org',
|
||||||
|
'city' => 'Dubai',
|
||||||
|
'address' => 'Address',
|
||||||
|
'nationality' => 'Emirati',
|
||||||
|
'country_code' => '+971',
|
||||||
|
'id_number' => '784-2000-1234567-1',
|
||||||
|
'full_name' => '', // Failed OCR name extraction
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertStatus(422)
|
||||||
|
->assertJsonValidationErrors(['full_name'])
|
||||||
|
->assertJsonPath('errors.full_name.0', 'Failed to extract name from the Emirates ID. Please upload a clearer document.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -80,11 +80,12 @@ public function test_employer_web_registration_with_emirates_id()
|
|||||||
$this->assertDatabaseHas('users', [
|
$this->assertDatabaseHas('users', [
|
||||||
'email' => 'abdullah@example.com',
|
'email' => 'abdullah@example.com',
|
||||||
'role' => 'employer',
|
'role' => 'employer',
|
||||||
|
'name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertDatabaseHas('employer_profiles', [
|
$this->assertDatabaseHas('employer_profiles', [
|
||||||
'phone' => '501234567',
|
'phone' => '501234567',
|
||||||
'company_name' => 'Abdullah Ahmed Household',
|
'company_name' => 'Mohammad Jobaier Mohammad Abul Kalam Household',
|
||||||
'emirates_id_front' => null, // File is not stored
|
'emirates_id_front' => null, // File is not stored
|
||||||
'address' => 'Villa 14, Al Safa, Dubai',
|
'address' => 'Villa 14, Al Safa, Dubai',
|
||||||
]);
|
]);
|
||||||
@ -106,6 +107,7 @@ public function test_employer_web_registration_with_emirates_id()
|
|||||||
'emirates_id_file' => null, // File is not stored
|
'emirates_id_file' => null, // File is not stored
|
||||||
'address' => 'Villa 14, Al Safa, Dubai',
|
'address' => 'Villa 14, Al Safa, Dubai',
|
||||||
'emirates_id' => '784-1987-5493842-5',
|
'emirates_id' => '784-1987-5493842-5',
|
||||||
|
'full_name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
||||||
'emirates_id_name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
'emirates_id_name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
||||||
'emirates_id_dob' => '1987-04-14',
|
'emirates_id_dob' => '1987-04-14',
|
||||||
'nationality' => 'Bangladesh',
|
'nationality' => 'Bangladesh',
|
||||||
@ -184,6 +186,19 @@ public function test_employer_web_registration_with_two_sided_emirates_id()
|
|||||||
$this->assertDatabaseHas('users', [
|
$this->assertDatabaseHas('users', [
|
||||||
'email' => 'fatima@example.com',
|
'email' => 'fatima@example.com',
|
||||||
'role' => 'employer',
|
'role' => 'employer',
|
||||||
|
'name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('employer_profiles', [
|
||||||
|
'phone' => '509876543',
|
||||||
|
'company_name' => 'Mohammad Jobaier Mohammad Abul Kalam Household',
|
||||||
|
'address' => 'Apartment 402, Al Nahda, Sharjah',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('sponsors', [
|
||||||
|
'email' => 'fatima@example.com',
|
||||||
|
'mobile' => '509876543',
|
||||||
|
'full_name' => 'Mohammad Jobaier Mohammad Abul Kalam',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$profile = EmployerProfile::where('phone', '509876543')->first();
|
$profile = EmployerProfile::where('phone', '509876543')->first();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user