debug: добавить скрипты отладки и бэкапы для диагностики проблем
- api_keys_backup_1758196936364.json - резервная копия API ключей - check-active-key.js - проверка активного API ключа - check-all-keys.js - проверка всех API ключей в системе - check-new-seller.js - проверка нового селлера - test-api-key-save.js - тестирование сохранения API ключей - test-graphql-stats.js - тестирование GraphQL статистики - test-resolver-direct.js - прямое тестирование резолверов - test-sidebar.html - тестирование сайдбара - test-statistics-direct.js - прямое тестирование статистики 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
53
api_keys_backup_1758196936364.json
Normal file
53
api_keys_backup_1758196936364.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"timestamp": "2025-09-18T12:02:16.363Z",
|
||||||
|
"apiKeys": [
|
||||||
|
{
|
||||||
|
"id": "cmfo4o2ym000ny5ccj72vkskc",
|
||||||
|
"marketplace": "WILDBERRIES",
|
||||||
|
"apiKey": "eyJhbGciOiJFUzI1NiIsImtpZCI6IjIwMjUwNTIwdjEiLCJ0eXAiOiJKV1QifQ.eyJlbnQiOjEsImV4cCI6MTc2NjgwODMzMiwiaWQiOiIwMTk3YjIyMy0xNDAwLTc1MTQtYjgwZS0wYzIyYjRiYWZlODYiLCJpaWQiOjM0MTU5NTU3LCJvaWQiOjI1MDAwOTkxMCwicyI6MTA3Mzc0OTc1OCwic2lkIjoiNTIwMmYwMzYtMWNiNC00MmIyLWFhODUtYWNiOWFjODJmYzYyIiwidCI6ZmFsc2UsInVpZCI6MzQxNTk1NTd9.tSjALISoFdkylX0iMuquXhpRJhTZwEMOZV_mfZh1wXUtRzyu4m8r5cvodaMVxcSNKifit2Vm2CWKw1Hp9z7_AQ",
|
||||||
|
"clientId": null,
|
||||||
|
"isActive": true,
|
||||||
|
"createdAt": "2025-09-17T15:19:35.423Z",
|
||||||
|
"updatedAt": "2025-09-17T15:19:35.423Z",
|
||||||
|
"validationData": "{\"sellerId\":\"5202f036-1cb4-42b2-aa85-acb9ac82fc62\",\"sellerName\":\"ИП Антипова Д. В.\",\"tradeMark\":\"Rennel\"}",
|
||||||
|
"organizationId": "cmfo4o1on000ly5ccsmshxlde",
|
||||||
|
"organization": {
|
||||||
|
"id": "cmfo4o1on000ly5ccsmshxlde",
|
||||||
|
"inn": "SELLER_1758122373766",
|
||||||
|
"kpp": null,
|
||||||
|
"name": "Rennel",
|
||||||
|
"fullName": "ИП Антипова Д. В.",
|
||||||
|
"ogrn": null,
|
||||||
|
"ogrnDate": null,
|
||||||
|
"type": "SELLER",
|
||||||
|
"market": null,
|
||||||
|
"createdAt": "2025-09-17T15:19:33.767Z",
|
||||||
|
"updatedAt": "2025-09-17T15:19:35.598Z",
|
||||||
|
"address": null,
|
||||||
|
"addressFull": null,
|
||||||
|
"status": null,
|
||||||
|
"actualityDate": null,
|
||||||
|
"registrationDate": null,
|
||||||
|
"liquidationDate": null,
|
||||||
|
"managementName": null,
|
||||||
|
"managementPost": null,
|
||||||
|
"opfCode": null,
|
||||||
|
"opfFull": null,
|
||||||
|
"opfShort": null,
|
||||||
|
"okato": null,
|
||||||
|
"oktmo": null,
|
||||||
|
"okpo": null,
|
||||||
|
"okved": null,
|
||||||
|
"phones": null,
|
||||||
|
"emails": null,
|
||||||
|
"employeeCount": null,
|
||||||
|
"revenue": null,
|
||||||
|
"taxSystem": null,
|
||||||
|
"dadataData": null,
|
||||||
|
"referralCode": "SL_78855599999_1758122373766",
|
||||||
|
"referredById": "cmfo4jpk1000ay5cc7sunfeso",
|
||||||
|
"referralPoints": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
47
check-active-key.js
Normal file
47
check-active-key.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function checkActiveKey() {
|
||||||
|
try {
|
||||||
|
// Найдем организацию Rennel
|
||||||
|
const org = await prisma.organization.findFirst({
|
||||||
|
where: { name: 'Rennel', type: 'SELLER' },
|
||||||
|
include: {
|
||||||
|
users: true,
|
||||||
|
apiKeys: {
|
||||||
|
where: {
|
||||||
|
marketplace: 'WILDBERRIES',
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!org) {
|
||||||
|
console.log('❌ Организация Rennel не найдена')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🏢 ОРГАНИЗАЦИЯ RENNEL:')
|
||||||
|
console.log('- ID:', org.id)
|
||||||
|
console.log('- Пользователей:', org.users.length)
|
||||||
|
console.log('- Активных WB ключей:', org.apiKeys.length)
|
||||||
|
|
||||||
|
if (org.apiKeys.length > 0) {
|
||||||
|
const activeKey = org.apiKeys[0] // Последний созданный
|
||||||
|
console.log('\n🔑 АКТИВНЫЙ КЛЮЧ (который будет использоваться):')
|
||||||
|
console.log('- ID:', activeKey.id)
|
||||||
|
console.log('- Длина:', activeKey.apiKey?.length)
|
||||||
|
console.log('- Тип:', activeKey.apiKey?.startsWith('eyJ') ? 'Валидный JWT' : 'Тестовый')
|
||||||
|
console.log('- Создан:', activeKey.createdAt.toISOString())
|
||||||
|
console.log('- Данные валидации:', JSON.stringify(activeKey.validationData, null, 2))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Ошибка:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkActiveKey()
|
55
check-all-keys.js
Normal file
55
check-all-keys.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function checkAllKeys() {
|
||||||
|
try {
|
||||||
|
const org = await prisma.organization.findFirst({
|
||||||
|
where: { name: 'Rennel', type: 'SELLER' },
|
||||||
|
include: {
|
||||||
|
apiKeys: {
|
||||||
|
where: { marketplace: 'WILDBERRIES' },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!org) {
|
||||||
|
console.log('❌ Организация Rennel не найдена')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🏢 ОРГАНИЗАЦИЯ RENNEL:')
|
||||||
|
console.log('- ID:', org.id)
|
||||||
|
console.log('- Всего WB ключей:', org.apiKeys.length)
|
||||||
|
|
||||||
|
console.log('\n🔍 ВСЕ КЛЮЧИ WILDBERRIES:')
|
||||||
|
org.apiKeys.forEach((key, index) => {
|
||||||
|
console.log(`\n--- КЛЮЧ ${index + 1} ---`)
|
||||||
|
console.log('- ID:', key.id)
|
||||||
|
console.log('- Длина:', key.apiKey?.length)
|
||||||
|
console.log('- Тип:', key.apiKey?.startsWith('eyJ') ? 'Валидный JWT' : 'Тестовый')
|
||||||
|
console.log('- Активен:', key.isActive)
|
||||||
|
console.log('- Создан:', key.createdAt.toISOString())
|
||||||
|
console.log('- Обновлен:', key.updatedAt.toISOString())
|
||||||
|
console.log('- Данные валидации:', JSON.stringify(key.validationData, null, 2))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Найдем самый новый валидный JWT ключ
|
||||||
|
const validJwtKey = org.apiKeys.find((key) => key.apiKey?.startsWith('eyJ') && key.isActive)
|
||||||
|
|
||||||
|
if (validJwtKey) {
|
||||||
|
console.log('\n✅ НАЙДЕН ВАЛИДНЫЙ JWT КЛЮЧ:')
|
||||||
|
console.log('- ID:', validJwtKey.id)
|
||||||
|
console.log('- Создан:', validJwtKey.createdAt.toISOString())
|
||||||
|
console.log('- Должен использоваться вместо тестового')
|
||||||
|
} else {
|
||||||
|
console.log('\n❌ ВАЛИДНЫЙ JWT КЛЮЧ НЕ НАЙДЕН')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Ошибка:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAllKeys()
|
71
check-new-seller.js
Normal file
71
check-new-seller.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function checkNewSeller() {
|
||||||
|
try {
|
||||||
|
// Найдем пользователя с номером 79988888888
|
||||||
|
const user = await prisma.user.findFirst({
|
||||||
|
where: { phone: '79988888888' },
|
||||||
|
include: {
|
||||||
|
organization: {
|
||||||
|
include: {
|
||||||
|
apiKeys: {
|
||||||
|
where: { marketplace: 'WILDBERRIES' },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
console.log('❌ Пользователь 79988888888 не найден')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('👤 НОВЫЙ ПОЛЬЗОВАТЕЛЬ 79988888888:')
|
||||||
|
console.log('- ID:', user.id)
|
||||||
|
console.log('- Телефон:', user.phone)
|
||||||
|
console.log('- Организация:', user.organization?.name || 'НЕ ПРИВЯЗАНА')
|
||||||
|
|
||||||
|
if (user.organization) {
|
||||||
|
console.log('\n🏢 ОРГАНИЗАЦИЯ:')
|
||||||
|
console.log('- ID:', user.organization.id)
|
||||||
|
console.log('- Название:', user.organization.name)
|
||||||
|
console.log('- Тип:', user.organization.type)
|
||||||
|
console.log('- WB ключей:', user.organization.apiKeys.length)
|
||||||
|
|
||||||
|
if (user.organization.apiKeys.length > 0) {
|
||||||
|
console.log('\n🔑 API КЛЮЧИ WILDBERRIES:')
|
||||||
|
user.organization.apiKeys.forEach((key, index) => {
|
||||||
|
console.log(`\n--- КЛЮЧ ${index + 1} ---`)
|
||||||
|
console.log('- ID:', key.id)
|
||||||
|
console.log('- Длина:', key.apiKey?.length)
|
||||||
|
console.log('- Тип:', key.apiKey?.startsWith('eyJ') ? 'Валидный JWT' : 'Тестовый')
|
||||||
|
console.log('- Активен:', key.isActive)
|
||||||
|
console.log('- Создан:', key.createdAt.toISOString())
|
||||||
|
console.log('- Данные валидации:', JSON.stringify(key.validationData, null, 2))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Найдем самый новый валидный ключ
|
||||||
|
const validKey = user.organization.apiKeys.find((key) => key.apiKey && key.apiKey.length > 100 && key.isActive)
|
||||||
|
|
||||||
|
if (validKey) {
|
||||||
|
console.log('\n✅ СТАТУС: Есть валидный API ключ')
|
||||||
|
console.log('- Можно получать статистику Wildberries')
|
||||||
|
} else {
|
||||||
|
console.log('\n⚠️ СТАТУС: Только тестовые ключи')
|
||||||
|
console.log('- Статистика будет пустой')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('\n❌ API КЛЮЧИ НЕ НАЙДЕНЫ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Ошибка:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNewSeller()
|
117
test-api-key-save.js
Normal file
117
test-api-key-save.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function testApiKeySave() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 ТЕСТ СОХРАНЕНИЯ API КЛЮЧА')
|
||||||
|
|
||||||
|
// Найдем организацию Rennel
|
||||||
|
const org = await prisma.organization.findFirst({
|
||||||
|
where: { name: 'Rennel', type: 'SELLER' },
|
||||||
|
include: {
|
||||||
|
apiKeys: {
|
||||||
|
where: { marketplace: 'WILDBERRIES' },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!org) {
|
||||||
|
console.log('❌ Организация Rennel не найдена')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n📊 СОСТОЯНИЕ ДО ТЕСТА:')
|
||||||
|
console.log('- Организация:', org.name)
|
||||||
|
console.log('- Всего WB ключей:', org.apiKeys.length)
|
||||||
|
|
||||||
|
if (org.apiKeys.length > 0) {
|
||||||
|
const currentKey = org.apiKeys[0]
|
||||||
|
console.log('- Текущий ключ ID:', currentKey.id)
|
||||||
|
console.log('- Длина:', currentKey.apiKey?.length)
|
||||||
|
console.log('- Тип:', currentKey.apiKey?.startsWith('eyJ') ? 'JWT' : 'Тестовый')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Тестовый валидный JWT ключ (более короткий для теста)
|
||||||
|
const testJwtKey =
|
||||||
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FjY291bnQud2lsZGJlcnJpZXMucnUiLCJzdWIiOjEyMzQ1Njc4OTAsImV4cCI6MTcyNjY3MjgwMCwidXNlclR5cGUiOiJzZWxsZXIiLCJzY29wZSI6WyJhZHZlcnRpc2luZyIsInN0YXRpc3RpY3MiLCJvcmRlcnMiXX0.test_signature_here'
|
||||||
|
|
||||||
|
console.log('\n🔄 ИМИТАЦИЯ ОБНОВЛЕНИЯ КЛЮЧА...')
|
||||||
|
|
||||||
|
// Имитируем обновление через API (как делает мутация)
|
||||||
|
const existingKey = await prisma.apiKey.findUnique({
|
||||||
|
where: {
|
||||||
|
organizationId_marketplace: {
|
||||||
|
organizationId: org.id,
|
||||||
|
marketplace: 'WILDBERRIES',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (existingKey) {
|
||||||
|
console.log('- Найден существующий ключ:', existingKey.id)
|
||||||
|
|
||||||
|
// Обновляем как в мутации
|
||||||
|
const updated = await prisma.apiKey.update({
|
||||||
|
where: {
|
||||||
|
organizationId_marketplace: {
|
||||||
|
organizationId: org.id,
|
||||||
|
marketplace: 'WILDBERRIES',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
apiKey: testJwtKey,
|
||||||
|
isActive: true,
|
||||||
|
validationData: { validatedAt: new Date().toISOString() },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Ключ обновлен:', updated.id)
|
||||||
|
console.log('- Новая длина:', updated.apiKey?.length)
|
||||||
|
console.log('- Новый тип:', updated.apiKey?.startsWith('eyJ') ? 'JWT' : 'Тестовый')
|
||||||
|
} else {
|
||||||
|
console.log('- Существующий ключ не найден, создаем новый')
|
||||||
|
|
||||||
|
const created = await prisma.apiKey.create({
|
||||||
|
data: {
|
||||||
|
organizationId: org.id,
|
||||||
|
marketplace: 'WILDBERRIES',
|
||||||
|
apiKey: testJwtKey,
|
||||||
|
isActive: true,
|
||||||
|
validationData: { validatedAt: new Date().toISOString() },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Новый ключ создан:', created.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверим результат
|
||||||
|
console.log('\n📊 СОСТОЯНИЕ ПОСЛЕ ТЕСТА:')
|
||||||
|
const updatedOrg = await prisma.organization.findFirst({
|
||||||
|
where: { name: 'Rennel', type: 'SELLER' },
|
||||||
|
include: {
|
||||||
|
apiKeys: {
|
||||||
|
where: { marketplace: 'WILDBERRIES' },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (updatedOrg && updatedOrg.apiKeys.length > 0) {
|
||||||
|
const newKey = updatedOrg.apiKeys[0]
|
||||||
|
console.log('- Ключ ID:', newKey.id)
|
||||||
|
console.log('- Длина:', newKey.apiKey?.length)
|
||||||
|
console.log('- Тип:', newKey.apiKey?.startsWith('eyJ') ? 'JWT' : 'Тестовый')
|
||||||
|
console.log('- Активен:', newKey.isActive)
|
||||||
|
console.log('- Обновлен:', newKey.updatedAt.toISOString())
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n🎯 ТЕСТ ЗАВЕРШЕН')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ ОШИБКА ТЕСТА:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testApiKeySave()
|
95
test-graphql-stats.js
Normal file
95
test-graphql-stats.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function testGraphQLStats() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 ТЕСТИРОВАНИЕ ЛОГИКИ РЕЗОЛВЕРА getWildberriesStatistics')
|
||||||
|
|
||||||
|
// Имитируем логику резолвера
|
||||||
|
const user = await prisma.user.findFirst({
|
||||||
|
where: { phone: '79988888888' },
|
||||||
|
include: {
|
||||||
|
organization: {
|
||||||
|
include: { apiKeys: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!user?.organization) {
|
||||||
|
console.log('❌ Пользователь не привязан к организации')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n👤 ПОЛЬЗОВАТЕЛЬ:')
|
||||||
|
console.log('- ID:', user.id)
|
||||||
|
console.log('- Телефон:', user.phone)
|
||||||
|
console.log('- Организация:', user.organization.name)
|
||||||
|
|
||||||
|
// Логика поиска API ключа как в резолвере
|
||||||
|
const apiKey = user.organization.apiKeys.find((key) => key.marketplace === 'WILDBERRIES' && key.isActive)
|
||||||
|
|
||||||
|
console.log('\n🔍 ПОИСК API КЛЮЧА:')
|
||||||
|
console.log('- Всего ключей в организации:', user.organization.apiKeys.length)
|
||||||
|
console.log('- Найденный ключ:', !!apiKey)
|
||||||
|
|
||||||
|
if (!apiKey) {
|
||||||
|
console.log('❌ ПРОБЛЕМА: API ключ не найден через find()')
|
||||||
|
|
||||||
|
// Выводим все ключи для дебага
|
||||||
|
user.organization.apiKeys.forEach((key, index) => {
|
||||||
|
console.log(`\n--- КЛЮЧ ${index + 1} ---`)
|
||||||
|
console.log('- ID:', key.id)
|
||||||
|
console.log('- Marketplace:', key.marketplace)
|
||||||
|
console.log('- Active:', key.isActive)
|
||||||
|
console.log('- Условие WILDBERRIES:', key.marketplace === 'WILDBERRIES')
|
||||||
|
console.log('- Условие Active:', key.isActive === true)
|
||||||
|
console.log('- Полное условие:', key.marketplace === 'WILDBERRIES' && key.isActive)
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n✅ API КЛЮЧ НАЙДЕН:')
|
||||||
|
console.log('- ID:', apiKey.id)
|
||||||
|
console.log('- Marketplace:', apiKey.marketplace)
|
||||||
|
console.log('- Active:', apiKey.isActive)
|
||||||
|
console.log('- Длина ключа:', apiKey.apiKey?.length)
|
||||||
|
console.log('- Тип:', apiKey.apiKey?.startsWith('eyJ') ? 'JWT' : 'Другой')
|
||||||
|
|
||||||
|
// Проверим, работает ли сам API ключ
|
||||||
|
console.log('\n🌐 ТЕСТИРОВАНИЕ ЗАПРОСА К WILDBERRIES API:')
|
||||||
|
|
||||||
|
const testUrl = 'https://statistics-api.wildberries.ru/api/v1/supplier/sales?dateFrom=2025-09-01'
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(testUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: apiKey.apiKey,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('- HTTP статус:', response.status)
|
||||||
|
console.log('- OK:', response.ok)
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json()
|
||||||
|
console.log('- Данные получены, тип:', typeof data)
|
||||||
|
console.log('- Является массивом:', Array.isArray(data))
|
||||||
|
console.log('- Длина:', data?.length || 'N/A')
|
||||||
|
} else {
|
||||||
|
const errorText = await response.text()
|
||||||
|
console.log('- Ошибка API:', errorText)
|
||||||
|
}
|
||||||
|
} catch (fetchError) {
|
||||||
|
console.error('❌ ОШИБКА ЗАПРОСА:', fetchError.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ КРИТИЧЕСКАЯ ОШИБКА:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testGraphQLStats()
|
114
test-resolver-direct.js
Normal file
114
test-resolver-direct.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Тест резолвера GraphQL getWildberriesStatistics напрямую
|
||||||
|
const testResolverDirect = async () => {
|
||||||
|
console.log('🧪 ПРЯМОЙ ТЕСТ РЕЗОЛВЕРА getWildberriesStatistics')
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
query GetWildberriesStatistics($period: String, $startDate: String, $endDate: String) {
|
||||||
|
getWildberriesStatistics(period: $period, startDate: $startDate, endDate: $endDate) {
|
||||||
|
success
|
||||||
|
message
|
||||||
|
data {
|
||||||
|
date
|
||||||
|
sales
|
||||||
|
orders
|
||||||
|
advertising
|
||||||
|
refusals
|
||||||
|
returns
|
||||||
|
revenue
|
||||||
|
buyoutPercentage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// Получаем JWT токен (предполагаем что пользователь авторизован)
|
||||||
|
// Замените на реальный токен из браузера или создайте новый
|
||||||
|
const JWT_TOKEN = 'YOUR_JWT_TOKEN_HERE'
|
||||||
|
|
||||||
|
const variables1 = { period: 'week' }
|
||||||
|
const variables2 = { startDate: '2025-09-01', endDate: '2025-09-18' }
|
||||||
|
|
||||||
|
console.log('\n🔍 ТЕСТ 1: period = "week"')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response1 = await fetch('http://localhost:3001/api/graphql', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${JWT_TOKEN}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query,
|
||||||
|
variables: variables1,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response1.ok) {
|
||||||
|
const result1 = await response1.json()
|
||||||
|
console.log('✅ Ответ получен:')
|
||||||
|
console.log('- success:', result1.data?.getWildberriesStatistics?.success)
|
||||||
|
console.log('- message:', result1.data?.getWildberriesStatistics?.message)
|
||||||
|
console.log('- data length:', result1.data?.getWildberriesStatistics?.data?.length)
|
||||||
|
|
||||||
|
if (result1.errors) {
|
||||||
|
console.log('❌ GraphQL ошибки:', result1.errors)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('❌ HTTP ошибка:', response1.status)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Ошибка запроса:', error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n🔍 ТЕСТ 2: startDate + endDate')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response2 = await fetch('http://localhost:3001/api/graphql', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${JWT_TOKEN}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query,
|
||||||
|
variables: variables2,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response2.ok) {
|
||||||
|
const result2 = await response2.json()
|
||||||
|
console.log('✅ Ответ получен:')
|
||||||
|
console.log('- success:', result2.data?.getWildberriesStatistics?.success)
|
||||||
|
console.log('- message:', result2.data?.getWildberriesStatistics?.message)
|
||||||
|
console.log('- data length:', result2.data?.getWildberriesStatistics?.data?.length)
|
||||||
|
|
||||||
|
if (result2.data?.getWildberriesStatistics?.data?.length > 0) {
|
||||||
|
console.log('- Первая запись:', JSON.stringify(result2.data.getWildberriesStatistics.data[0], null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result2.errors) {
|
||||||
|
console.log('❌ GraphQL ошибки:', result2.errors)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('❌ HTTP ошибка:', response2.status)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Ошибка запроса:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инструкция для пользователя
|
||||||
|
console.log(`
|
||||||
|
📋 ИНСТРУКЦИЯ ДЛЯ ЗАПУСКА ТЕСТА:
|
||||||
|
|
||||||
|
1. Откройте браузер на http://localhost:3001/seller/statistics
|
||||||
|
2. Авторизуйтесь под номером 79988888888 (код: 1234)
|
||||||
|
3. Откройте Developer Tools (F12) → Network → найдите GraphQL запрос
|
||||||
|
4. Скопируйте заголовок Authorization: Bearer ...
|
||||||
|
5. Замените JWT_TOKEN в этом файле на реальный токен
|
||||||
|
6. Запустите: node test-resolver-direct.js
|
||||||
|
|
||||||
|
Или используйте этот код прямо в консоли браузера (без токена):
|
||||||
|
`)
|
||||||
|
|
||||||
|
testResolverDirect()
|
219
test-sidebar.html
Normal file
219
test-sidebar.html
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Sidebar Visibility Test</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(135deg, #1a0f2e 0%, #2d1b3d 50%, #0f0a1a 100%);
|
||||||
|
color: white;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 16px;
|
||||||
|
top: 16px;
|
||||||
|
bottom: 16px;
|
||||||
|
width: 224px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
z-index: 50;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-section {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button.active {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 256px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-info {
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.visible {
|
||||||
|
background: #10b981;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.hidden {
|
||||||
|
background: #ef4444;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="test-sidebar" id="testSidebar">
|
||||||
|
<div class="profile-section">
|
||||||
|
<div class="avatar">T</div>
|
||||||
|
<div>
|
||||||
|
<div style="font-size: 14px; font-weight: 500;">Test Organization</div>
|
||||||
|
<div style="font-size: 12px; opacity: 0.7;">Логистика</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="flex: 1;">
|
||||||
|
<button class="nav-button active">🏠 Главная</button>
|
||||||
|
<button class="nav-button">🚛 Перевозки</button>
|
||||||
|
<button class="nav-button">💬 Мессенджер</button>
|
||||||
|
<button class="nav-button">💰 Экономика</button>
|
||||||
|
<button class="nav-button">🤝 Партнёры</button>
|
||||||
|
<button class="nav-button">🏪 Маркет</button>
|
||||||
|
<button class="nav-button">📈 Биржа</button>
|
||||||
|
<button class="nav-button">⚙️ Настройки</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="nav-button" style="margin-top: auto;">🚪 Выйти</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<div class="debug-info">
|
||||||
|
<h2>🔍 Sidebar Visibility Test</h2>
|
||||||
|
<p><strong>Статус:</strong> <span class="status visible" id="visibilityStatus">VISIBLE</span></p>
|
||||||
|
<p><strong>Позиция:</strong> fixed left-16px top-16px</p>
|
||||||
|
<p><strong>Z-index:</strong> 50</p>
|
||||||
|
<p><strong>Фон:</strong> rgba(255, 255, 255, 0.1) + backdrop-blur</p>
|
||||||
|
<p><strong>Размеры:</strong> 224px x auto</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="debug-info">
|
||||||
|
<h3>🎯 Тесты отображения</h3>
|
||||||
|
<button onclick="toggleSidebar()" style="background: #3b82f6; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; margin-right: 8px;">
|
||||||
|
Переключить сайдбар
|
||||||
|
</button>
|
||||||
|
<button onclick="checkZIndex()" style="background: #8b5cf6; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; margin-right: 8px;">
|
||||||
|
Проверить z-index
|
||||||
|
</button>
|
||||||
|
<button onclick="testBackdrop()" style="background: #10b981; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer;">
|
||||||
|
Тест backdrop-filter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="debug-info">
|
||||||
|
<h3>🧪 Результаты проверок</h3>
|
||||||
|
<div id="testResults">
|
||||||
|
<p>✅ Sidebar элемент создан и добавлен в DOM</p>
|
||||||
|
<p>✅ CSS стили применены корректно</p>
|
||||||
|
<p>✅ Позиционирование fixed работает</p>
|
||||||
|
<p>✅ Z-index установлен на 50</p>
|
||||||
|
<p>✅ Backdrop-filter поддерживается браузером</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="debug-info">
|
||||||
|
<h3>📊 Проблемы SFERA Sidebar</h3>
|
||||||
|
<p><strong>1. Условия рендеринга:</strong> Проверьте hideSidebar в AppShell</p>
|
||||||
|
<p><strong>2. Данные пользователя:</strong> Убедитесь что user?.organization?.type передается</p>
|
||||||
|
<p><strong>3. TypeScript ошибки:</strong> Исправьте проблемы с isCollapsed в уведомлениях</p>
|
||||||
|
<p><strong>4. CSS конфликты:</strong> Возможно другие элементы перекрывают z-index: 50</p>
|
||||||
|
<p><strong>5. SSR проблемы:</strong> dynamic import с ssr: false может вызывать проблемы</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function toggleSidebar() {
|
||||||
|
const sidebar = document.getElementById('testSidebar');
|
||||||
|
const status = document.getElementById('visibilityStatus');
|
||||||
|
|
||||||
|
if (sidebar.style.display === 'none') {
|
||||||
|
sidebar.style.display = 'flex';
|
||||||
|
status.textContent = 'VISIBLE';
|
||||||
|
status.className = 'status visible';
|
||||||
|
} else {
|
||||||
|
sidebar.style.display = 'none';
|
||||||
|
status.textContent = 'HIDDEN';
|
||||||
|
status.className = 'status hidden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkZIndex() {
|
||||||
|
const sidebar = document.getElementById('testSidebar');
|
||||||
|
const computedStyle = window.getComputedStyle(sidebar);
|
||||||
|
alert(`Z-index: ${computedStyle.zIndex}\nPosition: ${computedStyle.position}\nDisplay: ${computedStyle.display}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testBackdrop() {
|
||||||
|
const testDiv = document.createElement('div');
|
||||||
|
testDiv.style.backdropFilter = 'blur(10px)';
|
||||||
|
document.body.appendChild(testDiv);
|
||||||
|
|
||||||
|
const supported = window.getComputedStyle(testDiv).backdropFilter !== '';
|
||||||
|
document.body.removeChild(testDiv);
|
||||||
|
|
||||||
|
alert(`Backdrop-filter support: ${supported ? 'YES' : 'NO'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Автоматическая диагностика при загрузке
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
console.log('=== SIDEBAR VISIBILITY TEST ===');
|
||||||
|
console.log('Sidebar element:', document.getElementById('testSidebar'));
|
||||||
|
console.log('Computed styles:', window.getComputedStyle(document.getElementById('testSidebar')));
|
||||||
|
console.log('Viewport dimensions:', window.innerWidth, 'x', window.innerHeight);
|
||||||
|
console.log('Backdrop-filter support:', CSS.supports('backdrop-filter', 'blur(1px)'));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
82
test-statistics-direct.js
Normal file
82
test-statistics-direct.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
import { WildberriesService } from './src/services/wildberries-service.js'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function testStatisticsDirect() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 ПРЯМОЕ ТЕСТИРОВАНИЕ СТАТИСТИКИ WILDBERRIES')
|
||||||
|
|
||||||
|
// Найдем пользователя 79988888888
|
||||||
|
const user = await prisma.user.findFirst({
|
||||||
|
where: { phone: '79988888888' },
|
||||||
|
include: {
|
||||||
|
organization: {
|
||||||
|
include: {
|
||||||
|
apiKeys: {
|
||||||
|
where: { marketplace: 'WILDBERRIES', isActive: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!user?.organization?.apiKeys[0]) {
|
||||||
|
console.log('❌ API ключ не найден')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiKey = user.organization.apiKeys[0]
|
||||||
|
console.log('\n🔑 НАЙДЕННЫЙ API КЛЮЧ:')
|
||||||
|
console.log('- ID:', apiKey.id)
|
||||||
|
console.log('- Длина:', apiKey.apiKey?.length)
|
||||||
|
console.log('- Первые 10 символов:', apiKey.apiKey?.substring(0, 10))
|
||||||
|
console.log('- Активен:', apiKey.isActive)
|
||||||
|
|
||||||
|
// Тестируем WildberriesService напрямую
|
||||||
|
console.log('\n🧪 ТЕСТИРОВАНИЕ WILDBERRIES SERVICE:')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const wbService = new WildberriesService(apiKey.apiKey)
|
||||||
|
console.log('✅ WildberriesService создан успешно')
|
||||||
|
|
||||||
|
// Тестируем получение статистики
|
||||||
|
const startDate = '2025-09-01'
|
||||||
|
const endDate = '2025-09-18'
|
||||||
|
|
||||||
|
console.log(`\n📊 ЗАПРОС СТАТИСТИКИ (${startDate} - ${endDate}):`)
|
||||||
|
|
||||||
|
const statistics = await wbService.getStatistics(startDate, endDate)
|
||||||
|
|
||||||
|
console.log('✅ СТАТИСТИКА ПОЛУЧЕНА:')
|
||||||
|
console.log('- Тип данных:', typeof statistics)
|
||||||
|
console.log('- Является массивом:', Array.isArray(statistics))
|
||||||
|
console.log('- Длина:', statistics?.length || 'N/A')
|
||||||
|
|
||||||
|
if (Array.isArray(statistics) && statistics.length > 0) {
|
||||||
|
console.log('- Первая запись:', JSON.stringify(statistics[0], null, 2))
|
||||||
|
} else {
|
||||||
|
console.log('- Данные пусты или отсутствуют')
|
||||||
|
}
|
||||||
|
} catch (serviceError) {
|
||||||
|
console.error('❌ ОШИБКА WILDBERRIES SERVICE:', serviceError.message)
|
||||||
|
console.error('Стек:', serviceError.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверим что API ключ имеет правильные права доступа
|
||||||
|
console.log('\n🔐 ПРОВЕРКА ПРАВ API КЛЮЧА:')
|
||||||
|
console.log('- Данные валидации:', JSON.stringify(apiKey.validationData, null, 2))
|
||||||
|
|
||||||
|
if (apiKey.validationData?.sellerId) {
|
||||||
|
console.log('✅ SellerId найден:', apiKey.validationData.sellerId)
|
||||||
|
} else {
|
||||||
|
console.log('❌ SellerId отсутствует')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ КРИТИЧЕСКАЯ ОШИБКА:', error)
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testStatisticsDirect()
|
Reference in New Issue
Block a user