fix: Add Taxes if missing via Update Items (#23702)
* fix: Add Taxes if missing via Update Items * chore: PO Test for adding tax row via Update Items * chore: SO Test for adding tax row via Update Items
This commit is contained in:
parent
e3ad5f0bc3
commit
3b1be2b1de
@ -203,9 +203,39 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
|
|
||||||
def test_update_child_with_tax_template(self):
|
def test_update_child_with_tax_template(self):
|
||||||
|
"""
|
||||||
|
Test Action: Create a PO with one item having its tax account head already in the PO.
|
||||||
|
Add the same item + new item with tax template via Update Items.
|
||||||
|
Expected result: First Item's tax row is updated. New tax row is added for second Item.
|
||||||
|
"""
|
||||||
|
if not frappe.db.exists("Item", "Test Item with Tax"):
|
||||||
|
make_item("Test Item with Tax", {
|
||||||
|
'is_stock_item': 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not frappe.db.exists("Item Tax Template", {"title": 'Test Update Items Template'}):
|
||||||
|
frappe.get_doc({
|
||||||
|
'doctype': 'Item Tax Template',
|
||||||
|
'title': 'Test Update Items Template',
|
||||||
|
'company': '_Test Company',
|
||||||
|
'taxes': [
|
||||||
|
{
|
||||||
|
'tax_type': "_Test Account Service Tax - _TC",
|
||||||
|
'tax_rate': 10,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
new_item_with_tax = frappe.get_doc("Item", "Test Item with Tax")
|
||||||
|
|
||||||
|
new_item_with_tax.append("taxes", {
|
||||||
|
"item_tax_template": "Test Update Items Template",
|
||||||
|
"valid_from": nowdate()
|
||||||
|
})
|
||||||
|
new_item_with_tax.save()
|
||||||
|
|
||||||
tax_template = "_Test Account Excise Duty @ 10"
|
tax_template = "_Test Account Excise Duty @ 10"
|
||||||
item = "_Test Item Home Desktop 100"
|
item = "_Test Item Home Desktop 100"
|
||||||
|
|
||||||
if not frappe.db.exists("Item Tax", {"parent":item, "item_tax_template":tax_template}):
|
if not frappe.db.exists("Item Tax", {"parent":item, "item_tax_template":tax_template}):
|
||||||
item_doc = frappe.get_doc("Item", item)
|
item_doc = frappe.get_doc("Item", item)
|
||||||
item_doc.append("taxes", {
|
item_doc.append("taxes", {
|
||||||
@ -237,17 +267,25 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
|
|
||||||
items = json.dumps([
|
items = json.dumps([
|
||||||
{'item_code' : item, 'rate' : 500, 'qty' : 1, 'docname': po.items[0].name},
|
{'item_code' : item, 'rate' : 500, 'qty' : 1, 'docname': po.items[0].name},
|
||||||
{'item_code' : item, 'rate' : 100, 'qty' : 1} # added item
|
{'item_code' : item, 'rate' : 100, 'qty' : 1}, # added item whose tax account head already exists in PO
|
||||||
|
{'item_code' : new_item_with_tax.name, 'rate' : 100, 'qty' : 1} # added item whose tax account head is missing in PO
|
||||||
])
|
])
|
||||||
update_child_qty_rate('Purchase Order', items, po.name)
|
update_child_qty_rate('Purchase Order', items, po.name)
|
||||||
|
|
||||||
po.reload()
|
po.reload()
|
||||||
self.assertEqual(po.taxes[0].tax_amount, 60)
|
self.assertEqual(po.taxes[0].tax_amount, 70)
|
||||||
self.assertEqual(po.taxes[0].total, 660)
|
self.assertEqual(po.taxes[0].total, 770)
|
||||||
|
self.assertEqual(po.taxes[1].account_head, "_Test Account Service Tax - _TC")
|
||||||
|
self.assertEqual(po.taxes[1].tax_amount, 70)
|
||||||
|
self.assertEqual(po.taxes[1].total, 840)
|
||||||
|
|
||||||
|
# teardown
|
||||||
frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = NULL
|
frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = NULL
|
||||||
where parent = %(item)s and item_tax_template = %(tax)s""",
|
where parent = %(item)s and item_tax_template = %(tax)s""", {"item": item, "tax": tax_template})
|
||||||
{"item": item, "tax": tax_template})
|
po.cancel()
|
||||||
|
po.delete()
|
||||||
|
new_item_with_tax.delete()
|
||||||
|
frappe.get_doc("Item Tax Template", "Test Update Items Template").delete()
|
||||||
|
|
||||||
def test_update_child_uom_conv_factor_change(self):
|
def test_update_child_uom_conv_factor_change(self):
|
||||||
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
|
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
|
||||||
|
@ -1168,6 +1168,31 @@ def set_child_tax_template_and_map(item, child_item, parent_doc):
|
|||||||
if child_item.get("item_tax_template"):
|
if child_item.get("item_tax_template"):
|
||||||
child_item.item_tax_rate = get_item_tax_map(parent_doc.get('company'), child_item.item_tax_template, as_json=True)
|
child_item.item_tax_rate = get_item_tax_map(parent_doc.get('company'), child_item.item_tax_template, as_json=True)
|
||||||
|
|
||||||
|
def add_taxes_from_tax_template(child_item, parent_doc):
|
||||||
|
add_taxes_from_item_tax_template = frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template")
|
||||||
|
|
||||||
|
if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template:
|
||||||
|
tax_map = json.loads(child_item.get("item_tax_rate"))
|
||||||
|
for tax_type in tax_map:
|
||||||
|
tax_rate = flt(tax_map[tax_type])
|
||||||
|
taxes = parent_doc.get('taxes') or []
|
||||||
|
# add new row for tax head only if missing
|
||||||
|
found = any(tax.account_head == tax_type for tax in taxes)
|
||||||
|
if not found:
|
||||||
|
tax_row = parent_doc.append("taxes", {})
|
||||||
|
tax_row.update({
|
||||||
|
"description" : str(tax_type).split(' - ')[0],
|
||||||
|
"charge_type" : "On Net Total",
|
||||||
|
"account_head" : tax_type,
|
||||||
|
"rate" : tax_rate
|
||||||
|
})
|
||||||
|
if parent_doc.doctype == "Purchase Order":
|
||||||
|
tax_row.update({
|
||||||
|
"category" : "Total",
|
||||||
|
"add_deduct_tax" : "Add"
|
||||||
|
})
|
||||||
|
tax_row.db_insert()
|
||||||
|
|
||||||
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
|
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
|
||||||
"""
|
"""
|
||||||
Returns a Sales Order Item child item containing the default values
|
Returns a Sales Order Item child item containing the default values
|
||||||
@ -1183,6 +1208,7 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname,
|
|||||||
conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
|
conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
|
||||||
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
|
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
|
||||||
set_child_tax_template_and_map(item, child_item, p_doc)
|
set_child_tax_template_and_map(item, child_item, p_doc)
|
||||||
|
add_taxes_from_tax_template(child_item, p_doc)
|
||||||
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
||||||
if not child_item.warehouse:
|
if not child_item.warehouse:
|
||||||
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
|
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
|
||||||
@ -1207,6 +1233,7 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna
|
|||||||
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
||||||
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
||||||
set_child_tax_template_and_map(item, child_item, p_doc)
|
set_child_tax_template_and_map(item, child_item, p_doc)
|
||||||
|
add_taxes_from_tax_template(child_item, p_doc)
|
||||||
return child_item
|
return child_item
|
||||||
|
|
||||||
def validate_and_delete_children(parent, data):
|
def validate_and_delete_children(parent, data):
|
||||||
|
@ -506,6 +506,95 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
so.reload()
|
so.reload()
|
||||||
self.assertEqual(so.packed_items[0].qty, 8)
|
self.assertEqual(so.packed_items[0].qty, 8)
|
||||||
|
|
||||||
|
def test_update_child_with_tax_template(self):
|
||||||
|
"""
|
||||||
|
Test Action: Create a SO with one item having its tax account head already in the SO.
|
||||||
|
Add the same item + new item with tax template via Update Items.
|
||||||
|
Expected result: First Item's tax row is updated. New tax row is added for second Item.
|
||||||
|
"""
|
||||||
|
if not frappe.db.exists("Item", "Test Item with Tax"):
|
||||||
|
make_item("Test Item with Tax", {
|
||||||
|
'is_stock_item': 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not frappe.db.exists("Item Tax Template", {"title": 'Test Update Items Template'}):
|
||||||
|
frappe.get_doc({
|
||||||
|
'doctype': 'Item Tax Template',
|
||||||
|
'title': 'Test Update Items Template',
|
||||||
|
'company': '_Test Company',
|
||||||
|
'taxes': [
|
||||||
|
{
|
||||||
|
'tax_type': "_Test Account Service Tax - _TC",
|
||||||
|
'tax_rate': 10,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
new_item_with_tax = frappe.get_doc("Item", "Test Item with Tax")
|
||||||
|
|
||||||
|
new_item_with_tax.append("taxes", {
|
||||||
|
"item_tax_template": "Test Update Items Template",
|
||||||
|
"valid_from": nowdate()
|
||||||
|
})
|
||||||
|
new_item_with_tax.save()
|
||||||
|
|
||||||
|
tax_template = "_Test Account Excise Duty @ 10"
|
||||||
|
item = "_Test Item Home Desktop 100"
|
||||||
|
if not frappe.db.exists("Item Tax", {"parent":item, "item_tax_template":tax_template}):
|
||||||
|
item_doc = frappe.get_doc("Item", item)
|
||||||
|
item_doc.append("taxes", {
|
||||||
|
"item_tax_template": tax_template,
|
||||||
|
"valid_from": nowdate()
|
||||||
|
})
|
||||||
|
item_doc.save()
|
||||||
|
else:
|
||||||
|
# update valid from
|
||||||
|
frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = CURDATE()
|
||||||
|
where parent = %(item)s and item_tax_template = %(tax)s""",
|
||||||
|
{"item": item, "tax": tax_template})
|
||||||
|
|
||||||
|
so = make_sales_order(item_code=item, qty=1, do_not_save=1)
|
||||||
|
|
||||||
|
so.append("taxes", {
|
||||||
|
"account_head": "_Test Account Excise Duty - _TC",
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "Excise Duty",
|
||||||
|
"doctype": "Sales Taxes and Charges",
|
||||||
|
"rate": 10
|
||||||
|
})
|
||||||
|
so.insert()
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
self.assertEqual(so.taxes[0].tax_amount, 10)
|
||||||
|
self.assertEqual(so.taxes[0].total, 110)
|
||||||
|
|
||||||
|
old_stock_settings_value = frappe.db.get_single_value("Stock Settings", "default_warehouse")
|
||||||
|
frappe.db.set_value("Stock Settings", None, "default_warehouse", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
items = json.dumps([
|
||||||
|
{'item_code' : item, 'rate' : 100, 'qty' : 1, 'docname': so.items[0].name},
|
||||||
|
{'item_code' : item, 'rate' : 200, 'qty' : 1}, # added item whose tax account head already exists in PO
|
||||||
|
{'item_code' : new_item_with_tax.name, 'rate' : 100, 'qty' : 1} # added item whose tax account head is missing in PO
|
||||||
|
])
|
||||||
|
update_child_qty_rate('Sales Order', items, so.name)
|
||||||
|
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(so.taxes[0].tax_amount, 40)
|
||||||
|
self.assertEqual(so.taxes[0].total, 440)
|
||||||
|
self.assertEqual(so.taxes[1].account_head, "_Test Account Service Tax - _TC")
|
||||||
|
self.assertEqual(so.taxes[1].tax_amount, 40)
|
||||||
|
self.assertEqual(so.taxes[1].total, 480)
|
||||||
|
|
||||||
|
# teardown
|
||||||
|
frappe.db.sql("""UPDATE `tabItem Tax` set valid_from = NULL
|
||||||
|
where parent = %(item)s and item_tax_template = %(tax)s""", {"item": item, "tax": tax_template})
|
||||||
|
so.cancel()
|
||||||
|
so.delete()
|
||||||
|
new_item_with_tax.delete()
|
||||||
|
frappe.get_doc("Item Tax Template", "Test Update Items Template").delete()
|
||||||
|
frappe.db.set_value("Stock Settings", None, "default_warehouse", old_stock_settings_value)
|
||||||
|
|
||||||
def test_warehouse_user(self):
|
def test_warehouse_user(self):
|
||||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
|
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
|
||||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
|
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
|
||||||
|
@ -398,6 +398,11 @@ def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
|
|||||||
else:
|
else:
|
||||||
warehouse = args.get('warehouse')
|
warehouse = args.get('warehouse')
|
||||||
|
|
||||||
|
if not warehouse:
|
||||||
|
default_warehouse = frappe.db.get_single_value("Stock Settings", "default_warehouse")
|
||||||
|
if frappe.db.get_value("Warehouse", default_warehouse, "company") == args.company:
|
||||||
|
return default_warehouse
|
||||||
|
|
||||||
return warehouse
|
return warehouse
|
||||||
|
|
||||||
def update_barcode_value(out):
|
def update_barcode_value(out):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user