added previous monthes to vat allocation
This commit is contained in:
parent
d61275ca85
commit
6321a10b7c
|
|
@ -14,6 +14,10 @@ frappe.ui.form.on('VAT allocation', {
|
||||||
|
|
||||||
// Setup filter for Journal Entry
|
// Setup filter for Journal Entry
|
||||||
setup_journal_entry_query(frm);
|
setup_journal_entry_query(frm);
|
||||||
|
|
||||||
|
// Setup filter for Payment Entry
|
||||||
|
setup_payment_entry_query(frm);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -161,11 +165,11 @@ function show_sales_invoice_filters(frm) {
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to fill Payment Entries with filters
|
// Function to fill Payment Entries with filters - UPDATED to include previous months
|
||||||
function fill_payment_entries(frm, filters) {
|
function fill_payment_entries(frm, filters) {
|
||||||
// Call server method
|
// Call server method to get both current and previous payment entries
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_payment_entries',
|
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_payment_entries_with_previous',
|
||||||
args: {
|
args: {
|
||||||
year: frm.doc.year,
|
year: frm.doc.year,
|
||||||
month: frm.doc.month,
|
month: frm.doc.month,
|
||||||
|
|
@ -184,8 +188,14 @@ function fill_payment_entries(frm, filters) {
|
||||||
row.customer = payment.customer;
|
row.customer = payment.customer;
|
||||||
row.payment_entry = payment.payment_entry;
|
row.payment_entry = payment.payment_entry;
|
||||||
row.payment_entry_amount = payment.payment_entry_amount;
|
row.payment_entry_amount = payment.payment_entry_amount;
|
||||||
row.vat_free_amount = payment.payment_entry_amount; // Default: all amount is VAT free
|
row.vat_journal_entry = payment.vat_journal_entry || '';
|
||||||
row.unallocated_amount = payment.payment_entry_amount;
|
row.vat_amount = payment.vat_amount || 0;
|
||||||
|
row.vat_allocated_amount = payment.vat_allocated_amount || 0;
|
||||||
|
row.vat_free_amount = payment.vat_free_amount || payment.payment_entry_amount;
|
||||||
|
row.unallocated_amount = payment.unallocated_amount || 0;
|
||||||
|
row.allocated_amount = payment.allocated_amount || 0;
|
||||||
|
row.vat_allocated_allocated = payment.vat_allocated_allocated || 0;
|
||||||
|
row.vat_free_allocated = payment.vat_free_allocated || 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.refresh_field('payment_entry_table');
|
frm.refresh_field('payment_entry_table');
|
||||||
|
|
@ -197,9 +207,22 @@ function fill_payment_entries(frm, filters) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to fill Sales Invoice Items with filters
|
// Setup query filter for Payment Entry - UPDATED
|
||||||
|
function setup_payment_entry_query(frm) {
|
||||||
|
frm.fields_dict.payment_entry_table.grid.get_field('payment_entry').get_query = function(doc, cdt, cdn) {
|
||||||
|
return {
|
||||||
|
query: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_payment_entry_query',
|
||||||
|
filters: {
|
||||||
|
year: doc.year,
|
||||||
|
month: doc.month
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to fill Sales Invoice Items with filters - UPDATED to fill both tables
|
||||||
function fill_sales_invoice_items(frm, filters) {
|
function fill_sales_invoice_items(frm, filters) {
|
||||||
// Call server method
|
// Call both server methods - current month and previous months
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_sales_invoice_items',
|
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_sales_invoice_items',
|
||||||
args: {
|
args: {
|
||||||
|
|
@ -229,6 +252,52 @@ function fill_sales_invoice_items(frm, filters) {
|
||||||
} else {
|
} else {
|
||||||
frappe.msgprint(__('No Sales Invoice Items found for selected period'));
|
frappe.msgprint(__('No Sales Invoice Items found for selected period'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now load previous months items
|
||||||
|
load_previous_months_items(frm, filters);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to load previous months items
|
||||||
|
function load_previous_months_items(frm, filters) {
|
||||||
|
frappe.call({
|
||||||
|
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.get_sales_invoice_items_previous_months',
|
||||||
|
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) {
|
||||||
|
// Clear existing table
|
||||||
|
frm.clear_table('sales_invoice_previous_table');
|
||||||
|
|
||||||
|
if (r.message && r.message.length > 0) {
|
||||||
|
// Add new rows
|
||||||
|
r.message.forEach(function(item) {
|
||||||
|
let row = frm.add_child('sales_invoice_previous_table');
|
||||||
|
row.customer = item.customer;
|
||||||
|
row.item_tax_template = item.item_tax_template;
|
||||||
|
row.tax_article = item.tax_article;
|
||||||
|
row.amount = item.amount;
|
||||||
|
row.unallocated_amount = item.unallocated_amount;
|
||||||
|
row.allocated_amount = item.allocated_amount;
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('Previous months items loaded: {0} records', [r.message.length]),
|
||||||
|
indicator: 'blue'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __('No unpaid items from previous months'),
|
||||||
|
indicator: 'blue'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -279,6 +348,7 @@ frappe.ui.form.on('VAT allocation payment entry', {
|
||||||
recalculate_totals_manually(frm);
|
recalculate_totals_manually(frm);
|
||||||
frm.refresh_field('payment_entry_table');
|
frm.refresh_field('payment_entry_table');
|
||||||
frm.refresh_field('sales_invoice_table');
|
frm.refresh_field('sales_invoice_table');
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
},
|
},
|
||||||
|
|
||||||
// При изменении Payment Entry - обновить суммы
|
// При изменении Payment Entry - обновить суммы
|
||||||
|
|
@ -305,6 +375,7 @@ frappe.ui.form.on('VAT allocation payment entry', {
|
||||||
recalculate_totals_manually(frm);
|
recalculate_totals_manually(frm);
|
||||||
frm.refresh_field('payment_entry_table');
|
frm.refresh_field('payment_entry_table');
|
||||||
frm.refresh_field('sales_invoice_table');
|
frm.refresh_field('sales_invoice_table');
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -365,6 +436,7 @@ frappe.ui.form.on('VAT allocation payment entry', {
|
||||||
recalculate_totals_manually(frm);
|
recalculate_totals_manually(frm);
|
||||||
frm.refresh_field('payment_entry_table');
|
frm.refresh_field('payment_entry_table');
|
||||||
frm.refresh_field('sales_invoice_table');
|
frm.refresh_field('sales_invoice_table');
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -389,6 +461,7 @@ frappe.ui.form.on('VAT allocation payment entry', {
|
||||||
recalculate_totals_manually(frm);
|
recalculate_totals_manually(frm);
|
||||||
frm.refresh_field('payment_entry_table');
|
frm.refresh_field('payment_entry_table');
|
||||||
frm.refresh_field('sales_invoice_table');
|
frm.refresh_field('sales_invoice_table');
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
},
|
},
|
||||||
|
|
||||||
vat_journal_entry: function(frm, cdt, cdn) {
|
vat_journal_entry: function(frm, cdt, cdn) {
|
||||||
|
|
@ -501,7 +574,10 @@ function show_allocation_dialog(frm, payment_row_idx, customer) {
|
||||||
// Получаем sales invoice items для этого клиента из формы
|
// Получаем sales invoice items для этого клиента из формы
|
||||||
let vat_free_items = [];
|
let vat_free_items = [];
|
||||||
let vat_items = [];
|
let vat_items = [];
|
||||||
|
let vat_free_items_previous = [];
|
||||||
|
let vat_items_previous = [];
|
||||||
|
|
||||||
|
// Current month items
|
||||||
for (let item of frm.doc.sales_invoice_table || []) {
|
for (let item of frm.doc.sales_invoice_table || []) {
|
||||||
if (item.customer !== customer) {
|
if (item.customer !== customer) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -529,7 +605,6 @@ function show_allocation_dialog(frm, payment_row_idx, customer) {
|
||||||
|
|
||||||
let template = (item.item_tax_template || '').toLowerCase();
|
let template = (item.item_tax_template || '').toLowerCase();
|
||||||
|
|
||||||
// ИСПРАВЛЕНО: используем .includes() вместо 'in'
|
|
||||||
if (template.includes('ədv 0%') || template.includes('ədv-dən azadolma')) {
|
if (template.includes('ədv 0%') || template.includes('ədv-dən azadolma')) {
|
||||||
vat_free_items.push(item_data);
|
vat_free_items.push(item_data);
|
||||||
} else if (template.includes('ədv 18%') || template.includes('ədv daxil 18%')) {
|
} else if (template.includes('ədv 18%') || template.includes('ədv daxil 18%')) {
|
||||||
|
|
@ -537,8 +612,44 @@ function show_allocation_dialog(frm, payment_row_idx, customer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Previous months items
|
||||||
|
for (let item of frm.doc.sales_invoice_previous_table || []) {
|
||||||
|
if (item.customer !== customer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем существующие аллокации для этого item от текущего payment row
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let item_data = {
|
||||||
|
name: item.name,
|
||||||
|
item_tax_template: item.item_tax_template || '',
|
||||||
|
tax_article: item.tax_article || '',
|
||||||
|
amount: item.amount || 0,
|
||||||
|
unallocated_amount: item.unallocated_amount || 0,
|
||||||
|
allocated_amount: item.allocated_amount || 0,
|
||||||
|
current_allocation: current_allocation
|
||||||
|
};
|
||||||
|
|
||||||
|
let template = (item.item_tax_template || '').toLowerCase();
|
||||||
|
|
||||||
|
if (template.includes('ədv 0%') || template.includes('ədv-dən azadolma')) {
|
||||||
|
vat_free_items_previous.push(item_data);
|
||||||
|
} else if (template.includes('ədv 18%') || template.includes('ədv daxil 18%')) {
|
||||||
|
vat_items_previous.push(item_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there are items to allocate to
|
// Check if there are items to allocate to
|
||||||
if (vat_free_items.length === 0 && vat_items.length === 0) {
|
if (vat_free_items.length === 0 && vat_items.length === 0 &&
|
||||||
|
vat_free_items_previous.length === 0 && vat_items_previous.length === 0) {
|
||||||
frappe.msgprint(__('No sales invoice items available for this customer'));
|
frappe.msgprint(__('No sales invoice items available for this customer'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -554,19 +665,22 @@ function show_allocation_dialog(frm, payment_row_idx, customer) {
|
||||||
vat_free_available: vat_free_amount - vat_free_allocated,
|
vat_free_available: vat_free_amount - vat_free_allocated,
|
||||||
vat_allocated_available: vat_allocated_amount - vat_allocated_allocated,
|
vat_allocated_available: vat_allocated_amount - vat_allocated_allocated,
|
||||||
vat_free_items: vat_free_items,
|
vat_free_items: vat_free_items,
|
||||||
vat_items: vat_items
|
vat_items: vat_items,
|
||||||
|
vat_free_items_previous: vat_free_items_previous,
|
||||||
|
vat_items_previous: vat_items_previous
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create allocation dialog
|
// Create allocation dialog
|
||||||
create_allocation_dialog(frm, payment_row_idx, data, vat_free_items, vat_items);
|
create_allocation_dialog(frm, payment_row_idx, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_allocation_dialog(frm, payment_row_idx, data, vat_free_items, vat_items) {
|
function create_allocation_dialog(frm, payment_row_idx, data) {
|
||||||
let allocation_data = {};
|
let allocation_data_current = {};
|
||||||
|
let allocation_data_previous = {};
|
||||||
|
|
||||||
let dialog = new frappe.ui.Dialog({
|
let dialog = new frappe.ui.Dialog({
|
||||||
title: __('Allocate Amount'),
|
title: __('Allocate Amount'),
|
||||||
size: 'large',
|
size: 'extra-large',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
fieldname: 'info_section',
|
fieldname: 'info_section',
|
||||||
|
|
@ -601,22 +715,39 @@ function create_allocation_dialog(frm, payment_row_idx, data, vat_free_items, va
|
||||||
default: data.vat_allocated_available
|
default: data.vat_allocated_available
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'items_section',
|
fieldname: 'tabs_section',
|
||||||
fieldtype: 'Section Break',
|
fieldtype: 'Section Break'
|
||||||
label: __('Sales Invoice Items - Edit Allocations')
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'allocation_html',
|
fieldname: 'tabs_html',
|
||||||
fieldtype: 'HTML'
|
fieldtype: 'HTML'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
primary_action_label: __('Save Allocation'),
|
primary_action_label: __('Save Allocation'),
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
save_allocation_data(frm, payment_row_idx, allocation_data, dialog);
|
save_allocation_data(frm, payment_row_idx, allocation_data_current, allocation_data_previous, dialog);
|
||||||
},
|
},
|
||||||
secondary_action_label: __('Auto Allocate'),
|
secondary_action_label: __('Auto Allocate'),
|
||||||
secondary_action: function() {
|
secondary_action: function() {
|
||||||
auto_allocate(frm, payment_row_idx, data, vat_free_items, vat_items, allocation_data, dialog);
|
// 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
|
||||||
|
);
|
||||||
|
|
||||||
|
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,
|
||||||
|
allocation_data_previous);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -637,17 +768,121 @@ function create_allocation_dialog(frm, payment_row_idx, data, vat_free_items, va
|
||||||
`;
|
`;
|
||||||
dialog.fields_dict.payment_info_html.$wrapper.html(info_html);
|
dialog.fields_dict.payment_info_html.$wrapper.html(info_html);
|
||||||
|
|
||||||
// Build allocation HTML
|
// Build tabs HTML with Bootstrap
|
||||||
let html = build_allocation_html(vat_free_items, vat_items, allocation_data);
|
let html_current = build_allocation_html(data.vat_free_items, data.vat_items, allocation_data_current, 'current');
|
||||||
dialog.fields_dict.allocation_html.$wrapper.html(html);
|
let html_previous = build_allocation_html(data.vat_free_items_previous, data.vat_items_previous, allocation_data_previous, 'previous');
|
||||||
|
|
||||||
// Setup input handlers
|
let tabs_html = `
|
||||||
setup_allocation_inputs(dialog, allocation_data, data.vat_free_available, data.vat_allocated_available);
|
<style>
|
||||||
|
.allocation-tabs .nav-link {
|
||||||
|
color: #6c757d;
|
||||||
|
font-weight: 400;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 3px solid transparent;
|
||||||
|
padding: 10px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.allocation-tabs .nav-link:hover {
|
||||||
|
color: #495057;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-bottom-color: #dee2e6;
|
||||||
|
}
|
||||||
|
.allocation-tabs .nav-link.active {
|
||||||
|
color: #1f272e;
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom-color: #2490ef;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.allocation-tabs .nav-tabs {
|
||||||
|
border-bottom: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<ul class="nav nav-tabs allocation-tabs" role="tablist" style="margin-bottom: 15px;">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" id="tab-link-current" data-tab="current" href="#tab-current" role="tab">
|
||||||
|
${__('Current Month')}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" id="tab-link-previous" data-tab="previous" href="#tab-previous" role="tab">
|
||||||
|
${__('Previous Months')}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane fade show active" id="tab-current" role="tabpanel">
|
||||||
|
${html_current}
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade" id="tab-previous" role="tabpanel">
|
||||||
|
${html_previous}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
dialog.fields_dict.tabs_html.$wrapper.html(tabs_html);
|
||||||
|
|
||||||
|
// Setup custom tab switching (without Bootstrap's data-toggle)
|
||||||
|
dialog.$wrapper.find('.nav-link').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
let $this = $(this);
|
||||||
|
let target = $this.attr('href');
|
||||||
|
|
||||||
|
// Update nav links
|
||||||
|
dialog.$wrapper.find('.nav-link').removeClass('active');
|
||||||
|
$this.addClass('active');
|
||||||
|
|
||||||
|
// Update tab panes
|
||||||
|
dialog.$wrapper.find('.tab-pane').removeClass('show active');
|
||||||
|
dialog.$wrapper.find(target).addClass('show active');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup input handlers for both tabs
|
||||||
|
setup_allocation_inputs(dialog, allocation_data_current, data.vat_free_available, data.vat_allocated_available, 'current');
|
||||||
|
setup_allocation_inputs(dialog, allocation_data_previous, data.vat_free_available, data.vat_allocated_available, 'previous');
|
||||||
|
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_allocation_html(vat_free_items, vat_items, allocation_data) {
|
function calculate_available_amounts(data, allocation_data_current, allocation_data_previous) {
|
||||||
|
let total_vat_free_current = 0;
|
||||||
|
let total_vat_allocated_current = 0;
|
||||||
|
let total_vat_free_previous = 0;
|
||||||
|
let total_vat_allocated_previous = 0;
|
||||||
|
|
||||||
|
// Calculate totals from current month
|
||||||
|
for (let name in allocation_data_current) {
|
||||||
|
let alloc = allocation_data_current[name];
|
||||||
|
if (alloc.type === 'vat_free') {
|
||||||
|
total_vat_free_current += alloc.value || 0;
|
||||||
|
} else {
|
||||||
|
total_vat_allocated_current += alloc.value || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate totals from previous months
|
||||||
|
for (let name in allocation_data_previous) {
|
||||||
|
let alloc = allocation_data_previous[name];
|
||||||
|
if (alloc.type === 'vat_free') {
|
||||||
|
total_vat_free_previous += alloc.value || 0;
|
||||||
|
} else {
|
||||||
|
total_vat_allocated_previous += alloc.value || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate remaining available
|
||||||
|
let vat_free_available = data.vat_free_available - total_vat_free_current - total_vat_free_previous;
|
||||||
|
let vat_allocated_available = data.vat_allocated_available - total_vat_allocated_current - total_vat_allocated_previous;
|
||||||
|
|
||||||
|
return {
|
||||||
|
vat_free_available: Math.max(0, vat_free_available),
|
||||||
|
vat_allocated_available: Math.max(0, vat_allocated_available)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_allocation_html(vat_free_items, vat_items, allocation_data, tab_type) {
|
||||||
let html = '<div class="allocation-container" style="max-height: 400px; overflow-y: auto;">';
|
let html = '<div class="allocation-container" style="max-height: 400px; overflow-y: auto;">';
|
||||||
|
|
||||||
// VAT Free items section
|
// VAT Free items section
|
||||||
|
|
@ -671,7 +906,7 @@ function build_allocation_html(vat_free_items, vat_items, allocation_data) {
|
||||||
html += '<td>' + format_currency(item.amount) + '</td>';
|
html += '<td>' + format_currency(item.amount) + '</td>';
|
||||||
html += '<td>' + format_currency(item.unallocated_amount) + '</td>';
|
html += '<td>' + format_currency(item.unallocated_amount) + '</td>';
|
||||||
html += '<td style="background-color: #fff3cd;">' + format_currency(item.current_allocation || 0) + '</td>';
|
html += '<td style="background-color: #fff3cd;">' + format_currency(item.current_allocation || 0) + '</td>';
|
||||||
html += '<td><input type="number" class="form-control allocation-input" data-name="' + item.name + '" data-type="vat_free" data-max="' + (item.unallocated_amount + (item.current_allocation || 0)) + '" value="' + (item.current_allocation || 0) + '" min="0" step="0.01"></td>';
|
html += '<td><input type="number" class="form-control allocation-input-' + tab_type + '" data-name="' + item.name + '" data-type="vat_free" data-max="' + (item.unallocated_amount + (item.current_allocation || 0)) + '" value="' + (item.current_allocation || 0) + '" min="0" step="0.01"></td>';
|
||||||
html += '</tr>';
|
html += '</tr>';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -699,7 +934,7 @@ function build_allocation_html(vat_free_items, vat_items, allocation_data) {
|
||||||
html += '<td>' + format_currency(item.amount) + '</td>';
|
html += '<td>' + format_currency(item.amount) + '</td>';
|
||||||
html += '<td>' + format_currency(item.unallocated_amount) + '</td>';
|
html += '<td>' + format_currency(item.unallocated_amount) + '</td>';
|
||||||
html += '<td style="background-color: #fff3cd;">' + format_currency(item.current_allocation || 0) + '</td>';
|
html += '<td style="background-color: #fff3cd;">' + format_currency(item.current_allocation || 0) + '</td>';
|
||||||
html += '<td><input type="number" class="form-control allocation-input" data-name="' + item.name + '" data-type="vat_allocated" data-max="' + (item.unallocated_amount + (item.current_allocation || 0)) + '" value="' + (item.current_allocation || 0) + '" min="0" step="0.01"></td>';
|
html += '<td><input type="number" class="form-control allocation-input-' + tab_type + '" data-name="' + item.name + '" data-type="vat_allocated" data-max="' + (item.unallocated_amount + (item.current_allocation || 0)) + '" value="' + (item.current_allocation || 0) + '" min="0" step="0.01"></td>';
|
||||||
html += '</tr>';
|
html += '</tr>';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -709,13 +944,13 @@ function build_allocation_html(vat_free_items, vat_items, allocation_data) {
|
||||||
// Summary section
|
// Summary section
|
||||||
let formatted_zero = $(frappe.format(0, {fieldtype: 'Currency'})).text();
|
let formatted_zero = $(frappe.format(0, {fieldtype: 'Currency'})).text();
|
||||||
|
|
||||||
html += '<div class="allocation-summary" style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 5px;">';
|
html += '<div class="allocation-summary-' + tab_type + '" style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 5px;">';
|
||||||
html += '<div class="row">';
|
html += '<div class="row">';
|
||||||
html += '<div class="col-md-6"><strong>Total VAT Free to Allocate:</strong> <span id="total_vat_free" class="text-primary">' + formatted_zero + '</span></div>';
|
html += '<div class="col-md-6"><strong>Total VAT Free to Allocate:</strong> <span id="total_vat_free_' + tab_type + '" class="text-primary">' + formatted_zero + '</span></div>';
|
||||||
html += '<div class="col-md-6"><strong>Total VAT to Allocate:</strong> <span id="total_vat_allocated" class="text-warning">' + formatted_zero + '</span></div>';
|
html += '<div class="col-md-6"><strong>Total VAT to Allocate:</strong> <span id="total_vat_allocated_' + tab_type + '" class="text-warning">' + formatted_zero + '</span></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '<div class="row" style="margin-top: 10px;">';
|
html += '<div class="row" style="margin-top: 10px;">';
|
||||||
html += '<div class="col-md-12"><strong>Total:</strong> <span id="total_allocated" class="text-success">' + formatted_zero + '</span></div>';
|
html += '<div class="col-md-12"><strong>Total:</strong> <span id="total_allocated_' + tab_type + '" class="text-success">' + formatted_zero + '</span></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
|
|
@ -724,15 +959,16 @@ function build_allocation_html(vat_free_items, vat_items, allocation_data) {
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup_allocation_inputs(dialog, allocation_data, max_vat_free, max_vat_allocated) {
|
function setup_allocation_inputs(dialog, allocation_data, max_vat_free, max_vat_allocated, tab_type) {
|
||||||
let $wrapper = dialog.fields_dict.allocation_html.$wrapper;
|
// Ищем wrapper по ID вкладки в общем wrapper диалога
|
||||||
|
let $wrapper = dialog.$wrapper.find('#tab-' + tab_type);
|
||||||
|
|
||||||
// Initial calculation
|
// Initial calculation
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$wrapper.find('.allocation-input').first().trigger('input');
|
$wrapper.find('.allocation-input-' + tab_type).first().trigger('input');
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
$wrapper.find('.allocation-input').on('input', function() {
|
$wrapper.find('.allocation-input-' + tab_type).on('input', function() {
|
||||||
let $input = $(this);
|
let $input = $(this);
|
||||||
let name = $input.data('name');
|
let name = $input.data('name');
|
||||||
let type = $input.data('type');
|
let type = $input.data('type');
|
||||||
|
|
@ -755,11 +991,11 @@ function setup_allocation_inputs(dialog, allocation_data, max_vat_free, max_vat_
|
||||||
type: type
|
type: type
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate totals
|
// Calculate totals for this tab only
|
||||||
let total_vat_free = 0;
|
let total_vat_free = 0;
|
||||||
let total_vat_allocated = 0;
|
let total_vat_allocated = 0;
|
||||||
|
|
||||||
$wrapper.find('.allocation-input').each(function() {
|
$wrapper.find('.allocation-input-' + tab_type).each(function() {
|
||||||
let item_type = $(this).data('type');
|
let item_type = $(this).data('type');
|
||||||
let item_value = parseFloat($(this).val()) || 0;
|
let item_value = parseFloat($(this).val()) || 0;
|
||||||
|
|
||||||
|
|
@ -784,31 +1020,30 @@ function setup_allocation_inputs(dialog, allocation_data, max_vat_free, max_vat_
|
||||||
total_vat_free -= value;
|
total_vat_free -= value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update summary for this tab
|
||||||
// Update summary
|
$wrapper.find('#total_vat_free_' + tab_type).text($(frappe.format(total_vat_free, {fieldtype: 'Currency'})).text());
|
||||||
$wrapper.find('#total_vat_free').text($(frappe.format(total_vat_free, {fieldtype: 'Currency'})).text());
|
$wrapper.find('#total_vat_allocated_' + tab_type).text($(frappe.format(total_vat_allocated, {fieldtype: 'Currency'})).text());
|
||||||
$wrapper.find('#total_vat_allocated').text($(frappe.format(total_vat_allocated, {fieldtype: 'Currency'})).text());
|
$wrapper.find('#total_allocated_' + tab_type).text($(frappe.format(total_vat_free + total_vat_allocated, {fieldtype: 'Currency'})).text());
|
||||||
$wrapper.find('#total_allocated').text($(frappe.format(total_vat_free + total_vat_allocated, {fieldtype: 'Currency'})).text());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function auto_allocate(frm, payment_row_idx, data, vat_free_items, vat_items, allocation_data, dialog) {
|
function auto_allocate(frm, payment_row_idx, data, vat_free_items, vat_items, allocation_data, dialog, tab_type, available_amounts, other_allocation_data) {
|
||||||
// Call server method to calculate auto allocation
|
// Use calculated available amounts
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.calculate_auto_allocation',
|
method: 'taxes_az.taxes_az.doctype.vat_allocation.vat_allocation.calculate_auto_allocation',
|
||||||
args: {
|
args: {
|
||||||
vat_free_available: data.vat_free_available,
|
vat_free_available: available_amounts.vat_free_available,
|
||||||
vat_allocated_available: data.vat_allocated_available,
|
vat_allocated_available: available_amounts.vat_allocated_available,
|
||||||
vat_free_items: JSON.stringify(vat_free_items),
|
vat_free_items: JSON.stringify(vat_free_items),
|
||||||
vat_items: JSON.stringify(vat_items)
|
vat_items: JSON.stringify(vat_items)
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
let allocations = r.message;
|
let allocations = r.message;
|
||||||
let $wrapper = dialog.fields_dict.allocation_html.$wrapper;
|
let $wrapper = dialog.$wrapper.find('#tab-' + tab_type);
|
||||||
|
|
||||||
// Reset all inputs
|
// Reset all inputs for this tab
|
||||||
$wrapper.find('.allocation-input').val(0);
|
$wrapper.find('.allocation-input-' + tab_type).val(0);
|
||||||
|
|
||||||
// Update allocation data
|
// Update allocation data
|
||||||
for (let key in allocation_data) {
|
for (let key in allocation_data) {
|
||||||
|
|
@ -818,11 +1053,20 @@ function auto_allocate(frm, payment_row_idx, data, vat_free_items, vat_items, al
|
||||||
// Apply auto allocations
|
// Apply auto allocations
|
||||||
allocations.forEach(function(alloc) {
|
allocations.forEach(function(alloc) {
|
||||||
allocation_data[alloc.name].value = alloc.allocated;
|
allocation_data[alloc.name].value = alloc.allocated;
|
||||||
$wrapper.find('.allocation-input[data-name="' + alloc.name + '"]').val(alloc.allocated.toFixed(2));
|
$wrapper.find('.allocation-input-' + tab_type + '[data-name="' + alloc.name + '"]').val(alloc.allocated.toFixed(2));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trigger input event to update summary
|
// Trigger input event to update summary
|
||||||
$wrapper.find('.allocation-input').first().trigger('input');
|
$wrapper.find('.allocation-input-' + tab_type).first().trigger('input');
|
||||||
|
|
||||||
|
// Update available amounts in dialog fields
|
||||||
|
let new_available = calculate_available_amounts(data,
|
||||||
|
tab_type === 'current' ? allocation_data : other_allocation_data,
|
||||||
|
tab_type === 'previous' ? allocation_data : other_allocation_data
|
||||||
|
);
|
||||||
|
|
||||||
|
dialog.set_value('vat_free_available', new_available.vat_free_available);
|
||||||
|
dialog.set_value('vat_allocated_available', new_available.vat_allocated_available);
|
||||||
|
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
message: __('Auto allocation completed'),
|
message: __('Auto allocation completed'),
|
||||||
|
|
@ -834,12 +1078,23 @@ function auto_allocate(frm, payment_row_idx, data, vat_free_items, vat_items, al
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сохранение allocation - работает с несохраненным документом
|
// Сохранение allocation - работает с несохраненным документом
|
||||||
function save_allocation_data(frm, payment_row_idx, allocation_data, dialog) {
|
function save_allocation_data(frm, payment_row_idx, allocation_data_current, allocation_data_previous, dialog) {
|
||||||
// Prepare allocations array
|
// Prepare allocations array - combine both tabs
|
||||||
let allocations = [];
|
let allocations = [];
|
||||||
|
|
||||||
for (let name in allocation_data) {
|
// Add allocations from current month tab
|
||||||
let data = allocation_data[name];
|
for (let name in allocation_data_current) {
|
||||||
|
let data = allocation_data_current[name];
|
||||||
|
allocations.push({
|
||||||
|
name: name,
|
||||||
|
allocated: data.value,
|
||||||
|
type: data.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add allocations from previous months tab
|
||||||
|
for (let name in allocation_data_previous) {
|
||||||
|
let data = allocation_data_previous[name];
|
||||||
allocations.push({
|
allocations.push({
|
||||||
name: name,
|
name: name,
|
||||||
allocated: data.value,
|
allocated: data.value,
|
||||||
|
|
@ -892,6 +1147,7 @@ function save_allocation_data(frm, payment_row_idx, allocation_data, dialog) {
|
||||||
frm.refresh_field('allocation_links');
|
frm.refresh_field('allocation_links');
|
||||||
frm.refresh_field('payment_entry_table');
|
frm.refresh_field('payment_entry_table');
|
||||||
frm.refresh_field('sales_invoice_table');
|
frm.refresh_field('sales_invoice_table');
|
||||||
|
frm.refresh_field('sales_invoice_previous_table');
|
||||||
|
|
||||||
// Помечаем документ как измененный
|
// Помечаем документ как измененный
|
||||||
frm.dirty();
|
frm.dirty();
|
||||||
|
|
@ -899,7 +1155,7 @@ function save_allocation_data(frm, payment_row_idx, allocation_data, dialog) {
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция для пересчета totals без сохранения в БД
|
// Функция для пересчета totals без сохранения в БД - UPDATED
|
||||||
function recalculate_totals_manually(frm) {
|
function recalculate_totals_manually(frm) {
|
||||||
// Reset all allocated amounts
|
// Reset all allocated amounts
|
||||||
for (let pe_row of frm.doc.payment_entry_table || []) {
|
for (let pe_row of frm.doc.payment_entry_table || []) {
|
||||||
|
|
@ -912,6 +1168,10 @@ function recalculate_totals_manually(frm) {
|
||||||
si_row.allocated_amount = 0;
|
si_row.allocated_amount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let si_row of frm.doc.sales_invoice_previous_table || []) {
|
||||||
|
si_row.allocated_amount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate from links
|
// Calculate from links
|
||||||
for (let link of frm.doc.allocation_links || []) {
|
for (let link of frm.doc.allocation_links || []) {
|
||||||
let allocated = link.allocated_amount || 0;
|
let allocated = link.allocated_amount || 0;
|
||||||
|
|
@ -931,13 +1191,24 @@ function recalculate_totals_manually(frm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update sales invoice row
|
// Update sales invoice row - check both tables
|
||||||
|
let found = false;
|
||||||
for (let si_row of frm.doc.sales_invoice_table || []) {
|
for (let si_row of frm.doc.sales_invoice_table || []) {
|
||||||
if (si_row.name === link.sales_invoice_row) {
|
if (si_row.name === link.sales_invoice_row) {
|
||||||
si_row.allocated_amount = (si_row.allocated_amount || 0) + allocated;
|
si_row.allocated_amount = (si_row.allocated_amount || 0) + allocated;
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
for (let si_row of frm.doc.sales_invoice_previous_table || []) {
|
||||||
|
if (si_row.name === link.sales_invoice_row) {
|
||||||
|
si_row.allocated_amount = (si_row.allocated_amount || 0) + allocated;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate unallocated amounts
|
// Calculate unallocated amounts
|
||||||
|
|
@ -953,6 +1224,12 @@ function recalculate_totals_manually(frm) {
|
||||||
si_row.unallocated_amount = Math.max(0, total - allocated);
|
si_row.unallocated_amount = Math.max(0, total - allocated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let si_row of frm.doc.sales_invoice_previous_table || []) {
|
||||||
|
let total = si_row.amount || 0;
|
||||||
|
let allocated = si_row.allocated_amount || 0;
|
||||||
|
si_row.unallocated_amount = Math.max(0, total - allocated);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate tax template totals
|
// Calculate tax template totals
|
||||||
calculate_tax_template_totals(frm);
|
calculate_tax_template_totals(frm);
|
||||||
}
|
}
|
||||||
|
|
@ -966,7 +1243,7 @@ function calculate_tax_template_totals(frm) {
|
||||||
frm.doc.total_edv_18 = 0;
|
frm.doc.total_edv_18 = 0;
|
||||||
frm.doc.total_allocated_sum = 0;
|
frm.doc.total_allocated_sum = 0;
|
||||||
|
|
||||||
// Calculate totals from sales invoice table
|
// Calculate totals from sales invoice table (only current month)
|
||||||
for (let si_row of frm.doc.sales_invoice_table || []) {
|
for (let si_row of frm.doc.sales_invoice_table || []) {
|
||||||
let allocated = si_row.allocated_amount || 0;
|
let allocated = si_row.allocated_amount || 0;
|
||||||
if (allocated <= 0) continue;
|
if (allocated <= 0) continue;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
"payment_entry_table",
|
"payment_entry_table",
|
||||||
"sales_invoice_section",
|
"sales_invoice_section",
|
||||||
"sales_invoice_table",
|
"sales_invoice_table",
|
||||||
|
"section_break_fhfs",
|
||||||
|
"sales_invoice_previous_table",
|
||||||
"allocation_links_section",
|
"allocation_links_section",
|
||||||
"allocation_links",
|
"allocation_links",
|
||||||
"total_edv_18",
|
"total_edv_18",
|
||||||
|
|
@ -146,12 +148,22 @@
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_fhfs",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sales_invoice_previous_table",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Sales Invoice Previous Months",
|
||||||
|
"options": "VAT allocation sales invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-10-06 16:52:07.347647",
|
"modified": "2025-10-07 14:10:17.385408",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Taxes Az",
|
"module": "Taxes Az",
|
||||||
"name": "VAT allocation",
|
"name": "VAT allocation",
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,9 @@ class VATallocation(Document):
|
||||||
for si_row in self.sales_invoice_table:
|
for si_row in self.sales_invoice_table:
|
||||||
si_row.allocated_amount = 0
|
si_row.allocated_amount = 0
|
||||||
|
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
|
si_row.allocated_amount = 0
|
||||||
|
|
||||||
# Calculate from links
|
# Calculate from links
|
||||||
for link in self.allocation_links:
|
for link in self.allocation_links:
|
||||||
allocated = Decimal(str(link.allocated_amount or 0))
|
allocated = Decimal(str(link.allocated_amount or 0))
|
||||||
|
|
@ -66,8 +69,17 @@ class VATallocation(Document):
|
||||||
pe_row.vat_allocated_allocated = float(current_vat_allocated + allocated)
|
pe_row.vat_allocated_allocated = float(current_vat_allocated + allocated)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Update sales invoice row
|
# Update sales invoice row - check both tables
|
||||||
|
found = False
|
||||||
for si_row in self.sales_invoice_table:
|
for si_row in self.sales_invoice_table:
|
||||||
|
if si_row.name == link.sales_invoice_row:
|
||||||
|
current_allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
|
si_row.allocated_amount = float(current_allocated + allocated)
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
if si_row.name == link.sales_invoice_row:
|
if si_row.name == link.sales_invoice_row:
|
||||||
current_allocated = Decimal(str(si_row.allocated_amount or 0))
|
current_allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
si_row.allocated_amount = float(current_allocated + allocated)
|
si_row.allocated_amount = float(current_allocated + allocated)
|
||||||
|
|
@ -84,6 +96,11 @@ class VATallocation(Document):
|
||||||
allocated = Decimal(str(si_row.allocated_amount or 0))
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
si_row.unallocated_amount = float(max(Decimal('0'), total - allocated))
|
si_row.unallocated_amount = float(max(Decimal('0'), total - allocated))
|
||||||
|
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
|
total = Decimal(str(si_row.amount or 0))
|
||||||
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
|
si_row.unallocated_amount = float(max(Decimal('0'), total - allocated))
|
||||||
|
|
||||||
def validate_allocations(self):
|
def validate_allocations(self):
|
||||||
"""
|
"""
|
||||||
Validate that all allocations are mathematically correct
|
Validate that all allocations are mathematically correct
|
||||||
|
|
@ -106,7 +123,7 @@ class VATallocation(Document):
|
||||||
if vat_allocated_spent > vat_allocated_total + ROUNDING_TOLERANCE:
|
if vat_allocated_spent > vat_allocated_total + ROUNDING_TOLERANCE:
|
||||||
frappe.throw(_(f"VAT Allocated spent exceeds total for payment entry {pe_row.payment_entry}"))
|
frappe.throw(_(f"VAT Allocated spent exceeds total for payment entry {pe_row.payment_entry}"))
|
||||||
|
|
||||||
# Validate sales invoice items
|
# Validate sales invoice items - both tables
|
||||||
for si_row in self.sales_invoice_table:
|
for si_row in self.sales_invoice_table:
|
||||||
amount = Decimal(str(si_row.amount or 0))
|
amount = Decimal(str(si_row.amount or 0))
|
||||||
allocated = Decimal(str(si_row.allocated_amount or 0))
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
|
|
@ -121,6 +138,20 @@ class VATallocation(Document):
|
||||||
if abs(total_check - amount) > ROUNDING_TOLERANCE:
|
if abs(total_check - amount) > ROUNDING_TOLERANCE:
|
||||||
frappe.throw(_(f"Allocated + Unallocated != Amount for {si_row.item_tax_template}"))
|
frappe.throw(_(f"Allocated + Unallocated != Amount for {si_row.item_tax_template}"))
|
||||||
|
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
|
amount = Decimal(str(si_row.amount or 0))
|
||||||
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
|
unallocated = Decimal(str(si_row.unallocated_amount or 0))
|
||||||
|
|
||||||
|
# Check non-negative
|
||||||
|
if allocated < 0 or unallocated < -ROUNDING_TOLERANCE:
|
||||||
|
frappe.throw(_(f"Allocated amounts cannot be negative for previous month {si_row.item_tax_template}"))
|
||||||
|
|
||||||
|
# Check sum equals total (with tolerance)
|
||||||
|
total_check = allocated + unallocated
|
||||||
|
if abs(total_check - amount) > ROUNDING_TOLERANCE:
|
||||||
|
frappe.throw(_(f"Allocated + Unallocated != Amount for previous month {si_row.item_tax_template}"))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def validate_all_allocations(vat_allocation_name):
|
def validate_all_allocations(vat_allocation_name):
|
||||||
"""
|
"""
|
||||||
|
|
@ -351,6 +382,115 @@ def get_sales_invoice_items(year, month, customers=None, min_amount=None, max_am
|
||||||
|
|
||||||
return invoice_items
|
return invoice_items
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_sales_invoice_items_previous_months(year, month, customers=None, min_amount=None, max_amount=None):
|
||||||
|
"""
|
||||||
|
Get Sales Invoice items from previous VAT Allocation documents where unallocated_amount > 0
|
||||||
|
Grouped by customer, item_tax_template, and tax_article
|
||||||
|
"""
|
||||||
|
# Convert month name to number
|
||||||
|
months = {
|
||||||
|
"January": 1, "February": 2, "March": 3, "April": 4,
|
||||||
|
"May": 5, "June": 6, "July": 7, "August": 8,
|
||||||
|
"September": 9, "October": 10, "November": 11, "December": 12
|
||||||
|
}
|
||||||
|
|
||||||
|
month_number = months.get(month)
|
||||||
|
if not month_number:
|
||||||
|
frappe.throw(_("Invalid month"))
|
||||||
|
|
||||||
|
# Parse customers filter
|
||||||
|
customer_list = None
|
||||||
|
if customers:
|
||||||
|
if isinstance(customers, str):
|
||||||
|
customers = json.loads(customers)
|
||||||
|
if customers and len(customers) > 0:
|
||||||
|
customer_list = [c.get('customer') for c in customers if c.get('customer')]
|
||||||
|
|
||||||
|
# Find all previous VAT Allocation documents
|
||||||
|
# We need to find documents where (year < current_year) OR (year == current_year AND month < current_month)
|
||||||
|
vat_allocations = frappe.db.sql("""
|
||||||
|
SELECT name, year, month
|
||||||
|
FROM `tabVAT allocation`
|
||||||
|
WHERE docstatus = 1
|
||||||
|
AND (
|
||||||
|
year < %(year)s
|
||||||
|
OR (year = %(year)s AND month < %(month)s)
|
||||||
|
)
|
||||||
|
ORDER BY year DESC, month DESC
|
||||||
|
""", {
|
||||||
|
'year': year,
|
||||||
|
'month': month_number
|
||||||
|
}, as_dict=1)
|
||||||
|
|
||||||
|
if not vat_allocations:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Collect all items with unallocated_amount > 0 from previous VAT Allocations
|
||||||
|
all_items = []
|
||||||
|
|
||||||
|
for vat_alloc in vat_allocations:
|
||||||
|
# Get sales invoice items from this VAT Allocation
|
||||||
|
items = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
customer,
|
||||||
|
item_tax_template,
|
||||||
|
tax_article,
|
||||||
|
unallocated_amount
|
||||||
|
FROM `tabVAT allocation sales invoice`
|
||||||
|
WHERE parent = %(parent)s
|
||||||
|
AND unallocated_amount > 0
|
||||||
|
""", {
|
||||||
|
'parent': vat_alloc.name
|
||||||
|
}, as_dict=1)
|
||||||
|
|
||||||
|
all_items.extend(items)
|
||||||
|
|
||||||
|
# Group by customer, item_tax_template, tax_article and sum unallocated amounts
|
||||||
|
grouped_items = {}
|
||||||
|
|
||||||
|
for item in all_items:
|
||||||
|
# Apply customer filter
|
||||||
|
if customer_list and item.customer not in customer_list:
|
||||||
|
continue
|
||||||
|
|
||||||
|
key = (item.customer, item.item_tax_template or '', item.tax_article or '')
|
||||||
|
|
||||||
|
if key not in grouped_items:
|
||||||
|
grouped_items[key] = {
|
||||||
|
'customer': item.customer,
|
||||||
|
'item_tax_template': item.item_tax_template,
|
||||||
|
'tax_article': item.tax_article,
|
||||||
|
'amount': Decimal('0')
|
||||||
|
}
|
||||||
|
|
||||||
|
grouped_items[key]['amount'] += Decimal(str(item.unallocated_amount))
|
||||||
|
|
||||||
|
# Convert to list and apply amount filters
|
||||||
|
result = []
|
||||||
|
for key, item in grouped_items.items():
|
||||||
|
amount = float(item['amount'])
|
||||||
|
|
||||||
|
# Apply min/max amount filters
|
||||||
|
if min_amount and amount < float(min_amount):
|
||||||
|
continue
|
||||||
|
if max_amount and amount > float(max_amount):
|
||||||
|
continue
|
||||||
|
|
||||||
|
result.append({
|
||||||
|
'customer': item['customer'],
|
||||||
|
'item_tax_template': item['item_tax_template'],
|
||||||
|
'tax_article': item['tax_article'],
|
||||||
|
'amount': amount,
|
||||||
|
'unallocated_amount': amount, # Initially all is unallocated
|
||||||
|
'allocated_amount': 0
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sort by customer, item_tax_template, tax_article
|
||||||
|
result.sort(key=lambda x: (x['customer'], x['item_tax_template'] or '', x['tax_article'] or ''))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_allocation_data(vat_allocation_name, payment_entry_row_name, customer):
|
def get_allocation_data(vat_allocation_name, payment_entry_row_name, customer):
|
||||||
"""
|
"""
|
||||||
|
|
@ -405,6 +545,10 @@ def get_allocation_data(vat_allocation_name, payment_entry_row_name, customer):
|
||||||
# VAT templates (ƏDV 18% and ƏDV daxil 18%)
|
# VAT templates (ƏDV 18% and ƏDV daxil 18%)
|
||||||
vat_items = []
|
vat_items = []
|
||||||
|
|
||||||
|
vat_free_items_previous = []
|
||||||
|
vat_items_previous = []
|
||||||
|
|
||||||
|
# Current month items
|
||||||
for item in doc.sales_invoice_table:
|
for item in doc.sales_invoice_table:
|
||||||
if item.customer == customer:
|
if item.customer == customer:
|
||||||
# Get existing allocation for this item
|
# Get existing allocation for this item
|
||||||
|
|
@ -429,12 +573,39 @@ def get_allocation_data(vat_allocation_name, payment_entry_row_name, customer):
|
||||||
elif 'ədv 18%' in template or 'ədv daxil 18%' in template:
|
elif 'ədv 18%' in template or 'ədv daxil 18%' in template:
|
||||||
vat_items.append(item_data)
|
vat_items.append(item_data)
|
||||||
|
|
||||||
|
# Previous months items
|
||||||
|
for item in doc.sales_invoice_previous_table:
|
||||||
|
if item.customer == customer:
|
||||||
|
# Get existing allocation for this item
|
||||||
|
existing_alloc = existing_allocations.get(item.name, {'amount': 0, 'type': None})
|
||||||
|
|
||||||
|
item_data = {
|
||||||
|
'name': item.name,
|
||||||
|
'item_tax_template': item.item_tax_template or '',
|
||||||
|
'tax_article': item.tax_article or '',
|
||||||
|
'amount': item.amount,
|
||||||
|
'unallocated_amount': item.unallocated_amount,
|
||||||
|
'allocated_amount': item.allocated_amount or 0,
|
||||||
|
'current_allocation': existing_alloc['amount'] # Allocation from THIS payment row
|
||||||
|
}
|
||||||
|
|
||||||
|
template = (item.item_tax_template or '').lower()
|
||||||
|
|
||||||
|
# Check if it's VAT free template
|
||||||
|
if 'ədv 0%' in template or 'ədv-dən azadolma' in template:
|
||||||
|
vat_free_items_previous.append(item_data)
|
||||||
|
# Check if it's VAT 18% template
|
||||||
|
elif 'ədv 18%' in template or 'ədv daxil 18%' in template:
|
||||||
|
vat_items_previous.append(item_data)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'payment_row': payment_row,
|
'payment_row': payment_row,
|
||||||
'vat_free_available': vat_free_available,
|
'vat_free_available': vat_free_available,
|
||||||
'vat_allocated_available': vat_allocated_available,
|
'vat_allocated_available': vat_allocated_available,
|
||||||
'vat_free_items': vat_free_items,
|
'vat_free_items': vat_free_items,
|
||||||
'vat_items': vat_items
|
'vat_items': vat_items,
|
||||||
|
'vat_free_items_previous': vat_free_items_previous,
|
||||||
|
'vat_items_previous': vat_items_previous
|
||||||
}
|
}
|
||||||
|
|
||||||
def round_decimal(value, precision=2):
|
def round_decimal(value, precision=2):
|
||||||
|
|
@ -513,8 +684,9 @@ def save_allocation(vat_allocation_name, payment_entry_row_name, allocations):
|
||||||
"Total VAT Allocated ({0}) exceeds total amount ({1})"
|
"Total VAT Allocated ({0}) exceeds total amount ({1})"
|
||||||
).format(total_vat_allocated_new, vat_allocated_amount))
|
).format(total_vat_allocated_new, vat_allocated_amount))
|
||||||
|
|
||||||
# Validate each SI item
|
# Validate each SI item - check both tables
|
||||||
si_items_map = {item.name: item for item in doc.sales_invoice_table}
|
si_items_map = {item.name: item for item in doc.sales_invoice_table}
|
||||||
|
si_items_map.update({item.name: item for item in doc.sales_invoice_previous_table})
|
||||||
|
|
||||||
for allocation in allocations:
|
for allocation in allocations:
|
||||||
si_row_name = allocation['name']
|
si_row_name = allocation['name']
|
||||||
|
|
@ -716,6 +888,9 @@ def recalculate_totals_from_links(self):
|
||||||
for si_row in self.sales_invoice_table:
|
for si_row in self.sales_invoice_table:
|
||||||
si_row.allocated_amount = 0
|
si_row.allocated_amount = 0
|
||||||
|
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
|
si_row.allocated_amount = 0
|
||||||
|
|
||||||
# Calculate from links
|
# Calculate from links
|
||||||
for link in self.allocation_links:
|
for link in self.allocation_links:
|
||||||
allocated = Decimal(str(link.allocated_amount or 0))
|
allocated = Decimal(str(link.allocated_amount or 0))
|
||||||
|
|
@ -736,8 +911,17 @@ def recalculate_totals_from_links(self):
|
||||||
pe_row.vat_allocated_allocated = float(current_vat_allocated + allocated)
|
pe_row.vat_allocated_allocated = float(current_vat_allocated + allocated)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Update sales invoice row
|
# Update sales invoice row - check both tables
|
||||||
|
found = False
|
||||||
for si_row in self.sales_invoice_table:
|
for si_row in self.sales_invoice_table:
|
||||||
|
if si_row.name == link.sales_invoice_row:
|
||||||
|
current_allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
|
si_row.allocated_amount = float(current_allocated + allocated)
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
if si_row.name == link.sales_invoice_row:
|
if si_row.name == link.sales_invoice_row:
|
||||||
current_allocated = Decimal(str(si_row.allocated_amount or 0))
|
current_allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
si_row.allocated_amount = float(current_allocated + allocated)
|
si_row.allocated_amount = float(current_allocated + allocated)
|
||||||
|
|
@ -754,6 +938,11 @@ def recalculate_totals_from_links(self):
|
||||||
allocated = Decimal(str(si_row.allocated_amount or 0))
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
si_row.unallocated_amount = float(max(Decimal('0'), total - allocated))
|
si_row.unallocated_amount = float(max(Decimal('0'), total - allocated))
|
||||||
|
|
||||||
|
for si_row in self.sales_invoice_previous_table:
|
||||||
|
total = Decimal(str(si_row.amount or 0))
|
||||||
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
|
si_row.unallocated_amount = float(max(Decimal('0'), total - allocated))
|
||||||
|
|
||||||
# Calculate totals by tax template
|
# Calculate totals by tax template
|
||||||
self.calculate_tax_template_totals()
|
self.calculate_tax_template_totals()
|
||||||
|
|
||||||
|
|
@ -768,7 +957,7 @@ def calculate_tax_template_totals(self):
|
||||||
self.total_edv_18 = 0
|
self.total_edv_18 = 0
|
||||||
self.total_allocated_sum = 0
|
self.total_allocated_sum = 0
|
||||||
|
|
||||||
# Calculate totals
|
# Calculate totals - only from current month table
|
||||||
for si_row in self.sales_invoice_table:
|
for si_row in self.sales_invoice_table:
|
||||||
allocated = Decimal(str(si_row.allocated_amount or 0))
|
allocated = Decimal(str(si_row.allocated_amount or 0))
|
||||||
if allocated <= 0:
|
if allocated <= 0:
|
||||||
|
|
@ -788,3 +977,187 @@ def calculate_tax_template_totals(self):
|
||||||
|
|
||||||
# Add to total sum
|
# Add to total sum
|
||||||
self.total_allocated_sum = float(Decimal(str(self.total_allocated_sum or 0)) + allocated)
|
self.total_allocated_sum = float(Decimal(str(self.total_allocated_sum or 0)) + allocated)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_payment_entries_previous_months(year, month, customers=None, min_amount=None, max_amount=None):
|
||||||
|
"""
|
||||||
|
Get Payment Entries from previous VAT Allocation documents where unallocated_amount > 0
|
||||||
|
Returns the most recent state of each Payment Entry
|
||||||
|
"""
|
||||||
|
# Convert month name to number
|
||||||
|
months = {
|
||||||
|
"January": 1, "February": 2, "March": 3, "April": 4,
|
||||||
|
"May": 5, "June": 6, "July": 7, "August": 8,
|
||||||
|
"September": 9, "October": 10, "November": 11, "December": 12
|
||||||
|
}
|
||||||
|
|
||||||
|
month_number = months.get(month)
|
||||||
|
if not month_number:
|
||||||
|
frappe.throw(_("Invalid month"))
|
||||||
|
|
||||||
|
# Parse customers filter
|
||||||
|
customer_list = None
|
||||||
|
if customers:
|
||||||
|
if isinstance(customers, str):
|
||||||
|
customers = json.loads(customers)
|
||||||
|
if customers and len(customers) > 0:
|
||||||
|
customer_list = [c.get('customer') for c in customers if c.get('customer')]
|
||||||
|
|
||||||
|
# Find all previous VAT Allocation documents
|
||||||
|
vat_allocations = frappe.db.sql("""
|
||||||
|
SELECT name, year, month
|
||||||
|
FROM `tabVAT allocation`
|
||||||
|
WHERE docstatus = 1
|
||||||
|
AND (
|
||||||
|
year < %(year)s
|
||||||
|
OR (year = %(year)s AND month < %(month)s)
|
||||||
|
)
|
||||||
|
ORDER BY year DESC, month DESC
|
||||||
|
""", {
|
||||||
|
'year': year,
|
||||||
|
'month': month_number
|
||||||
|
}, as_dict=1)
|
||||||
|
|
||||||
|
if not vat_allocations:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Collect all payment entries with unallocated_amount > 0
|
||||||
|
# Keep only the most recent entry for each payment_entry
|
||||||
|
payment_entries_map = {}
|
||||||
|
|
||||||
|
for vat_alloc in vat_allocations:
|
||||||
|
# Get payment entries from this VAT Allocation
|
||||||
|
entries = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
payment_entry,
|
||||||
|
customer,
|
||||||
|
payment_entry_amount,
|
||||||
|
vat_journal_entry,
|
||||||
|
vat_amount,
|
||||||
|
vat_allocated_amount,
|
||||||
|
vat_free_amount,
|
||||||
|
vat_allocated_allocated,
|
||||||
|
vat_free_allocated,
|
||||||
|
unallocated_amount
|
||||||
|
FROM `tabVAT allocation payment entry`
|
||||||
|
WHERE parent = %(parent)s
|
||||||
|
AND unallocated_amount > 0
|
||||||
|
""", {
|
||||||
|
'parent': vat_alloc.name
|
||||||
|
}, as_dict=1)
|
||||||
|
|
||||||
|
for entry in entries:
|
||||||
|
# Apply customer filter
|
||||||
|
if customer_list and entry.customer not in customer_list:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Apply min/max amount filters to payment_entry_amount
|
||||||
|
if min_amount and (entry.payment_entry_amount or 0) < float(min_amount):
|
||||||
|
continue
|
||||||
|
if max_amount and (entry.payment_entry_amount or 0) > float(max_amount):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Keep only the most recent (first encountered due to ORDER BY DESC)
|
||||||
|
if entry.payment_entry not in payment_entries_map:
|
||||||
|
# Calculate remaining amounts
|
||||||
|
vat_allocated_remaining = Decimal(str(entry.vat_allocated_amount or 0)) - Decimal(str(entry.vat_allocated_allocated or 0))
|
||||||
|
vat_free_remaining = Decimal(str(entry.vat_free_amount or 0)) - Decimal(str(entry.vat_free_allocated or 0))
|
||||||
|
|
||||||
|
payment_entries_map[entry.payment_entry] = {
|
||||||
|
'payment_entry': entry.payment_entry,
|
||||||
|
'customer': entry.customer,
|
||||||
|
'payment_entry_amount': entry.payment_entry_amount,
|
||||||
|
'vat_journal_entry': entry.vat_journal_entry,
|
||||||
|
'vat_amount': entry.vat_amount,
|
||||||
|
'vat_allocated_amount': float(vat_allocated_remaining),
|
||||||
|
'vat_free_amount': float(vat_free_remaining),
|
||||||
|
'unallocated_amount': 0, # Will be calculated
|
||||||
|
'allocated_amount': 0,
|
||||||
|
'vat_allocated_allocated': 0,
|
||||||
|
'vat_free_allocated': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert to list
|
||||||
|
result = list(payment_entries_map.values())
|
||||||
|
|
||||||
|
# Sort by payment_entry
|
||||||
|
result.sort(key=lambda x: x['payment_entry'])
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_payment_entries_with_previous(year, month, customers=None, min_amount=None, max_amount=None):
|
||||||
|
"""
|
||||||
|
Get Payment Entries - both current month and previous months with unallocated amounts
|
||||||
|
"""
|
||||||
|
# Get current month payment entries
|
||||||
|
current_entries = get_payment_entries(year, month, customers, min_amount, max_amount)
|
||||||
|
|
||||||
|
# Get previous months payment entries
|
||||||
|
previous_entries = get_payment_entries_previous_months(year, month, customers, min_amount, max_amount)
|
||||||
|
|
||||||
|
# Create a set of payment_entry names from current month
|
||||||
|
current_pe_names = {entry['payment_entry'] for entry in current_entries}
|
||||||
|
|
||||||
|
# Filter out previous entries that are already in current month
|
||||||
|
filtered_previous = [entry for entry in previous_entries if entry['payment_entry'] not in current_pe_names]
|
||||||
|
|
||||||
|
# Combine and return
|
||||||
|
return current_entries + filtered_previous
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
|
def get_payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
"""
|
||||||
|
Custom query for filtering Payment Entries - includes both current month and those with remaining balance
|
||||||
|
"""
|
||||||
|
year = filters.get('year')
|
||||||
|
month = filters.get('month')
|
||||||
|
|
||||||
|
if not all([year, month]):
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Convert month name to number
|
||||||
|
months = {
|
||||||
|
"January": 1, "February": 2, "March": 3, "April": 4,
|
||||||
|
"May": 5, "June": 6, "July": 7, "August": 8,
|
||||||
|
"September": 9, "October": 10, "November": 11, "December": 12
|
||||||
|
}
|
||||||
|
|
||||||
|
month_number = months.get(month)
|
||||||
|
if not month_number:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Get Payment Entries from current month OR from previous VAT Allocations with balance
|
||||||
|
return frappe.db.sql("""
|
||||||
|
SELECT DISTINCT pe.name, pe.posting_date, pe.paid_amount
|
||||||
|
FROM `tabPayment Entry` pe
|
||||||
|
WHERE pe.docstatus = 1
|
||||||
|
AND pe.payment_type = 'Receive'
|
||||||
|
AND pe.party_type = 'Customer'
|
||||||
|
AND pe.name LIKE %(txt)s
|
||||||
|
AND (
|
||||||
|
(YEAR(pe.posting_date) = %(year)s AND MONTH(pe.posting_date) = %(month)s)
|
||||||
|
OR
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM `tabVAT allocation payment entry` vape
|
||||||
|
INNER JOIN `tabVAT allocation` va ON va.name = vape.parent
|
||||||
|
WHERE vape.payment_entry = pe.name
|
||||||
|
AND va.docstatus = 1
|
||||||
|
AND vape.unallocated_amount > 0
|
||||||
|
AND (
|
||||||
|
va.year < %(year)s
|
||||||
|
OR (va.year = %(year)s AND va.month < %(month)s)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY pe.posting_date DESC
|
||||||
|
LIMIT %(start)s, %(page_len)s
|
||||||
|
""", {
|
||||||
|
'year': year,
|
||||||
|
'month': month_number,
|
||||||
|
'txt': f"%{txt}%",
|
||||||
|
'start': start,
|
||||||
|
'page_len': page_len
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-10-07 14:07:17.398766",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"customer",
|
||||||
|
"payment_entry",
|
||||||
|
"item_tax_template",
|
||||||
|
"tax_article",
|
||||||
|
"amount",
|
||||||
|
"allocated_amount",
|
||||||
|
"unallocated_amount"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "customer",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Customer",
|
||||||
|
"options": "Customer",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "payment_entry",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Payment Entry",
|
||||||
|
"options": "Payment Entry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "item_tax_template",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Item tax template",
|
||||||
|
"options": "Item Tax Template",
|
||||||
|
"precision": "2",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "tax_article",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Tax Article",
|
||||||
|
"options": "Tax Article",
|
||||||
|
"precision": "2",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Amount",
|
||||||
|
"precision": "2",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "allocated_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Allocated amount",
|
||||||
|
"precision": "2",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "unallocated_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Unallocated amount",
|
||||||
|
"precision": "2",
|
||||||
|
"read_only": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-10-07 14:07:17.398766",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Taxes Az",
|
||||||
|
"name": "VAT allocation sales invoice previous months",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2025, Jey Soft and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class VATallocationsalesinvoicepreviousmonths(Document):
|
||||||
|
pass
|
||||||
Loading…
Reference in New Issue