From d5a9a7b14b5a0e999b4f9172d13a4fe99567d76e Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Mon, 23 Feb 2026 22:20:55 +0400 Subject: [PATCH] opening entryies has been added to vat allocation --- .../doctype/vat_allocation/vat_allocation.js | 393 +++++++++++++++--- .../vat_allocation/vat_allocation.json | 14 +- .../doctype/vat_allocation/vat_allocation.py | 187 +++++++-- .../vat_allocation_opening_entry.json | 68 +++ .../vat_allocation_opening_entry.py | 9 + 5 files changed, 577 insertions(+), 94 deletions(-) create mode 100644 taxes_az/taxes_az/doctype/vat_allocation_opening_entry/vat_allocation_opening_entry.json create mode 100644 taxes_az/taxes_az/doctype/vat_allocation_opening_entry/vat_allocation_opening_entry.py diff --git a/taxes_az/taxes_az/doctype/vat_allocation/vat_allocation.js b/taxes_az/taxes_az/doctype/vat_allocation/vat_allocation.js index 92223b0..d197555 100644 --- a/taxes_az/taxes_az/doctype/vat_allocation/vat_allocation.js +++ b/taxes_az/taxes_az/doctype/vat_allocation/vat_allocation.js @@ -10,6 +10,11 @@ frappe.ui.form.on('VAT allocation', { frm.add_custom_button(__('Fill Sales Invoice Items'), function() { show_sales_invoice_filters(frm); }); + + // Add button for filling Opening Entries + frm.add_custom_button(__('Fill Opening Entries'), function() { + show_opening_entry_filters(frm); + }); } // Setup filter for Journal Entry @@ -302,6 +307,108 @@ function load_previous_months_items(frm, filters) { }); } +// Function to show filter dialog for Opening Entries +function show_opening_entry_filters(frm) { + if (!frm.doc.year || !frm.doc.month) { + frappe.msgprint(__('Please select Year and Month first')); + return; + } + + let dialog = new frappe.ui.Dialog({ + title: __('Opening Entry Filters'), + fields: [ + { + fieldname: 'customers_section', + fieldtype: 'Section Break', + label: __('Select Customers (Optional)') + }, + { + fieldname: 'customers', + fieldtype: 'Table', + label: __('Customers'), + description: __('Leave empty to get all customers'), + fields: [ + { + fieldname: 'customer', + fieldtype: 'Link', + label: __('Customer'), + options: 'Customer', + in_list_view: 1 + } + ] + }, + { + fieldname: 'amount_section', + fieldtype: 'Section Break', + label: __('Amount Range (Optional)') + }, + { + fieldname: 'min_amount', + fieldtype: 'Currency', + label: __('Minimum Amount'), + description: __('Only grouped amounts >= this amount') + }, + { + fieldname: 'column_break_1', + fieldtype: 'Column Break' + }, + { + fieldname: 'max_amount', + fieldtype: 'Currency', + label: __('Maximum Amount'), + description: __('Only grouped amounts <= this amount') + } + ], + primary_action_label: __('Fill Table'), + primary_action: function(values) { + fill_opening_entries(frm, values); + dialog.hide(); + } + }); + + dialog.show(); + + setTimeout(function() { + dialog.$wrapper.find('.frappe-control[data-fieldname="customers"] .grid-scroll-bar').css({ + 'visibility': 'hidden', + 'height': '0px' + }); + }, 100); +} + +// Function to fill Opening Entries table +function fill_opening_entries(frm, filters) { + frappe.call({ + method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_opening_entries', + args: { + year: frm.doc.year, + month: frm.doc.month, + customers: filters.customers ? JSON.stringify(filters.customers) : null, + min_amount: filters.min_amount || null, + max_amount: filters.max_amount || null + }, + callback: function(r) { + frm.clear_table('opening_entry_table'); + + if (r.message && r.message.length > 0) { + r.message.forEach(function(item) { + let row = frm.add_child('opening_entry_table'); + row.customer = item.customer; + row.amount = item.amount; + row.unallocated_amount = item.amount; + row.allocated_amount = 0; + }); + + frm.refresh_field('opening_entry_table'); + frappe.msgprint(__('Opening Entries loaded successfully: {0} records', [r.message.length])); + } else { + frm.refresh_field('opening_entry_table'); + frappe.msgprint(__('No Opening Entries found for selected period')); + } + } + }); +} + // Setup query filter for Journal Entry function setup_journal_entry_query(frm) { frm.fields_dict.payment_entry_table.grid.get_field('vat_journal_entry').get_query = function(doc, cdt, cdn) { @@ -349,8 +456,9 @@ frappe.ui.form.on('VAT allocation payment entry', { frm.refresh_field('payment_entry_table'); frm.refresh_field('sales_invoice_table'); frm.refresh_field('sales_invoice_previous_table'); + frm.refresh_field('opening_entry_table'); }, - + // При изменении Payment Entry - обновить суммы payment_entry: function(frm, cdt, cdn) { let row = locals[cdt][cdn]; @@ -376,10 +484,11 @@ frappe.ui.form.on('VAT allocation payment entry', { frm.refresh_field('payment_entry_table'); frm.refresh_field('sales_invoice_table'); frm.refresh_field('sales_invoice_previous_table'); - + frm.refresh_field('opening_entry_table'); + return; } - + // Получаем данные из Payment Entry frappe.call({ method: 'frappe.client.get_value', @@ -437,11 +546,12 @@ frappe.ui.form.on('VAT allocation payment entry', { frm.refresh_field('payment_entry_table'); frm.refresh_field('sales_invoice_table'); frm.refresh_field('sales_invoice_previous_table'); + frm.refresh_field('opening_entry_table'); } } }); }, - + // При удалении строки - удалить связанные links payment_entry_table_remove: function(frm, cdt, cdn) { // Собираем список всех существующих row names из текущей таблицы @@ -462,6 +572,7 @@ frappe.ui.form.on('VAT allocation payment entry', { frm.refresh_field('payment_entry_table'); frm.refresh_field('sales_invoice_table'); frm.refresh_field('sales_invoice_previous_table'); + frm.refresh_field('opening_entry_table'); }, vat_journal_entry: function(frm, cdt, cdn) { @@ -647,19 +758,45 @@ function show_allocation_dialog(frm, payment_row_idx, customer) { } } + // Opening entry items + let opening_entry_items = []; + for (let item of frm.doc.opening_entry_table || []) { + if (item.customer !== customer) { + continue; + } + + let current_allocation = 0; + for (let link of frm.doc.allocation_links || []) { + if (link.payment_entry_row === payment_row.name && + link.sales_invoice_row === item.name) { + current_allocation = link.allocated_amount || 0; + break; + } + } + + opening_entry_items.push({ + name: item.name, + amount: item.amount || 0, + unallocated_amount: item.unallocated_amount || 0, + allocated_amount: item.allocated_amount || 0, + current_allocation: current_allocation + }); + } + // Check if there are items to allocate to - if (vat_free_items.length === 0 && vat_items.length === 0 && - vat_free_items_previous.length === 0 && vat_items_previous.length === 0) { + if (vat_free_items.length === 0 && vat_items.length === 0 && + vat_free_items_previous.length === 0 && vat_items_previous.length === 0 && + opening_entry_items.length === 0) { frappe.msgprint(__('No sales invoice items available for this customer')); return; } - + // Вычисляем available amounts из текущих данных формы let vat_free_amount = payment_row.vat_free_amount || 0; let vat_free_allocated = payment_row.vat_free_allocated || 0; let vat_allocated_amount = payment_row.vat_allocated_amount || 0; let vat_allocated_allocated = payment_row.vat_allocated_allocated || 0; - + let data = { payment_row: payment_row, vat_free_available: vat_free_amount - vat_free_allocated, @@ -667,9 +804,10 @@ function show_allocation_dialog(frm, payment_row_idx, customer) { vat_free_items: vat_free_items, vat_items: vat_items, vat_free_items_previous: vat_free_items_previous, - vat_items_previous: vat_items_previous + vat_items_previous: vat_items_previous, + opening_entry_items: opening_entry_items }; - + // Create allocation dialog create_allocation_dialog(frm, payment_row_idx, data); } @@ -677,7 +815,8 @@ function show_allocation_dialog(frm, payment_row_idx, customer) { function create_allocation_dialog(frm, payment_row_idx, data) { let allocation_data_current = {}; let allocation_data_previous = {}; - + let allocation_data_opening = {}; + let dialog = new frappe.ui.Dialog({ title: __('Allocate Amount'), size: 'extra-large', @@ -725,32 +864,37 @@ function create_allocation_dialog(frm, payment_row_idx, data) { ], primary_action_label: __('Save Allocation'), primary_action: function() { - save_allocation_data(frm, payment_row_idx, allocation_data_current, allocation_data_previous, dialog); + save_allocation_data(frm, payment_row_idx, allocation_data_current, allocation_data_previous, allocation_data_opening, dialog); }, secondary_action_label: __('Auto Allocate'), secondary_action: function() { // Determine which tab is active let active_tab = dialog.$wrapper.find('.nav-tabs .nav-link.active').data('tab'); - + // Calculate remaining available amounts let available_amounts = calculate_available_amounts( - data, - allocation_data_current, - allocation_data_previous + data, + allocation_data_current, + allocation_data_previous, + allocation_data_opening ); - + if (active_tab === 'current') { - auto_allocate(frm, payment_row_idx, data, data.vat_free_items, data.vat_items, - allocation_data_current, dialog, 'current', available_amounts, + auto_allocate(frm, payment_row_idx, data, data.vat_free_items, data.vat_items, + allocation_data_current, dialog, 'current', available_amounts, allocation_data_previous); + } else if (active_tab === 'opening') { + auto_allocate(frm, payment_row_idx, data, data.opening_entry_items, [], + allocation_data_opening, dialog, 'opening', available_amounts, + allocation_data_current); } else { - auto_allocate(frm, payment_row_idx, data, data.vat_free_items_previous, data.vat_items_previous, + auto_allocate(frm, payment_row_idx, data, data.vat_free_items_previous, data.vat_items_previous, allocation_data_previous, dialog, 'previous', available_amounts, allocation_data_current); } } }); - + // Build payment info HTML let info_html = `
@@ -767,11 +911,12 @@ function create_allocation_dialog(frm, payment_row_idx, data) {
`; dialog.fields_dict.payment_info_html.$wrapper.html(info_html); - + // Build tabs HTML with Bootstrap let html_current = build_allocation_html(data.vat_free_items, data.vat_items, allocation_data_current, 'current'); let html_previous = build_allocation_html(data.vat_free_items_previous, data.vat_items_previous, allocation_data_previous, 'previous'); - + let html_opening = build_allocation_html(data.opening_entry_items, [], allocation_data_opening, 'opening'); + let tabs_html = `