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 = $('
' + __('XML Fields Mapping') + '
'); + 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:')}

+
    +
  1. ${__('Paste your XML sample into the XML Content field')}
  2. +
  3. ${__('Click "Parse XML" button')}
  4. +
  5. ${__('Select a Target DocType')}
  6. +
  7. ${__('Map XML fields to DocType fields using the dropdown selectors')}
  8. +
  9. ${__('Save your mapping settings by clicking the Save button')}
  10. +
  11. ${__('Use the client-side script in your target DocType to add the export button')}
  12. +
+
+ `); + } + + // Добавляем кнопку сохранения для явного сохранения маппинга + 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