From 291591f3a96156b26a5cfbc05c8b6fbd05b4541d Mon Sep 17 00:00:00 2001 From: mohanmd Date: Wed, 24 Jun 2026 15:42:59 +0530 Subject: [PATCH 1/2] api changes --- resources/js/Pages/Employer/Workers/Show.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/js/Pages/Employer/Workers/Show.jsx b/resources/js/Pages/Employer/Workers/Show.jsx index bd5ff46..850c46c 100644 --- a/resources/js/Pages/Employer/Workers/Show.jsx +++ b/resources/js/Pages/Employer/Workers/Show.jsx @@ -676,7 +676,8 @@ export default function Show({ worker }) { )} - {visaDoc.ocr_data ? (() => { +
+ {visaDoc.ocr_data ? (() => { const sponsorObj = visaDoc.ocr_data?.sponsor; const isSponsorObj = sponsorObj && typeof sponsorObj === 'object' && !Array.isArray(sponsorObj); const sponsorName = isSponsorObj From fab61468d27410c784db8b3a65ba646d115dd8ac Mon Sep 17 00:00:00 2001 From: mohanmd Date: Wed, 24 Jun 2026 16:35:09 +0530 Subject: [PATCH 2/2] api changes --- .../Controllers/Api/WorkerAuthController.php | 2 +- .../Api/WorkerProfileController.php | 2 +- ...dize_visa_ocr_data_in_worker_documents.php | 89 ++++++ public/swagger.json | 285 ++++++++++-------- tests/Feature/WorkerJourneyApiTest.php | 10 +- 5 files changed, 250 insertions(+), 138 deletions(-) create mode 100644 database/migrations/2026_06_24_145817_standardize_visa_ocr_data_in_worker_documents.php diff --git a/app/Http/Controllers/Api/WorkerAuthController.php b/app/Http/Controllers/Api/WorkerAuthController.php index 17e79f1..ab9d800 100644 --- a/app/Http/Controllers/Api/WorkerAuthController.php +++ b/app/Http/Controllers/Api/WorkerAuthController.php @@ -1246,7 +1246,7 @@ private function cleanVisaData(array $visaDataInput): array $rawEntryPermitNo = $visaDataInput['entry_permit_no'] ?? $visaDataInput['file_number'] ?? $visaDataInput['id_number'] ?? $visaDataInput['number'] ?? null; $rawIssueDate = $visaDataInput['issue_date'] ?? null; $rawValidUntil = $visaDataInput['valid_until'] ?? $visaDataInput['expiry_date'] ?? null; - $rawUidNo = $visaDataInput['uid_no'] ?? null; + $rawUidNo = $visaDataInput['uid_no'] ?? $visaDataInput['id_number'] ?? null; $rawFullName = $visaDataInput['full_name'] ?? $visaDataInput['name'] ?? null; $rawNationality = $visaDataInput['nationality'] ?? null; $rawPlaceOfBirth = $visaDataInput['place_of_birth'] ?? null; diff --git a/app/Http/Controllers/Api/WorkerProfileController.php b/app/Http/Controllers/Api/WorkerProfileController.php index 9161643..5eded75 100644 --- a/app/Http/Controllers/Api/WorkerProfileController.php +++ b/app/Http/Controllers/Api/WorkerProfileController.php @@ -768,7 +768,7 @@ private function cleanVisaData(array $visaDataInput): array $rawEntryPermitNo = $visaDataInput['entry_permit_no'] ?? $visaDataInput['file_number'] ?? $visaDataInput['id_number'] ?? $visaDataInput['number'] ?? null; $rawIssueDate = $visaDataInput['issue_date'] ?? null; $rawValidUntil = $visaDataInput['valid_until'] ?? $visaDataInput['expiry_date'] ?? null; - $rawUidNo = $visaDataInput['uid_no'] ?? null; + $rawUidNo = $visaDataInput['uid_no'] ?? $visaDataInput['id_number'] ?? null; $rawFullName = $visaDataInput['full_name'] ?? $visaDataInput['name'] ?? null; $rawNationality = $visaDataInput['nationality'] ?? null; $rawPlaceOfBirth = $visaDataInput['place_of_birth'] ?? null; diff --git a/database/migrations/2026_06_24_145817_standardize_visa_ocr_data_in_worker_documents.php b/database/migrations/2026_06_24_145817_standardize_visa_ocr_data_in_worker_documents.php new file mode 100644 index 0000000..114f01e --- /dev/null +++ b/database/migrations/2026_06_24_145817_standardize_visa_ocr_data_in_worker_documents.php @@ -0,0 +1,89 @@ +where('type', 'visa')->get(); + foreach ($visaDocuments as $doc) { + $ocrData = json_decode($doc->ocr_data, true); + if (is_array($ocrData)) { + $cleaned = $this->cleanVisaData($ocrData); + \DB::table('worker_documents')->where('id', $doc->id)->update([ + 'ocr_data' => json_encode($cleaned) + ]); + } + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Cleaning up or reverting structure is not strictly necessary or possible + // since we map legacy fields to modern ones. + } + + private function cleanVisaData(array $visaDataInput): array + { + $rawVisaType = $visaDataInput['visa_type'] ?? null; + $rawEntryPermitNo = $visaDataInput['entry_permit_no'] ?? $visaDataInput['file_number'] ?? $visaDataInput['id_number'] ?? $visaDataInput['number'] ?? null; + $rawIssueDate = $visaDataInput['issue_date'] ?? null; + $rawValidUntil = $visaDataInput['valid_until'] ?? $visaDataInput['expiry_date'] ?? null; + $rawUidNo = $visaDataInput['uid_no'] ?? $visaDataInput['id_number'] ?? null; + $rawFullName = $visaDataInput['full_name'] ?? $visaDataInput['name'] ?? null; + $rawNationality = $visaDataInput['nationality'] ?? null; + $rawPlaceOfBirth = $visaDataInput['place_of_birth'] ?? null; + $rawDateOfBirth = $visaDataInput['date_of_birth'] ?? $visaDataInput['dob'] ?? null; + $rawPassportNo = $visaDataInput['passport_no'] ?? $visaDataInput['passport_number'] ?? null; + $rawProfession = $visaDataInput['profession'] ?? null; + $rawSponsorName = $visaDataInput['sponsor_name'] ?? null; + $rawOcrAccuracy = $visaDataInput['ocr_accuracy'] ?? null; + + // Clean sponsor + $sponsorData = $visaDataInput['sponsor'] ?? []; + if (is_string($sponsorData)) { + $sponsorNameFromObj = $sponsorData; + $sponsorAddress = ''; + $sponsorPhone = ''; + } else { + $sponsorNameFromObj = $sponsorData['name'] ?? $sponsorData['sponsor_name'] ?? $sponsorData['full_name'] ?? ''; + $sponsorAddress = $sponsorData['address'] ?? ''; + $sponsorPhone = $sponsorData['phone'] ?? $sponsorData['mobile'] ?? $sponsorData['mobile_number'] ?? $sponsorData['phone_number'] ?? ''; + } + if (empty($rawSponsorName)) { + $rawSponsorName = $sponsorNameFromObj; + } + + return [ + 'document_type' => 'uae_visa', + 'country' => 'United Arab Emirates', + 'visa_type' => $rawVisaType ?: 'ENTRY PERMIT', + 'entry_permit_no' => $rawEntryPermitNo ?: '', + 'issue_date' => $rawIssueDate ?: '', + 'valid_until' => $rawValidUntil ?: '', + 'uid_no' => $rawUidNo ?: '', + 'full_name' => $rawFullName ?: '', + 'nationality' => $rawNationality ?: '', + 'place_of_birth' => $rawPlaceOfBirth ?: '', + 'date_of_birth' => $rawDateOfBirth ?: '', + 'passport_no' => $rawPassportNo ?: '', + 'profession' => $rawProfession ?: '', + 'sponsor_name' => $rawSponsorName ?: '', + 'ocr_accuracy' => $rawOcrAccuracy !== null ? (int)$rawOcrAccuracy : 99, + 'sponsor' => [ + 'name' => $sponsorNameFromObj ?: '', + 'address' => $sponsorAddress ?: '', + 'phone' => $sponsorPhone ?: '', + ] + ]; + } +}; diff --git a/public/swagger.json b/public/swagger.json index 172e042..d245244 100644 --- a/public/swagger.json +++ b/public/swagger.json @@ -1102,92 +1102,85 @@ }, "visa": { "type": "object", - "description": "Optional JSON object containing extracted visa details.", + "description": "Standardized UAE Visa metadata.", "properties": { - "accompanied_by": { - "type": "string" + "document_type": { + "type": "string", + "example": "uae_visa" }, "country": { "type": "string", "example": "United Arab Emirates" }, - "date_of_birth": { + "visa_type": { "type": "string", - "example": "25-JUN-1999" - }, - "document_type": { - "type": "string", - "example": "uae_visa" + "example": "ENTRY PERMIT" }, "entry_permit_no": { "type": "string", "example": "77003098 / 2019 / 204" }, - "expiry_date": { - "type": "string", - "example": "2024-02-15" - }, - "file_number": { - "type": "string" - }, - "full_name": { - "type": "string", - "example": "Mr.MUHAMMAD NADEEM RASHEED" - }, - "id_number": { - "type": "string" - }, "issue_date": { "type": "string", "example": "2022-02-16" }, - "name": { - "type": "string" - }, - "nationality": { + "valid_until": { "type": "string", - "example": "PAKISTAN" - }, - "ocr_accuracy": { - "type": "number", - "format": "float", - "example": 99 - }, - "passport_no": { - "type": "string", - "example": "EN9458281" - }, - "passport_number": { - "type": "string" - }, - "place_of_birth": { - "type": "string", - "example": "SIALKOT PAK" - }, - "place_of_issue": { - "type": "string" - }, - "profession": { - "type": "string", - "example": "SALES REPRESENTATIVE" - }, - "sponsor": { - "type": "string" - }, - "sponsor_name": { - "type": "string" + "example": "2024-02-15" }, "uid_no": { "type": "string", "example": "207404887" }, - "valid_until": { + "full_name": { "type": "string", - "example": "04-MAR-2019" + "example": "Mr.MUHAMMAD NADEEM RASHEED" }, - "visa_type": { + "nationality": { "type": "string", - "example": "ENTRY PERMIT" + "example": "PAKISTAN" + }, + "place_of_birth": { + "type": "string", + "example": "SIALKOT PAK" + }, + "date_of_birth": { + "type": "string", + "example": "25-JUN-1999" + }, + "passport_no": { + "type": "string", + "example": "EN9458281" + }, + "profession": { + "type": "string", + "example": "SALES REPRESENTATIVE" + }, + "sponsor_name": { + "type": "string", + "example": "Sponsor Name" + }, + "ocr_accuracy": { + "type": "number", + "format": "float", + "example": 97.4 + }, + "sponsor": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "Sponsor Name" + }, + "address": { + "type": "string", + "example": "Dubai Marina, Dubai" + }, + "phone": { + "type": "string", + "example": "2977725" + } + } } } } @@ -6648,82 +6641,108 @@ "type": "string", "example": "uploads/licenses/1234567890_emirates_id.pdf" }, + "license_expiry": { + "type": "string", + "nullable": true, + "example": "2026-05-03" + }, + "validity": { + "type": "string", + "example": "Valid" + }, + "joined_at": { + "type": "string", + "format": "date-time" + }, "fcm_token": { "type": "string", "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" + "license": { + "type": "object", + "properties": { + "license_number": { + "type": "string", + "example": "828302" + }, + "organization_name": { + "type": "string", + "example": "MSJ INTERNATIONAL TECHNICAL SERVICES L.L.C" + }, + "expiry_date": { + "type": "string", + "example": "2026-05-03" + }, + "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" + } + } } } } diff --git a/tests/Feature/WorkerJourneyApiTest.php b/tests/Feature/WorkerJourneyApiTest.php index dfdf483..47e9aa0 100644 --- a/tests/Feature/WorkerJourneyApiTest.php +++ b/tests/Feature/WorkerJourneyApiTest.php @@ -531,9 +531,13 @@ public function test_register_passport_and_visa_with_direct_json_payload() $visaDoc = \App\Models\WorkerDocument::where('worker_id', $workerId)->where('type', 'visa')->first(); $this->assertNotNull($visaDoc->ocr_data); - $this->assertEquals('784198839607839', $visaDoc->ocr_data['id_number']); + $this->assertEquals('784198839607839', $visaDoc->ocr_data['uid_no']); $this->assertEquals('CLEANER', $visaDoc->ocr_data['profession']); - $this->assertEquals('Sponsor Name', $visaDoc->ocr_data['sponsor']); + $this->assertEquals([ + 'name' => 'Sponsor Name', + 'address' => '', + 'phone' => '', + ], $visaDoc->ocr_data['sponsor']); } /** @@ -630,7 +634,7 @@ public function test_register_visa_with_full_ocr_fields() $this->assertEquals('uae_visa', $visaDoc->ocr_data['document_type']); $this->assertEquals('ENTRY PERMIT', $visaDoc->ocr_data['visa_type']); $this->assertEquals('Mr.MUHAMMAD NADEEM RASHEED', $visaDoc->ocr_data['full_name']); - $this->assertEquals(97.4, $visaDoc->ocr_data['ocr_accuracy']); + $this->assertEquals(97.4, $visaDoc->ocr_accuracy); } /**