164 lines
5.3 KiB
PHP
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);
|
|
});
|