81bc62153b
Task 2.1: SalesAttachmentService.lookup(login→tenant по contact_email ИЛИ inn) + submit(menedzher, login): не найден→заявка not_found + письмо; свободен→pending + письма менеджеру и всем начальникам; занят другим→pending с пометкой конфликта в comment; уже свой→исключение. Mailable AttachmentSubmittedMail/AttachmentNotFoundMail + blade. Тест 7/7 (Mail::fake), весь sales 82/82, stan 0. Один эскейп на сессию. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
171 lines
7.1 KiB
PHP
171 lines
7.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Mail\Sales\AttachmentNotFoundMail;
|
|
use App\Mail\Sales\AttachmentSubmittedMail;
|
|
use App\Models\SalesAttachmentRequest;
|
|
use App\Models\SalesClientAssignment;
|
|
use App\Models\SalesUser;
|
|
use App\Models\Tenant;
|
|
use App\Models\TenantRequisites;
|
|
use App\Services\Sales\SalesAttachmentService;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
/**
|
|
* TDD: SalesAttachmentService — поиск клиента и подача заявки на привязку.
|
|
*
|
|
* Покрывает Task 2.1: lookup() и submit() со всеми ветками:
|
|
* - not_found → status='not_found' + AttachmentNotFoundMail менеджеру
|
|
* - свободен → status='pending' + AttachmentSubmittedMail менеджеру и всем начальникам
|
|
* - занят другим → status='pending' + comment с именем другого менеджера
|
|
* - уже у этого → DomainException "Этот клиент уже ваш."
|
|
*
|
|
* Изоляция: DatabaseTransactions — откат в конце каждого теста.
|
|
* DB_DATABASE=liderra_testing, DEFAULT connection (pgsql).
|
|
*/
|
|
uses(DatabaseTransactions::class);
|
|
|
|
// ── helpers ─────────────────────────────────────────────────────────────────
|
|
|
|
function makeManager(array $attrs = []): SalesUser
|
|
{
|
|
return SalesUser::create(array_merge([
|
|
'name' => 'Менеджер '.uniqid(),
|
|
'email' => 'mgr'.uniqid().'@sales.local',
|
|
'password' => bcrypt('secret'),
|
|
'role' => 'manager',
|
|
], $attrs));
|
|
}
|
|
|
|
function makeHead(array $attrs = []): SalesUser
|
|
{
|
|
return SalesUser::create(array_merge([
|
|
'name' => 'Руководитель '.uniqid(),
|
|
'email' => 'head'.uniqid().'@sales.local',
|
|
'password' => bcrypt('secret'),
|
|
'role' => 'head',
|
|
'is_active' => true,
|
|
], $attrs));
|
|
}
|
|
|
|
function makeService(): SalesAttachmentService
|
|
{
|
|
return app(SalesAttachmentService::class);
|
|
}
|
|
|
|
// ── lookup() ─────────────────────────────────────────────────────────────────
|
|
|
|
test('lookup находит тенанта по contact_email', function (): void {
|
|
$tenant = Tenant::factory()->create(['contact_email' => 'client-email@example.com']);
|
|
|
|
$found = makeService()->lookup('client-email@example.com');
|
|
|
|
expect($found)->not->toBeNull()
|
|
->and($found->id)->toBe($tenant->id);
|
|
});
|
|
|
|
test('lookup находит тенанта по ИНН из tenant_requisites', function (): void {
|
|
$tenant = Tenant::factory()->create();
|
|
TenantRequisites::create([
|
|
'tenant_id' => $tenant->id,
|
|
'subject_type' => 'sole_proprietor',
|
|
'contact_name' => 'Тест ИП',
|
|
'contact_phone' => '+79000000001',
|
|
'inn' => '245210851872',
|
|
]);
|
|
|
|
$found = makeService()->lookup('245210851872');
|
|
|
|
expect($found)->not->toBeNull()
|
|
->and($found->id)->toBe($tenant->id);
|
|
});
|
|
|
|
test('lookup возвращает null если нет совпадения ни по email ни по ИНН', function (): void {
|
|
$result = makeService()->lookup('nobody@nowhere.test');
|
|
|
|
expect($result)->toBeNull();
|
|
});
|
|
|
|
// ── submit() — not_found ──────────────────────────────────────────────────────
|
|
|
|
test('submit для несуществующего логина создаёт заявку not_found и шлёт AttachmentNotFoundMail', function (): void {
|
|
Mail::fake();
|
|
$manager = makeManager();
|
|
|
|
$req = makeService()->submit($manager, 'nobody@nowhere.test');
|
|
|
|
expect($req)->toBeInstanceOf(SalesAttachmentRequest::class)
|
|
->and($req->status)->toBe('not_found')
|
|
->and($req->sales_user_id)->toBe($manager->id)
|
|
->and($req->login_input)->toBe('nobody@nowhere.test')
|
|
->and($req->tenant_id)->toBeNull();
|
|
|
|
Mail::assertQueued(AttachmentNotFoundMail::class, fn ($mail): bool => $mail->hasTo($manager->email)
|
|
);
|
|
});
|
|
|
|
// ── submit() — свободный клиент ───────────────────────────────────────────────
|
|
|
|
test('submit для свободного клиента создаёт pending-заявку и шлёт AttachmentSubmittedMail менеджеру и начальнику', function (): void {
|
|
Mail::fake();
|
|
$manager = makeManager();
|
|
$head = makeHead();
|
|
$tenant = Tenant::factory()->create(['contact_email' => 'free-client@example.com']);
|
|
|
|
$req = makeService()->submit($manager, 'free-client@example.com');
|
|
|
|
expect($req->status)->toBe('pending')
|
|
->and($req->tenant_id)->toBe($tenant->id)
|
|
->and($req->comment)->toBeNull();
|
|
|
|
// Письмо должно уйти менеджеру
|
|
Mail::assertQueued(AttachmentSubmittedMail::class, fn ($mail): bool => $mail->hasTo($manager->email)
|
|
);
|
|
|
|
// Письмо должно уйти начальнику
|
|
Mail::assertQueued(AttachmentSubmittedMail::class, fn ($mail): bool => $mail->hasTo($head->email)
|
|
);
|
|
});
|
|
|
|
// ── submit() — клиент уже занят другим менеджером ─────────────────────────────
|
|
|
|
test('submit для клиента занятого другим менеджером создаёт pending с комментарием о конфликте', function (): void {
|
|
Mail::fake();
|
|
$manager = makeManager();
|
|
$otherManager = makeManager(['name' => 'Другой Менеджер']);
|
|
$tenant = Tenant::factory()->create(['contact_email' => 'taken-client@example.com']);
|
|
|
|
SalesClientAssignment::create([
|
|
'sales_user_id' => $otherManager->id,
|
|
'tenant_id' => $tenant->id,
|
|
'tariff_params' => [],
|
|
'assigned_at' => now(),
|
|
]);
|
|
|
|
$req = makeService()->submit($manager, 'taken-client@example.com');
|
|
|
|
expect($req->status)->toBe('pending')
|
|
->and($req->tenant_id)->toBe($tenant->id)
|
|
->and($req->comment)->toContain('Другой Менеджер');
|
|
});
|
|
|
|
// ── submit() — клиент уже у этого менеджера ──────────────────────────────────
|
|
|
|
test('submit для клиента уже привязанного к этому менеджеру бросает DomainException', function (): void {
|
|
Mail::fake();
|
|
$manager = makeManager();
|
|
$tenant = Tenant::factory()->create(['contact_email' => 'own-client@example.com']);
|
|
|
|
SalesClientAssignment::create([
|
|
'sales_user_id' => $manager->id,
|
|
'tenant_id' => $tenant->id,
|
|
'tariff_params' => [],
|
|
'assigned_at' => now(),
|
|
]);
|
|
|
|
expect(fn (): SalesAttachmentRequest => makeService()->submit($manager, 'own-client@example.com'))
|
|
->toThrow(DomainException::class, 'Этот клиент уже ваш.');
|
|
});
|