toBeTrue(); expect(Schema::hasColumns('supplier_leads', [ 'id', 'supplier_project_id', 'platform', 'raw_payload', 'vid', 'phone', 'received_at', 'source', 'processed_at', 'deals_created_count', ]))->toBeTrue(); }); test('supplier_leads has FK to supplier_projects with ON DELETE SET NULL', function () { $row = DB::selectOne( "SELECT c.confdeltype FROM pg_constraint c JOIN pg_class t ON c.conrelid = t.oid JOIN pg_class r ON c.confrelid = r.oid WHERE t.relname = 'supplier_leads' AND r.relname = 'supplier_projects' AND c.contype = 'f'" ); expect($row)->not->toBeNull(); // confdeltype: 'a'=NO ACTION, 'r'=RESTRICT, 'c'=CASCADE, 'n'=SET NULL, 'd'=SET DEFAULT expect($row->confdeltype)->toBe('n'); }); test('supplier_leads.source has CHECK enum', function () { // Valid source: должно пройти. $insertedId = DB::table('supplier_leads')->insertGetId([ 'platform' => 'B1', 'raw_payload' => json_encode(['test' => 'valid_source']), 'vid' => 1000001, 'phone' => '+79991234567', 'source' => 'webhook', ]); expect($insertedId)->toBeGreaterThan(0); DB::table('supplier_leads')->where('id', $insertedId)->delete(); // Invalid source: должно отклониться CHECK constraint'ом. expect(fn () => DB::table('supplier_leads')->insert([ 'platform' => 'B1', 'raw_payload' => json_encode(['test' => 'invalid']), 'vid' => 1000002, 'phone' => '+79991234568', 'source' => 'invalid_source', ]))->toThrow(QueryException::class); }); test('projects.delivered_today exists with default 0', function () { expect(Schema::hasColumn('projects', 'delivered_today'))->toBeTrue(); $col = DB::selectOne( "SELECT column_default FROM information_schema.columns WHERE table_name = 'projects' AND column_name = 'delivered_today'" ); expect($col)->not->toBeNull(); expect($col->column_default)->toContain('0'); }); test('UNIQUE INDEX on vid prevents duplicate inserts (idempotency)', function () { DB::statement("INSERT INTO supplier_leads (platform, raw_payload, vid, phone, received_at, source) VALUES ('B1', '{}', 999000111, '79991234567', NOW(), 'webhook')"); expect(fn () => DB::statement( "INSERT INTO supplier_leads (platform, raw_payload, vid, phone, received_at, source) VALUES ('B2', '{}', 999000111, '79991234567', NOW(), 'webhook')" ))->toThrow(QueryException::class); }); test('system_settings seed rows exist for supplier_webhook_secret + supplier_ip_allowlist', function () { $secret = DB::table('system_settings') ->where('key', 'supplier_webhook_secret') ->first(); expect($secret)->not->toBeNull(); expect($secret->type)->toBe('string'); // Placeholder only valid in dev/test — production must override via deploy script. // Real secret strength validation belongs to a deploy-time validator (out of scope). expect($secret->value)->toBe('__SET_ON_DEPLOY__'); $allowlist = DB::table('system_settings') ->where('key', 'supplier_ip_allowlist') ->first(); expect($allowlist)->not->toBeNull(); expect($allowlist->type)->toBe('json'); $decoded = json_decode($allowlist->value, true); expect($decoded)->toBeArray(); });