// === НАСТРОЙКА === const FILES_ROWS_NODE = 'editfiletobd1'; // <--- имя ноды, где формировались filesRows // === ВХОД ИЗ PG === const sql = $json || {}; const claim_id = sql?.claim?.claim_id || $json.claim_id || null; const docs = Array.isArray(sql.documents) ? sql.documents : []; // === filesRows из предыдущей ноды === const filesRows = $items(FILES_ROWS_NODE)?.[0]?.json?.filesRows || []; // === Получаем project_id и project_name === // Пробуем получить из Edit Fields6, затем из текущего $json, затем из предыдущих нод let project_id = null; let project_name = null; // 1. Пробуем из Edit Fields6 try { const editFields6 = $('Edit Fields6').first().json.propertyName || {}; project_id = editFields6.project_id || null; project_name = editFields6.project_name || null; } catch (e) { // Игнорируем, пробуем другие источники } // 2. Пробуем из текущего $json if (!project_id) { project_id = $json?.project_id || null; } if (!project_name) { project_name = $json?.project_name || null; } // 3. Пробуем из предыдущей ноды (если есть нода, которая получает данные из Redis) if (!project_name) { try { // Пробуем найти ноду, которая получает данные сессии из Redis const redisNode = $node["Get Session"] || $node["GetSession"] || $node["Redis Get"]; if (redisNode && redisNode.json) { const sessionData = typeof redisNode.json.value === 'string' ? JSON.parse(redisNode.json.value) : redisNode.json.value; if (!project_name) { project_name = sessionData?.project_name || null; } if (!project_id) { project_id = sessionData?.project_id || null; } } } catch (e) { // Игнорируем ошибки } } // === Утилиты === const S = v => (v == null ? '' : String(v)); const extOf = n => (S(n).match(/\.([a-z0-9]+)$/i)?.[1]?.toLowerCase() || 'pdf'); const baseName = k => S(k).split('/').pop() || 'file.pdf'; const slugify = s => { s = S(s).toLowerCase().trim(); const map = {а:'a',б:'b',в:'v',г:'g',д:'d',е:'e',ё:'e',ж:'zh',з:'z',и:'i',й:'y',к:'k',л:'l', м:'m',н:'n',о:'o',п:'p',р:'r',с:'s',т:'t',у:'u',ф:'f',х:'h',ц:'c',ч:'ch',ш:'sh', щ:'sch',ъ:'',ы:'y',ь:'',э:'e',ю:'yu',я:'ya'}; s = s.replace(/[а-яё]/g, ch => map[ch] ?? ch); return s.replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,'') || 'doc'; }; // field_name -> doc_id const byField = Object.create(null); for (const d of docs) if (d?.field_name && d?.id) byField[d.field_name] = d.id; // Правило финального пути // Новый формат: /f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/crm2/CRM_Active_Files/Documents/Project/{project_name}_{project_id}/{doc_id}__{slug}.{ext} // Пример: /.../Project/ERV_6381_КлиентПрав_398957/{doc_id}__{slug}.{ext} // project_name уже содержит "ERV_6381_КлиентПрав", просто добавляем к нему _project_id const buildFinalKey = (row, doc_id) => { const bucketPrefix = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c'; const basePath = 'crm2/CRM_Active_Files/Documents/Project'; // Используем название поля из формы визарда // Приоритет: field_label (из uploads_field_labels) > field_name (из uploads_field_names) > description > group_index // field_label должен приходить из n8n workflow, где формируется filesRows из uploads_field_labels[i] const fieldLabel = row.field_label || row.field_name || row.description || `group-${row.group_index}`; const slug = slugify(fieldLabel); const ext = extOf(row.original_name || 'pdf'); // Формируем название папки: {project_name}_{project_id} // project_name уже содержит "ERV_6381_КлиентПрав", добавляем к нему _project_id let projectFolder = 'unknown'; if (project_name && project_id) { projectFolder = `${project_name}_${project_id}`; } else if (project_id) { // Fallback: если нет project_name, используем старый формат projectFolder = `${project_id}_Клиентправ`; } // Очищаем от недопустимых символов для пути projectFolder = String(projectFolder) .replace(/[\/\\\?\*\:\|\"<>]/g, '_') .replace(/^\.+|\.+$/g, '') .trim() || 'unknown'; // Формируем путь: /{bucketPrefix}/{basePath}/{project_folder}/{doc_id}__{slug}.{ext} return `/${bucketPrefix}/${basePath}/${projectFolder}/${doc_id}__${slug}.${ext}`; }; // Собираем renames + финальные метаданные const renames = []; const finalDocumentsMeta = []; const nowIso = new Date().toISOString(); for (const row of filesRows) { const g = Number(row.group_index) || 0; const field_name = `uploads[${g}][0]`; const doc_id = byField[field_name] || `grp${g}`; // фолбэк если чего-то не сошлось const fromKey = S(row.draft_key); const toKey = buildFinalKey(row, doc_id); // Получаем название поля из row (field_label должен быть добавлен в ноде editfiletobd1) const field_label = row.field_label || row.field_name || row.description || `group-${g}`; renames.push({ from: fromKey, to: toKey, doc_id, field_name, field_label // ✅ Добавляем название поля }); finalDocumentsMeta.push({ field_name, field_label, // ✅ Добавляем название поля file_id: toKey, file_name: baseName(toKey), original_file_name: baseName(row.original_name || toKey), uploaded_at: nowIso }); } return [{ json: { claim_id, project_id, renames, // план копирования/переименования на S3 payload_partial_json: { documents_meta: finalDocumentsMeta } // для финального апдейта в БД } }];