From 0ca80210a23a770b0f0ba530a2a3b03f6fa17828 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Mon, 30 Mar 2026 14:48:50 +0000 Subject: [PATCH] push from mvp --- taxes_az/fixtures/client_script.json | 11 ----------- ...ion_related_to_salaried_and_non_salaried_work.json | 8 ++++---- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/taxes_az/fixtures/client_script.json b/taxes_az/fixtures/client_script.json index c390282..27f112a 100644 --- a/taxes_az/fixtures/client_script.json +++ b/taxes_az/fixtures/client_script.json @@ -21,17 +21,6 @@ "script": "\r\nfrappe.ui.form.on('Declaration of value added tax', {\r\n onload: function(frm) {\r\n if (!frm.doc.__islocal) return; \r\n\r\n if (!frm.doc.əlavə1_2_yeni) {\r\n frm.set_value('əlavə1_2_yeni', []); \r\n }\r\n\r\n const default_rows = [\r\n { sətirkodu: '308 VM 175.1-ci maddəsinə əsasən alınmış elektron qaimə-fakturalar (elektron vergi hesab-fakturalar) üzrə nağdsız qaydada ödənilmiş məbləğ', SahəAdı2: 'Məlumat' },\r\n { sətirkodu: '314 VM 175.3-cü maddəsinə əsasən əvəzləşdirilməsinə yol verilməyən ƏDV məbləği', SahəAdı2: 'Məlumat' },\r\n { sətirkodu: '316 ƏDV sıfır (0) faiz dərəcəsi ilə ödənilmiş məbləğ', SahəAdı2: 'Məlumat' },\r\n \r\n ];\r\n\r\n default_rows.forEach(row => {\r\n frm.add_child('əlavə1_2_yeni', row);\r\n });\r\n\r\n frm.refresh_field('əlavə1_2_yeni'); \r\n }\r\n});", "view": "Form" }, - { - "docstatus": 0, - "doctype": "Client Script", - "dt": "Declaration of value added tax", - "enabled": 1, - "modified": "2026-03-26 19:36:59.952941", - "module": "Taxes Az", - "name": "Formula_Editor_Script_for_Declaration of value added tax", - "script": "// Generated by Formula Editor\nfrappe.ui.form.on(\"Declaration of value added tax\", {\n});\n\n\n // Функция для обработки и выполнения формул\n async function processFormula(frm, formula) {\n try {\n // Проверяем наличие вызовов отчетов\n if (formula.includes(\"report(\")) {\n // Извлекаем все вызовы report() из формулы\n const reportRegex = /report\\(([^)]+)\\)/g;\n let match;\n let processedFormula = formula;\n \n // Массив для хранения промисов запросов к отчетам\n const reportPromises = [];\n const reportPlaceholders = [];\n \n // Находим все вызовы report() и заменяем их на плейсхолдеры\n while ((match = reportRegex.exec(formula)) !== null) {\n const fullMatch = match[0]; // report(fieldName)\n const fieldName = match[1]; // fieldName\n \n // Создаем уникальный плейсхолдер\n const placeholder = `__REPORT_PLACEHOLDER_${reportPromises.length}__`;\n \n // Ищем данные отчета в хранилище\n const reportFields = JSON.parse(frm.doc.report_fields_storage || \"{}\");\n const reportField = Object.values(reportFields).find(f => f.name === fieldName);\n \n if (reportField) {\n // Добавляем промис запроса к отчету\n reportPromises.push(\n getReportFieldValue(\n frm,\n reportField.report, \n JSON.parse(reportField.filters_json || \"{}\"), \n reportField.field_name, \n reportField.aggregation || 'sum'\n )\n );\n \n // Запоминаем соответствие плейсхолдера и вызова\n reportPlaceholders.push({\n placeholder: placeholder,\n original: fullMatch\n });\n \n // Заменяем вызов отчета на плейсхолдер\n processedFormula = processedFormula.replace(fullMatch, placeholder);\n }\n }\n \n // Если нашли вызовы отчетов, ждем выполнения всех запросов\n if (reportPromises.length > 0) {\n const reportResults = await Promise.all(reportPromises);\n \n // Заменяем плейсхолдеры на результаты\n for (let i = 0; i < reportPlaceholders.length; i++) {\n // Убедимся, что результат - числовое значение\n const reportValue = reportResults[i] !== undefined ? Number(reportResults[i]) : 0;\n processedFormula = processedFormula.replace(\n reportPlaceholders[i].placeholder, \n reportValue\n );\n }\n \n // Теперь формула не содержит вызовов report(), обрабатываем её обычным способом\n let transformResult = transform_expression(processedFormula, false);\n \n // Если есть внешняя трансформация, применяем её\n let result;\n if (transformResult && transformResult.transformed) {\n result = eval(transformResult.transformed);\n } else {\n // Иначе просто вычисляем выражение\n result = eval(processedFormula);\n }\n \n // Возвращаем результат\n return isNaN(result) ? 0 : result;\n }\n }\n \n // Стандартная обработка для формул без отчетов\n let transformResult = transform_expression(formula, false);\n let result = eval(transformResult.transformed);\n return isNaN(result) ? 0 : result;\n } catch (e) {\n return 0;\n }\n }\n\n\n // Функция для расчета универсальных полей\n async function calculate_universal_fields(frm) {\n \n }\n \n // Функция для обработки квартала (rüb) и года (il)\n function processQuarterDateField(docValues) {\n // Проверяем, есть ли у нас значения rüb и il\n if (docValues && docValues.rüb && docValues.il) {\n // Получаем номер квартала (преобразуем из строки вида \"1 Rüb\" в число 1)\n const quarterStr = docValues.rüb;\n const quarterMatch = quarterStr.match(/(\\d+)/);\n \n if (!quarterMatch) {\n return null;\n }\n \n const quarterNum = parseInt(quarterMatch[1]);\n \n // Получаем год из поля il или используем текущий год\n let year = docValues.il || new Date().getFullYear();\n \n // Определяем начальный и конечный месяц квартала\n let startMonth, endMonth;\n \n switch(quarterNum) {\n case 1:\n startMonth = 1; // Январь\n endMonth = 3; // Март\n break;\n case 2:\n startMonth = 4; // Апрель\n endMonth = 6; // Июнь\n break;\n case 3:\n startMonth = 7; // Июль\n endMonth = 9; // Сентябрь\n break;\n case 4:\n startMonth = 10; // Октябрь\n endMonth = 12; // Декабрь\n break;\n default:\n return null;\n }\n \n // Определяем первый день квартала (1-е число начального месяца)\n const firstDay = new Date(year, startMonth - 1, 1);\n \n // Последний день квартала (последнее число конечного месяца)\n const lastDay = new Date(year, endMonth, 0);\n \n // Форматируем даты в формате YYYY-MM-DD\n const firstDayStr = `${year}-${String(startMonth).padStart(2, '0')}-01`;\n const lastDayStr = `${year}-${String(endMonth).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}`; \n \n // Возвращаем объект с диапазоном дат\n return {\n start: firstDayStr,\n end: lastDayStr\n };\n }\n \n // Если это не специальное поле или значение не распознано, возвращаем null\n return null;\n }\n \n // Функция для обработки специальных полей с азербайджанскими месяцами\n function processAzerbayjanDateField(docValues) {\n // Словарь для сопоставления названий месяцев с их номерами\n const monthNames = {\n \"Yanvar\": 1,\n \"Fevral\": 2,\n \"Mart\": 3,\n \"Aprel\": 4,\n \"May\": 5,\n \"İyun\": 6,\n \"İyul\": 7,\n \"Avqust\": 8,\n \"Sentyabr\": 9,\n \"Oktyabr\": 10,\n \"Noyabr\": 11,\n \"Dekabr\": 12\n };\n \n // Проверяем наличие квартала (rüb) и года (il)\n if (docValues && docValues.rüb && docValues.il) {\n // Вызываем специальную функцию для обработки квартала\n return processQuarterDateField(docValues);\n }\n \n // Проверяем, есть ли у нас значения ay и il\n if (docValues && docValues.ay && monthNames[docValues.ay]) {\n // Получаем номер месяца\n const monthNum = monthNames[docValues.ay];\n \n // Получаем год из поля il или используем текущий год\n let year = docValues.il || new Date().getFullYear();\n \n // Определяем первый день месяца (1-е число)\n const firstDay = new Date(year, monthNum - 1, 1);\n \n // Последний день месяца (получаем последнее число месяца)\n const lastDay = new Date(year, monthNum, 0);\n \n // Форматируем даты в формате YYYY-MM-DD\n const firstDayStr = `${year}-${String(monthNum).padStart(2, '0')}-01`;\n const lastDayStr = `${year}-${String(monthNum).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')}`; \n \n // Возвращаем объект с диапазоном дат\n return {\n start: firstDayStr,\n end: lastDayStr\n };\n }\n \n // Если это не специальное поле или значение не распознано, возвращаем null\n return null;\n }\n \n\n\n function transform_expression(expression, for_child_table = false, table_name = null) {\n let transformed = expression;\n let needsAsync = false;\n let reportCalls = [];\n\n // === Обработка report(...) ===\n const reportRegex = /report\\(([^)]+)\\)/g;\n let match;\n \n // Находим все вызовы report() в выражении\n while ((match = reportRegex.exec(expression)) !== null) {\n const reportName = match[1]; // Имя поля отчета\n const fullMatch = match[0]; // Полный текст match - \"report(xyz)\"\n needsAsync = true;\n \n // Создаем уникальный плейсхолдер\n const placeholder = `__REPORT_PLACEHOLDER_${reportCalls.length}__`;\n \n // Ищем соответствующее поле отчета по имени\n \n }\n\n // === Обработка table(...) ===\n const tableRegex = /table\\(([^,)]+),\\s*([^,)]+),\\s*([^)]+)\\)/g;\n let tableMatch;\n while ((tableMatch = tableRegex.exec(expression)) !== null) {\n const fullMatch = tableMatch[0];\n const tableName = tableMatch[1].trim().replace(/['\"]/g, '');\n const rowNumber = tableMatch[2].trim();\n const fieldName = tableMatch[3].trim().replace(/['\"]/g, '');\n \n const replacement = `(function() { \n try {\n if (!frm.doc[\"${tableName}\"] || !frm.doc[\"${tableName}\"][${rowNumber} - 1]) {\n return 0;\n }\n const value = frm.doc[\"${tableName}\"][${rowNumber} - 1][\"${fieldName}\"];\n return parseFloat(value) || 0;\n } catch (e) {\n return 0;\n }\n })()`;\n \n transformed = transformed.replace(fullMatch, replacement);\n }\n\n // === Обработка universal полей ===\n \n\n // === Обработка val() и row() ===\n // Динамически получаем список всех табличных частей из DocType\n const tablePrefixes = [\"hesabat_dövriyyəsi\",\"debitor_borc\",\"əvəzləşdirilən_table\",\"dəqiqləşdirilən_table\",\"hesablaşmalar_table\",\"əlavə_1\",\"əlavə_1_2\",\"əlavə1_yeni\",\"əlavə1_2_yeni\",\"əlavə_2\",\"əlavə_2_2\",\"əlavə_2_3\",\"əlavə_4\",\"əlavə_5\",\"əlavə_7\",\"əlavə_9\",\"əlavə_10\",\"əlavə_10_2\",\"əlavə_3_1\",\"əlavə_3_2\",\"müəssisə_sertifikat\",\"müəssisə_malın_dəyəri\"];\n\n for (const prefix of tablePrefixes) {\n const sumPattern = new RegExp(`sum\\\\(${prefix}_([^)]+)\\\\)`, 'g');\n transformed = transformed.replace(sumPattern, (m, f) => \n `(frm.doc[\"${prefix}\"] && frm.doc[\"${prefix}\"].reduce((s, r) => s + (parseFloat(r[\"${f}\"]) || 0), 0) || 0)`\n );\n\n const valPattern = new RegExp(`val\\\\(${prefix}_([^)]+)\\\\)`, 'g');\n transformed = transformed.replace(valPattern, (m, f) => \n `(frm.doc[\"${prefix}\"] && frm.doc[\"${prefix}\"].reduce((s, r) => s + (parseFloat(r[\"${f}\"]) || 0), 0) || 0)`\n );\n }\n\n if (for_child_table) {\n transformed = transformed.replace(/row\\(([^)]+)\\)/g, (m, f) => \n `(parseFloat(row[\"${f}\"]) || 0)`\n );\n\n transformed = transformed.replace(/val\\(([^)]+)\\)/g, (m, f) => {\n if (f.startsWith(table_name + '_')) {\n return `(parseFloat(row[\"${f.slice(table_name.length + 1)}\"]) || 0)`;\n }\n return `(parseFloat(frm.doc[\"${f}\"]) || 0)`;\n });\n } else {\n transformed = transformed.replace(/val\\(([^)]+)\\)/g, (m, f) => \n `(parseFloat(frm.doc[\"${f}\"]) || 0)`\n );\n\n transformed = transformed.replace(/row\\(([^)]+)\\)/g, () => \n `0 /* ERROR: row() вне табличной части */`\n );\n }\n\n return { transformed, needsAsync, reportCalls };\n }\n\n\n// Функция для получения индекса строки по её имени (name/cdn)\nfunction get_row_index(frm, tableName, rowName) {\n \n // Проверяем наличие таблицы\n if (!frm.doc[tableName]) {\n return -1;\n }\n \n // Выводим все строки для отладки\n frm.doc[tableName].forEach((row, idx) => {\n });\n \n // Ищем индекс строки по имени\n for (let i = 0; i < frm.doc[tableName].length; i++) {\n if (frm.doc[tableName][i].name === rowName) {\n return i;\n }\n }\n return -1;\n}\n\n// Функция для доступа к полям конкретных строк таблицы\nfunction table_row(tableName, rowIndex, fieldName) {\n // Проверяем наличие необходимых аргументов\n if (!tableName || rowIndex === undefined || !fieldName) {\n return 0;\n }\n \n // Преобразуем rowIndex в число (на случай, если передана строка)\n const rowIdx = parseInt(rowIndex) - 1; // Индексация с 1 для пользователя, но с 0 в массиве\n \n try {\n // Проверяем наличие таблицы и строки\n if (!frm.doc[tableName] || !frm.doc[tableName][rowIdx]) {\n return 0;\n }\n \n // Получаем значение поля\n const value = frm.doc[tableName][rowIdx][fieldName];\n \n // Проверяем на NaN и возвращаем значение или 0\n const numValue = parseFloat(value);\n if (isNaN(numValue)) {\n return 0;\n }\n return numValue;\n } catch (error) {\n return 0;\n }\n}\n\n// Функция для обновления значения поля конкретной строки таблицы\nfunction set_table_row(frm, tableName, rowIndex, fieldName, value) {\n // Проверяем наличие необходимых аргументов\n if (!frm || !tableName || rowIndex === undefined || !fieldName) {\n return false;\n }\n \n // Преобразуем rowIndex в число (на случай, если передана строка)\n const rowIdx = parseInt(rowIndex) - 1; // Индексация с 1 для пользователя, но с 0 в массиве\n \n try {\n // Проверяем наличие таблицы и строки\n if (!frm.doc[tableName] || !frm.doc[tableName][rowIdx]) {\n return false;\n }\n \n // Получаем строку таблицы\n const row = frm.doc[tableName][rowIdx];\n \n // Получаем сетевое имя cdt и cdn для Frappe\n const cdt = frm.fields_dict[tableName].grid.doctype;\n const cdn = row.name;\n \n // Проверяем, является ли значение NaN, и если да, заменяем его на 0\n let finalValue = value;\n if (typeof value === 'number' && isNaN(value)) {\n finalValue = 0;\n }\n \n // Обновляем значение поля\n frappe.model.set_value(cdt, cdn, fieldName, finalValue);\n \n return true;\n } catch (error) {\n return false;\n }\n}\n\n// Функция для поиска строки таблицы по значению поля\nfunction find_table_row(frm, tableName, fieldName, value) {\n // Проверяем наличие необходимых аргументов\n if (!frm || !tableName || !fieldName) {\n return -1;\n }\n \n try {\n // Проверяем наличие таблицы\n if (!frm.doc[tableName]) {\n return -1;\n }\n \n // Ищем строку с указанным значением поля\n for (let i = 0; i < frm.doc[tableName].length; i++) {\n if (frm.doc[tableName][i][fieldName] == value) {\n // Возвращаем индекс строки (начиная с 1 для пользователя)\n return i + 1;\n }\n }\n \n // Если строка не найдена\n return -1;\n } catch (error) {\n return -1;\n }\n}", - "view": "Form" - }, { "docstatus": 0, "doctype": "Client Script", diff --git a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.json b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.json index 5ab89be..51cbc81 100644 --- a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.json +++ b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.json @@ -63,7 +63,7 @@ "hiss\u0259_4", "\u0259lav\u02592", "html_dhqi", - "table_cuov", + "elave_2", "\u0259lav\u02594", "data_ssvq", "vergi", @@ -632,15 +632,15 @@ "options": "Single Declaration-Bolme2_hisse3" }, { - "fieldname": "table_cuov", + "fieldname": "elave_2", "fieldtype": "Table", "options": "SingleDeclaration-Elave2" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2026-02-26 18:29:52.170183", - "modified_by": "Administrator", + "modified": "2026-03-27 22:52:18.790138", + "modified_by": "nihad_m@jeysoft.az", "module": "Taxes Az", "name": "Single declaration related to salaried and non-salaried work", "owner": "Administrator",