fix: Item wise tax rate for consolidated POS invoice (#25029)
* fix: Item wise tax rate for consolidated POS invoice * fix: Do not alter item wise taxes for consolidated invoices * fix: Add test case * fix: Update * fix: Set opening stock for test item * fix: Add valuation rate for opening stock
This commit is contained in:
parent
c36e48a869
commit
5f3d7f547c
@ -12,6 +12,7 @@ from frappe.utils.background_jobs import enqueue
|
|||||||
from frappe.model.mapper import map_doc, map_child_doc
|
from frappe.model.mapper import map_doc, map_child_doc
|
||||||
from frappe.utils.scheduler import is_scheduler_inactive
|
from frappe.utils.scheduler import is_scheduler_inactive
|
||||||
from frappe.core.page.background_jobs.background_jobs import get_info
|
from frappe.core.page.background_jobs.background_jobs import get_info
|
||||||
|
import json
|
||||||
|
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
@ -131,12 +132,14 @@ class POSInvoiceMergeLog(Document):
|
|||||||
if t.account_head == tax.account_head and t.cost_center == tax.cost_center:
|
if t.account_head == tax.account_head and t.cost_center == tax.cost_center:
|
||||||
t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount_after_discount_amount)
|
t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount_after_discount_amount)
|
||||||
t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount_after_discount_amount)
|
t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount_after_discount_amount)
|
||||||
|
update_item_wise_tax_detail(t, tax)
|
||||||
found = True
|
found = True
|
||||||
if not found:
|
if not found:
|
||||||
tax.charge_type = 'Actual'
|
tax.charge_type = 'Actual'
|
||||||
tax.included_in_print_rate = 0
|
tax.included_in_print_rate = 0
|
||||||
tax.tax_amount = tax.tax_amount_after_discount_amount
|
tax.tax_amount = tax.tax_amount_after_discount_amount
|
||||||
tax.base_tax_amount = tax.base_tax_amount_after_discount_amount
|
tax.base_tax_amount = tax.base_tax_amount_after_discount_amount
|
||||||
|
tax.item_wise_tax_detail = tax.item_wise_tax_detail
|
||||||
taxes.append(tax)
|
taxes.append(tax)
|
||||||
|
|
||||||
for payment in doc.get('payments'):
|
for payment in doc.get('payments'):
|
||||||
@ -187,6 +190,26 @@ class POSInvoiceMergeLog(Document):
|
|||||||
si.flags.ignore_validate = True
|
si.flags.ignore_validate = True
|
||||||
si.cancel()
|
si.cancel()
|
||||||
|
|
||||||
|
def update_item_wise_tax_detail(consolidate_tax_row, tax_row):
|
||||||
|
consolidated_tax_detail = json.loads(consolidate_tax_row.item_wise_tax_detail)
|
||||||
|
tax_row_detail = json.loads(tax_row.item_wise_tax_detail)
|
||||||
|
|
||||||
|
if not consolidated_tax_detail:
|
||||||
|
consolidated_tax_detail = {}
|
||||||
|
|
||||||
|
for item_code, tax_data in tax_row_detail.items():
|
||||||
|
if consolidated_tax_detail.get(item_code):
|
||||||
|
consolidated_tax_data = consolidated_tax_detail.get(item_code)
|
||||||
|
consolidated_tax_detail.update({
|
||||||
|
item_code: [consolidated_tax_data[0], consolidated_tax_data[1] + tax_data[1]]
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
consolidated_tax_detail.update({
|
||||||
|
item_code: [tax_data[0], tax_data[1]]
|
||||||
|
})
|
||||||
|
|
||||||
|
consolidate_tax_row.item_wise_tax_detail = json.dumps(consolidated_tax_detail, separators=(',', ':'))
|
||||||
|
|
||||||
def get_all_unconsolidated_invoices():
|
def get_all_unconsolidated_invoices():
|
||||||
filters = {
|
filters = {
|
||||||
'consolidated_invoice': [ 'in', [ '', None ]],
|
'consolidated_invoice': [ 'in', [ '', None ]],
|
||||||
@ -214,7 +237,7 @@ def consolidate_pos_invoices(pos_invoices=[], closing_entry={}):
|
|||||||
|
|
||||||
if len(invoices) >= 5 and closing_entry:
|
if len(invoices) >= 5 and closing_entry:
|
||||||
closing_entry.set_status(update=True, status='Queued')
|
closing_entry.set_status(update=True, status='Queued')
|
||||||
enqueue_job(create_merge_logs, invoice_by_customer, closing_entry)
|
enqueue_job(create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry)
|
||||||
else:
|
else:
|
||||||
create_merge_logs(invoice_by_customer, closing_entry)
|
create_merge_logs(invoice_by_customer, closing_entry)
|
||||||
|
|
||||||
@ -227,7 +250,7 @@ def unconsolidate_pos_invoices(closing_entry):
|
|||||||
|
|
||||||
if len(merge_logs) >= 5:
|
if len(merge_logs) >= 5:
|
||||||
closing_entry.set_status(update=True, status='Queued')
|
closing_entry.set_status(update=True, status='Queued')
|
||||||
enqueue_job(cancel_merge_logs, merge_logs, closing_entry)
|
enqueue_job(cancel_merge_logs, merge_logs=merge_logs, closing_entry=closing_entry)
|
||||||
else:
|
else:
|
||||||
cancel_merge_logs(merge_logs, closing_entry)
|
cancel_merge_logs(merge_logs, closing_entry)
|
||||||
|
|
||||||
@ -256,7 +279,7 @@ def cancel_merge_logs(merge_logs, closing_entry={}):
|
|||||||
closing_entry.set_status(update=True, status='Cancelled')
|
closing_entry.set_status(update=True, status='Cancelled')
|
||||||
closing_entry.update_opening_entry(for_cancel=True)
|
closing_entry.update_opening_entry(for_cancel=True)
|
||||||
|
|
||||||
def enqueue_job(job, invoice_by_customer, closing_entry):
|
def enqueue_job(job, merge_logs=None, invoice_by_customer=None, closing_entry=None):
|
||||||
check_scheduler_status()
|
check_scheduler_status()
|
||||||
|
|
||||||
job_name = closing_entry.get("name")
|
job_name = closing_entry.get("name")
|
||||||
@ -269,6 +292,7 @@ def enqueue_job(job, invoice_by_customer, closing_entry):
|
|||||||
job_name=job_name,
|
job_name=job_name,
|
||||||
closing_entry=closing_entry,
|
closing_entry=closing_entry,
|
||||||
invoice_by_customer=invoice_by_customer,
|
invoice_by_customer=invoice_by_customer,
|
||||||
|
merge_logs=merge_logs,
|
||||||
now=frappe.conf.developer_mode or frappe.flags.in_test
|
now=frappe.conf.developer_mode or frappe.flags.in_test
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
import json
|
||||||
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
|
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
|
||||||
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
|
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
|
||||||
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
|
||||||
@ -99,4 +100,51 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
|
|||||||
frappe.db.sql("delete from `tabPOS Profile`")
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
frappe.db.sql("delete from `tabPOS Invoice`")
|
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||||
|
|
||||||
|
def test_consolidated_invoice_item_taxes(self):
|
||||||
|
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||||
|
|
||||||
|
try:
|
||||||
|
inv = create_pos_invoice(qty=1, rate=100, do_not_save=True)
|
||||||
|
|
||||||
|
inv.append("taxes", {
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "VAT",
|
||||||
|
"doctype": "Sales Taxes and Charges",
|
||||||
|
"rate": 9
|
||||||
|
})
|
||||||
|
inv.insert()
|
||||||
|
inv.submit()
|
||||||
|
|
||||||
|
inv2 = create_pos_invoice(qty=1, rate=100, do_not_save=True)
|
||||||
|
inv2.get('items')[0].item_code = '_Test Item 2'
|
||||||
|
inv2.append("taxes", {
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "VAT",
|
||||||
|
"doctype": "Sales Taxes and Charges",
|
||||||
|
"rate": 5
|
||||||
|
})
|
||||||
|
inv2.insert()
|
||||||
|
inv2.submit()
|
||||||
|
|
||||||
|
consolidate_pos_invoices()
|
||||||
|
inv.load_from_db()
|
||||||
|
|
||||||
|
consolidated_invoice = frappe.get_doc('Sales Invoice', inv.consolidated_invoice)
|
||||||
|
item_wise_tax_detail = json.loads(consolidated_invoice.get('taxes')[0].item_wise_tax_detail)
|
||||||
|
|
||||||
|
tax_rate, amount = item_wise_tax_detail.get('_Test Item')
|
||||||
|
self.assertEqual(tax_rate, 9)
|
||||||
|
self.assertEqual(amount, 9)
|
||||||
|
|
||||||
|
tax_rate2, amount2 = item_wise_tax_detail.get('_Test Item 2')
|
||||||
|
self.assertEqual(tax_rate2, 5)
|
||||||
|
self.assertEqual(amount2, 5)
|
||||||
|
finally:
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||||
|
|
||||||
|
@ -147,7 +147,9 @@ class calculate_taxes_and_totals(object):
|
|||||||
validate_taxes_and_charges(tax)
|
validate_taxes_and_charges(tax)
|
||||||
validate_inclusive_tax(tax, self.doc)
|
validate_inclusive_tax(tax, self.doc)
|
||||||
|
|
||||||
tax.item_wise_tax_detail = {}
|
if not self.doc.get('is_consolidated'):
|
||||||
|
tax.item_wise_tax_detail = {}
|
||||||
|
|
||||||
tax_fields = ["total", "tax_amount_after_discount_amount",
|
tax_fields = ["total", "tax_amount_after_discount_amount",
|
||||||
"tax_amount_for_current_item", "grand_total_for_current_item",
|
"tax_amount_for_current_item", "grand_total_for_current_item",
|
||||||
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
|
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
|
||||||
@ -338,7 +340,9 @@ class calculate_taxes_and_totals(object):
|
|||||||
current_tax_amount = tax_rate * item.qty
|
current_tax_amount = tax_rate * item.qty
|
||||||
|
|
||||||
current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
|
current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
|
||||||
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
|
|
||||||
|
if not self.doc.get("is_consolidated"):
|
||||||
|
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
|
||||||
|
|
||||||
return current_tax_amount
|
return current_tax_amount
|
||||||
|
|
||||||
@ -440,8 +444,9 @@ class calculate_taxes_and_totals(object):
|
|||||||
self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
|
self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
|
||||||
|
|
||||||
def _cleanup(self):
|
def _cleanup(self):
|
||||||
for tax in self.doc.get("taxes"):
|
if not self.doc.get('is_consolidated'):
|
||||||
tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':'))
|
for tax in self.doc.get("taxes"):
|
||||||
|
tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':'))
|
||||||
|
|
||||||
def set_discount_amount(self):
|
def set_discount_amount(self):
|
||||||
if self.doc.additional_discount_percentage:
|
if self.doc.additional_discount_percentage:
|
||||||
|
@ -59,6 +59,8 @@
|
|||||||
"show_in_website": 1,
|
"show_in_website": 1,
|
||||||
"website_warehouse": "_Test Warehouse - _TC",
|
"website_warehouse": "_Test Warehouse - _TC",
|
||||||
"gst_hsn_code": "999800",
|
"gst_hsn_code": "999800",
|
||||||
|
"opening_stock": 10,
|
||||||
|
"valuation_rate": 100,
|
||||||
"item_defaults": [{
|
"item_defaults": [{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"default_warehouse": "_Test Warehouse - _TC",
|
"default_warehouse": "_Test Warehouse - _TC",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user