'Менеджер-API '.uniqid(), 'email' => 'apimgr'.uniqid().'@sales.local', 'password' => bcrypt('secret'), 'role' => 'manager', 'is_active' => true, ], $attrs)); } function apiHead(array $attrs = []): SalesUser { return SalesUser::create(array_merge([ 'name' => 'Начальник-API '.uniqid(), 'email' => 'apihead'.uniqid().'@sales.local', 'password' => bcrypt('secret'), 'role' => 'head', 'is_active' => true, ], $attrs)); } function apiTenant(string $email = ''): Tenant { return Tenant::factory()->create([ 'contact_email' => $email !== '' ? $email : 'apiclient'.uniqid().'@example.com', ]); } // ── store: POST /api/sales/attachments ─────────────────────────────────────── test('manager POST /api/sales/attachments with existing client email → 201 pending', function () { Mail::fake(); $manager = apiManager(); $tenant = apiTenant('known-client@example.com'); $response = $this->actingAs($manager, 'sales') ->postJson('/api/sales/attachments', ['login' => 'known-client@example.com']); $response->assertCreated(); expect($response->json('status'))->toBe('pending'); expect($response->json('tenant_id'))->toBe($tenant->id); expect($response->json('status_label'))->toBe('На рассмотрении'); }); test('manager POST with unknown login → 201 not_found', function () { Mail::fake(); $manager = apiManager(); $response = $this->actingAs($manager, 'sales') ->postJson('/api/sales/attachments', ['login' => 'nobody-xyz@unknown.test']); $response->assertCreated(); expect($response->json('status'))->toBe('not_found'); expect($response->json('tenant_id'))->toBeNull(); expect($response->json('status_label'))->toBe('Клиент не найден'); }); test('manager POST for client already assigned to them → 422 with plain-Russian message', function () { Mail::fake(); $manager = apiManager(); $tenant = apiTenant('own-api-client@example.com'); SalesClientAssignment::create([ 'sales_user_id' => $manager->id, 'tenant_id' => $tenant->id, 'tariff_params' => [], 'assigned_at' => now(), ]); $response = $this->actingAs($manager, 'sales') ->postJson('/api/sales/attachments', ['login' => 'own-api-client@example.com']); $response->assertStatus(422); expect($response->json('message'))->toBe('Этот клиент уже ваш.'); }); test('POST without login field → 422 validation error', function () { $manager = apiManager(); $this->actingAs($manager, 'sales') ->postJson('/api/sales/attachments', []) ->assertStatus(422); }); // ── index: GET /api/sales/attachments ──────────────────────────────────────── test('manager GET /api/sales/attachments sees only their own requests', function () { Mail::fake(); $managerA = apiManager(); $managerB = apiManager(); // Создаём заявки для обоих менеджеров SalesAttachmentRequest::create([ 'sales_user_id' => $managerA->id, 'login_input' => 'client-a@example.com', 'status' => 'pending', ]); SalesAttachmentRequest::create([ 'sales_user_id' => $managerB->id, 'login_input' => 'client-b@example.com', 'status' => 'pending', ]); $response = $this->actingAs($managerA, 'sales') ->getJson('/api/sales/attachments'); $response->assertOk(); $data = $response->json('data'); expect($data)->not->toBeNull()->toHaveCount(1); expect($data[0]['login_input'])->toBe('client-a@example.com'); }); test('head GET /api/sales/attachments sees pending queue including other managers requests', function () { Mail::fake(); $manager = apiManager(); $head = apiHead(); // Pending заявка от менеджера SalesAttachmentRequest::create([ 'sales_user_id' => $manager->id, 'login_input' => 'head-visible@example.com', 'status' => 'pending', ]); $response = $this->actingAs($head, 'sales') ->getJson('/api/sales/attachments'); $response->assertOk(); expect($response->json('pending'))->not->toBeNull(); expect($response->json('history'))->not->toBeNull(); $pending = $response->json('pending'); $logins = array_column($pending, 'login_input'); expect($logins)->toContain('head-visible@example.com'); }); test('head GET index returns manager_name in pending rows', function () { Mail::fake(); $manager = apiManager(['name' => 'Иван Тестов '.uniqid()]); $head = apiHead(); SalesAttachmentRequest::create([ 'sales_user_id' => $manager->id, 'login_input' => 'head-mgr-name@example.com', 'status' => 'pending', ]); $response = $this->actingAs($head, 'sales') ->getJson('/api/sales/attachments'); $response->assertOk(); $pending = $response->json('pending'); expect($pending)->not->toBeEmpty(); // Ищем нашу заявку $found = collect($pending)->firstWhere('login_input', 'head-mgr-name@example.com'); expect($found)->not->toBeNull(); expect($found['manager_name'])->toContain('Иван Тестов'); }); // ── decide: POST /api/sales/attachments/{id}/decide ────────────────────────── test('head POST decide approve → 200, assignment created', function () { Mail::fake(); $manager = apiManager(); $head = apiHead(); $tenant = apiTenant('decide-test@example.com'); $req = SalesAttachmentRequest::create([ 'sales_user_id' => $manager->id, 'login_input' => 'decide-test@example.com', 'tenant_id' => $tenant->id, 'status' => 'pending', ]); $response = $this->actingAs($head, 'sales') ->postJson("/api/sales/attachments/{$req->id}/decide", ['action' => 'approve']); $response->assertOk(); expect($response->json('status'))->toBe('approved'); expect($response->json('status_label'))->toBe('Одобрено'); // Spot-check: assignment создан $assignment = SalesClientAssignment::where('tenant_id', $tenant->id)->first(); expect($assignment)->not->toBeNull(); expect($assignment->sales_user_id)->toBe($manager->id); }); test('manager POST decide → 403 plain Russian message', function () { Mail::fake(); $manager = apiManager(); $otherManager = apiManager(); $tenant = apiTenant('mgr-decide@example.com'); $req = SalesAttachmentRequest::create([ 'sales_user_id' => $otherManager->id, 'login_input' => 'mgr-decide@example.com', 'tenant_id' => $tenant->id, 'status' => 'pending', ]); $response = $this->actingAs($manager, 'sales') ->postJson("/api/sales/attachments/{$req->id}/decide", ['action' => 'approve']); $response->assertStatus(403); expect($response->json('message'))->toBe('Только начальник может решать по заявкам.'); }); test('decide with invalid action → 422 validation error', function () { $head = apiHead(); $manager = apiManager(); $tenant = apiTenant('bad-action@example.com'); $req = SalesAttachmentRequest::create([ 'sales_user_id' => $manager->id, 'login_input' => 'bad-action@example.com', 'tenant_id' => $tenant->id, 'status' => 'pending', ]); $this->actingAs($head, 'sales') ->postJson("/api/sales/attachments/{$req->id}/decide", ['action' => 'invalidaction']) ->assertStatus(422); }); // ── unauthenticated ─────────────────────────────────────────────────────────── test('unauthenticated POST /api/sales/attachments → 401', function () { $this->postJson('/api/sales/attachments', ['login' => 'test@example.com']) ->assertUnauthorized(); }); test('unauthenticated GET /api/sales/attachments → 401', function () { $this->getJson('/api/sales/attachments') ->assertUnauthorized(); });