/home/alixis5/integrate.sellofinance.com/src/Services
NameSizeModeActions
ApplicationService.php290940644editdlrm
AuthService.php127280644editdlrm
CatalogAggregator.php57910644editdlrm
CustomerBundleLoader.php39520644editdlrm
EligibilityEvaluator.php176030644editdlrm
GoogleAuthService.php82850644editdlrm
MeritRanker.php62790644editdlrm
OnboardingService.php229470644editdlrm
ProductPolicyLoader.php38180644editdlrm
VerificationService.php37520644editdlrm
Edit: /home/alixis5/integrate.sellofinance.com/src/Services/MeritRanker.php (6279B)
invNormalize($minSalary, $salaryMin, $salaryMax); $scoreBreadth = $this->invNormalize($minScore, $scoreMin, $scoreMax); return 0.6 * $salaryBreadth + 0.4 * $scoreBreadth; } /** * Linearly map x to [0,1], then invert. Returns 0.5 when range is flat. */ private function invNormalize(int $x, int $min, int $max): float { if ($max === $min) return 0.5; $t = ($x - $min) / ($max - $min); return max(0.0, min(1.0, 1.0 - $t)); } /** * Freshness score: exp(-ageDays / TAU). */ public function freshness(int $ageDays): float { return exp(-$ageDays / self::FRESHNESS_TAU_DAYS); } /** * Combined score. */ public function score(float $rate, float $eligibility, float $freshness): float { return self::WEIGHT_RATE * $rate + self::WEIGHT_ELIGIBILITY * $eligibility + self::WEIGHT_FRESHNESS * $freshness; } /** * Apply per-institution diversity cap. Products must already be sorted * by _score desc. * * @param array> $sortedProducts * @return array> */ public function applyDiversityCap(array $sortedProducts, int $limitPerInstitution = 3, int $finalLimit = 5): array { $picked = []; $perInstitution = []; foreach ($sortedProducts as $p) { $acc = $p['accountId'] ?? ''; if (($perInstitution[$acc] ?? 0) >= $limitPerInstitution) { continue; } $picked[] = $p; $perInstitution[$acc] = ($perInstitution[$acc] ?? 0) + 1; if (count($picked) >= $finalLimit) break; } return $picked; } /** * Full pipeline: score every product, sort desc by score (ties by * modifiedAt desc, then id asc), apply diversity cap, return top-K. * * @param array> $products * @return array> */ public function rank(array $products, \DateTimeImmutable $now, int $limit = 5): array { // Category averages for rate competitiveness $byCategory = []; foreach ($products as $p) { $cid = $p['categoryId'] ?? ''; $mid = (((float)($p['profitRateMin'] ?? 0)) + ((float)($p['profitRateMax'] ?? 0))) / 2; $byCategory[$cid][] = $mid; } $categoryAvg = []; foreach ($byCategory as $cid => $rates) { $categoryAvg[$cid] = count($rates) ? array_sum($rates) / count($rates) : 0.0; } // ProductType ranges for eligibility breadth $byType = []; foreach ($products as $p) { $t = $p['productType'] ?? ''; $byType[$t]['salaries'][] = (int)($p['minSalary'] ?? 0); $byType[$t]['scores'][] = (int)($p['minCreditScore'] ?? 0); } $typeRange = []; foreach ($byType as $t => $vals) { $typeRange[$t] = [ 'salaryMin' => min($vals['salaries']), 'salaryMax' => max($vals['salaries']), 'scoreMin' => min($vals['scores']), 'scoreMax' => max($vals['scores']), ]; } // Score each $scored = []; foreach ($products as $p) { $cid = $p['categoryId'] ?? ''; $t = $p['productType'] ?? ''; $mid = (((float)($p['profitRateMin'] ?? 0)) + ((float)($p['profitRateMax'] ?? 0))) / 2; $rateC = $this->rateCompetitiveness($mid, $categoryAvg[$cid] ?? 0); $range = $typeRange[$t] ?? ['salaryMin' => 0, 'salaryMax' => 0, 'scoreMin' => 0, 'scoreMax' => 0]; $elig = $this->eligibilityBreadth( (int)($p['minSalary'] ?? 0), $range['salaryMin'], $range['salaryMax'], (int)($p['minCreditScore'] ?? 0), $range['scoreMin'], $range['scoreMax'], ); $created = $p['createdAt'] ?? ''; $ageDays = 0; if ($created !== '') { $createdDt = new \DateTimeImmutable($created); $ageDays = max(0, (int) floor(($now->getTimestamp() - $createdDt->getTimestamp()) / 86400)); } $fresh = $this->freshness($ageDays); $scoreV = $this->score($rateC, $elig, $fresh); $p['_score'] = $scoreV; $scored[] = $p; } // Sort: score desc, then modifiedAt desc, then id asc usort($scored, function ($a, $b) { if ($b['_score'] !== $a['_score']) return $b['_score'] <=> $a['_score']; $am = $a['modifiedAt'] ?? ''; $bm = $b['modifiedAt'] ?? ''; if ($bm !== $am) return $bm <=> $am; return ($a['id'] ?? '') <=> ($b['id'] ?? ''); }); return $this->applyDiversityCap($scored, limitPerInstitution: 3, finalLimit: $limit); } }