fix: Исправление загрузки документов и SQL запросов
- Исправлена потеря документов при обновлении черновика (SQL объединяет вместо перезаписи) - Исправлено определение типа документа (приоритет field_label над field_name) - Исправлены дубликаты в documents_meta и documents_uploaded - Добавлена передача group_index с фронтенда для правильного field_name - Исправлены все документы в таблице clpr_claim_documents с правильными field_name - Обновлены SQL запросы: claimsave и claimsave_final для нового флоу - Добавлена поддержка multi-file upload для одного документа - Исправлены дубликаты в списке загруженных документов на фронтенде Файлы: - SQL: SQL_CLAIMSAVE_FIXED_NEW_FLOW.sql, SQL_CLAIMSAVE_FINAL_FIXED_NEW_FLOW_WITH_UPLOADED.sql - n8n: N8N_CODE_PROCESS_UPLOADED_FILES_FIXED.js (поддержка group_index) - Backend: documents.py (передача group_index в n8n) - Frontend: StepWizardPlan.tsx (передача group_index, исправление дубликатов) - Скрипты: fix_claim_documents_field_names.py, fix_documents_meta_duplicates.py Результат: документы больше не теряются, имеют правильные типы и field_name
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// ========================================
|
||||
// Code Node: Мерж данных проекта в сессию
|
||||
// v2.0 - с расширенным логированием для отладки
|
||||
// ========================================
|
||||
|
||||
// 1. Берём первый item
|
||||
@@ -12,25 +13,62 @@ if (!inputItem || !inputItem.json) {
|
||||
// root — то, что реально пришло в эту ноду
|
||||
const root = inputItem.json;
|
||||
|
||||
// ✅ ОТЛАДКА: смотрим что пришло
|
||||
console.log('🔍 DEBUG: root keys:', Object.keys(root));
|
||||
console.log('🔍 DEBUG: root.body exists:', !!root.body);
|
||||
console.log('🔍 DEBUG: root.other exists:', !!root.other);
|
||||
|
||||
// 2. Универсально получаем body
|
||||
// - если нода стоит сразу после Webhook → данные лежат в root.body
|
||||
// - если кто-то выше уже отдал только body → root и есть body
|
||||
const body = root.body || root;
|
||||
|
||||
console.log('🔍 DEBUG: body keys:', Object.keys(body));
|
||||
console.log('🔍 DEBUG: body.other exists:', !!body.other);
|
||||
console.log('🔍 DEBUG: body.other type:', typeof body.other);
|
||||
|
||||
// 3. Парсим body.other (если есть) как сессию
|
||||
// ✅ ВАЖНО: Также проверяем root.other напрямую (если данные пришли не через body)
|
||||
let sessionData = {};
|
||||
const rawOther = body.other;
|
||||
let rawOther = body.other || root.other;
|
||||
|
||||
// ✅ Пробуем также достать other из Webhook напрямую
|
||||
if (!rawOther) {
|
||||
try {
|
||||
const webhookJson = $('Webhook').first()?.json;
|
||||
if (webhookJson?.body?.other) {
|
||||
rawOther = webhookJson.body.other;
|
||||
console.log('✅ Взяли other напрямую из Webhook');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('⚠️ Не удалось достать other из Webhook:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔍 DEBUG: rawOther exists:', !!rawOther);
|
||||
console.log('🔍 DEBUG: rawOther type:', typeof rawOther);
|
||||
if (rawOther) {
|
||||
console.log('🔍 DEBUG: rawOther preview:', typeof rawOther === 'string' ? rawOther.substring(0, 200) : JSON.stringify(rawOther).substring(0, 200));
|
||||
}
|
||||
|
||||
if (rawOther) {
|
||||
if (typeof rawOther === 'string') {
|
||||
try {
|
||||
sessionData = JSON.parse(rawOther);
|
||||
console.log('✅ Распарсили other как JSON. Ключи:', Object.keys(sessionData));
|
||||
console.log('✅ sessionData.session_id:', sessionData.session_id);
|
||||
console.log('✅ sessionData.phone:', sessionData.phone);
|
||||
console.log('✅ sessionData.firstname:', sessionData.firstname);
|
||||
} catch (e) {
|
||||
throw new Error('Не смог распарсить body.other как JSON: ' + e.message + '. rawOther: ' + rawOther);
|
||||
throw new Error('Не смог распарсить other как JSON: ' + e.message + '. rawOther: ' + rawOther.substring(0, 500));
|
||||
}
|
||||
} else if (typeof rawOther === 'object') {
|
||||
sessionData = rawOther;
|
||||
console.log('✅ other уже объект. Ключи:', Object.keys(sessionData));
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ other отсутствует или пустой. Проверьте структуру данных!');
|
||||
console.log('⚠️ root:', JSON.stringify(root).substring(0, 500));
|
||||
}
|
||||
|
||||
// 4. Определяем claimId (основной путь)
|
||||
@@ -94,19 +132,75 @@ if (!projectResult || !projectResult.project_id) {
|
||||
}
|
||||
|
||||
// 8. Собираем обновлённую сессию
|
||||
// ✅ Используем spread оператор, но с фильтрацией undefined значений
|
||||
// Сначала создаём базовый объект из sessionData, фильтруя undefined
|
||||
const baseSession = Object.keys(sessionData).reduce((acc, key) => {
|
||||
if (sessionData[key] !== undefined && sessionData[key] !== null) {
|
||||
acc[key] = sessionData[key];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
console.log('📦 baseSession после фильтрации:', Object.keys(baseSession));
|
||||
console.log('📦 baseSession sample:', {
|
||||
session_id: baseSession.session_id,
|
||||
phone: baseSession.phone,
|
||||
unified_id: baseSession.unified_id,
|
||||
contact_id: baseSession.contact_id,
|
||||
firstname: baseSession.firstname,
|
||||
lastname: baseSession.lastname,
|
||||
});
|
||||
|
||||
const updatedSession = {
|
||||
...sessionData, // всё, что было в other
|
||||
claim_id: claimId, // актуальный claim_id
|
||||
// ✅ Шаг 1: Все данные из sessionData (body.other) - базовая сессия
|
||||
...baseSession,
|
||||
|
||||
// ✅ Шаг 2: Дополняем данными из body (если их нет в sessionData)
|
||||
...(body.phone && !baseSession.phone ? { phone: body.phone } : {}),
|
||||
...(body.unified_id && !baseSession.unified_id ? { unified_id: body.unified_id } : {}),
|
||||
...(body.contact_id && !baseSession.contact_id ? { contact_id: body.contact_id } : {}),
|
||||
...(body.email && !baseSession.email ? { email: body.email } : {}),
|
||||
|
||||
// ✅ Шаг 3: Данные проекта (новые, всегда перезаписываем)
|
||||
claim_id: claimId, // актуальный claim_id (перезаписываем null из sessionData)
|
||||
project_id: projectResult.project_id, // id проекта из CRM
|
||||
project_name: projectResult.project_name || null, // название проекта из CRM (новое поле)
|
||||
project_name: projectResult.project_name || null, // название проекта из CRM
|
||||
is_new_project: projectResult.is_new, // флаг новый/старый
|
||||
current_step: 2, // двигаем визард на шаг 2
|
||||
|
||||
// ✅ Шаг 4: Данные анализа из body (приоритет body)
|
||||
problem: body.problem || baseSession.problem || null,
|
||||
last_analysis_output: body.output || baseSession.last_analysis_output || null,
|
||||
|
||||
// ✅ Шаг 5: Метаданные (всегда обновляем)
|
||||
updated_at: new Date().toISOString(),
|
||||
// опционально дотащим полезные поля из body:
|
||||
problem: body.problem ?? sessionData.problem,
|
||||
last_analysis_output: body.output ?? sessionData.last_analysis_output,
|
||||
};
|
||||
|
||||
// ✅ Логируем результат для отладки
|
||||
console.log('📦 sessionData keys:', Object.keys(sessionData));
|
||||
console.log('📦 sessionData sample:', {
|
||||
session_id: sessionData.session_id,
|
||||
phone: sessionData.phone,
|
||||
unified_id: sessionData.unified_id,
|
||||
contact_id: sessionData.contact_id,
|
||||
firstname: sessionData.firstname,
|
||||
lastname: sessionData.lastname,
|
||||
middle_name: sessionData.middle_name,
|
||||
});
|
||||
console.log('📦 updatedSession keys:', Object.keys(updatedSession));
|
||||
console.log('📦 updatedSession sample:', {
|
||||
session_id: updatedSession.session_id,
|
||||
phone: updatedSession.phone,
|
||||
unified_id: updatedSession.unified_id,
|
||||
contact_id: updatedSession.contact_id,
|
||||
firstname: updatedSession.firstname,
|
||||
lastname: updatedSession.lastname,
|
||||
middle_name: updatedSession.middle_name,
|
||||
claim_id: updatedSession.claim_id,
|
||||
project_id: updatedSession.project_id,
|
||||
});
|
||||
console.log('📦 updatedSession FULL:', JSON.stringify(updatedSession, null, 2));
|
||||
|
||||
// 9. Возвращаем один item для Redis SET
|
||||
return [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user