Merge pull request #40878 from ruthra-kumar/merge_taxes_from_DN_to_sales_invoice
refactor: merge taxes from delivery note to Sales Invoice
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 2e28b76..2f7159f 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -3632,6 +3632,105 @@
self.assertEqual(1, len(advances))
self.assertEqual(advances[0].reference_name, pe.name)
+ def test_taxes_merging_from_delivery_note(self):
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+ dn1 = create_delivery_note(do_not_submit=1)
+ dn1.items[0].qty = 10
+ dn1.items[0].rate = 100
+ dn1.append(
+ "taxes",
+ {
+ "charge_type": "Actual",
+ "account_head": "Freight and Forwarding Charges - _TC",
+ "description": "movement charges",
+ "tax_amount": 100,
+ },
+ )
+ dn1.append(
+ "taxes",
+ {
+ "charge_type": "Actual",
+ "account_head": "Marketing Expenses - _TC",
+ "description": "marketing",
+ "tax_amount": 150,
+ },
+ )
+ dn1.save().submit()
+
+ dn2 = create_delivery_note(do_not_submit=1)
+ dn2.items[0].qty = 5
+ dn2.items[0].rate = 100
+ dn2.append(
+ "taxes",
+ {
+ "charge_type": "Actual",
+ "account_head": "Freight and Forwarding Charges - _TC",
+ "description": "movement charges",
+ "tax_amount": 20,
+ },
+ )
+ dn2.append(
+ "taxes",
+ {
+ "charge_type": "Actual",
+ "account_head": "Miscellaneous Expenses - _TC",
+ "description": "marketing",
+ "tax_amount": 60,
+ },
+ )
+ dn2.save().submit()
+
+ # si = make_sales_invoice(dn1.name)
+ si = create_sales_invoice(do_not_submit=True)
+ si.customer = dn1.customer
+ si.items.clear()
+
+ from frappe.model.mapper import map_docs
+
+ map_docs(
+ method="erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
+ source_names=frappe.json.dumps([dn1.name, dn2.name]),
+ target_doc=si,
+ args=frappe.json.dumps({"customer": dn1.customer, "merge_taxes": 1, "filtered_children": []}),
+ )
+ si.save().submit()
+
+ expected = [
+ {
+ "charge_type": "Actual",
+ "account_head": "Freight and Forwarding Charges - _TC",
+ "tax_amount": 120.0,
+ "total": 1520.0,
+ "base_total": 1520.0,
+ },
+ {
+ "charge_type": "Actual",
+ "account_head": "Marketing Expenses - _TC",
+ "tax_amount": 150.0,
+ "total": 1670.0,
+ "base_total": 1670.0,
+ },
+ {
+ "charge_type": "Actual",
+ "account_head": "Miscellaneous Expenses - _TC",
+ "tax_amount": 60.0,
+ "total": 1610.0,
+ "base_total": 1610.0,
+ },
+ ]
+ actual = [
+ dict(
+ charge_type=x.charge_type,
+ account_head=x.account_head,
+ tax_amount=x.tax_amount,
+ total=x.total,
+ base_total=x.base_total,
+ )
+ for x in si.taxes
+ ]
+ self.assertEqual(expected, actual)
+
def set_advance_flag(company, flag, default_account):
frappe.db.set_value(
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c9e8e4e..883563c 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -3521,6 +3521,37 @@
return False
+def merge_taxes(source_taxes, target_doc):
+ from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import (
+ update_item_wise_tax_detail,
+ )
+
+ existing_taxes = target_doc.get("taxes") or []
+ idx = 1
+ for tax in source_taxes:
+ found = False
+ for t in existing_taxes:
+ 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.idx = idx
+ idx += 1
+ tax.included_in_print_rate = 0
+ tax.dont_recompute_tax = 1
+ tax.row_id = ""
+ 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
+ existing_taxes.append(tax)
+
+ target_doc.set("taxes", existing_taxes)
+
+
@erpnext.allow_regional
def validate_regional(doc):
pass
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index a1b181f..4127218 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -934,7 +934,7 @@
if (opts.source_doctype) {
let data_fields = [];
- if (opts.source_doctype == "Purchase Receipt") {
+ if (["Purchase Receipt", "Delivery Note"].includes(opts.source_doctype)) {
data_fields.push({
fieldname: "merge_taxes",
fieldtype: "Check",
@@ -960,7 +960,10 @@
return;
}
opts.source_name = values;
- if (opts.allow_child_item_selection || opts.source_doctype == "Purchase Receipt") {
+ if (
+ opts.allow_child_item_selection ||
+ ["Purchase Receipt", "Delivery Note"].includes(opts.source_doctype)
+ ) {
// args contains filtered child docnames
opts.args = args;
}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 9561e47..771cecc 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -10,7 +10,7 @@
from frappe.model.utils import get_fetch_values
from frappe.utils import cint, flt
-from erpnext.controllers.accounts_controller import get_taxes_and_charges
+from erpnext.controllers.accounts_controller import get_taxes_and_charges, merge_taxes
from erpnext.controllers.selling_controller import SellingController
from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no
@@ -960,7 +960,7 @@
@frappe.whitelist()
-def make_sales_invoice(source_name, target_doc=None):
+def make_sales_invoice(source_name, target_doc=None, args=None):
doc = frappe.get_doc("Delivery Note", source_name)
to_make_invoice_qty_map = {}
@@ -974,6 +974,9 @@
if len(target.get("items")) == 0:
frappe.throw(_("All these items have already been Invoiced/Returned"))
+ if args and args.get("merge_taxes"):
+ merge_taxes(source.get("taxes") or [], target)
+
target.run_method("calculate_taxes_and_totals")
# set company address
@@ -1038,7 +1041,11 @@
if not doc.get("is_return")
else get_pending_qty(d) > 0,
},
- "Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "add_if_empty": True},
+ "Sales Taxes and Charges": {
+ "doctype": "Sales Taxes and Charges",
+ "add_if_empty": True,
+ "ignore": args.get("merge_taxes") if args else 0,
+ },
"Sales Team": {
"doctype": "Sales Team",
"field_map": {"incentives": "incentives"},
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 0eb42b1..ae101df 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -15,6 +15,7 @@
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.buying.utils import check_on_hold_or_closed_status
+from erpnext.controllers.accounts_controller import merge_taxes
from erpnext.controllers.buying_controller import BuyingController
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_transaction
@@ -1123,37 +1124,6 @@
)
-def merge_taxes(source_taxes, target_doc):
- from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import (
- update_item_wise_tax_detail,
- )
-
- existing_taxes = target_doc.get("taxes") or []
- idx = 1
- for tax in source_taxes:
- found = False
- for t in existing_taxes:
- 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.idx = idx
- idx += 1
- tax.included_in_print_rate = 0
- tax.dont_recompute_tax = 1
- tax.row_id = ""
- 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
- existing_taxes.append(tax)
-
- target_doc.set("taxes", existing_taxes)
-
-
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None, args=None):
from erpnext.accounts.party import get_payment_terms_template