381ce39142
ремонт: incident-followup cleanup batch — 4 хвоста 1. Larastan baseline regenerated (was 161 errors pre-existing IDE helper drift) 2. Deptrac Mail: [Model, Service] + ADR-005 amend (was 4 pre-existing violations) 3. PG logrotate config in setup-logrotate.yml 4. F1 6 mismatches — RCA updated (algorithm divergence trigger global vs verify per-tenant) +3 cspell words: notifempty, missingok, верифицируется. Ref: docs/incidents/2026-05-29-disk-full-pg-recovery.md §4-5
82 lines
2.7 KiB
PHP
82 lines
2.7 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Services\Supplier;
|
||
|
||
use App\Models\Project;
|
||
|
||
/**
|
||
* DRY-хелперы для группировки Лидерра-проектов по (subject × platform-set).
|
||
*
|
||
* Используется в:
|
||
* - SyncSupplierProjectJob (онлайн-режим, один проект)
|
||
* - SyncSupplierProjectsJob (ночной батч, все проекты)
|
||
*
|
||
* Spec: docs/superpowers/specs/2026-05-20-project-migration-redesign-design.md §4.3
|
||
* Plan: docs/superpowers/plans/2026-05-20-project-migration-redesign-plan-3-export.md Task 6
|
||
*/
|
||
final class SupplierProjectGrouping
|
||
{
|
||
/**
|
||
* Unique identifier key — единая агностическая формула для всех платформ
|
||
* (Stage 4 §4.4.1 R-17, ранее разделялась на platform-specific buildUniqueKey:
|
||
* B3 использовал sender alone, B2 sender+keyword, что создавало orphan
|
||
* supplier_projects при rebalance шеринга — мы не могли сопоставить B2/B3
|
||
* как одну группу):
|
||
* site/call → signal_identifier
|
||
* sms+keyword → sender+keyword
|
||
* sms без keyword → sender
|
||
*/
|
||
public static function buildUniqueKeyAgnostic(Project $project): string
|
||
{
|
||
if (in_array($project->signal_type, ['site', 'call'], true)) {
|
||
return (string) $project->signal_identifier;
|
||
}
|
||
|
||
$sender = (string) ($project->sms_senders[0] ?? '');
|
||
if ($project->sms_keyword !== null && $project->sms_keyword !== '') {
|
||
return $sender.'+'.$project->sms_keyword;
|
||
}
|
||
|
||
return $sender;
|
||
}
|
||
|
||
/**
|
||
* Возвращает список uppercase platform-кодов для данного project.
|
||
* Коды соответствуют CHECK constraint: 'B1' / 'B2' / 'B3'.
|
||
*
|
||
* @return list<string>
|
||
*/
|
||
public static function resolvePlatforms(Project $project): array
|
||
{
|
||
if (in_array($project->signal_type, ['site', 'call'], true)) {
|
||
return ['B1', 'B2', 'B3'];
|
||
}
|
||
|
||
if ($project->signal_type === 'sms') {
|
||
return ($project->sms_keyword !== null && $project->sms_keyword !== '')
|
||
? ['B2', 'B3']
|
||
: ['B3'];
|
||
}
|
||
|
||
return [];
|
||
}
|
||
|
||
/**
|
||
* Returns subjects (region codes 1..89) for a project.
|
||
* Empty regions → [null] (one group, "Вся РФ" pool).
|
||
*
|
||
* @return list<int|null>
|
||
*/
|
||
public static function subjectsOf(Project $project): array
|
||
{
|
||
$regions = array_values((array) $project->regions);
|
||
if (count($regions) === 0) {
|
||
return [null];
|
||
}
|
||
|
||
return array_map(fn ($r) => (int) $r, $regions);
|
||
}
|
||
}
|