evaluationRunId); if (! $run || $run->isCanceled()) { return; } $coordinator = new EvaluationCoordinator(); try { $ruleSet = EvaluationRuleSet::find($run->rule_set_id); if (! $ruleSet) { $coordinator->eventError($run, 'Duplicitní QSO nelze vyhodnotit: chybí ruleset.', [ 'step' => 'duplicate_resolution', ]); return; } $coordinator->eventInfo($run, 'Duplicate: krok spuštěn.', [ 'step' => 'duplicate_resolution', 'round_id' => $run->round_id, ]); $coordinator->eventInfo($run, 'Detekce duplicitních QSO.', [ 'step' => 'match', 'round_id' => $run->round_id, 'step_progress_done' => null, 'step_progress_total' => $run->progress_total, ]); $strategy = $ruleSet->dupResolutionStrategy(); $working = WorkingQso::where('evaluation_run_id', $run->id)->get(); $byLog = $working->groupBy('log_id'); foreach ($byLog as $logId => $items) { if (EvaluationRun::isCanceledRun($run->id)) { return; } $byDupeKey = $items->groupBy('dupe_key'); foreach ($byDupeKey as $dupeKey => $dupes) { if (! $dupeKey || $dupes->count() < 2) { continue; } $sorted = $dupes->sort(function ($a, $b) use ($strategy, $run) { $resultA = QsoResult::where('evaluation_run_id', $run->id) ->where('log_qso_id', $a->log_qso_id) ->first(); $resultB = QsoResult::where('evaluation_run_id', $run->id) ->where('log_qso_id', $b->log_qso_id) ->first(); foreach ($strategy as $rule) { if ($rule === 'paired_first') { $aPaired = $resultA && $resultA->matched_log_qso_id !== null; $bPaired = $resultB && $resultB->matched_log_qso_id !== null; if ($aPaired !== $bPaired) { return $aPaired ? -1 : 1; } } if ($rule === 'ok_first') { $aOk = $resultA && $resultA->error_code === QsoErrorCode::OK; $bOk = $resultB && $resultB->error_code === QsoErrorCode::OK; if ($aOk !== $bOk) { return $aOk ? -1 : 1; } } if ($rule === 'earlier_time') { $tsA = $a->ts_utc?->getTimestamp() ?? PHP_INT_MAX; $tsB = $b->ts_utc?->getTimestamp() ?? PHP_INT_MAX; if ($tsA !== $tsB) { return $tsA <=> $tsB; } } if ($rule === 'lower_id') { if ($a->log_qso_id !== $b->log_qso_id) { return $a->log_qso_id <=> $b->log_qso_id; } } } return $a->log_qso_id <=> $b->log_qso_id; })->values(); $survivor = $sorted->shift(); foreach ($sorted as $dupe) { QsoResult::where('evaluation_run_id', $run->id) ->where('log_qso_id', $dupe->log_qso_id) ->update([ 'is_duplicate' => true, 'is_valid' => false, 'error_code' => QsoErrorCode::DUP, 'error_side' => 'NONE', ]); } } } EvaluationRun::where('id', $run->id)->increment('progress_done'); $coordinator->eventInfo($run, 'Duplicate: krok dokončen.', [ 'step' => 'duplicate_resolution', 'round_id' => $run->round_id, ]); } catch (Throwable $e) { $coordinator->eventError($run, 'Duplicate: krok selhal.', [ 'step' => 'duplicate_resolution', 'round_id' => $run->round_id, 'error' => $e->getMessage(), ]); throw $e; } } }