158 lines
6.2 KiB
JavaScript
158 lines
6.2 KiB
JavaScript
|
|
// ============================================================================
|
|||
|
|
// n8n Code Node: Обработка загруженных файлов (ИСПРАВЛЕННАЯ ВЕРСИЯ)
|
|||
|
|
// ============================================================================
|
|||
|
|
// OCR возвращает объединённые документы: один файл на группу (group_index)
|
|||
|
|
// Структура: { data: [{ group_index_num: 0, files_count: 2, newfile: "...", ... }] }
|
|||
|
|
// Решение: обрабатываем каждый элемент из data как объединённый документ
|
|||
|
|
// ============================================================================
|
|||
|
|
|
|||
|
|
// ==== INPUT SHAPE SUPPORT ====
|
|||
|
|
// OCR возвращает: { data: [ ...объединённые документы... ] }
|
|||
|
|
const raw = $json;
|
|||
|
|
const items = Array.isArray(raw?.data) ? raw.data : (Array.isArray(raw) ? raw : []);
|
|||
|
|
|
|||
|
|
if (!items.length) {
|
|||
|
|
return [{
|
|||
|
|
json: {
|
|||
|
|
claim_id: null,
|
|||
|
|
payload_partial_json: { documents_meta: [], edit_fields_raw: null, edit_fields_parsed: null },
|
|||
|
|
filesRows: []
|
|||
|
|
}
|
|||
|
|
}];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==== CLAIM_ID DISCOVERY ====
|
|||
|
|
let claim_id = $json.claim_id
|
|||
|
|
|| $items('Edit Fields6')?.[0]?.json?.propertyName?.case_id
|
|||
|
|
|| $('Edit Fields6').first().json.body.claim_id
|
|||
|
|
|| null;
|
|||
|
|
|
|||
|
|
// ==== UTILS ====
|
|||
|
|
const safeStr = (v) => (v == null ? '' : String(v));
|
|||
|
|
const nowIso = new Date().toISOString();
|
|||
|
|
const tryParseJSON = (x) => {
|
|||
|
|
if (x == null) return null;
|
|||
|
|
if (typeof x === 'object') return x;
|
|||
|
|
if (typeof x === 'string') { try { return JSON.parse(x); } catch { return null; } }
|
|||
|
|
return null;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ==== ПРЕДВАРИТЕЛЬНО СОБИРАЕМ uploads_field_labels ИЗ BODY ====
|
|||
|
|
const editRaw = $items('Edit Fields6')?.[0]?.json || null;
|
|||
|
|
const body = editRaw?.body || null;
|
|||
|
|
|
|||
|
|
let uploads_descriptions = [];
|
|||
|
|
let uploads_field_names = [];
|
|||
|
|
let uploads_field_labels = [];
|
|||
|
|
|
|||
|
|
if (body && typeof body === 'object') {
|
|||
|
|
const d = [];
|
|||
|
|
const f = [];
|
|||
|
|
const l = [];
|
|||
|
|
for (const k of Object.keys(body)) {
|
|||
|
|
const mD = k.match(/^uploads_descriptions\[(\d+)\]$/);
|
|||
|
|
const mF = k.match(/^uploads_field_names\[(\d+)\]$/);
|
|||
|
|
const mL = k.match(/^uploads_field_labels\[(\d+)\]$/);
|
|||
|
|
if (mD) d[Number(mD[1])] = safeStr(body[k]);
|
|||
|
|
if (mF) f[Number(mF[1])] = safeStr(body[k]);
|
|||
|
|
if (mL) l[Number(mL[1])] = safeStr(body[k]);
|
|||
|
|
}
|
|||
|
|
uploads_descriptions = d.filter(v => v !== undefined);
|
|||
|
|
uploads_field_names = f.filter(v => v !== undefined);
|
|||
|
|
uploads_field_labels = l.filter(v => v !== undefined);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==== BUILD documents_meta + filesRows ====
|
|||
|
|
// OCR возвращает объединённые документы: один файл на group_index
|
|||
|
|
// Каждый элемент из data - это уже объединённый PDF (может содержать несколько страниц)
|
|||
|
|
const documents_meta = [];
|
|||
|
|
const filesRows = [];
|
|||
|
|
|
|||
|
|
for (const it of items) {
|
|||
|
|
// ✅ ПРИОРИТЕТ: Используем group_index из body (переданный с фронтенда)
|
|||
|
|
// Если его нет - используем group_index_num из OCR
|
|||
|
|
// Если и его нет - пытаемся определить по document_type из uploads_field_names
|
|||
|
|
let grp = null;
|
|||
|
|
|
|||
|
|
if (body && body.group_index !== undefined && body.group_index !== null) {
|
|||
|
|
grp = Number(body.group_index);
|
|||
|
|
} else if (it.group_index_num !== undefined && it.group_index_num !== null) {
|
|||
|
|
grp = Number(it.group_index_num);
|
|||
|
|
} else {
|
|||
|
|
// Fallback: пытаемся определить по document_type
|
|||
|
|
const doc_type = uploads_field_names[0] || uploads_field_labels[0] || '';
|
|||
|
|
// Ищем индекс в documents_required по типу документа
|
|||
|
|
// Это не идеально, но лучше чем всегда 0
|
|||
|
|
grp = 0; // По умолчанию 0, если не можем определить
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
grp = grp || 0;
|
|||
|
|
const file_index = 0; // После объединения всегда один файл на группу
|
|||
|
|
|
|||
|
|
const field_name = `uploads[${grp}][${file_index}]`;
|
|||
|
|
const field_label = uploads_field_labels[grp] || uploads_field_names[grp] || uploads_descriptions[grp] || `group-${grp}`;
|
|||
|
|
|
|||
|
|
// OCR уже объединил файлы, используем newfile (путь к объединённому файлу)
|
|||
|
|
const draft_key = safeStr(it.newfile || (it.folder && it.file_name ? `${it.folder}/${it.file_name}` : ''));
|
|||
|
|
const original_name = safeStr(it.file_name || `group_${grp}.pdf`);
|
|||
|
|
const description = safeStr(it.description || uploads_descriptions[grp] || '');
|
|||
|
|
const prefix = safeStr(it.prefix || '');
|
|||
|
|
|
|||
|
|
// files_count показывает, сколько исходных файлов было объединено
|
|||
|
|
const files_count = Number(it.files_count) || 1;
|
|||
|
|
const pages = Number(it.pages) || null;
|
|||
|
|
|
|||
|
|
documents_meta.push({
|
|||
|
|
field_name,
|
|||
|
|
field_label,
|
|||
|
|
file_id: draft_key,
|
|||
|
|
file_name: original_name,
|
|||
|
|
original_file_name: original_name,
|
|||
|
|
uploaded_at: nowIso,
|
|||
|
|
files_count, // Информация: сколько файлов было объединено
|
|||
|
|
pages, // Информация: сколько страниц в объединённом PDF
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
filesRows.push({
|
|||
|
|
claim_id,
|
|||
|
|
group_index: grp,
|
|||
|
|
file_index, // Всегда 0 для объединённого документа
|
|||
|
|
original_name,
|
|||
|
|
draft_key,
|
|||
|
|
mime: 'application/pdf',
|
|||
|
|
size_bytes: null,
|
|||
|
|
description,
|
|||
|
|
prefix,
|
|||
|
|
field_name,
|
|||
|
|
field_label,
|
|||
|
|
files_count, // Информация для отладки
|
|||
|
|
pages, // Информация для отладки
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==== ПОДТЯГИВАЕМ ВСЁ ИЗ "Edit Fields" ====
|
|||
|
|
const propertyName = editRaw?.propertyName || null;
|
|||
|
|
const answers_parsed = body ? (tryParseJSON(body.answers) || null) : null;
|
|||
|
|
const wizard_plan_parsed = body ? (tryParseJSON(body.wizard_plan) || null) : null;
|
|||
|
|
|
|||
|
|
// ==== OUTPUT ====
|
|||
|
|
return [{
|
|||
|
|
json: {
|
|||
|
|
claim_id,
|
|||
|
|
payload_partial_json: {
|
|||
|
|
documents_meta,
|
|||
|
|
edit_fields_raw: editRaw || null,
|
|||
|
|
edit_fields_parsed: {
|
|||
|
|
propertyName,
|
|||
|
|
body,
|
|||
|
|
uploads_descriptions,
|
|||
|
|
uploads_field_names,
|
|||
|
|
uploads_field_labels,
|
|||
|
|
answers_parsed,
|
|||
|
|
wizard_plan_parsed,
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
filesRows
|
|||
|
|
}
|
|||
|
|
}];
|