fixed bug with duplicate in script

This commit is contained in:
Ali 2025-08-19 14:23:01 +04:00
parent 7b811fb607
commit 34171eaa3c
1 changed files with 178 additions and 133 deletions

View File

@ -246,94 +246,94 @@ frappe.require([
// Добавляем функцию для обработки и выполнения формул // Добавляем функцию для обработки и выполнения формул
functions.push(` functions.push(`
// Функция для обработки и выполнения формул // Функция для обработки и выполнения формул
async function processFormula(frm, formula) { async function processFormula(frm, formula) {
try { try {
// Проверяем наличие вызовов отчетов // Проверяем наличие вызовов отчетов
if (formula.includes("report(")) { if (formula.includes("report(")) {
// Извлекаем все вызовы report() из формулы // Извлекаем все вызовы report() из формулы
const reportRegex = /report\\(([^)]+)\\)/g; const reportRegex = /report\\(([^)]+)\\)/g;
let match; let match;
let processedFormula = formula; let processedFormula = formula;
// Массив для хранения промисов запросов к отчетам // Массив для хранения промисов запросов к отчетам
const reportPromises = []; const reportPromises = [];
const reportPlaceholders = []; const reportPlaceholders = [];
// Находим все вызовы report() и заменяем их на плейсхолдеры // Находим все вызовы report() и заменяем их на плейсхолдеры
while ((match = reportRegex.exec(formula)) !== null) { while ((match = reportRegex.exec(formula)) !== null) {
const fullMatch = match[0]; // report(fieldName) const fullMatch = match[0]; // report(fieldName)
const fieldName = match[1]; // fieldName const fieldName = match[1]; // fieldName
// Создаем уникальный плейсхолдер // Создаем уникальный плейсхолдер
const placeholder = \`__REPORT_PLACEHOLDER_\${reportPromises.length}__\`; const placeholder = \`__REPORT_PLACEHOLDER_\${reportPromises.length}__\`;
// Ищем данные отчета в хранилище // Ищем данные отчета в хранилище
const reportFields = JSON.parse(frm.doc.report_fields_storage || "{}"); const reportFields = JSON.parse(frm.doc.report_fields_storage || "{}");
const reportField = Object.values(reportFields).find(f => f.name === fieldName); const reportField = Object.values(reportFields).find(f => f.name === fieldName);
if (reportField) { if (reportField) {
// Добавляем промис запроса к отчету // Добавляем промис запроса к отчету
reportPromises.push( reportPromises.push(
getReportFieldValue( getReportFieldValue(
frm, frm,
reportField.report, reportField.report,
JSON.parse(reportField.filters_json || "{}"), JSON.parse(reportField.filters_json || "{}"),
reportField.field_name, reportField.field_name,
reportField.aggregation || 'sum' reportField.aggregation || 'sum'
) )
); );
// Запоминаем соответствие плейсхолдера и вызова // Запоминаем соответствие плейсхолдера и вызова
reportPlaceholders.push({ reportPlaceholders.push({
placeholder: placeholder, placeholder: placeholder,
original: fullMatch original: fullMatch
}); });
// Заменяем вызов отчета на плейсхолдер // Заменяем вызов отчета на плейсхолдер
processedFormula = processedFormula.replace(fullMatch, placeholder); processedFormula = processedFormula.replace(fullMatch, placeholder);
}
}
// Если нашли вызовы отчетов, ждем выполнения всех запросов
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
);
}
// Теперь формула не содержит вызовов report(), обрабатываем её обычным способом
let transformResult = transform_expression(processedFormula, false);
// Если есть внешняя трансформация, применяем её
let result;
if (transformResult && transformResult.transformed) {
result = eval(transformResult.transformed);
} else {
// Иначе просто вычисляем выражение
result = eval(processedFormula);
}
// Возвращаем результат
return isNaN(result) ? 0 : result;
} }
} }
// Если нашли вызовы отчетов, ждем выполнения всех запросов // Стандартная обработка для формул без отчетов
if (reportPromises.length > 0) { let transformResult = transform_expression(formula, false);
const reportResults = await Promise.all(reportPromises); let result = eval(transformResult.transformed);
return isNaN(result) ? 0 : result;
// Заменяем плейсхолдеры на результаты } catch (e) {
for (let i = 0; i < reportPlaceholders.length; i++) { return 0;
// Убедимся, что результат - числовое значение
const reportValue = reportResults[i] !== undefined ? Number(reportResults[i]) : 0;
processedFormula = processedFormula.replace(
reportPlaceholders[i].placeholder,
reportValue
);
}
// Теперь формула не содержит вызовов report(), обрабатываем её обычным способом
let transformResult = transform_expression(processedFormula, false);
// Если есть внешняя трансформация, применяем её
let result;
if (transformResult && transformResult.transformed) {
result = eval(transformResult.transformed);
} else {
// Иначе просто вычисляем выражение
result = eval(processedFormula);
}
// Возвращаем результат
return isNaN(result) ? 0 : result;
}
} }
}`);
// Стандартная обработка для формул без отчетов
let transformResult = transform_expression(formula, false);
let result = eval(transformResult.transformed);
return isNaN(result) ? 0 : result;
} catch (e) {
return 0;
}
}`);
// Добавляем функцию для расчета универсальных полей // Добавляем функцию для расчета универсальных полей
functions.push(generateUniversalFieldsFunction(universal_fields)); functions.push(generateUniversalFieldsFunction(universal_fields));
@ -343,16 +343,8 @@ frappe.require([
functions.push(generateReportFieldsFunction(report_fields)); functions.push(generateReportFieldsFunction(report_fields));
} }
// Добавляем обработчики для ay и il - для расчета универсальных полей // НЕ добавляем обработчики для ay и il здесь отдельно
triggerHandlers["ay"] = { // Они будут добавлены позже вместе с другими обработчиками
isAsync: true,
handlers: ["// Вычисляем универсальные поля только когда меняется ay", "await calculate_universal_fields(frm);"]
};
triggerHandlers["il"] = {
isAsync: true,
handlers: ["// Вычисляем универсальные поля только когда меняется il", "await calculate_universal_fields(frm);"]
};
// Добавляем функцию преобразования выражений // Добавляем функцию преобразования выражений
functions.push(generateTransformExpressionFunction(universal_fields, report_fields)); functions.push(generateTransformExpressionFunction(universal_fields, report_fields));
@ -440,39 +432,39 @@ frappe.require([
} else { } else {
// Используем единый подход для всех формул через transform_expression // Используем единый подход для всех формул через transform_expression
functions.push(` functions.push(`
async function calculate_${fieldname}(frm) { async function calculate_${fieldname}(frm) {
try { try {
${formula.includes("univ(") ? 'await calculate_universal_fields(frm);' : ''} ${formula.includes("univ(") ? 'await calculate_universal_fields(frm);' : ''}
const { transformed, needsAsync, reportCalls } = transform_expression(${JSON.stringify(formula)}, false); const { transformed, needsAsync, reportCalls } = transform_expression(${JSON.stringify(formula)}, false);
// Обработка вызовов отчетов, если они есть // Обработка вызовов отчетов, если они есть
let finalExpression = transformed; let finalExpression = transformed;
if (reportCalls && reportCalls.length > 0) { if (reportCalls && reportCalls.length > 0) {
// Собираем все результаты отчетов // Собираем все результаты отчетов
const reportResults = []; const reportResults = [];
for (const call of reportCalls) { for (const call of reportCalls) {
const result = await getReportFieldValue( const result = await getReportFieldValue(
frm, frm,
call.reportName, call.reportName,
call.filters, call.filters,
call.fieldName, call.fieldName,
call.aggregation call.aggregation
); );
reportResults.push({ placeholder: call.placeholder, value: result }); reportResults.push({ placeholder: call.placeholder, value: result });
}
// Заменяем плейсхолдеры на полученные значения
for (const result of reportResults) {
finalExpression = finalExpression.replace(result.placeholder, result.value);
}
} }
// Заменяем плейсхолдеры на полученные значения // Теперь можно безопасно вычислить выражение
for (const result of reportResults) { const result = eval(finalExpression);
finalExpression = finalExpression.replace(result.placeholder, result.value); frm.set_value("${fieldname}", isNaN(result) ? 0 : result);
} } catch (e) {
} }
}`);
// Теперь можно безопасно вычислить выражение
const result = eval(finalExpression);
frm.set_value("${fieldname}", isNaN(result) ? 0 : result);
} catch (e) {
}
}`);
// Проверяем триггеры // Проверяем триггеры
if (field_info.triggers) { if (field_info.triggers) {
@ -577,23 +569,76 @@ frappe.require([
'frappe.ui.form.on("' + target_doctype + '", {\n' + refreshHandlerBody); 'frappe.ui.form.on("' + target_doctype + '", {\n' + refreshHandlerBody);
} }
// Теперь создаем обработчики для каждого триггера
Object.keys(triggerHandlers).forEach(trigger => {
const handler = triggerHandlers[trigger];
main_script += ` "${trigger}": ${handler.isAsync ? 'async ' : ''}function(frm) {
${handler.handlers.join('\n ')}
},\n`;
});
// Обработчики для табличных частей и триггеры, связанные с ними // Обработчики для табличных частей и триггеры, связанные с ними
const tableRowFormulaHandlers = processTableRowFormulas(table_row_formulas, table_doctypes); const tableRowFormulaHandlers = processTableRowFormulas(table_row_formulas, table_doctypes);
// ВАЖНО: Объединяем обработчики формул строк таблиц с основными обработчиками
Object.keys(tableRowFormulaHandlers).forEach(trigger => { Object.keys(tableRowFormulaHandlers).forEach(trigger => {
const handler = tableRowFormulaHandlers[trigger]; const handler = tableRowFormulaHandlers[trigger];
main_script += ` "${trigger}": ${handler.isAsync ? 'async ' : ''}function(frm) {
${handler.isAsync ? 'await calculate_universal_fields(frm);' : '// Универсальные поля не используются'}
${handler.handlers.join('\n ')} // Проверяем, есть ли уже обработчик для этого триггера
},\n`; if (triggerHandlers[trigger]) {
// Объединяем обработчики
// Если хотя бы один требует async, делаем весь обработчик async
if (handler.isAsync) {
triggerHandlers[trigger].isAsync = true;
}
// Добавляем новые обработчики к существующим
triggerHandlers[trigger].handlers = triggerHandlers[trigger].handlers.concat(handler.handlers);
} else {
// Если обработчика еще нет, создаем новый
triggerHandlers[trigger] = handler;
}
});
// Проверяем, нужны ли обработчики для ay и il для универсальных полей и основных формул
const needsAyIlHandlers = fieldsUsingUniversalOrReports.some(f => f.uses_universal) ||
Object.keys(table_row_formulas).some(id => {
const formula = table_row_formulas[id];
return formula.formula && formula.formula.includes("univ(");
});
if (needsAyIlHandlers) {
// Добавляем или обновляем обработчики для ay и il
['ay', 'il'].forEach(field => {
if (!triggerHandlers[field]) {
triggerHandlers[field] = {
isAsync: true,
handlers: []
};
} else {
triggerHandlers[field].isAsync = true;
}
// Добавляем вызов calculate_universal_fields в начало обработчика
const hasUniversalCall = triggerHandlers[field].handlers.some(h =>
h.includes('calculate_universal_fields')
);
if (!hasUniversalCall) {
triggerHandlers[field].handlers.unshift('await calculate_universal_fields(frm);');
}
});
}
// Теперь создаем обработчики для каждого триггера (без дубликатов)
Object.keys(triggerHandlers).forEach(trigger => {
const handler = triggerHandlers[trigger];
main_script += ` "${trigger}": ${handler.isAsync ? 'async ' : ''}function(frm) {\n`;
// Для ay и il добавляем комментарий о вычислении универсальных полей
if (trigger === 'ay' || trigger === 'il') {
if (handler.handlers.some(h => h.includes('calculate_universal_fields'))) {
main_script += ` // Вычисляем универсальные поля только когда меняется ${trigger}\n`;
}
}
// Добавляем все обработчики
handler.handlers.forEach(handlerCode => {
main_script += ` ${handlerCode}\n`;
});
main_script += ' },\n';
}); });
main_script += `});`; main_script += `});`;