Files
portal/app/tests/Feature/Admin/SupplierIntegrationAuditTest.php
T
2026-05-22 18:53:11 +03:00

164 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\Project;
use App\Models\SupplierManualSyncQueue;
use App\Models\SupplierProject;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Supplier\Channel\SupplierProjectChannel;
use App\Services\Supplier\Dto\SupplierProjectDto;
use App\Services\Supplier\SupplierPortalClient;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
uses(DatabaseTransactions::class);
// Creates a stub saas_admin_users row and returns its id.
function stubAdminUser(string $email = 'audit-stub@test.local'): int
{
$existing = DB::table('saas_admin_users')->where('email', $email)->value('id');
if ($existing !== null) {
return (int) $existing;
}
return (int) DB::table('saas_admin_users')->insertGetId([
'email' => $email,
'full_name' => 'Audit Test Stub',
'password_hash' => '$2y$04$system-stub-not-loginable',
'role' => 'super_admin',
'is_active' => false,
'sso_provider' => 'local',
'is_break_glass' => false,
]);
}
it('setExportMode writes audit log row', function (): void {
$adminId = stubAdminUser();
$this->actingAs(User::factory()->create());
DB::table('system_settings')->updateOrInsert(
['key' => 'supplier_export_mode'],
['value' => 'batch', 'type' => 'string', 'updated_at' => now()],
);
$countBefore = DB::table('saas_admin_audit_log')->count();
$this->postJson('/api/admin/supplier-integration/export-mode', [
'mode' => 'online',
'admin_user_id' => $adminId,
])->assertOk();
expect(DB::table('saas_admin_audit_log')->count())->toBe($countBefore + 1);
$row = DB::table('saas_admin_audit_log')
->orderByDesc('id')
->first();
expect($row->action)->toBe('supplier_integration.export_mode_set')
->and($row->target_type)->toBe('system_setting')
->and($row->target_id)->toBeNull()
->and($row->admin_user_id)->toBe($adminId);
$after = json_decode($row->payload_after, true);
expect($after['mode'])->toBe('online');
});
it('manualQueueResolve writes audit log row', function (): void {
$adminId = stubAdminUser();
$admin = User::factory()->create();
$this->actingAs($admin);
$tenant = Tenant::factory()->create();
$project = Project::factory()->for($tenant)->create();
$queueRow = SupplierManualSyncQueue::create([
'project_id' => $project->id,
'platform' => 'B1',
'operation' => 'create',
'payload_snapshot' => ['signal_type' => 'site', 'unique_key' => 'audit-test.ru'],
'failure_reason' => 'contract_break',
'status' => 'pending',
]);
$channelMock = new class implements SupplierProjectChannel
{
public function createProject(SupplierProjectDto $dto): int
{
return 0;
}
public function updateProject(int $externalId, SupplierProjectDto $dto): void {}
public function listProjects(): array
{
return [['id' => 77777, 'platform' => 'B1', 'signal_type' => 'site', 'unique_key' => 'audit-test.ru']];
}
};
app()->instance(SupplierProjectChannel::class, $channelMock);
$countBefore = DB::table('saas_admin_audit_log')->count();
$this->postJson("/api/admin/supplier-integration/manual-queue/{$queueRow->id}/resolve", [
'admin_user_id' => $adminId,
])->assertOk();
expect(DB::table('saas_admin_audit_log')->count())->toBe($countBefore + 1);
$row = DB::table('saas_admin_audit_log')
->orderByDesc('id')
->first();
expect($row->action)->toBe('supplier_integration.manual_queue_resolved')
->and($row->target_type)->toBe('manual_queue_item')
->and((int) $row->target_id)->toBe($queueRow->id)
->and($row->admin_user_id)->toBe($adminId);
});
it('projectsDestroy writes audit log row', function (): void {
$adminId = stubAdminUser();
$this->actingAs(User::factory()->create());
$clientMock = new class extends SupplierPortalClient
{
public function __construct() {}
public function deleteProject(int $externalId): void {}
};
app()->instance(SupplierPortalClient::class, $clientMock);
$sp = SupplierProject::query()->create([
'platform' => 'B1',
'signal_type' => 'site',
'unique_key' => 'audit-destroy.ru',
'subject_code' => 77,
'current_limit' => 0,
'current_workdays' => [1, 2, 3, 4, 5, 6, 7],
'current_regions' => null,
'sync_status' => 'ok',
'supplier_external_id' => '12345',
]);
$countBefore = DB::table('saas_admin_audit_log')->count();
$this->postJson('/api/admin/supplier-integration/projects/delete', [
'ids' => [$sp->id],
'admin_user_id' => $adminId,
])->assertOk()->assertJson(['deleted' => 1, 'failures' => []]);
expect(DB::table('saas_admin_audit_log')->count())->toBe($countBefore + 1);
$row = DB::table('saas_admin_audit_log')
->orderByDesc('id')
->first();
expect($row->action)->toBe('supplier_integration.projects_destroyed')
->and($row->target_type)->toBe('supplier_projects_bulk')
->and($row->target_id)->toBeNull()
->and($row->admin_user_id)->toBe($adminId);
$after = json_decode($row->payload_after, true);
expect($after['deleted'])->toBe(1);
});