getPersonFromContract($contract); if ($personId) { Log::info('EntityResolutionService: Found Person from processed Contract', [ 'person_id' => $personId, 'contract_id' => $contract->id, ]); return $personId; } } // 2. Check if ClientCase already processed in this row if ($clientCase = $context['client_case']['entity'] ?? null) { if ($clientCase->person_id) { Log::info('EntityResolutionService: Found Person from processed ClientCase', [ 'person_id' => $clientCase->person_id, 'client_case_id' => $clientCase->id, ]); return $clientCase->person_id; } } // 3. Check for existing Contract by reference (before it's processed) if ($contractRef = $mapped['contract']['reference'] ?? null) { $personId = $this->getPersonFromContractReference($import->client_id, $contractRef); if ($personId) { Log::info('EntityResolutionService: Found Person from existing Contract reference', [ 'person_id' => $personId, 'contract_reference' => $contractRef, ]); return $personId; } } // 4. Check for existing ClientCase by client_ref (before it's processed) if ($clientRef = $mapped['client_case']['client_ref'] ?? null) { $personId = $this->getPersonFromClientRef($import->client_id, $clientRef); if ($personId) { Log::info('EntityResolutionService: Found Person from existing ClientCase client_ref', [ 'person_id' => $personId, 'client_ref' => $clientRef, ]); return $personId; } } // 5. Check for existing Person by contact values (email/phone/address) $personId = $this->resolvePersonByContacts($mapped); if ($personId) { Log::info('EntityResolutionService: Found Person from contact values', [ 'person_id' => $personId, ]); return $personId; } // No existing Person found return null; } /** * Check if ClientCase exists for this client_ref. * * @param int|null $clientId * @param string $clientRef * @return bool */ public function clientCaseExists(?int $clientId, string $clientRef): bool { if (!$clientId || !$clientRef) { return false; } return ClientCase::where('client_id', $clientId) ->where('client_ref', $clientRef) ->exists(); } /** * Check if Contract exists for this reference. * * @param int|null $clientId * @param string $reference * @return bool */ public function contractExists(?int $clientId, string $reference): bool { if (!$clientId || !$reference) { return false; } return Contract::query() ->join('client_cases', 'contracts.client_case_id', '=', 'client_cases.id') ->where('client_cases.client_id', $clientId) ->where('contracts.reference', $reference) ->exists(); } /** * Get existing ClientCase by client_ref. * * @param int|null $clientId * @param string $clientRef * @return ClientCase|null */ public function getExistingClientCase(?int $clientId, string $clientRef): ?ClientCase { if (!$clientId || !$clientRef) { return null; } return ClientCase::where('client_id', $clientId) ->where('client_ref', $clientRef) ->first(); } /** * Get existing Contract by reference for this client. * * @param int|null $clientId * @param string $reference * @return Contract|null */ public function getExistingContract(?int $clientId, string $reference): ?Contract { if (!$clientId || !$reference) { return null; } return Contract::query() ->join('client_cases', 'contracts.client_case_id', '=', 'client_cases.id') ->where('client_cases.client_id', $clientId) ->where('contracts.reference', $reference) ->select('contracts.*') ->first(); } /** * Get Person ID from a Contract entity. * * @param Contract $contract * @return int|null */ protected function getPersonFromContract(Contract $contract): ?int { if ($contract->client_case_id) { return ClientCase::where('id', $contract->client_case_id) ->value('person_id'); } return null; } /** * Get Person ID from existing Contract by reference. * * @param int|null $clientId * @param string $reference * @return int|null */ protected function getPersonFromContractReference(?int $clientId, string $reference): ?int { if (!$clientId) { return null; } $clientCaseId = Contract::query() ->join('client_cases', 'contracts.client_case_id', '=', 'client_cases.id') ->where('client_cases.client_id', $clientId) ->where('contracts.reference', $reference) ->value('contracts.client_case_id'); if ($clientCaseId) { return ClientCase::where('id', $clientCaseId) ->value('person_id'); } return null; } /** * Get Person ID from existing ClientCase by client_ref. * * @param int|null $clientId * @param string $clientRef * @return int|null */ protected function getPersonFromClientRef(?int $clientId, string $clientRef): ?int { if (!$clientId) { return null; } return ClientCase::where('client_id', $clientId) ->where('client_ref', $clientRef) ->value('person_id'); } /** * Resolve Person by contact values (email, phone, address). * Checks existing contact records and returns associated Person ID. * * @param array $mapped * @return int|null */ protected function resolvePersonByContacts(array $mapped): ?int { // Check email (support both single and array formats) $email = $this->extractContactValue($mapped, 'email', 'value', 'emails'); if ($email) { $personId = Email::where('value', trim($email))->value('person_id'); if ($personId) { return $personId; } } // Check phone (support both single and array formats) $phone = $this->extractContactValue($mapped, 'phone', 'nu', 'person_phones'); if ($phone) { $personId = PersonPhone::where('nu', trim($phone))->value('person_id'); if ($personId) { return $personId; } } // Check address (support both single and array formats) $address = $this->extractContactValue($mapped, 'address', 'address', 'person_addresses'); if ($address) { $personId = PersonAddress::where('address', trim($address))->value('person_id'); if ($personId) { return $personId; } } return null; } /** * Extract contact value from mapped data, supporting multiple formats. * * @param array $mapped * @param string $singularKey e.g., 'email', 'phone', 'address' * @param string $field Field name within the contact data * @param string $pluralKey e.g., 'emails', 'person_phones', 'person_addresses' * @return string|null */ protected function extractContactValue(array $mapped, string $singularKey, string $field, string $pluralKey): ?string { // Try singular key first (e.g., 'email') if (isset($mapped[$singularKey][$field])) { return $mapped[$singularKey][$field]; } // Try plural key (e.g., 'emails') if (isset($mapped[$pluralKey])) { // If it's an array of contacts if (is_array($mapped[$pluralKey])) { // Try first element if it's an indexed array if (isset($mapped[$pluralKey][0][$field])) { return $mapped[$pluralKey][0][$field]; } // Try direct field access if it's a single hash if (isset($mapped[$pluralKey][$field])) { return $mapped[$pluralKey][$field]; } } } return null; } /** * Check if this row should skip Person creation based on existing entities. * Used by PersonHandler to determine if Person already exists via chain. * * @param Import $import * @param array $mapped * @param array $context * @return bool True if Person should be skipped (already exists) */ public function shouldSkipPersonCreation(Import $import, array $mapped, array $context): bool { // If we can resolve existing Person, we should skip creation $personId = $this->resolvePersonFromContext($import, $mapped, $context); return $personId !== null; } /** * Get or create ClientCase for Contract creation. * Reuses existing ClientCase if found by client_ref. * * @param Import $import * @param array $mapped * @param array $context * @return int|null ClientCase ID */ public function resolveOrCreateClientCaseForContract(Import $import, array $mapped, array $context): ?int { $clientId = $import->client_id; if (!$clientId) { return null; } // If ClientCase already processed in this row, use it if ($clientCaseId = $context['client_case']['entity']?->id ?? null) { return $clientCaseId; } // Try to find by client_ref $clientRef = $mapped['client_case']['client_ref'] ?? $mapped['client_ref'] ?? null; if ($clientRef) { $existing = $this->getExistingClientCase($clientId, $clientRef); if ($existing) { Log::info('EntityResolutionService: Reusing existing ClientCase for Contract', [ 'client_case_id' => $existing->id, 'client_ref' => $clientRef, ]); return $existing->id; } } // Need to create new ClientCase // Get Person from context (should be processed before Contract now) $personId = $context['person']['entity']?->id ?? null; if (!$personId) { // Person wasn't in import or wasn't found, try to resolve $personId = $this->resolvePersonFromContext($import, $mapped, $context); if (!$personId) { // Create minimal Person as last resort $personId = Person::create(['type_id' => 1])->id; Log::info('EntityResolutionService: Created minimal Person for new ClientCase', [ 'person_id' => $personId, ]); } } $clientCase = ClientCase::create([ 'client_id' => $clientId, 'person_id' => $personId, 'client_ref' => $clientRef, ]); Log::info('EntityResolutionService: Created new ClientCase', [ 'client_case_id' => $clientCase->id, 'person_id' => $personId, 'client_ref' => $clientRef, ]); return $clientCase->id; } }