Teren-app/app/Services/Import/Handlers/PersonHandler.php
Simon Pocrnjič 36b63a180d fixed import
2025-12-28 13:55:09 +01:00

201 lines
6.3 KiB
PHP

<?php
namespace App\Services\Import\Handlers;
use App\Models\Import;
use App\Models\Person\Person;
use App\Models\Person\PersonGroup;
use App\Models\Person\PersonType;
use App\Services\Import\DateNormalizer;
use App\Services\Import\BaseEntityHandler;
use App\Services\Import\EntityResolutionService;
use Illuminate\Support\Facades\Log;
class PersonHandler extends BaseEntityHandler
{
protected EntityResolutionService $resolutionService;
public function __construct($entityConfig = null)
{
parent::__construct($entityConfig);
$this->resolutionService = new EntityResolutionService();
}
public function getEntityClass(): string
{
return Person::class;
}
public function resolve(array $mapped, array $context = []): mixed
{
// PHASE 3: Use EntityResolutionService to check chain-based deduplication
// This prevents creating duplicate Persons when Contract/ClientCase already exists
$import = $context['import'] ?? null;
if ($import) {
$personId = $this->resolutionService->resolvePersonFromContext($import, $mapped, $context);
if ($personId) {
$person = Person::find($personId);
if ($person) {
Log::info('PersonHandler: Resolved existing Person via chain', [
'person_id' => $personId,
'resolution_method' => 'EntityResolutionService',
]);
return $person;
}
}
}
// Fall back to configured deduplication fields (tax_number, SSN)
$dedupeBy = $this->getOption('deduplicate_by', ['tax_number', 'social_security_number']);
foreach ($dedupeBy as $field) {
if (! empty($mapped[$field])) {
$person = Person::where($field, $mapped[$field])->first();
if ($person) {
Log::info('PersonHandler: Resolved existing Person by identifier', [
'person_id' => $person->id,
'field' => $field,
]);
return $person;
}
}
}
return null;
}
public function process(Import $import, array $mapped, array $raw, array $context = []): array
{
// Add import to context for EntityResolutionService
$context['import'] = $import;
$existing = $this->resolve($mapped, $context);
if ($existing) {
// Update if configured
$mode = $this->getOption('update_mode', 'update');
if ($mode === 'skip') {
return [
'action' => 'skipped',
'entity' => $existing,
'message' => 'Person already exists (skip mode)',
];
}
$payload = $this->buildPayload($mapped, $existing);
$appliedFields = $this->trackAppliedFields($existing, $payload);
if (empty($appliedFields)) {
return [
'action' => 'skipped',
'entity' => $existing,
'message' => 'No changes detected',
];
}
$existing->fill($payload);
$existing->save();
return [
'action' => 'updated',
'entity' => $existing,
'applied_fields' => $appliedFields,
];
}
// Create new person
Log::info('PersonHandler: Creating new Person (no existing entity found)', [
'has_tax_number' => !empty($mapped['tax_number']),
'has_ssn' => !empty($mapped['social_security_number']),
'has_contract' => isset($context['contract']),
'has_client_case' => isset($context['client_case']),
]);
$person = new Person;
$payload = $this->buildPayload($mapped, $person);
// Ensure required foreign keys have defaults
if (!isset($payload['group_id'])) {
$payload['group_id'] = $this->getDefaultPersonGroupId();
}
if (!isset($payload['type_id'])) {
$payload['type_id'] = $this->getDefaultPersonTypeId();
}
Log::debug('PersonHandler: Payload before fill', [
'payload' => $payload,
'has_group_id' => isset($payload['group_id']),
'group_id_value' => $payload['group_id'] ?? null,
]);
$person->fill($payload);
Log::debug('PersonHandler: Person attributes after fill', [
'attributes' => $person->getAttributes(),
'has_group_id' => isset($person->group_id),
'group_id_value' => $person->group_id ?? null,
]);
$person->save();
Log::info('PersonHandler: Created new Person', [
'person_id' => $person->id,
]);
return [
'action' => 'inserted',
'entity' => $person,
'applied_fields' => array_keys($payload),
];
}
protected function buildPayload(array $mapped, $model): array
{
$payload = [];
$fieldMap = [
'first_name' => 'first_name',
'last_name' => 'last_name',
'full_name' => 'full_name',
'gender' => 'gender',
'birthday' => 'birthday',
'tax_number' => 'tax_number',
'social_security_number' => 'social_security_number',
'description' => 'description',
'group_id' => 'group_id',
'type_id' => 'type_id',
];
foreach ($fieldMap as $source => $target) {
if (array_key_exists($source, $mapped)) {
$value = $mapped[$source];
// Normalize date fields
if ($source === 'birthday' && $value) {
$value = DateNormalizer::toDate((string) $value);
}
$payload[$target] = $value;
}
}
return $payload;
}
private function getDefaultPersonGroupId(): int
{
return (int) (PersonGroup::min('id') ?? 1);
}
private function getDefaultPersonTypeId(): int
{
return (int) (PersonType::min('id') ?? 1);
}
}