From 5f3d7f547c2c0cadca23d007f296c370ef37a98c Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 12 Apr 2021 10:56:47 +0530 Subject: [PATCH] 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 --- .../pos_invoice_merge_log.py | 34 +++++++++++-- .../test_pos_invoice_merge_log.py | 48 +++++++++++++++++++ erpnext/controllers/taxes_and_totals.py | 13 +++-- erpnext/stock/doctype/item/test_records.json | 2 + 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index 40f77b4088..2f5ee01baf 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -12,6 +12,7 @@ from frappe.utils.background_jobs import enqueue from frappe.model.mapper import map_doc, map_child_doc from frappe.utils.scheduler import is_scheduler_inactive from frappe.core.page.background_jobs.background_jobs import get_info +import json 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: 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) + update_item_wise_tax_detail(t, tax) found = True if not found: tax.charge_type = 'Actual' tax.included_in_print_rate = 0 tax.tax_amount = tax.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) for payment in doc.get('payments'): @@ -172,7 +175,7 @@ class POSInvoiceMergeLog(Document): sales_invoice.posting_date = getdate(nowdate()) return sales_invoice - + def update_pos_invoices(self, invoice_docs, sales_invoice='', credit_note=''): for doc in invoice_docs: doc.load_from_db() @@ -187,6 +190,26 @@ class POSInvoiceMergeLog(Document): si.flags.ignore_validate = True 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(): filters = { 'consolidated_invoice': [ 'in', [ '', None ]], @@ -214,7 +237,7 @@ def consolidate_pos_invoices(pos_invoices=[], closing_entry={}): if len(invoices) >= 5 and closing_entry: 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: create_merge_logs(invoice_by_customer, closing_entry) @@ -227,7 +250,7 @@ def unconsolidate_pos_invoices(closing_entry): if len(merge_logs) >= 5: 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: cancel_merge_logs(merge_logs, closing_entry) @@ -241,7 +264,7 @@ def create_merge_logs(invoice_by_customer, closing_entry={}): merge_log.set('pos_invoices', invoices) merge_log.save(ignore_permissions=True) merge_log.submit() - + if closing_entry: closing_entry.set_status(update=True, status='Submitted') closing_entry.update_opening_entry() @@ -256,7 +279,7 @@ def cancel_merge_logs(merge_logs, closing_entry={}): closing_entry.set_status(update=True, status='Cancelled') 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() job_name = closing_entry.get("name") @@ -269,6 +292,7 @@ def enqueue_job(job, invoice_by_customer, closing_entry): job_name=job_name, closing_entry=closing_entry, invoice_by_customer=invoice_by_customer, + merge_logs=merge_logs, now=frappe.conf.developer_mode or frappe.flags.in_test ) diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py index d880caa3c7..040a815fab 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe import unittest +import json 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_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 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`") diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 5f73c55836..7653a5dfdc 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -147,7 +147,9 @@ class calculate_taxes_and_totals(object): validate_taxes_and_charges(tax) 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_amount_for_current_item", "grand_total_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 = 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 @@ -440,8 +444,9 @@ class calculate_taxes_and_totals(object): self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"]) def _cleanup(self): - for tax in self.doc.get("taxes"): - tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(',', ':')) + if not self.doc.get('is_consolidated'): + 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): if self.doc.additional_discount_percentage: diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json index c1f20a47b7..6cec85288f 100644 --- a/erpnext/stock/doctype/item/test_records.json +++ b/erpnext/stock/doctype/item/test_records.json @@ -59,6 +59,8 @@ "show_in_website": 1, "website_warehouse": "_Test Warehouse - _TC", "gst_hsn_code": "999800", + "opening_stock": 10, + "valuation_rate": 100, "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC",