Merge pull request #36780 from rtdany10/rounded-row-wise-tax
feat: item(row) wise tax amount rounding
diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py
index a910af6..efeaeed 100644
--- a/erpnext/regional/united_arab_emirates/utils.py
+++ b/erpnext/regional/united_arab_emirates/utils.py
@@ -7,32 +7,32 @@
def update_itemised_tax_data(doc):
+ # maybe this should be a standard function rather than a regional one
if not doc.taxes:
return
+ if not doc.items:
+ return
+
+ meta = frappe.get_meta(doc.items[0].doctype)
+ if not meta.has_field("tax_rate"):
+ return
+
itemised_tax = get_itemised_tax(doc.taxes)
for row in doc.items:
- tax_rate = 0.0
- item_tax_rate = 0.0
+ tax_rate, tax_amount = 0.0, 0.0
+ # dont even bother checking in item tax template as it contains both input and output accounts - double the tax rate
+ item_code = row.item_code or row.item_name
+ if itemised_tax.get(item_code):
+ for tax in itemised_tax.get(row.item_code).values():
+ _tax_rate = flt(tax.get("tax_rate", 0), row.precision("tax_rate"))
+ tax_amount += flt((row.net_amount * _tax_rate) / 100, row.precision("tax_amount"))
+ tax_rate += _tax_rate
- if row.item_tax_rate:
- item_tax_rate = frappe.parse_json(row.item_tax_rate)
-
- # First check if tax rate is present
- # If not then look up in item_wise_tax_detail
- if item_tax_rate:
- for account, rate in item_tax_rate.items():
- tax_rate += rate
- elif row.item_code and itemised_tax.get(row.item_code):
- tax_rate = sum([tax.get("tax_rate", 0) for d, tax in itemised_tax.get(row.item_code).items()])
-
- meta = frappe.get_meta(row.doctype)
-
- if meta.has_field("tax_rate"):
- row.tax_rate = flt(tax_rate, row.precision("tax_rate"))
- row.tax_amount = flt((row.net_amount * tax_rate) / 100, row.precision("net_amount"))
- row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
+ row.tax_rate = flt(tax_rate, row.precision("tax_rate"))
+ row.tax_amount = flt(tax_amount, row.precision("tax_amount"))
+ row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))
def get_account_currency(account):
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index aae0fee..b91002e 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -606,29 +606,37 @@
def get_requested_item_qty(sales_order):
- return frappe._dict(
- frappe.db.sql(
- """
- select sales_order_item, sum(qty)
- from `tabMaterial Request Item`
- where docstatus = 1
- and sales_order = %s
- group by sales_order_item
- """,
- sales_order,
- )
- )
+ result = {}
+ for d in frappe.db.get_all(
+ "Material Request Item",
+ filters={"docstatus": 1, "sales_order": sales_order},
+ fields=["sales_order_item", "sum(qty) as qty", "sum(received_qty) as received_qty"],
+ group_by="sales_order_item",
+ ):
+ result[d.sales_order_item] = frappe._dict({"qty": d.qty, "received_qty": d.received_qty})
+
+ return result
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):
requested_item_qty = get_requested_item_qty(source_name)
+ def get_remaining_qty(so_item):
+ return flt(
+ flt(so_item.qty)
+ - flt(requested_item_qty.get(so_item.name, {}).get("qty"))
+ - max(
+ flt(so_item.get("delivered_qty"))
+ - flt(requested_item_qty.get(so_item.name, {}).get("received_qty")),
+ 0,
+ )
+ )
+
def update_item(source, target, source_parent):
# qty is for packed items, because packed items don't have stock_qty field
- qty = source.get("qty")
target.project = source_parent.project
- target.qty = qty - requested_item_qty.get(source.name, 0) - flt(source.get("delivered_qty"))
+ target.qty = get_remaining_qty(source)
target.stock_qty = flt(target.qty) * flt(target.conversion_factor)
args = target.as_dict().copy()
@@ -661,8 +669,8 @@
"Sales Order Item": {
"doctype": "Material Request Item",
"field_map": {"name": "sales_order_item", "parent": "sales_order"},
- "condition": lambda doc: not frappe.db.exists("Product Bundle", doc.item_code)
- and (doc.stock_qty - flt(doc.get("delivered_qty"))) > requested_item_qty.get(doc.name, 0),
+ "condition": lambda item: not frappe.db.exists("Product Bundle", item.item_code)
+ and get_remaining_qty(item) > 0,
"postprocess": update_item,
},
},