diff --git a/app/Services/ImportProcessor.php b/app/Services/ImportProcessor.php index 0194b02..11be0cb 100644 --- a/app/Services/ImportProcessor.php +++ b/app/Services/ImportProcessor.php @@ -28,12 +28,14 @@ use Illuminate\Database\QueryException; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; class ImportProcessor { /** * Track contracts that already existed and were matched during history imports. + * * @var array */ private array $historyFoundContractIds = []; @@ -220,6 +222,11 @@ public function process(Import $import, ?Authenticatable $user = null): array try { DB::statement('SAVEPOINT import_row_'.$rowNum); } catch (\Throwable $se) { + Log::error('Import savepoint_failed', [ + 'import_id' => $import->id, + 'row_number' => $rowNum, + 'exception' => $this->exceptionContext($se), + ]); ImportEvent::create([ 'import_id' => $import->id, 'user_id' => $user?->getAuthIdentifier(), @@ -1096,6 +1103,11 @@ public function process(Import $import, ?Authenticatable $user = null): array } } if ($rollbackFailed) { + Log::error('Import row_rollback_failed', [ + 'import_id' => $import->id, + 'row_number' => $rowNum, + 'exception' => $this->exceptionContext($rollbackError ?? $e), + ]); // Abort the whole import if we cannot rollback to the row savepoint (transaction is poisoned) ImportEvent::create([ 'import_id' => $import->id, @@ -1137,6 +1149,12 @@ public function process(Import $import, ?Authenticatable $user = null): array } $failedRows[] = $rowNum; $invalid++; + Log::error('Import row_exception', [ + 'import_id' => $import->id, + 'row_number' => $rowNum, + 'exception' => $this->exceptionContext($e), + 'raw_preview' => isset($rawAssoc) ? $this->buildRawDataPreview($rawAssoc) : [], + ]); try { ImportEvent::create([ 'import_id' => $import->id, @@ -1154,6 +1172,12 @@ public function process(Import $import, ?Authenticatable $user = null): array ], ]); } catch (\Throwable $evtErr) { + Log::error('Import row_exception_event_failed', [ + 'import_id' => $import->id, + 'row_number' => $rowNum, + 'exception' => $this->exceptionContext($evtErr), + 'original_exception' => $this->exceptionContext($e), + ]); // Swallow secondary failure to ensure loop continues } @@ -1226,6 +1250,10 @@ public function process(Import $import, ?Authenticatable $user = null): array // Mark failed and log after rollback (so no partial writes persist) $import->refresh(); $import->update(['status' => 'failed', 'failed_at' => now()]); + Log::error('Import processing_failed', [ + 'import_id' => $import->id, + 'exception' => $this->exceptionContext($e), + ]); ImportEvent::create([ 'import_id' => $import->id, 'user_id' => $user?->getAuthIdentifier(), @@ -2047,7 +2075,7 @@ private function upsertActivity(Import $import, array $mapped, $mappings, ?array } $data = array_filter($applyInsert, fn ($v) => ! is_null($v)); - $activityModel = new Activity(); + $activityModel = new Activity; $activityModel->forceFill($data); if (array_key_exists('created_at', $data)) { // Preserve provided timestamps by disabling automatic timestamps for this save @@ -2271,6 +2299,7 @@ private function upsertContractChain(Import $import, array $mapped, $mappings, b if ($existing) { if ($historyImport) { $this->historyFoundContractIds[$existing->id] = true; + return ['action' => 'skipped_history', 'contract' => $existing, 'message' => 'Existing contract left unchanged (history import)']; } // 1) Prepare contract field changes (non-null) @@ -3090,8 +3119,8 @@ private function upsertAddress(int $personId, array $addrData, $mappings): array if (mb_strlen($addressLine) < 3) { return ['action' => 'skipped', 'message' => 'Invalid address value']; } - // Allow only basic address characters to avoid noisy special chars - if (! preg_match('/^[A-Za-z0-9\\s\\.,\\-\\/\\#\\\'"\\(\\)&]+$/', $addressLine)) { + // Allow letters (incl. diacritics), numbers, and common separators + if (! preg_match('/^[\\p{L}0-9\\s\\.,\\-\\/\\#\\\'"\\(\\)&]+$/u', $addressLine)) { return ['action' => 'skipped', 'message' => 'Invalid address value']; } // Default country SLO if not provided @@ -3343,3 +3372,6 @@ protected function attemptContractReactivation(Contract $contract, ?Authenticata } } } + + +