Files
aiform_dev/docs/CODE_MERGE_PROJECT_TO_SESSION.js
AI Assistant 02689e65db 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
2025-11-26 19:54:51 +03:00

215 lines
8.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ========================================
// Code Node: Мерж данных проекта в сессию
// v2.0 - с расширенным логированием для отладки
// ========================================
// 1. Берём первый item
const inputItem = $input.all()[0];
if (!inputItem || !inputItem.json) {
throw new Error('Пустой input в Code Node (нет 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 = {};
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('Не смог распарсить 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 (основной путь)
let claimId = body.claim_id || sessionData.claim_id || null;
// 5. Fallback: пробуем достать claim_id напрямую из Webhook, если его до сих пор нет
if (!claimId) {
try {
const webhookNodeJson = $('Webhook').first()?.json;
if (webhookNodeJson?.body?.claim_id) {
claimId = webhookNodeJson.body.claim_id;
}
} catch (e) {
// молча игнорируем, просто не удалось взять из Webhook
}
}
// 6. Если всё ещё нет claimId — это реально критичная ситуация
if (!claimId) {
throw new Error(
'Нет claim_id ни в body, ни в sessionData, ни в Webhook. ' +
'body: ' + JSON.stringify(body) +
', sessionData: ' + JSON.stringify(sessionData)
);
}
// 7. Забираем результат ноды CreateClientProject (или CreateWebPorject, если опечатка в названии ноды)
let projectNode = null;
let projectNodeName = null;
// Пробуем найти ноду безопасно
try {
projectNode = $node["CreateClientProject"];
if (projectNode && projectNode.json) {
projectNodeName = "CreateClientProject";
}
} catch (e) {
// Нода CreateClientProject не найдена, пробуем альтернативное название
}
if (!projectNode || !projectNode.json) {
try {
projectNode = $node["CreateWebPorject"];
if (projectNode && projectNode.json) {
projectNodeName = "CreateWebPorject";
}
} catch (e) {
// Нода CreateWebPorject тоже не найдена
}
}
if (!projectNode || !projectNode.json) {
throw new Error('Нет данных от ноды CreateClientProject/CreateWebPorject. Убедитесь, что нода существует и выполнена.');
}
const projectResult = projectNode.json.result;
// Ожидаем что-то типа: { "project_id": "398095", "project_name": "Иванов_КлиентПрав", "is_new": false }
if (!projectResult || !projectResult.project_id) {
throw new Error('Нет projectResult.project_id. result: ' + JSON.stringify(projectNode.json));
}
// 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 = {
// ✅ Шаг 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
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(),
};
// ✅ Логируем результат для отладки
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 [
{
json: {
redis_key: `claim:${claimId}`,
redis_value: JSON.stringify(updatedSession),
ttl: 604800, // 7 дней
},
},
];