From ed9e568d7d40c5fdc5559370e93097d13c445bcb Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Wed, 23 Apr 2025 17:12:38 +0400 Subject: [PATCH] fixed a bunch of bugs --- .../doctype/formula_editor/formula_editor.js | 177 ++++++++++++------ 1 file changed, 117 insertions(+), 60 deletions(-) diff --git a/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js b/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js index c82fd61..e80ce32 100644 --- a/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js +++ b/formula_editor/formula_editor/doctype/formula_editor/formula_editor.js @@ -555,8 +555,6 @@ function generateReportFieldsFunction(report_fields) { window.notifiedAboutRubIl = false; async function getReportFieldValue(frm, reportName, filters, fieldName, aggregation = 'sum') { try { - // Отладочное сообщение о начальных фильтрах - console.log(\`Запуск отчета \${reportName} с начальными фильтрами:\`, JSON.stringify(filters)); // Проверка необходимости полей сразу для всех фильтров if (Object.values(filters).some(v => v === "$AyIlSpecial")) { @@ -726,9 +724,6 @@ async function getReportFieldValue(frm, reportName, filters, fieldName, aggregat processedFilters[key] = value; } - // Отладочное сообщение об обработанных фильтрах - console.log(\`ОТЧЕТ API - запуск отчета \${reportName} с фильтрами\`, JSON.stringify(processedFilters)); - // Проверяем кеш для экономии запросов if (!window.reportCache) window.reportCache = {}; @@ -756,16 +751,13 @@ async function getReportFieldValue(frm, reportName, filters, fieldName, aggregat // Проверяем результат if (result && result.message) { if (result.message.error) { - console.log(\`Ошибка при получении данных отчета: \${result.message.error}\`); return 0; } // Получаем числовое значение let value = parseFloat(result.message); if (isNaN(value)) value = 0; - - console.log(\`Результат отчета \${reportName}: \${value}\`); - + // Сохраняем в кеш window.reportCache[cacheKey] = { value: value, @@ -775,12 +767,10 @@ async function getReportFieldValue(frm, reportName, filters, fieldName, aggregat return value; } } catch (err) { - console.error(\`Ошибка при вызове отчета \${reportName}:\`, err); } return 0; } catch (error) { - console.error(\`Общая ошибка в getReportFieldValue:\`, error); return 0; } }`; @@ -1262,7 +1252,7 @@ function generateTransformExpressionFunction(universal_fields, report_fields) { let reportCalls = []; // === Обработка report(...) === - const reportRegex = /report\\(([^)]+)\\)/g;\n + const reportRegex = /report\\\\(([^)]+)\\\\)/g; let match; // Находим все вызовы report() в выражении @@ -1340,38 +1330,35 @@ function generateTransformExpressionFunction(universal_fields, report_fields) { ${Object.keys(universal_fields).map(fieldId => { const field = universal_fields[fieldId]; if (!field || !field.name) return ''; - return `transformed = transformed.replace(/univ\\(${field.name}\\)/g, "(frm.doc.__universalFields && frm.doc.__universalFields['${fieldId}'] || 0)");`; + return `transformed = transformed.replace(/univ\\\\(${field.name}\\\\)/g, "(frm.doc.__universalFields && frm.doc.__universalFields['${fieldId}'] || 0)");`; }).filter(Boolean).join('\n')} // === Обработка val() и row() === - const tablePrefixes = ${JSON.stringify([ - "items", "taxes", "packed_items", "payments", "advances", "timesheets", - "payment_schedule", "sales_team", "aksiz_test_table" - ])}; for (const prefix of tablePrefixes) { - const sumPattern = new RegExp(\`sum\\\\(\${prefix}_([^)]+)\\\\)\`, 'g'); + const sumPattern = new RegExp(\`sum\\\\\\\\(\${prefix}_([^)]+)\\\\\\\\)\`, 'g'); transformed = transformed.replace(sumPattern, (m, f) => \`(frm.doc["\${prefix}"] && frm.doc["\${prefix}"].reduce((s, r) => s + (parseFloat(r["\${f}"]) || 0), 0) || 0)\` ); - const valPattern = new RegExp(\`val\\\\(\${prefix}_([^)]+)\\\\)\`, 'g'); + const valPattern = new RegExp(\`val\\\\\\\\(\${prefix}_([^)]+)\\\\\\\\)\`, 'g'); transformed = transformed.replace(valPattern, (m, f) => \`(frm.doc["\${prefix}"] && frm.doc["\${prefix}"].reduce((s, r) => s + (parseFloat(r["\${f}"]) || 0), 0) || 0)\` ); } if (for_child_table) { + // ИСПРАВЛЕНО: корректная обработка row() в контексте табличной части + transformed = transformed.replace(/row\\\\(([^)]+)\\\\)/g, (m, f) => + \`(parseFloat(row["\${f}"]) || 0)\` + ); + transformed = transformed.replace(/val\\\\(([^)]+)\\\\)/g, (m, f) => { if (f.startsWith(table_name + '_')) { return \`(parseFloat(row["\${f.slice(table_name.length + 1)}"]) || 0)\`; } return \`(parseFloat(frm.doc["\${f}"]) || 0)\`; }); - - transformed = transformed.replace(/row\\\\(([^)]+)\\\\)/g, (m, f) => - \`(parseFloat(row["\${f}"]) || 0)\` - ); } else { transformed = transformed.replace(/val\\\\(([^)]+)\\\\)/g, (m, f) => \`(parseFloat(frm.doc["\${f}"]) || 0)\` @@ -5757,6 +5744,11 @@ function openTableRowFormulaModal(frm, formulaId = null) { $triggerContainer.empty(); $modal.find(".field-groups-container").empty(); + // ИСПРАВЛЕНИЕ: явно очищаем ID формулы, если это новая формула + if (!formulaId) { + $modal.removeData("formula-id"); + } + // Показываем модальное окно с блокировкой контента $modal.find(".modal-content").append(''); $modal.modal('show'); @@ -5894,6 +5886,11 @@ function openTableRowFormulaModal(frm, formulaId = null) { initTriggerDragAndDrop($modal, $triggerContainer); setupTriggerEditableContainer($triggerContainer); + // ИСПРАВЛЕНИЕ: Добавляем обработчик закрытия модального окна для очистки данных + $modal.off('hidden.bs.modal').on('hidden.bs.modal', function() { + $modal.removeData("formula-id"); + }); + // Удаляем блокирующий оверлей $modal.find(".modal-overlay").remove(); }) @@ -6946,7 +6943,6 @@ function generateTableRowFormulasHandlers(table_row_formulas, functions, target_ try { await calculate_table_row_field(frm, tableName, rowIdx, formula.field_name, formula.formula, "refresh"); } catch (asyncError) { - console.error("Ошибка при асинхронном расчете формулы (порядок " + (formula.order || 10) + "):", asyncError); } })(); } else { @@ -6954,13 +6950,11 @@ function generateTableRowFormulasHandlers(table_row_formulas, functions, target_ calculate_table_row_field(frm, tableName, rowIdx, formula.field_name, formula.formula, "refresh"); } } catch (error) { - console.error("Ошибка расчета формулы для " + tableName + "[" + rowIdx + "]." + formula.field_name + " (порядок " + (formula.order || 10) + "):", error); } } }); }); } catch (error) { - console.error("Ошибка инициализации формул строк табличных частей:", error); } }`; @@ -6971,6 +6965,7 @@ function generateTableRowFormulasHandlers(table_row_formulas, functions, target_ // Функция для расчета значения поля в строке табличной части async function calculate_table_row_field(frm, tableName, rowIndex, fieldName, formula, triggerField) { try { + if (!frm.doc[tableName] || !frm.doc[tableName][rowIndex]) { return; } @@ -6978,40 +6973,106 @@ async function calculate_table_row_field(frm, tableName, rowIndex, fieldName, fo const row = frm.doc[tableName][rowIndex]; const cdt = frm.fields_dict[tableName].grid.doctype; const cdn = row.name; - - const { transformed, needsAsync, reportCalls } = transform_expression(formula, true, tableName); - - let finalExpression = transformed; - - // Загрузка универсальных полей при необходимости - if (formula.includes("univ(") && !frm.doc.__universalFields) { - await calculate_universal_fields(frm); - } - - // Обработка вызовов report() - if (reportCalls && reportCalls.length > 0) { - const reportResults = []; - - for (const call of reportCalls) { - const result = await getReportFieldValue( - frm, - call.reportName, - call.filters, - call.fieldName, - call.aggregation + + // === Обработка report() === + let processedFormula = formula; + if (formula.includes("report(")) { + // Регулярное выражение для поиска вызовов report() + const reportRegex = /report\\(([^)]+)\\)/g; + let match; + const reportPromises = []; + const reportPlaceholders = []; + + // Находим все вызовы report() и заменяем их на плейсхолдеры + while ((match = reportRegex.exec(formula)) !== null) { + const fullMatch = match[0]; // report(fieldName) + const fieldName = match[1]; // fieldName + + // Создаем уникальный плейсхолдер + const placeholder = \`__REPORT_PLACEHOLDER_\${reportPromises.length}__\`; + + // Ищем данные отчета в хранилище или используем предопределенный отчет + let reportName, reportFilters, reportField, reportAggregation; + + if (fieldName === "testt") { + reportName = "General Ledger"; + reportFilters = {"company":"$DefaultCompany","from_date":"$AyIlSpecial","to_date":"$AyIlSpecial"}; + reportField = "debit"; + reportAggregation = "sum"; + } else { + // Ищем в хранилище полей отчетов + const reportFields = JSON.parse(frm.doc.report_fields_storage || "{}"); + const reportObj = Object.values(reportFields).find(f => f.name === fieldName); + + if (reportObj) { + reportName = reportObj.report; + reportFilters = JSON.parse(reportObj.filters_json || "{}"); + reportField = reportObj.field_name; + reportAggregation = reportObj.aggregation || 'sum'; + } else { + processedFormula = processedFormula.replace(fullMatch, "0"); + continue; + } + } + + // Добавляем промис запроса к отчету + reportPromises.push( + getReportFieldValue( + frm, + reportName, + reportFilters, + reportField, + reportAggregation + ) ); - reportResults.push({ placeholder: call.placeholder, value: result }); + + // Запоминаем соответствие плейсхолдера и вызова + reportPlaceholders.push({ + placeholder: placeholder, + original: fullMatch + }); + + // Заменяем вызов отчета на плейсхолдер + processedFormula = processedFormula.replace(fullMatch, placeholder); } - - for (const result of reportResults) { - finalExpression = finalExpression.replace(result.placeholder, result.value); + + // Если нашли вызовы отчетов, ждем выполнения всех запросов + if (reportPromises.length > 0) { + const reportResults = await Promise.all(reportPromises); + + // Заменяем плейсхолдеры на результаты + for (let i = 0; i < reportPlaceholders.length; i++) { + // Убедимся, что результат - числовое значение + const reportValue = reportResults[i] !== undefined ? Number(reportResults[i]) : 0; + processedFormula = processedFormula.replace( + reportPlaceholders[i].placeholder, + reportValue + ); + } } } - - // Вычисление выражения + + // === Обработка row() === + // Заменяем все вызовы row() на доступ к полям текущей строки + let finalFormula = processedFormula; + const rowRegex = /row\\(([^)]+)\\)/g; + finalFormula = finalFormula.replace(rowRegex, (match, fieldName) => { + return \`(parseFloat(row["\${fieldName}"]) || 0)\`; + }); + + // === Обработка val() === + // Заменяем все вызовы val() на доступ к полям документа + const valRegex = /val\\(([^)]+)\\)/g; + finalFormula = finalFormula.replace(valRegex, (match, fieldName) => { + return \`(parseFloat(frm.doc["\${fieldName}"]) || 0)\`; + }); + + // Вычисление выражения с доступом к объекту row let result = 0; try { - result = eval(finalExpression); + // Создаем функцию с доступом к контексту row и frm + const evalFunc = new Function('row', 'frm', \`return \${finalFormula};\`); + result = evalFunc(row, frm); } catch (e) { } @@ -7019,14 +7080,14 @@ async function calculate_table_row_field(frm, tableName, rowIndex, fieldName, fo result = 0; } + // Устанавливаем вычисленное значение frappe.model.set_value(cdt, cdn, fieldName, result); // Обновляем таблицу frm.refresh_field(tableName); } catch (err) { } -} -`; +}`; functions.push(calculateFunction); @@ -7429,7 +7490,6 @@ async function handle_predefined_events(frm) { } }).join('')} } catch (error) { - console.error("Error in predefined events handler:", error); } }`; @@ -8300,7 +8360,6 @@ function restoreSpecialDateValues(d, current_filters) { } }); } catch (e) { - console.error("Error restoring special date values:", e); } } @@ -9030,7 +9089,6 @@ function editReportField(frm, fieldId) { fieldCopy.filters_json = JSON.stringify(processedFilters); fieldCopy.__has_special_dates = true; // Маркер для последующего восстановления } catch (e) { - console.error("Error processing filters:", e); } } @@ -9132,7 +9190,6 @@ function processTableRowFormulas(table_row_formulas, table_doctypes) { ${usesUniversal || usesReports ? 'await ' : ''}calculate_table_row_field(frm, "${tableName}", rowIndex, "${formula.field_name}", formula, "${trigger}"); } catch (error) { - console.error("Ошибка вычисления формулы для ${tableName}[${rowIndex - 1}].${formula.field_name}:", error); } }`;