From b3c219aa5756a4ea333aa3b1451ac91b4a6121b5 Mon Sep 17 00:00:00 2001 From: Chaim Date: Tue, 7 Apr 2026 15:27:23 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20add=20LegalAid=20entity=20=E2=80=94=20c?= =?UTF-8?q?entralized=20legal=20aid=20data=20management?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace scattered Case fields with a dedicated LegalAid entity that holds all legal aid data (aid type, urgency, client contact, proceeding details, legal analysis, recommendation, etc.). DirectAccessReport now pulls from LegalAid for DOCX generation with automatic checkbox mapping. - Add LegalAid entity with controller, layouts, i18n (he/en/fa) - Remove cAidType, cUrgencyLevel, cAppointmentDate, cFilingDeadline, cLegalAidType from Case (migrated to LegalAid) - Add legalAidType field to LegalAid (DirectAccess/Regular/Duty) - Update DirectAccessReportService to use LegalAid entity - Add update_legal_aid and get_legal_aid SmartAssistant tools - Fix AfterInstall template entityType to LegalAid Co-Authored-By: Claude Opus 4.6 (1M context) --- .../LegalAssistance/Controllers/LegalAid.php | 9 + .../Resources/i18n/en_US/Global.json | 6 +- .../Resources/i18n/en_US/LegalAid.json | 161 ++++++++++ .../Resources/i18n/fa_IR/Global.json | 6 +- .../Resources/i18n/fa_IR/LegalAid.json | 161 ++++++++++ .../Resources/i18n/he_IL/Case.json | 18 +- .../Resources/i18n/he_IL/Global.json | 6 +- .../Resources/i18n/he_IL/LegalAid.json | 161 ++++++++++ .../Resources/layouts/LegalAid/detail.json | 84 +++++ .../Resources/layouts/LegalAid/list.json | 11 + .../metadata/clientDefs/LegalAid.json | 36 +++ .../Resources/metadata/entityDefs/Case.json | 39 +-- .../metadata/entityDefs/LegalAid.json | 300 ++++++++++++++++++ .../Resources/metadata/scopes/LegalAid.json | 16 + .../Services/DirectAccessReportService.php | 209 ++++++------ manifest.json | 6 +- plugins/legal-assistance/tools.json | 35 +- scripts/AfterInstall.php | 2 +- 18 files changed, 1100 insertions(+), 166 deletions(-) create mode 100644 files/custom/Espo/Modules/LegalAssistance/Controllers/LegalAid.php create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/i18n/en_US/LegalAid.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/i18n/fa_IR/LegalAid.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/i18n/he_IL/LegalAid.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/layouts/LegalAid/detail.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/layouts/LegalAid/list.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/metadata/clientDefs/LegalAid.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/metadata/entityDefs/LegalAid.json create mode 100644 files/custom/Espo/Modules/LegalAssistance/Resources/metadata/scopes/LegalAid.json diff --git a/files/custom/Espo/Modules/LegalAssistance/Controllers/LegalAid.php b/files/custom/Espo/Modules/LegalAssistance/Controllers/LegalAid.php new file mode 100644 index 0000000..b3b48be --- /dev/null +++ b/files/custom/Espo/Modules/LegalAssistance/Controllers/LegalAid.php @@ -0,0 +1,9 @@ +entityManager->getEntityById('Contact', $contactId); } - // Build report name $contactName = $contact - ? ($contact->get('firstName') . ' ' . $contact->get('lastName')) + ? trim($contact->get('firstName') . ' ' . $contact->get('lastName')) : 'ללא איש קשר'; - $reportName = "דוח גישה ישירה — {$contactName}"; // Extract legal analysis from nested object $legalAnalysis = $params['legalAnalysis'] ?? []; @@ -44,102 +42,12 @@ class DirectAccessReportService $legalAnalysis = json_decode($legalAnalysis, true) ?? []; } - // Create DirectAccessReport entity - $report = $this->entityManager->getNewEntity('DirectAccessReport'); - $report->set([ - 'name' => $reportName, - 'status' => 'Draft', - 'caseId' => $caseId, - 'assignedUserId' => $userId, + // Find or create LegalAid entity for this case + $legalAid = $this->findOrCreateLegalAid($case, $contact, $contactName, $userId, $params, $legalAnalysis); - // Section ב' — מהות הסיוע - 'aidType' => $params['aidType'] ?? null, - 'urgencyLevel' => $params['urgencyLevel'] ?? null, - 'appointmentDate' => $this->normalizeDate($params['appointmentDate'] ?? null), - 'filingDeadline' => $this->normalizeDate($params['filingDeadline'] ?? null), - 'additionalUrgency' => $params['additionalUrgency'] ?? null, - 'additionalDeadline' => $params['additionalDeadline'] ?? null, - - // Section ג' — קשר עם הלקוח - 'firstContactDate' => $this->normalizeDate($params['firstContactDate'] ?? null), - 'contactDelayReason' => $params['contactDelayReason'] ?? null, - 'meetingDate' => $this->normalizeDate($params['meetingDate'] ?? null), - 'meetingDelayReason' => $params['meetingDelayReason'] ?? null, - 'meetingAttendees' => $params['meetingAttendees'] ?? null, - 'contactStatus' => $params['contactStatus'] ?? null, - 'contactStatusDetail' => $params['contactStatusDetail'] ?? null, - - // Section ד' — פרטי ההליך - 'proceedingNumber' => $params['proceedingNumber'] ?? $case->get('cCourtCaseNumber'), - 'courtName' => $params['courtName'] ?? null, - 'proceedingSubject' => $params['proceedingSubject'] ?? null, - 'claimSummary' => $params['claimSummary'] ?? null, - 'defenseClaims' => $params['defenseClaims'] ?? null, - - // Section ה'-ז' — בחינת סיכוי משפטי - 'q1DocsReviewed' => $legalAnalysis['q1DocsReviewed'] ?? false, - 'q1DocsDetail' => $legalAnalysis['q1DocsDetail'] ?? null, - 'q2Reasoned' => $legalAnalysis['q2Reasoned'] ?? false, - 'q2ReasonDetail' => $legalAnalysis['q2ReasonDetail'] ?? null, - 'q3PanelMatch' => $legalAnalysis['q3PanelMatch'] ?? false, - 'q4PanelComposition' => $legalAnalysis['q4PanelComposition'] ?? null, - 'q5ComplaintsAddressed' => $legalAnalysis['q5ComplaintsAddressed'] ?? false, - 'q6ComplaintsDetail' => $legalAnalysis['q6ComplaintsDetail'] ?? null, - 'q7ClinicalExam' => $legalAnalysis['q7ClinicalExam'] ?? false, - 'q8ClinicalGap' => $legalAnalysis['q8ClinicalGap'] ?? null, - 'q9MoharaApplied' => $legalAnalysis['q9MoharaApplied'] ?? false, - 'q9MoharaDetail' => $legalAnalysis['q9MoharaDetail'] ?? null, - 'q10RehabGap' => $legalAnalysis['q10RehabGap'] ?? false, - 'q10RehabDetail' => $legalAnalysis['q10RehabDetail'] ?? null, - 'q11ScoreGap' => $legalAnalysis['q11ScoreGap'] ?? false, - 'q11ScoreDetail' => $legalAnalysis['q11ScoreDetail'] ?? null, - 'q12UniqueAspects' => $legalAnalysis['q12UniqueAspects'] ?? false, - 'q12UniqueDetail' => $legalAnalysis['q12UniqueDetail'] ?? null, - - // Section ח' — המלצה - 'recommendationType' => $params['recommendationType'] ?? null, - 'recommendationDetail' => $params['recommendationDetail'] ?? null, - - // Section ט' — מיצוי זכויות - 'additionalAidNeeded' => $params['additionalAidNeeded'] ?? null, - 'additionalAidNIDetail' => $params['additionalAidNIDetail'] ?? null, - 'additionalAidOtherDetail' => $params['additionalAidOtherDetail'] ?? null, - 'additionalAidUrgency' => $params['additionalAidUrgency'] ?? null, - 'additionalAidDeadlines' => $params['additionalAidDeadlines'] ?? null, - 'willingToRepresent' => $params['willingToRepresent'] ?? false, - - // Section י' — הערות - 'notes' => $params['notes'] ?? null, - ]); - - $this->entityManager->saveEntity($report); - - $this->log->info("LegalAssistance: Created DirectAccessReport {$report->getId()} for case {$caseId}"); - - // Also update Case fields if provided - $caseUpdated = false; - if (!empty($params['appointmentDate']) && !$case->get('cAppointmentDate')) { - $case->set('cAppointmentDate', $this->normalizeDate($params['appointmentDate'])); - $caseUpdated = true; - } - if (!empty($params['aidType']) && !$case->get('cAidType')) { - $case->set('cAidType', $params['aidType']); - $caseUpdated = true; - } - if (!empty($params['urgencyLevel']) && !$case->get('cUrgencyLevel')) { - $case->set('cUrgencyLevel', $params['urgencyLevel']); - $caseUpdated = true; - } - if (!empty($params['filingDeadline']) && !$case->get('cFilingDeadline')) { - $case->set('cFilingDeadline', $this->normalizeDate($params['filingDeadline'])); - $caseUpdated = true; - } - if ($caseUpdated) { - $this->entityManager->saveEntity($case, ['skipHooks' => true]); - } - - // Generate DOCX using template - $docxResult = $this->generateDocx($report, $case, $contact, $userId); + // Generate DOCX using template from LegalAid entity + $reportName = "דוח גישה ישירה — {$contactName}"; + $docxResult = $this->generateDocx($legalAid, $reportName); $msg = "✅ דוח גישה ישירה נוצר בהצלחה: \"{$reportName}\""; if (!empty($docxResult['fileName'])) { @@ -149,14 +57,104 @@ class DirectAccessReportService return [ 'success' => true, 'message' => $msg, - 'entityType' => 'DirectAccessReport', - 'entityId' => $report->getId(), + 'entityType' => 'LegalAid', + 'entityId' => $legalAid->getId(), ]; } - private function generateDocx($report, $case, $contact, string $userId): array + private function findOrCreateLegalAid($case, $contact, string $contactName, string $userId, array $params, array $legalAnalysis) + { + $caseId = $case->getId(); + + // Look for existing LegalAid record for this case + $legalAid = $this->entityManager + ->getRDBRepository('LegalAid') + ->where(['caseId' => $caseId]) + ->findOne(); + + if (!$legalAid) { + $legalAid = $this->entityManager->getNewEntity('LegalAid'); + } + + $legalAid->set([ + 'name' => "סיוע משפטי — {$contactName}", + 'status' => 'Active', + 'caseId' => $caseId, + 'contactId' => $contact ? $contact->getId() : null, + 'contactName' => $contactName, + 'assignedUserId' => $userId, + 'legalAidNumber' => $case->get('cLegalAidNumber') ?? '', + 'reportDate' => date('Y-m-d'), + + // מהות הסיוע + 'aidType' => $params['aidType'] ?? $legalAid->get('aidType'), + 'urgencyLevel' => $params['urgencyLevel'] ?? $legalAid->get('urgencyLevel'), + 'appointmentDate' => $this->normalizeDate($params['appointmentDate'] ?? null) ?? $legalAid->get('appointmentDate'), + 'filingDeadline' => $this->normalizeDate($params['filingDeadline'] ?? null) ?? $legalAid->get('filingDeadline'), + 'additionalUrgency' => $params['additionalUrgency'] ?? $legalAid->get('additionalUrgency'), + 'additionalDeadline' => $params['additionalDeadline'] ?? $legalAid->get('additionalDeadline'), + + // קשר עם הלקוח + 'firstContactDate' => $this->normalizeDate($params['firstContactDate'] ?? null) ?? $legalAid->get('firstContactDate'), + 'contactDelayReason' => $params['contactDelayReason'] ?? $legalAid->get('contactDelayReason'), + 'meetingDate' => $this->normalizeDate($params['meetingDate'] ?? null) ?? $legalAid->get('meetingDate'), + 'meetingDelayReason' => $params['meetingDelayReason'] ?? $legalAid->get('meetingDelayReason'), + 'meetingAttendees' => $params['meetingAttendees'] ?? $legalAid->get('meetingAttendees'), + 'contactStatus' => $params['contactStatus'] ?? $legalAid->get('contactStatus'), + 'contactStatusDetail' => $params['contactStatusDetail'] ?? $legalAid->get('contactStatusDetail'), + + // פרטי ההליך + 'proceedingNumber' => $params['proceedingNumber'] ?? $legalAid->get('proceedingNumber') ?? $case->get('cCourtCaseNumber'), + 'courtName' => $params['courtName'] ?? $legalAid->get('courtName'), + 'proceedingSubject' => $params['proceedingSubject'] ?? $legalAid->get('proceedingSubject'), + 'claimSummary' => $params['claimSummary'] ?? $legalAid->get('claimSummary'), + 'defenseClaims' => $params['defenseClaims'] ?? $legalAid->get('defenseClaims'), + + // בחינת סיכוי משפטי + 'q1DocsReviewed' => $legalAnalysis['q1DocsReviewed'] ?? $legalAid->get('q1DocsReviewed') ?? false, + 'q1DocsDetail' => $legalAnalysis['q1DocsDetail'] ?? $legalAid->get('q1DocsDetail'), + 'q2Reasoned' => $legalAnalysis['q2Reasoned'] ?? $legalAid->get('q2Reasoned') ?? false, + 'q2ReasonDetail' => $legalAnalysis['q2ReasonDetail'] ?? $legalAid->get('q2ReasonDetail'), + 'q3PanelMatch' => $legalAnalysis['q3PanelMatch'] ?? $legalAid->get('q3PanelMatch') ?? false, + 'q4PanelComposition' => $legalAnalysis['q4PanelComposition'] ?? $legalAid->get('q4PanelComposition'), + 'q5ComplaintsAddressed' => $legalAnalysis['q5ComplaintsAddressed'] ?? $legalAid->get('q5ComplaintsAddressed') ?? false, + 'q6ComplaintsDetail' => $legalAnalysis['q6ComplaintsDetail'] ?? $legalAid->get('q6ComplaintsDetail'), + 'q7ClinicalExam' => $legalAnalysis['q7ClinicalExam'] ?? $legalAid->get('q7ClinicalExam') ?? false, + 'q8ClinicalGap' => $legalAnalysis['q8ClinicalGap'] ?? $legalAid->get('q8ClinicalGap'), + 'q9MoharaApplied' => $legalAnalysis['q9MoharaApplied'] ?? $legalAid->get('q9MoharaApplied') ?? false, + 'q9MoharaDetail' => $legalAnalysis['q9MoharaDetail'] ?? $legalAid->get('q9MoharaDetail'), + 'q10RehabGap' => $legalAnalysis['q10RehabGap'] ?? $legalAid->get('q10RehabGap') ?? false, + 'q10RehabDetail' => $legalAnalysis['q10RehabDetail'] ?? $legalAid->get('q10RehabDetail'), + 'q11ScoreGap' => $legalAnalysis['q11ScoreGap'] ?? $legalAid->get('q11ScoreGap') ?? false, + 'q11ScoreDetail' => $legalAnalysis['q11ScoreDetail'] ?? $legalAid->get('q11ScoreDetail'), + 'q12UniqueAspects' => $legalAnalysis['q12UniqueAspects'] ?? $legalAid->get('q12UniqueAspects') ?? false, + 'q12UniqueDetail' => $legalAnalysis['q12UniqueDetail'] ?? $legalAid->get('q12UniqueDetail'), + + // המלצה + 'recommendationType' => $params['recommendationType'] ?? $legalAid->get('recommendationType'), + 'recommendationDetail' => $params['recommendationDetail'] ?? $legalAid->get('recommendationDetail'), + + // מיצוי זכויות + 'additionalAidNeeded' => $params['additionalAidNeeded'] ?? $legalAid->get('additionalAidNeeded'), + 'additionalAidNIDetail' => $params['additionalAidNIDetail'] ?? $legalAid->get('additionalAidNIDetail'), + 'additionalAidOtherDetail' => $params['additionalAidOtherDetail'] ?? $legalAid->get('additionalAidOtherDetail'), + 'additionalAidUrgency' => $params['additionalAidUrgency'] ?? $legalAid->get('additionalAidUrgency'), + 'additionalAidDeadlines' => $params['additionalAidDeadlines'] ?? $legalAid->get('additionalAidDeadlines'), + 'willingToRepresent' => $params['willingToRepresent'] ?? $legalAid->get('willingToRepresent') ?? false, + + // הערות + 'notes' => $params['notes'] ?? $legalAid->get('notes'), + ]); + + $this->entityManager->saveEntity($legalAid); + + $this->log->info("LegalAssistance: Saved LegalAid {$legalAid->getId()} for case {$case->getId()}"); + + return $legalAid; + } + + private function generateDocx($legalAid, string $documentSubject): array { - // Try to use LocalDocumentTemplateService if available try { $templateServiceClass = 'Espo\\Modules\\LocalDocuments\\Services\\LocalDocumentTemplateService'; if (!class_exists($templateServiceClass)) { @@ -168,7 +166,6 @@ class DirectAccessReportService return ['success' => false, 'error' => 'No template service']; } - // Find the template $template = $this->entityManager ->getRDBRepository('DocumentTemplate') ->where(['name' => 'דוח גישה ישירה']) @@ -183,9 +180,9 @@ class DirectAccessReportService $result = $templateService->createFromTemplate( $template->getId(), - 'Case', - $case->getId(), - $report->get('name') + 'LegalAid', + $legalAid->getId(), + $documentSubject ); return $result; diff --git a/manifest.json b/manifest.json index b6cb2b4..f1249f5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { "name": "LegalAssistance", - "version": "1.3.2", + "version": "1.4.1", "acceptableVersions": [">=8.0.0"], "php": [">=8.1"], - "releaseDate": "2026-04-06", + "releaseDate": "2026-04-07", "author": "Marcus-Law", - "description": "סיוע משפטי — דוח גישה ישירה, משימות אוטומטיות, אינטגרציה עם שירה", + "description": "סיוע משפטי — ישות LegalAid מרכזית, דוח גישה ישירה, משימות אוטומטיות, אינטגרציה עם שירה", "scripts": { "afterInstall": "scripts/AfterInstall.php", "afterUninstall": "scripts/AfterUninstall.php" diff --git a/plugins/legal-assistance/tools.json b/plugins/legal-assistance/tools.json index 857199d..4615d70 100644 --- a/plugins/legal-assistance/tools.json +++ b/plugins/legal-assistance/tools.json @@ -1,7 +1,7 @@ { "tools": { "generate_initial_report": { - "description": "Generate Direct Access initial report (דוח דיווח ראשוני — גישה ישירה). Call ONLY after collecting ALL required data through conversation with the lawyer. This tool creates a DirectAccessReport entity and generates a DOCX document.", + "description": "Generate Direct Access initial report (דוח דיווח ראשוני — גישה ישירה). Call ONLY after collecting ALL required data through conversation with the lawyer. This tool creates/updates a LegalAid entity and generates a DOCX document from it.", "parameters": { "type": "object", "properties": { @@ -148,6 +148,39 @@ }, "required": ["aidType", "proceedingSubject", "recommendationType"] } + }, + "update_legal_aid": { + "description": "Update fields on an existing LegalAid entity. Use this to fill or modify any field on the legal aid record. Pass only the fields you want to update — existing values are preserved for unspecified fields. You can update any combination of fields.", + "parameters": { + "type": "object", + "properties": { + "legalAidId": { + "type": "string", + "description": "ID of the LegalAid entity to update" + }, + "fields": { + "type": "object", + "description": "Key-value pairs of fields to update. Any field from the LegalAid entity is valid: aidType, urgencyLevel, appointmentDate, filingDeadline, firstContactDate, contactDelayReason, meetingDate, meetingDelayReason, meetingAttendees, contactStatus, contactStatusDetail, proceedingNumber, courtName, proceedingSubject, claimSummary, defenseClaims, q1DocsReviewed, q1DocsDetail, q2Reasoned, q2ReasonDetail, q3PanelMatch, q4PanelComposition, q5ComplaintsAddressed, q6ComplaintsDetail, q7ClinicalExam, q8ClinicalGap, q9MoharaApplied, q9MoharaDetail, q10RehabGap, q10RehabDetail, q11ScoreGap, q11ScoreDetail, q12UniqueAspects, q12UniqueDetail, recommendationType, recommendationDetail, additionalAidNeeded, additionalAidNIDetail, additionalAidOtherDetail, additionalAidUrgency, additionalAidDeadlines, willingToRepresent, notes, status, contactName, legalAidNumber, reportDate, additionalUrgency, additionalDeadline" + } + }, + "required": ["legalAidId", "fields"] + } + }, + "get_legal_aid": { + "description": "Read an existing LegalAid entity and return all its field values. Use this to check what data has already been filled before updating.", + "parameters": { + "type": "object", + "properties": { + "legalAidId": { + "type": "string", + "description": "ID of the LegalAid entity to read" + }, + "caseId": { + "type": "string", + "description": "Alternatively, find the LegalAid by Case ID" + } + } + } } } } diff --git a/scripts/AfterInstall.php b/scripts/AfterInstall.php index 41e33ab..31808c8 100644 --- a/scripts/AfterInstall.php +++ b/scripts/AfterInstall.php @@ -153,7 +153,7 @@ class AfterInstall $template = $entityManager->getNewEntity('DocumentTemplate'); $template->set([ 'name' => 'דוח גישה ישירה', - 'entityType' => 'Case', + 'entityType' => 'LegalAid', 'fileId' => $attachment->getId(), ]); $entityManager->saveEntity($template);