Merge pull request #25 from CoralMinister/feat/slepok-stage-1
Feat/slepok stage 1
This commit is contained in:
@@ -59,19 +59,14 @@ class CleanupInactiveSupplierProjectsJob implements ShouldQueue
|
||||
{
|
||||
$client ??= app(SupplierPortalClient::class);
|
||||
|
||||
// Подзапрос — DISTINCT id'шники supplier_projects, на которые ссылается
|
||||
// хотя бы один Лидерра-project с is_active=true через любой из трёх FK.
|
||||
// Источник истинности активности — `project_supplier_links` pivot (Plan 3+).
|
||||
// Legacy FK `supplier_b{1,2,3}_project_id` оставлены для read-compat,
|
||||
// но не определяют активность.
|
||||
$activeIdsSubquery = <<<'SQL'
|
||||
SELECT DISTINCT id FROM (
|
||||
SELECT supplier_b1_project_id AS id FROM projects
|
||||
WHERE is_active = true AND supplier_b1_project_id IS NOT NULL
|
||||
UNION
|
||||
SELECT supplier_b2_project_id FROM projects
|
||||
WHERE is_active = true AND supplier_b2_project_id IS NOT NULL
|
||||
UNION
|
||||
SELECT supplier_b3_project_id FROM projects
|
||||
WHERE is_active = true AND supplier_b3_project_id IS NOT NULL
|
||||
) AS active_supplier_ids
|
||||
SELECT DISTINCT psl.supplier_project_id AS id
|
||||
FROM project_supplier_links psl
|
||||
INNER JOIN projects p ON p.id = psl.project_id
|
||||
WHERE p.is_active = true
|
||||
SQL;
|
||||
|
||||
// Phase A — re-activate (СНАЧАЛА для safety: до Phase C, чтобы недавно
|
||||
|
||||
@@ -63,7 +63,7 @@ class LeadRouter
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM tenants
|
||||
WHERE tenants.id = projects.tenant_id
|
||||
AND (tenants.balance_leads > 0 OR tenants.balance_rub > 0)
|
||||
AND tenants.balance_rub > 0
|
||||
)
|
||||
ORDER BY
|
||||
projects.tenant_id,
|
||||
@@ -94,7 +94,7 @@ class LeadRouter
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM tenants
|
||||
WHERE tenants.id = projects.tenant_id
|
||||
AND (tenants.balance_leads > 0 OR tenants.balance_rub > 0)
|
||||
AND tenants.balance_rub > 0
|
||||
)
|
||||
ORDER BY
|
||||
projects.tenant_id,
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\SupplierProject;
|
||||
use App\Models\Tenant;
|
||||
use App\Services\LeadRouter;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\Concerns\SharesSupplierPdo;
|
||||
|
||||
uses(DatabaseTransactions::class);
|
||||
uses(SharesSupplierPdo::class);
|
||||
|
||||
beforeEach(function (): void {
|
||||
// Clear tenant context — LeadRouter operates without it (sharing across tenants).
|
||||
DB::statement("SELECT set_config('app.current_tenant_id', '0', true)");
|
||||
});
|
||||
|
||||
it('does not match project for tenant with only balance_leads (no balance_rub)', function () {
|
||||
$tenant = Tenant::factory()->create([
|
||||
'balance_rub' => '0.00',
|
||||
'balance_leads' => 999, // legacy — должно игнорироваться после фикса
|
||||
]);
|
||||
$project = Project::factory()->for($tenant)->create([
|
||||
'is_active' => true,
|
||||
'delivery_days_mask' => 127,
|
||||
'daily_limit_target' => 10,
|
||||
'delivered_today' => 0,
|
||||
]);
|
||||
$sp = SupplierProject::factory()->create();
|
||||
\DB::table('project_supplier_links')->insert([
|
||||
'project_id' => $project->id,
|
||||
'supplier_project_id' => $sp->id,
|
||||
'platform' => $sp->platform,
|
||||
'subject_code' => null,
|
||||
]);
|
||||
|
||||
$matched = app(LeadRouter::class)->matchEligibleProjects($sp);
|
||||
|
||||
expect($matched)->toHaveCount(0); // balance_rub=0 → не eligible
|
||||
});
|
||||
|
||||
it('matches project for tenant with balance_rub > 0 (balance_leads ignored)', function () {
|
||||
$tenant = Tenant::factory()->create([
|
||||
'balance_rub' => '500.00',
|
||||
'balance_leads' => 0,
|
||||
]);
|
||||
$project = Project::factory()->for($tenant)->create([
|
||||
'is_active' => true,
|
||||
'delivery_days_mask' => 127,
|
||||
'daily_limit_target' => 10,
|
||||
'delivered_today' => 0,
|
||||
]);
|
||||
$sp = SupplierProject::factory()->create();
|
||||
\DB::table('project_supplier_links')->insert([
|
||||
'project_id' => $project->id,
|
||||
'supplier_project_id' => $sp->id,
|
||||
'platform' => $sp->platform,
|
||||
'subject_code' => null,
|
||||
]);
|
||||
|
||||
$matched = app(LeadRouter::class)->matchEligibleProjects($sp);
|
||||
|
||||
expect($matched)->toHaveCount(1);
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Jobs\Supplier\CleanupInactiveSupplierProjectsJob;
|
||||
use App\Models\Project;
|
||||
use App\Models\SupplierProject;
|
||||
use App\Models\Tenant;
|
||||
|
||||
it('does not mark inactive supplier_project that has pivot link to active project', function () {
|
||||
$tenant = Tenant::factory()->create();
|
||||
$project = Project::factory()->for($tenant)->create([
|
||||
'is_active' => true,
|
||||
// легаси FK НЕ заполнены (Plan 3+ архитектура):
|
||||
'supplier_b1_project_id' => null,
|
||||
'supplier_b2_project_id' => null,
|
||||
'supplier_b3_project_id' => null,
|
||||
]);
|
||||
$sp = SupplierProject::factory()->create([
|
||||
'inactive_since' => null,
|
||||
]);
|
||||
\DB::table('project_supplier_links')->insert([
|
||||
'project_id' => $project->id,
|
||||
'supplier_project_id' => $sp->id,
|
||||
'platform' => $sp->platform,
|
||||
'subject_code' => null,
|
||||
]);
|
||||
|
||||
(new CleanupInactiveSupplierProjectsJob)->handle(app(\App\Services\Supplier\SupplierPortalClient::class));
|
||||
|
||||
expect($sp->fresh()->inactive_since)->toBeNull();
|
||||
});
|
||||
|
||||
it('marks supplier_project inactive when no pivot link exists', function () {
|
||||
$sp = SupplierProject::factory()->create(['inactive_since' => null]);
|
||||
// нет project_supplier_links
|
||||
|
||||
(new CleanupInactiveSupplierProjectsJob)->handle(app(\App\Services\Supplier\SupplierPortalClient::class));
|
||||
|
||||
expect($sp->fresh()->inactive_since)->not->toBeNull();
|
||||
});
|
||||
Reference in New Issue
Block a user