Merge branch 'develop' into UAE-VAT-Format

This commit is contained in:
Nabin Hait 2020-10-22 21:44:55 +05:30 committed by GitHub
commit c77ce99ce8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 199 additions and 16 deletions

View File

@ -203,9 +203,39 @@ class TestPurchaseOrder(unittest.TestCase):
frappe.set_user("Administrator")
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"
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", {
@ -237,17 +267,25 @@ class TestPurchaseOrder(unittest.TestCase):
items = json.dumps([
{'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)
po.reload()
self.assertEqual(po.taxes[0].tax_amount, 60)
self.assertEqual(po.taxes[0].total, 660)
self.assertEqual(po.taxes[0].tax_amount, 70)
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
where parent = %(item)s and item_tax_template = %(tax)s""",
{"item": item, "tax": tax_template})
where parent = %(item)s and item_tax_template = %(tax)s""", {"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):
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")

View File

@ -605,8 +605,6 @@ class AccountsController(TransactionBase):
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
if self.is_return: return
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
unlink_ref_doc_from_payment_entries(self)
@ -1170,6 +1168,31 @@ def set_child_tax_template_and_map(item, child_item, parent_doc):
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)
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):
"""
Returns a Sales Order Item child item containing the default values
@ -1185,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"))
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
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)
if not child_item.warehouse:
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
@ -1209,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_amount = 1 # Initiallize value will update in parent validation
set_child_tax_template_and_map(item, child_item, p_doc)
add_taxes_from_tax_template(child_item, p_doc)
return child_item
def validate_and_delete_children(parent, data):

View File

@ -403,7 +403,7 @@ class TestSalesOrder(unittest.TestCase):
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 2, 'docname': so.items[0].name}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
def test_update_child_with_precision(self):
from frappe.model.meta import get_field_precision
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
@ -437,7 +437,7 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
test_user.remove_roles("Accounts User")
frappe.set_user("Administrator")
def test_update_child_qty_rate_with_workflow(self):
from frappe.model.workflow import apply_workflow
@ -506,6 +506,95 @@ class TestSalesOrder(unittest.TestCase):
so.reload()
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):
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")

View File

@ -205,7 +205,9 @@ class StockEntry(StockController):
for f in ("uom", "stock_uom", "description", "item_name", "expense_account",
"cost_center", "conversion_factor"):
if f in ["stock_uom", "conversion_factor"] or not item.get(f):
if f == "stock_uom" or not item.get(f):
item.set(f, item_details.get(f))
if f == 'conversion_factor' and item.uom == item_details.get('stock_uom'):
item.set(f, item_details.get(f))
if not item.transfer_qty and item.qty:

View File

@ -795,6 +795,32 @@ class TestStockEntry(unittest.TestCase):
])
)
def test_conversion_factor_change(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
repack_entry = frappe.copy_doc(test_records[3])
repack_entry.posting_date = nowdate()
repack_entry.posting_time = nowtime()
repack_entry.set_stock_entry_type()
repack_entry.insert()
# check current uom and conversion factor
self.assertTrue(repack_entry.items[0].uom, "_Test UOM")
self.assertTrue(repack_entry.items[0].conversion_factor, 1)
# change conversion factor
repack_entry.items[0].uom = "_Test UOM 1"
repack_entry.items[0].stock_uom = "_Test UOM 1"
repack_entry.items[0].conversion_factor = 2
repack_entry.save()
repack_entry.submit()
self.assertEqual(repack_entry.items[0].conversion_factor, 2)
self.assertEqual(repack_entry.items[0].uom, "_Test UOM 1")
self.assertEqual(repack_entry.items[0].qty, 50)
self.assertEqual(repack_entry.items[0].transfer_qty, 100)
frappe.db.set_default("allow_negative_stock", 0)
def make_serialized_item(**args):
args = frappe._dict(args)
se = frappe.copy_doc(test_records[0])

View File

@ -238,7 +238,6 @@
"oldfieldname": "conversion_factor",
"oldfieldtype": "Currency",
"print_hide": 1,
"read_only": 1,
"reqd": 1
},
{
@ -498,15 +497,14 @@
"depends_on": "eval:parent.purpose===\"Repack\" && doc.t_warehouse",
"fieldname": "set_basic_rate_manually",
"fieldtype": "Check",
"label": "Set Basic Rate Manually",
"show_days": 1,
"show_seconds": 1
"label": "Set Basic Rate Manually"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2020-06-08 12:57:03.172887",
"modified": "2020-09-22 17:55:03.384138",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Detail",

View File

@ -398,6 +398,11 @@ def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
else:
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
def update_barcode_value(out):