From 6a4a65f24f8558dd28851309d8c3d827a66072ce Mon Sep 17 00:00:00 2001
From: Ali <010109ali@gmail.com>
Date: Sat, 31 May 2025 15:10:49 +0400
Subject: [PATCH] test commit
---
taxes_az/hooks.py | 9 +
.../js/xml_mapping/doctype_field_selector.js | 115 ++++++++++++
.../public/js/xml_mapping/field_generator.js | 167 ++++++++++++++++++
.../public/js/xml_mapping/mapping_storage.js | 0
.../public/js/xml_mapping/xml_generator.js | 117 ++++++++++++
taxes_az/public/js/xml_mapping/xml_parser.js | 77 ++++++++
...truction_and_simplified_tax_declaration.js | 41 ++++-
...icate_on_non_emergence_of_tax_liability.js | 41 ++++-
.../declaration_of_mining_tax.js | 41 ++++-
.../declaration_of_mining_tax.json | 14 +-
.../declaration_of_simplified_tax.js | 41 ++++-
...n_of_simplified_tax_on_cash_withdrawals.js | 41 ++++-
.../declaration_of_value_added_tax.js | 41 ++++-
...laration_of_withholding_tax_on_winnings.js | 41 ++++-
.../excise_declaration/excise_declaration.js | 41 ++++-
.../export_declaration/export_declaration.js | 41 ++++-
...construction_simplified_tax_declaration.js | 41 ++++-
.../income_tax_return/income_tax_return.js | 41 ++++-
.../income_tax_return_of_a_private_notary.js | 41 ++++-
.../land_tax_declaration.js | 41 ++++-
.../profit_tax_with_special_tax_regime.js | 41 ++++-
.../property_tax_return.js | 41 ++++-
...rterly_report_on_unemployment_insurance.js | 41 ++++-
.../real_estate_simplified_tax_declaration.js | 41 ++++-
.../reference_on_controlled_transactions.js | 41 ++++-
.../report_on_collection_of_state_duty.js | 41 ++++-
.../taxes_az/doctype/road_tax_2/road_tax_2.js | 41 ++++-
...lated_to_salaried_and_non_salaried_work.js | 41 ++++-
...ax_return_withheld_at_source_of_payment.js | 41 ++++-
...ed_on_the_amount_paid_to_a_non_resident.js | 41 ++++-
...ng_tax_return_of_foreign_subcontractors.js | 41 ++++-
.../doctype/xml_mapping_tool/__init__.py | 0
.../xml_mapping_tool/test_xml_mapping_tool.py | 30 ++++
.../xml_mapping_tool/xml_mapping_tool.js | 86 +++++++++
.../xml_mapping_tool/xml_mapping_tool.json | 74 ++++++++
.../xml_mapping_tool/xml_mapping_tool.py | 124 +++++++++++++
36 files changed, 1598 insertions(+), 199 deletions(-)
create mode 100644 taxes_az/public/js/xml_mapping/doctype_field_selector.js
create mode 100644 taxes_az/public/js/xml_mapping/field_generator.js
create mode 100644 taxes_az/public/js/xml_mapping/mapping_storage.js
create mode 100644 taxes_az/public/js/xml_mapping/xml_generator.js
create mode 100644 taxes_az/public/js/xml_mapping/xml_parser.js
create mode 100644 taxes_az/taxes_az/doctype/xml_mapping_tool/__init__.py
create mode 100644 taxes_az/taxes_az/doctype/xml_mapping_tool/test_xml_mapping_tool.py
create mode 100644 taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.js
create mode 100644 taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.json
create mode 100644 taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.py
diff --git a/taxes_az/hooks.py b/taxes_az/hooks.py
index adb1439..0724b4c 100644
--- a/taxes_az/hooks.py
+++ b/taxes_az/hooks.py
@@ -19,6 +19,15 @@ fixtures = [
}
]
+doctype_js = {
+ "XML Mapping Tool": [
+ "public/js/xml_mapping/xml_parser.js",
+ "public/js/xml_mapping/field_generator.js",
+ "public/js/xml_mapping/doctype_field_selector.js",
+ "public/js/xml_mapping/mapping_storage.js",
+ "public/js/xml_mapping/xml_generator.js"
+ ]
+}
# Includes in
diff --git a/taxes_az/public/js/xml_mapping/doctype_field_selector.js b/taxes_az/public/js/xml_mapping/doctype_field_selector.js
new file mode 100644
index 0000000..d9b641c
--- /dev/null
+++ b/taxes_az/public/js/xml_mapping/doctype_field_selector.js
@@ -0,0 +1,115 @@
+// taxes_az/public/js/xml_mapping/doctype_field_selector.js
+
+frappe.provide("taxes_az.xml_mapping");
+
+taxes_az.xml_mapping.DoctypeFieldSelector = class DoctypeFieldSelector {
+ constructor(frm) {
+ this.frm = frm;
+ }
+
+ // Получить список полей DocType
+ async getFieldsForDoctype(doctype) {
+ return new Promise((resolve, reject) => {
+ frappe.model.with_doctype(doctype, () => {
+ try {
+ const meta = frappe.get_meta(doctype);
+ if (!meta) {
+ throw new Error(`DocType ${doctype} not found`);
+ }
+
+ const fields = meta.fields.filter(field => {
+ // Исключаем служебные поля и разделы
+ return !['Section Break', 'Column Break', 'Tab Break', 'HTML', 'Button'].includes(field.fieldtype);
+ });
+
+ resolve(fields);
+ } catch (error) {
+ reject(error);
+ }
+ });
+ });
+ }
+
+ // Добавить селекторы полей для каждого XML-пути
+ async attachFieldSelectors(container, xmlPaths) {
+ if (!this.frm.doc.target_doctype) {
+ frappe.throw(__('Please select a target DocType first'));
+ return;
+ }
+
+ try {
+ const fields = await this.getFieldsForDoctype(this.frm.doc.target_doctype);
+
+ // Добавляем селектор для каждого XML-пути
+ container.find('.xml-field-row').each((i, row) => {
+ const $row = $(row);
+ const xmlPath = $row.data('path');
+ const $selector = $row.find('.xml-field-selector');
+
+ // Создаем выпадающий список
+ const select = document.createElement('select');
+ select.classList.add('form-control', 'xml-field-map-select');
+ select.dataset.xmlPath = xmlPath;
+
+ // Опция "Не сопоставлять"
+ const defaultOption = document.createElement('option');
+ defaultOption.value = "";
+ defaultOption.textContent = __("-- Not mapped --");
+ select.appendChild(defaultOption);
+
+ // Добавляем опции для каждого поля DocType
+ fields.forEach(field => {
+ const option = document.createElement('option');
+ option.value = field.fieldname;
+ option.textContent = `${field.label || field.fieldname} (${field.fieldname})`;
+ select.appendChild(option);
+ });
+
+ // Добавляем селектор в контейнер
+ $selector.empty().append(select);
+
+ // Устанавливаем выбранное значение из сохраненных данных
+ if (this.frm.doc.mapping_data) {
+ try {
+ const mappingData = JSON.parse(this.frm.doc.mapping_data);
+ if (mappingData[xmlPath]) {
+ select.value = mappingData[xmlPath];
+ }
+ } catch (e) {
+ console.error('Error parsing mapping data:', e);
+ }
+ }
+
+ // Обработчик изменения
+ $(select).on('change', () => {
+ this._saveMappingData();
+ });
+ });
+ } catch (error) {
+ frappe.throw(`Error loading DocType fields: ${error.message}`);
+ }
+ }
+
+ _saveMappingData() {
+ const mappingData = {};
+
+ $('.xml-field-map-select').each((i, select) => {
+ const $select = $(select);
+ const xmlPath = $select.data('xml-path');
+ const fieldname = $select.val();
+
+ if (fieldname) {
+ mappingData[xmlPath] = fieldname;
+ }
+ });
+
+ // Просто устанавливаем значение, но не сохраняем автоматически
+ this.frm.set_value('mapping_data', JSON.stringify(mappingData));
+
+ // Уведомление об обновлении маппинга
+ frappe.show_alert({
+ message: __('Mapping updated. Remember to save the document.'),
+ indicator: 'blue'
+ });
+ }
+};
\ No newline at end of file
diff --git a/taxes_az/public/js/xml_mapping/field_generator.js b/taxes_az/public/js/xml_mapping/field_generator.js
new file mode 100644
index 0000000..b4ff0a1
--- /dev/null
+++ b/taxes_az/public/js/xml_mapping/field_generator.js
@@ -0,0 +1,167 @@
+// taxes_az/public/js/xml_mapping/field_generator.js
+
+frappe.provide("taxes_az.xml_mapping");
+
+taxes_az.xml_mapping.FieldGenerator = class FieldGenerator {
+ constructor(frm) {
+ this.frm = frm;
+ this.fieldContainer = $('');
+ }
+
+ // Очистить все динамически созданные поля
+ clearFields() {
+ this.fieldContainer.empty();
+ if (this.section) {
+ this.section.remove();
+ }
+ }
+
+ // Создать UI для выбора полей
+ createFieldsUI(xmlStructure) {
+ // Проверяем, существует ли уже секция
+ if ($('.xml-mapping-section').length) {
+ this.clearFields();
+ } else {
+ this.clearFields();
+
+ // Создаем секцию для полей XML
+ this.section = $('');
+ const sectionTitle = $('');
+ this.section.append(sectionTitle);
+
+ // Добавляем поле поиска
+ const searchField = $(`
+
+ `);
+
+ this.section.append(searchField);
+ this.section.append(this.fieldContainer);
+
+ // Добавляем секцию в форму после основной области формы
+ $('.form-layout').after(this.section);
+
+ // Добавляем обработчик поиска
+ searchField.find('.xml-search-field, .xml-search-button').on('keyup click', () => {
+ const searchText = searchField.find('.xml-search-field').val().toLowerCase();
+
+ this.fieldContainer.find('.xml-field-row').each((i, row) => {
+ const $row = $(row);
+ const path = $row.find('.xml-field-path').text().toLowerCase();
+ const value = $row.find('.xml-field-value').text().toLowerCase();
+
+ if (path.includes(searchText) || value.includes(searchText)) {
+ $row.show();
+ } else {
+ $row.hide();
+ }
+ });
+ });
+ }
+
+ // Для каждого пути создаем элемент интерфейса
+ xmlStructure.fieldPaths.forEach(fieldInfo => {
+ this._createFieldElement(fieldInfo);
+ });
+
+ // Инициализируем селектор DocType полей
+ if (this.frm.doc.target_doctype) {
+ const fieldSelector = new taxes_az.xml_mapping.DoctypeFieldSelector(this.frm);
+ fieldSelector.attachFieldSelectors(this.fieldContainer, xmlStructure.fieldPaths);
+ }
+
+ // Добавляем стили для полей
+ this._addStyles();
+ }
+
+ clearFields() {
+ this.fieldContainer = $('');
+
+ // Если секция существует, очищаем только контейнер полей
+ if ($('.xml-mapping-section').length) {
+ $('.xml-fields-container').replaceWith(this.fieldContainer);
+ }
+ }
+
+
+ clearFields() {
+ this.fieldContainer = $('');
+ if (this.section) {
+ this.section.remove();
+ }
+ }
+
+ clearFields() {
+ this.fieldContainer = $('');
+ if (this.section) {
+ this.section.remove();
+ }
+ }
+
+ // Создание отдельного элемента поля
+ _createFieldElement(fieldInfo) {
+ const fieldRow = $(`
+
+
${fieldInfo.path}
+
${fieldInfo.value}
+
+
+ `);
+
+ this.fieldContainer.append(fieldRow);
+ }
+
+ // Добавление стилей для UI полей
+ _addStyles() {
+ if (!$('#xml_mapping_styles').length) {
+ $('head').append(`
+
+ `);
+ }
+ }
+};
\ No newline at end of file
diff --git a/taxes_az/public/js/xml_mapping/mapping_storage.js b/taxes_az/public/js/xml_mapping/mapping_storage.js
new file mode 100644
index 0000000..e69de29
diff --git a/taxes_az/public/js/xml_mapping/xml_generator.js b/taxes_az/public/js/xml_mapping/xml_generator.js
new file mode 100644
index 0000000..5104224
--- /dev/null
+++ b/taxes_az/public/js/xml_mapping/xml_generator.js
@@ -0,0 +1,117 @@
+// taxes_az/public/js/xml_mapping/xml_generator.js
+
+frappe.provide("taxes_az.xml_mapping");
+
+taxes_az.xml_mapping.XMLGenerator = class XMLGenerator {
+ constructor(frm) {
+ this.frm = frm;
+ }
+
+ // Генерация XML на основе данных DocType и правил маппинга
+ async generateXML(doctypeName, docname) {
+ try {
+ // Загружаем данные DocType
+ const docData = await this._loadDocTypeData(doctypeName, docname);
+
+ // Загружаем правила маппинга
+ const mappingRules = JSON.parse(this.frm.doc.mapping_data || '{}');
+
+ // Загружаем шаблон XML
+ const xmlTemplate = this.frm.doc.xml_sample_file;
+
+ // Создаем DOM из шаблона XML
+ const parser = new DOMParser();
+ const xmlDoc = parser.parseFromString(xmlTemplate, "text/xml");
+
+ // Применяем правила маппинга
+ for (const xmlPath in mappingRules) {
+ const doctypeField = mappingRules[xmlPath];
+ const value = docData[doctypeField];
+
+ if (value !== undefined) {
+ this._setXMLValueByPath(xmlDoc, xmlPath, value);
+ }
+ }
+
+ // Преобразуем DOM обратно в строку XML
+ const serializer = new XMLSerializer();
+ const xmlString = serializer.serializeToString(xmlDoc);
+
+ return xmlString;
+ } catch (error) {
+ frappe.throw(`Error generating XML: ${error.message}`);
+ return null;
+ }
+ }
+
+ // Загрузка данных DocType
+ async _loadDocTypeData(doctypeName, docname) {
+ return new Promise((resolve, reject) => {
+ frappe.call({
+ method: 'frappe.client.get',
+ args: {
+ doctype: doctypeName,
+ name: docname
+ },
+ callback: (response) => {
+ if (response.message) {
+ resolve(response.message);
+ } else {
+ reject(new Error('Failed to load document data'));
+ }
+ }
+ });
+ });
+ }
+
+ // Установка значения в XML по пути
+ _setXMLValueByPath(xmlDoc, path, value) {
+ try {
+ // Проверяем, является ли путь атрибутом
+ if (path.includes('@')) {
+ const [elementPath, attrName] = path.split('@');
+ const elementPathParts = elementPath.split('/').filter(p => p);
+
+ // Получаем элемент
+ let element = xmlDoc.documentElement;
+ for (const part of elementPathParts) {
+ if (part !== element.nodeName) {
+ const elements = element.getElementsByTagName(part);
+ if (elements.length === 0) {
+ throw new Error(`Element ${part} not found in path ${path}`);
+ }
+ element = elements[0];
+ }
+ }
+
+ // Устанавливаем атрибут
+ element.setAttribute(attrName, value);
+ } else {
+ // Путь к элементу
+ const pathParts = path.split('/').filter(p => p);
+
+ // Получаем элемент
+ let element = xmlDoc.documentElement;
+ for (let i = 0; i < pathParts.length; i++) {
+ const part = pathParts[i];
+
+ if (i === pathParts.length - 1) {
+ // Последний элемент в пути - целевой элемент
+ const elements = element.getElementsByTagName(part);
+ if (elements.length) {
+ elements[0].textContent = value;
+ }
+ } else if (part !== element.nodeName) {
+ const elements = element.getElementsByTagName(part);
+ if (elements.length === 0) {
+ throw new Error(`Element ${part} not found in path ${path}`);
+ }
+ element = elements[0];
+ }
+ }
+ }
+ } catch (error) {
+ console.error(`Error setting value for path ${path}:`, error);
+ }
+ }
+};
\ No newline at end of file
diff --git a/taxes_az/public/js/xml_mapping/xml_parser.js b/taxes_az/public/js/xml_mapping/xml_parser.js
new file mode 100644
index 0000000..3444df2
--- /dev/null
+++ b/taxes_az/public/js/xml_mapping/xml_parser.js
@@ -0,0 +1,77 @@
+// taxes_az/public/js/xml_mapping/xml_parser.js
+
+frappe.provide("taxes_az.xml_mapping");
+
+taxes_az.xml_mapping.XMLParser = class XMLParser {
+ constructor() {
+ this.fieldPaths = [];
+ }
+
+ // Основная функция парсинга XML
+ parseXML(xmlString) {
+ const parser = new DOMParser();
+ try {
+ const xmlDoc = parser.parseFromString(xmlString, "text/xml");
+
+ // Проверка наличия ошибок парсинга
+ const parseError = xmlDoc.getElementsByTagName("parsererror");
+ if (parseError.length > 0) {
+ frappe.throw(__("Invalid XML: ") + parseError[0].textContent);
+ return null;
+ }
+
+ // Получить корневой элемент
+ const rootElement = xmlDoc.documentElement;
+ this.fieldPaths = [];
+
+ // Рекурсивно извлечь пути к полям
+ this._extractFieldPaths(rootElement, "");
+
+ return {
+ rootElement: rootElement.nodeName,
+ fieldPaths: this.fieldPaths
+ };
+ } catch (error) {
+ frappe.throw(__("Error parsing XML: ") + error.message);
+ return null;
+ }
+ }
+
+ // Рекурсивное извлечение путей к полям
+ _extractFieldPaths(element, currentPath) {
+ const nodeName = element.nodeName;
+ const newPath = currentPath ? `${currentPath}/${nodeName}` : nodeName;
+
+ // Если у элемента есть текстовое содержимое и нет дочерних элементов,
+ // считаем его полем
+ if (element.childNodes.length === 1 && element.childNodes[0].nodeType === 3) {
+ this.fieldPaths.push({
+ path: newPath,
+ value: element.textContent.trim(),
+ type: 'field'
+ });
+ return;
+ }
+
+ // Если у элемента есть атрибуты, извлекаем их как поля
+ if (element.attributes && element.attributes.length > 0) {
+ for (let i = 0; i < element.attributes.length; i++) {
+ const attr = element.attributes[i];
+ this.fieldPaths.push({
+ path: `${newPath}/@${attr.name}`,
+ value: attr.value,
+ type: 'attribute'
+ });
+ }
+ }
+
+ // Рекурсивно обрабатываем дочерние элементы
+ const childElements = element.childNodes;
+ for (let i = 0; i < childElements.length; i++) {
+ const child = childElements[i];
+ if (child.nodeType === 1) { // ELEMENT_NODE
+ this._extractFieldPaths(child, newPath);
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/building_construction_and_simplified_tax_declaration/building_construction_and_simplified_tax_declaration.js b/taxes_az/taxes_az/doctype/building_construction_and_simplified_tax_declaration/building_construction_and_simplified_tax_declaration.js
index 1efb8db..09e2b13 100644
--- a/taxes_az/taxes_az/doctype/building_construction_and_simplified_tax_declaration/building_construction_and_simplified_tax_declaration.js
+++ b/taxes_az/taxes_az/doctype/building_construction_and_simplified_tax_declaration/building_construction_and_simplified_tax_declaration.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Building construction and simplified tax declaration", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Building construction and simplified tax declaration', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Building construction and simplified tax declaration', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Building construction and simplified tax declaration', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/certificate_on_non_emergence_of_tax_liability/certificate_on_non_emergence_of_tax_liability.js b/taxes_az/taxes_az/doctype/certificate_on_non_emergence_of_tax_liability/certificate_on_non_emergence_of_tax_liability.js
index 19df8da..58c1849 100644
--- a/taxes_az/taxes_az/doctype/certificate_on_non_emergence_of_tax_liability/certificate_on_non_emergence_of_tax_liability.js
+++ b/taxes_az/taxes_az/doctype/certificate_on_non_emergence_of_tax_liability/certificate_on_non_emergence_of_tax_liability.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Certificate on non-emergence of tax liability", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Certificate on non-emergence of tax liability', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Certificate on non-emergence of tax liability', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Certificate on non-emergence of tax liability', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.js b/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.js
index 936419d..ee4574c 100644
--- a/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.js
+++ b/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Declaration of mining tax", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Declaration of mining tax', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Declaration of mining tax', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Declaration of mining tax', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.json b/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.json
index 0e5bb8c..b194dbd 100644
--- a/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.json
+++ b/taxes_az/taxes_az/doctype/declaration_of_mining_tax/declaration_of_mining_tax.json
@@ -42,7 +42,7 @@
"topdansat\u0131\u015f_qiym\u0259ti_il\u0259_tab",
"html_hken",
"section_break_oytj",
- "table_rhfx",
+ "topdansat\u0131\u015f_qiym\u0259ti_il\u0259",
"723b\u00fcdc\u0259y\u0259\u00f6d\u0259nilm\u0259livergininm\u0259bl\u0259\u011fi",
"faydal\u0131_qaz\u0131nt\u0131lar\u0131n_hasilat\u0131n_miqdar\u0131_il\u0259_tab",
"html_ybie",
@@ -236,11 +236,6 @@
"fieldname": "section_break_oytj",
"fieldtype": "Section Break"
},
- {
- "fieldname": "table_rhfx",
- "fieldtype": "Table",
- "options": "Declaration of mining tax Topdansatis qiymeti"
- },
{
"fieldname": "section_break_rpno",
"fieldtype": "Section Break"
@@ -283,11 +278,16 @@
"fieldname": "717hesablanm\u0131\u015fvergim\u0259bl\u0259\u011fininc\u0259mi",
"fieldtype": "Int",
"label": "717. Hesablanm\u0131\u015f vergi m\u0259bl\u0259\u011finin c\u0259mi"
+ },
+ {
+ "fieldname": "topdansat\u0131\u015f_qiym\u0259ti_il\u0259",
+ "fieldtype": "Table",
+ "options": "Declaration of mining tax Topdansatis qiymeti"
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2025-01-12 17:23:11.436483",
+ "modified": "2025-04-22 22:09:55.802593",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Declaration of mining tax",
diff --git a/taxes_az/taxes_az/doctype/declaration_of_simplified_tax/declaration_of_simplified_tax.js b/taxes_az/taxes_az/doctype/declaration_of_simplified_tax/declaration_of_simplified_tax.js
index 357c222..43f2704 100644
--- a/taxes_az/taxes_az/doctype/declaration_of_simplified_tax/declaration_of_simplified_tax.js
+++ b/taxes_az/taxes_az/doctype/declaration_of_simplified_tax/declaration_of_simplified_tax.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Declaration of simplified tax", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Declaration of simplified tax', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Declaration of simplified tax', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Declaration of simplified tax', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/declaration_of_simplified_tax_on_cash_withdrawals/declaration_of_simplified_tax_on_cash_withdrawals.js b/taxes_az/taxes_az/doctype/declaration_of_simplified_tax_on_cash_withdrawals/declaration_of_simplified_tax_on_cash_withdrawals.js
index 2fc6a13..9e53b29 100644
--- a/taxes_az/taxes_az/doctype/declaration_of_simplified_tax_on_cash_withdrawals/declaration_of_simplified_tax_on_cash_withdrawals.js
+++ b/taxes_az/taxes_az/doctype/declaration_of_simplified_tax_on_cash_withdrawals/declaration_of_simplified_tax_on_cash_withdrawals.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Declaration of simplified tax on cash withdrawals", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Declaration of simplified tax on cash withdrawals', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Declaration of simplified tax on cash withdrawals', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Declaration of simplified tax on cash withdrawals', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js b/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js
index d6d336e..ff5785d 100644
--- a/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js
+++ b/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Declaration of value added tax", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Declaration of value added tax', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Declaration of value added tax', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Declaration of value added tax', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/declaration_of_withholding_tax_on_winnings/declaration_of_withholding_tax_on_winnings.js b/taxes_az/taxes_az/doctype/declaration_of_withholding_tax_on_winnings/declaration_of_withholding_tax_on_winnings.js
index 2a5faf3..8d12bb2 100644
--- a/taxes_az/taxes_az/doctype/declaration_of_withholding_tax_on_winnings/declaration_of_withholding_tax_on_winnings.js
+++ b/taxes_az/taxes_az/doctype/declaration_of_withholding_tax_on_winnings/declaration_of_withholding_tax_on_winnings.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Declaration of withholding tax on winnings", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Declaration of withholding tax on winnings', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Declaration of withholding tax on winnings', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Declaration of withholding tax on winnings', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/excise_declaration/excise_declaration.js b/taxes_az/taxes_az/doctype/excise_declaration/excise_declaration.js
index 35afc6d..9c4caf7 100644
--- a/taxes_az/taxes_az/doctype/excise_declaration/excise_declaration.js
+++ b/taxes_az/taxes_az/doctype/excise_declaration/excise_declaration.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2024, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Excise declaration", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Excise declaration', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Excise declaration', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Excise declaration', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/export_declaration/export_declaration.js b/taxes_az/taxes_az/doctype/export_declaration/export_declaration.js
index fae148c..624d637 100644
--- a/taxes_az/taxes_az/doctype/export_declaration/export_declaration.js
+++ b/taxes_az/taxes_az/doctype/export_declaration/export_declaration.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2024, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Export declaration", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Export declaration', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Export declaration', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Export declaration', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/housing_construction_simplified_tax_declaration/housing_construction_simplified_tax_declaration.js b/taxes_az/taxes_az/doctype/housing_construction_simplified_tax_declaration/housing_construction_simplified_tax_declaration.js
index 2754e5d..fc00bbe 100644
--- a/taxes_az/taxes_az/doctype/housing_construction_simplified_tax_declaration/housing_construction_simplified_tax_declaration.js
+++ b/taxes_az/taxes_az/doctype/housing_construction_simplified_tax_declaration/housing_construction_simplified_tax_declaration.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Housing construction simplified tax declaration", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Housing construction simplified tax declaration', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Housing construction simplified tax declaration', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Housing construction simplified tax declaration', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/income_tax_return/income_tax_return.js b/taxes_az/taxes_az/doctype/income_tax_return/income_tax_return.js
index d4db8ea..5672556 100644
--- a/taxes_az/taxes_az/doctype/income_tax_return/income_tax_return.js
+++ b/taxes_az/taxes_az/doctype/income_tax_return/income_tax_return.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Income tax return", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Income tax return', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Income tax return', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Income tax return', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/income_tax_return_of_a_private_notary/income_tax_return_of_a_private_notary.js b/taxes_az/taxes_az/doctype/income_tax_return_of_a_private_notary/income_tax_return_of_a_private_notary.js
index dbfbef9..7d2f254 100644
--- a/taxes_az/taxes_az/doctype/income_tax_return_of_a_private_notary/income_tax_return_of_a_private_notary.js
+++ b/taxes_az/taxes_az/doctype/income_tax_return_of_a_private_notary/income_tax_return_of_a_private_notary.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Income tax return of a private notary", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Income tax return of a private notary', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Income tax return of a private notary', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Income tax return of a private notary', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js b/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js
index 91d51f4..4ddd4dd 100644
--- a/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js
+++ b/taxes_az/taxes_az/doctype/land_tax_declaration/land_tax_declaration.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Land tax declaration", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Land tax declaration', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Land tax declaration', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Land tax declaration', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/profit_tax_with_special_tax_regime/profit_tax_with_special_tax_regime.js b/taxes_az/taxes_az/doctype/profit_tax_with_special_tax_regime/profit_tax_with_special_tax_regime.js
index eb548e2..c5d010a 100644
--- a/taxes_az/taxes_az/doctype/profit_tax_with_special_tax_regime/profit_tax_with_special_tax_regime.js
+++ b/taxes_az/taxes_az/doctype/profit_tax_with_special_tax_regime/profit_tax_with_special_tax_regime.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Profit tax with special tax regime", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Profit tax with special tax regime', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Profit tax with special tax regime', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Profit tax with special tax regime', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.js b/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.js
index ae1f69d..bf79762 100644
--- a/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.js
+++ b/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Property tax return", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Property tax return', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Property tax return', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Property tax return', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/quarterly_report_on_unemployment_insurance/quarterly_report_on_unemployment_insurance.js b/taxes_az/taxes_az/doctype/quarterly_report_on_unemployment_insurance/quarterly_report_on_unemployment_insurance.js
index cb4621c..997d029 100644
--- a/taxes_az/taxes_az/doctype/quarterly_report_on_unemployment_insurance/quarterly_report_on_unemployment_insurance.js
+++ b/taxes_az/taxes_az/doctype/quarterly_report_on_unemployment_insurance/quarterly_report_on_unemployment_insurance.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Quarterly report on unemployment insurance", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Quarterly report on unemployment insurance', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Quarterly report on unemployment insurance', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Quarterly report on unemployment insurance', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/real_estate_simplified_tax_declaration/real_estate_simplified_tax_declaration.js b/taxes_az/taxes_az/doctype/real_estate_simplified_tax_declaration/real_estate_simplified_tax_declaration.js
index 056f0bb..e117897 100644
--- a/taxes_az/taxes_az/doctype/real_estate_simplified_tax_declaration/real_estate_simplified_tax_declaration.js
+++ b/taxes_az/taxes_az/doctype/real_estate_simplified_tax_declaration/real_estate_simplified_tax_declaration.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Real estate simplified tax declaration", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Real estate simplified tax declaration', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Real estate simplified tax declaration', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Real estate simplified tax declaration', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/reference_on_controlled_transactions/reference_on_controlled_transactions.js b/taxes_az/taxes_az/doctype/reference_on_controlled_transactions/reference_on_controlled_transactions.js
index 068ab0b..c106fd0 100644
--- a/taxes_az/taxes_az/doctype/reference_on_controlled_transactions/reference_on_controlled_transactions.js
+++ b/taxes_az/taxes_az/doctype/reference_on_controlled_transactions/reference_on_controlled_transactions.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("REFERENCE on controlled transactions", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('REFERENCE on controlled transactions', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'REFERENCE on controlled transactions', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'REFERENCE on controlled transactions', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/report_on_collection_of_state_duty/report_on_collection_of_state_duty.js b/taxes_az/taxes_az/doctype/report_on_collection_of_state_duty/report_on_collection_of_state_duty.js
index b806a95..d45c1fa 100644
--- a/taxes_az/taxes_az/doctype/report_on_collection_of_state_duty/report_on_collection_of_state_duty.js
+++ b/taxes_az/taxes_az/doctype/report_on_collection_of_state_duty/report_on_collection_of_state_duty.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Report on collection of state duty", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Report on collection of state duty', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Report on collection of state duty', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Report on collection of state duty', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/road_tax_2/road_tax_2.js b/taxes_az/taxes_az/doctype/road_tax_2/road_tax_2.js
index 7f526f8..1e3856b 100644
--- a/taxes_az/taxes_az/doctype/road_tax_2/road_tax_2.js
+++ b/taxes_az/taxes_az/doctype/road_tax_2/road_tax_2.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Road tax 2", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Road tax 2', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Road tax 2', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Road tax 2', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
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.js b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js
index 904cb8f..d5f7ebf 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.js
+++ b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Single declaration related to salaried and non-salaried work", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Single declaration related to salaried and non-salaried work', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Single declaration related to salaried and non-salaried work', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Single declaration related to salaried and non-salaried work', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/tax_return_withheld_at_source_of_payment/tax_return_withheld_at_source_of_payment.js b/taxes_az/taxes_az/doctype/tax_return_withheld_at_source_of_payment/tax_return_withheld_at_source_of_payment.js
index 7ab742e..5a601c2 100644
--- a/taxes_az/taxes_az/doctype/tax_return_withheld_at_source_of_payment/tax_return_withheld_at_source_of_payment.js
+++ b/taxes_az/taxes_az/doctype/tax_return_withheld_at_source_of_payment/tax_return_withheld_at_source_of_payment.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Tax return withheld at source of payment", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Tax return withheld at source of payment', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Tax return withheld at source of payment', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Tax return withheld at source of payment', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/vat_calculated_on_the_amount_paid_to_a_non_resident/vat_calculated_on_the_amount_paid_to_a_non_resident.js b/taxes_az/taxes_az/doctype/vat_calculated_on_the_amount_paid_to_a_non_resident/vat_calculated_on_the_amount_paid_to_a_non_resident.js
index a4fe757..11b4762 100644
--- a/taxes_az/taxes_az/doctype/vat_calculated_on_the_amount_paid_to_a_non_resident/vat_calculated_on_the_amount_paid_to_a_non_resident.js
+++ b/taxes_az/taxes_az/doctype/vat_calculated_on_the_amount_paid_to_a_non_resident/vat_calculated_on_the_amount_paid_to_a_non_resident.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("VAT calculated on the amount paid to a non-resident", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('VAT calculated on the amount paid to a non-resident', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'VAT calculated on the amount paid to a non-resident', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'VAT calculated on the amount paid to a non-resident', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/withholding_tax_return_of_foreign_subcontractors/withholding_tax_return_of_foreign_subcontractors.js b/taxes_az/taxes_az/doctype/withholding_tax_return_of_foreign_subcontractors/withholding_tax_return_of_foreign_subcontractors.js
index f97086a..97c47da 100644
--- a/taxes_az/taxes_az/doctype/withholding_tax_return_of_foreign_subcontractors/withholding_tax_return_of_foreign_subcontractors.js
+++ b/taxes_az/taxes_az/doctype/withholding_tax_return_of_foreign_subcontractors/withholding_tax_return_of_foreign_subcontractors.js
@@ -1,8 +1,33 @@
-// Copyright (c) 2025, Jey Soft and contributors
-// For license information, please see license.txt
-
-// frappe.ui.form.on("Withholding tax return of foreign subcontractors", {
-// refresh(frm) {
-
-// },
-// });
+// Код для экспорта XML
+frappe.ui.form.on('Withholding tax return of foreign subcontractors', {
+ refresh: function(frm) {
+ frm.add_custom_button(__('Export XML'), function() {
+ frappe.call({
+ method: 'taxes_az.taxes_az.doctype.xml_mapping_tool.xml_mapping_tool.generate_xml',
+ args: {
+ mapping_tool: 'Withholding tax return of foreign subcontractors', // Замените на имя вашего документа XML Mapping Tool
+ doctype: 'Withholding tax return of foreign subcontractors', // Замените на имя DocType
+ docname: frm.docname
+ },
+ callback: function(r) {
+ if (r.message) {
+ // Создаем временный элемент для скачивания
+ var element = document.createElement('a');
+ element.setAttribute('href', 'data:text/xml;charset=utf-8,' + encodeURIComponent(r.message));
+ element.setAttribute('download', frm.docname + '.xml');
+ element.style.display = 'none';
+ document.body.appendChild(element);
+ element.click();
+ document.body.removeChild(element);
+
+ frappe.show_alert({
+ message: __('XML file generated and downloaded'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ }, __('Actions'));
+ }
+ }
+);
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/xml_mapping_tool/__init__.py b/taxes_az/taxes_az/doctype/xml_mapping_tool/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/taxes_az/taxes_az/doctype/xml_mapping_tool/test_xml_mapping_tool.py b/taxes_az/taxes_az/doctype/xml_mapping_tool/test_xml_mapping_tool.py
new file mode 100644
index 0000000..2338429
--- /dev/null
+++ b/taxes_az/taxes_az/doctype/xml_mapping_tool/test_xml_mapping_tool.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2025, Jey Soft and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests import IntegrationTestCase, UnitTestCase
+
+
+# On IntegrationTestCase, the doctype test records and all
+# link-field test record depdendencies are recursively loaded
+# Use these module variables to add/remove to/from that list
+EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
+IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
+
+
+class UnitTestXMLMappingTool(UnitTestCase):
+ """
+ Unit tests for XMLMappingTool.
+ Use this class for testing individual functions and methods.
+ """
+
+ pass
+
+
+class IntegrationTestXMLMappingTool(IntegrationTestCase):
+ """
+ Integration tests for XMLMappingTool.
+ Use this class for testing interactions between multiple components.
+ """
+
+ pass
diff --git a/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.js b/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.js
new file mode 100644
index 0000000..cffa7c0
--- /dev/null
+++ b/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.js
@@ -0,0 +1,86 @@
+frappe.ui.form.on('XML Mapping Tool', {
+ refresh: function(frm) {
+ // Инициализация объектов
+ frm.xmlParser = new taxes_az.xml_mapping.XMLParser();
+ frm.fieldGenerator = new taxes_az.xml_mapping.FieldGenerator(frm);
+ frm.doctypeFieldSelector = new taxes_az.xml_mapping.DoctypeFieldSelector(frm);
+
+ // Добавление кнопки для парсинга XML
+ frm.add_custom_button(__('Parse XML'), function() {
+ const xmlContent = frm.doc.xml_sample_file;
+ if (!xmlContent) {
+ frappe.throw(__('Please enter XML content first'));
+ return;
+ }
+
+ // Парсинг XML и создание полей
+ const xmlStructure = frm.xmlParser.parseXML(xmlContent);
+ if (xmlStructure) {
+ // Сохраняем структуру в поле формы
+ frm.set_value('xml_structure', JSON.stringify(xmlStructure));
+
+ // Создаем UI для полей
+ frm.fieldGenerator.createFieldsUI(xmlStructure);
+
+ frappe.show_alert({
+ message: __('XML successfully parsed'),
+ indicator: 'green'
+ });
+ }
+ }).addClass('btn-primary');
+
+ // Если структура XML уже загружена и выбран целевой DocType,
+ // только тогда обновляем UI и только если секция еще не создана
+ if (frm.doc.xml_structure && frm.doc.target_doctype && !$('.xml-mapping-section').length) {
+ try {
+ const xmlStructure = JSON.parse(frm.doc.xml_structure);
+ frm.fieldGenerator.createFieldsUI(xmlStructure);
+ } catch (e) {
+ console.error('Error parsing XML structure:', e);
+ }
+ }
+
+ // Добавляем информационное сообщение о процессе использования
+ if (!frm.doc.__islocal) {
+ frm.set_intro(`
+
+
${__('How to use this tool:')}
+
+ - ${__('Paste your XML sample into the XML Content field')}
+ - ${__('Click "Parse XML" button')}
+ - ${__('Select a Target DocType')}
+ - ${__('Map XML fields to DocType fields using the dropdown selectors')}
+ - ${__('Save your mapping settings by clicking the Save button')}
+ - ${__('Use the client-side script in your target DocType to add the export button')}
+
+
+ `);
+ }
+
+ // Добавляем кнопку сохранения для явного сохранения маппинга
+ frm.add_custom_button(__('Save Mapping'), function() {
+ frm.save();
+ }).addClass('btn-primary');
+ },
+
+ target_doctype: function(frm) {
+ // При изменении целевого DocType, нам нужно обновить только выпадающие списки,
+ // но не пересоздавать всю секцию
+ if (frm.doc.xml_structure && frm.doc.target_doctype) {
+ try {
+ const xmlStructure = JSON.parse(frm.doc.xml_structure);
+
+ // Если секция уже существует, просто обновим выпадающие списки
+ if ($('.xml-mapping-section').length) {
+ const fieldSelector = new taxes_az.xml_mapping.DoctypeFieldSelector(frm);
+ fieldSelector.attachFieldSelectors($('.xml-fields-container'), xmlStructure.fieldPaths);
+ } else {
+ // Если секции еще нет, создаем полный UI
+ frm.fieldGenerator.createFieldsUI(xmlStructure);
+ }
+ } catch (e) {
+ console.error('Error parsing XML structure:', e);
+ }
+ }
+ }
+});
diff --git a/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.json b/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.json
new file mode 100644
index 0000000..2a66d22
--- /dev/null
+++ b/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.json
@@ -0,0 +1,74 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2025-04-18 18:47:47.135855",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "tittle",
+ "xml_sample_file",
+ "target_doctype",
+ "is_active",
+ "xml_structure",
+ "mapping_data"
+ ],
+ "fields": [
+ {
+ "fieldname": "tittle",
+ "fieldtype": "Data",
+ "label": "Tittle"
+ },
+ {
+ "fieldname": "xml_sample_file",
+ "fieldtype": "Text",
+ "ignore_xss_filter": 1,
+ "label": "XML Sample File"
+ },
+ {
+ "fieldname": "target_doctype",
+ "fieldtype": "Link",
+ "label": "Target Doctype",
+ "options": "DocType"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_active",
+ "fieldtype": "Check",
+ "label": "Is active"
+ },
+ {
+ "fieldname": "xml_structure",
+ "fieldtype": "Long Text",
+ "label": "Xml structure"
+ },
+ {
+ "fieldname": "mapping_data",
+ "fieldtype": "JSON",
+ "label": "Mapping data"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2025-04-22 12:58:25.456299",
+ "modified_by": "Administrator",
+ "module": "Taxes Az",
+ "name": "XML Mapping Tool",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.py b/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.py
new file mode 100644
index 0000000..3189bda
--- /dev/null
+++ b/taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.py
@@ -0,0 +1,124 @@
+# taxes_az/taxes_az/doctype/xml_mapping_tool/xml_mapping_tool.py
+
+import frappe
+import json
+from frappe.model.document import Document
+from frappe import _
+from xml.etree import ElementTree as ET
+
+class XMLMappingTool(Document):
+ pass
+
+@frappe.whitelist()
+def generate_xml(mapping_tool, doctype, docname):
+ try:
+ # Получаем документ с правилами маппинга
+ mapping = frappe.get_doc("XML Mapping Tool", mapping_tool)
+
+ # Проверяем наличие необходимых данных
+ if not mapping.xml_sample_file or not mapping.mapping_data:
+ frappe.throw(_("Mapping tool doesn't have sample XML or mapping data"))
+
+ # Получаем данные документа
+ doc_data = frappe.get_doc(doctype, docname)
+
+ # Применяем маппинг для создания XML
+ try:
+ root = ET.fromstring(mapping.xml_sample_file)
+ except Exception as e:
+ frappe.throw(_("Error parsing XML template: {0}").format(str(e)))
+
+ # Загружаем правила маппинга
+ mapping_rules = json.loads(mapping.mapping_data)
+
+ # Применяем правила маппинга
+ for xml_path, field_name in mapping_rules.items():
+ if not field_name:
+ continue
+
+ try:
+ # Получаем значение поля из документа
+ field_value = doc_data.get(field_name)
+
+ # Обрабатываем путь XML
+ if '@' in xml_path: # Это атрибут
+ element_path, attr_name = xml_path.rsplit('@', 1)
+ element_path = element_path.rstrip('/')
+
+ # Находим элемент по пути
+ element = _find_element_by_path(root, element_path)
+ if element is not None:
+ element.set(attr_name, str(field_value) if field_value is not None else '')
+ else: # Это обычный элемент
+ # Находим элемент по пути
+ element = _find_element_by_path(root, xml_path)
+ if element is not None:
+ element.text = str(field_value) if field_value is not None else ''
+ except Exception as e:
+ frappe.log_error(_("Error setting value for {0}: {1}").format(xml_path, str(e)))
+
+ # Конвертируем обратно в строку
+ xml_string = ET.tostring(root, encoding='utf-8', method='xml').decode('utf-8')
+
+ # Добавляем XML декларацию
+ xml_declaration = '\n'
+ xml_string = xml_declaration + xml_string
+
+ return xml_string
+ except Exception as e:
+ frappe.log_error(_("Error generating XML: {0}").format(str(e)))
+ frappe.throw(_("Error generating XML: {0}").format(str(e)))
+
+def _find_element_by_path(root, path):
+ """
+ Находит элемент по пути XPath в XML дереве.
+ Эта функция нужна, поскольку простой root.find() не всегда правильно работает
+ с вложенными путями.
+ """
+ if not path:
+ return None
+
+ # Удаляем имя корневого элемента из пути, если оно там есть
+ if path.startswith(root.tag + '/'):
+ path = path[len(root.tag) + 1:]
+
+ # Разбиваем путь на компоненты
+ components = path.split('/')
+
+ # Начинаем с корневого элемента
+ current_element = root
+
+ # Проходим по каждому компоненту пути
+ for i, component in enumerate(components):
+ if not component: # Пропускаем пустые компоненты
+ continue
+
+ if component == current_element.tag:
+ # Если текущий компонент соответствует тегу элемента, просто продолжаем
+ continue
+
+ # Для путей с множественными элементами (например, row в HesaplamaUzreEnt)
+ # мы должны найти все подходящие элементы и выбрать нужный
+ # Для простоты, возьмем первый найденный
+ found = False
+ for child in current_element.findall('./'):
+ if child.tag == component:
+ current_element = child
+ found = True
+ break
+
+ if not found:
+ # Пробуем найти через XPath напрямую
+ try:
+ result = current_element.find('.//' + component)
+ if result is not None:
+ current_element = result
+ found = True
+ except:
+ pass
+
+ if not found:
+ # Если элемент не найден, возвращаем None
+ return None
+
+ return current_element
\ No newline at end of file