2025-11-24 13:36:14 +03:00
|
|
|
|
// ========================================
|
|
|
|
|
|
// Code Node: Мерж данных проекта в сессию
|
2025-11-26 19:54:51 +03:00
|
|
|
|
// v2.0 - с расширенным логированием для отладки
|
2025-11-24 13:36:14 +03:00
|
|
|
|
// ========================================
|
|
|
|
|
|
|
|
|
|
|
|
// 1. Берём первый item
|
|
|
|
|
|
const inputItem = $input.all()[0];
|
|
|
|
|
|
|
|
|
|
|
|
if (!inputItem || !inputItem.json) {
|
|
|
|
|
|
throw new Error('Пустой input в Code Node (нет json)');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// root — то, что реально пришло в эту ноду
|
|
|
|
|
|
const root = inputItem.json;
|
|
|
|
|
|
|
2025-11-26 19:54:51 +03:00
|
|
|
|
// ✅ ОТЛАДКА: смотрим что пришло
|
|
|
|
|
|
console.log('🔍 DEBUG: root keys:', Object.keys(root));
|
|
|
|
|
|
console.log('🔍 DEBUG: root.body exists:', !!root.body);
|
|
|
|
|
|
console.log('🔍 DEBUG: root.other exists:', !!root.other);
|
|
|
|
|
|
|
2025-11-24 13:36:14 +03:00
|
|
|
|
// 2. Универсально получаем body
|
|
|
|
|
|
// - если нода стоит сразу после Webhook → данные лежат в root.body
|
|
|
|
|
|
// - если кто-то выше уже отдал только body → root и есть body
|
|
|
|
|
|
const body = root.body || root;
|
|
|
|
|
|
|
2025-11-26 19:54:51 +03:00
|
|
|
|
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);
|
|
|
|
|
|
|
2025-11-24 13:36:14 +03:00
|
|
|
|
// 3. Парсим body.other (если есть) как сессию
|
2025-11-26 19:54:51 +03:00
|
|
|
|
// ✅ ВАЖНО: Также проверяем root.other напрямую (если данные пришли не через body)
|
2025-11-24 13:36:14 +03:00
|
|
|
|
let sessionData = {};
|
2025-11-26 19:54:51 +03:00
|
|
|
|
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));
|
|
|
|
|
|
}
|
2025-11-24 13:36:14 +03:00
|
|
|
|
|
|
|
|
|
|
if (rawOther) {
|
|
|
|
|
|
if (typeof rawOther === 'string') {
|
|
|
|
|
|
try {
|
|
|
|
|
|
sessionData = JSON.parse(rawOther);
|
2025-11-26 19:54:51 +03:00
|
|
|
|
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);
|
2025-11-24 13:36:14 +03:00
|
|
|
|
} catch (e) {
|
2025-11-26 19:54:51 +03:00
|
|
|
|
throw new Error('Не смог распарсить other как JSON: ' + e.message + '. rawOther: ' + rawOther.substring(0, 500));
|
2025-11-24 13:36:14 +03:00
|
|
|
|
}
|
|
|
|
|
|
} else if (typeof rawOther === 'object') {
|
|
|
|
|
|
sessionData = rawOther;
|
2025-11-26 19:54:51 +03:00
|
|
|
|
console.log('✅ other уже объект. Ключи:', Object.keys(sessionData));
|
2025-11-24 13:36:14 +03:00
|
|
|
|
}
|
2025-11-26 19:54:51 +03:00
|
|
|
|
} else {
|
|
|
|
|
|
console.log('⚠️ other отсутствует или пустой. Проверьте структуру данных!');
|
|
|
|
|
|
console.log('⚠️ root:', JSON.stringify(root).substring(0, 500));
|
2025-11-24 13:36:14 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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. Собираем обновлённую сессию
|
2025-11-26 19:54:51 +03:00
|
|
|
|
// ✅ Используем 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,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-24 13:36:14 +03:00
|
|
|
|
const updatedSession = {
|
2025-11-26 19:54:51 +03:00
|
|
|
|
// ✅ Шаг 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)
|
2025-11-24 13:36:14 +03:00
|
|
|
|
project_id: projectResult.project_id, // id проекта из CRM
|
2025-11-26 19:54:51 +03:00
|
|
|
|
project_name: projectResult.project_name || null, // название проекта из CRM
|
2025-11-24 13:36:14 +03:00
|
|
|
|
is_new_project: projectResult.is_new, // флаг новый/старый
|
|
|
|
|
|
current_step: 2, // двигаем визард на шаг 2
|
2025-11-26 19:54:51 +03:00
|
|
|
|
|
|
|
|
|
|
// ✅ Шаг 4: Данные анализа из body (приоритет body)
|
|
|
|
|
|
problem: body.problem || baseSession.problem || null,
|
|
|
|
|
|
last_analysis_output: body.output || baseSession.last_analysis_output || null,
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Шаг 5: Метаданные (всегда обновляем)
|
2025-11-24 13:36:14 +03:00
|
|
|
|
updated_at: new Date().toISOString(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-26 19:54:51 +03:00
|
|
|
|
// ✅ Логируем результат для отладки
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
2025-11-24 13:36:14 +03:00
|
|
|
|
// 9. Возвращаем один item для Redis SET
|
|
|
|
|
|
return [
|
|
|
|
|
|
{
|
|
|
|
|
|
json: {
|
|
|
|
|
|
redis_key: `claim:${claimId}`,
|
|
|
|
|
|
redis_value: JSON.stringify(updatedSession),
|
|
|
|
|
|
ttl: 604800, // 7 дней
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
|