From 127c7b93ac75480bf56f1386c4e869a62c8a22ba Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Sat, 29 Mar 2025 15:34:22 +0530 Subject: [PATCH 1/3] fix: map tax table while creating purchase order from sales order (cherry picked from commit 1e18569be7f971ba094bec93839e62eb46a141a3) --- erpnext/selling/doctype/sales_order/sales_order.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 220dafb2e45..f7bf732e8e8 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1427,6 +1427,8 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.customer = target.customer_name = target.shipping_address = None target.run_method("set_missing_values") + if not target.taxes: + target.append_taxes_from_item_tax_template() target.run_method("calculate_taxes_and_totals") def update_item(source, target, source_parent): From 5a20b9e94f5d2f12d8f2c31f30558edb33313e84 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Sat, 29 Mar 2025 15:35:01 +0530 Subject: [PATCH 2/3] test: add unit test to validate tax values in Purchase Order from Sales Order (cherry picked from commit a393195866a681ade86380b88b7a6d544f971799) # Conflicts: # erpnext/selling/doctype/sales_order/test_sales_order.py --- .../doctype/sales_order/test_sales_order.py | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 16c7431c315..32c4398b0d9 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2160,6 +2160,155 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): self.assertRaises(frappe.ValidationError, so1.update_status, "Draft") +<<<<<<< HEAD +======= + @IntegrationTestCase.change_settings("Stock Settings", {"enable_stock_reservation": True}) + def test_warehouse_mapping_based_on_stock_reservation(self): + self.create_company(company_name="Glass Ceiling", abbr="GC") + self.create_item("Lamy Safari 2", True, self.warehouse_stores, self.company, 2000) + self.create_customer() + self.clear_old_entries() + + so = frappe.new_doc("Sales Order") + so.company = self.company + so.customer = self.customer + so.transaction_date = today() + so.append( + "items", + { + "item_code": self.item, + "qty": 10, + "rate": 2000, + "warehouse": self.warehouse_stores, + "delivery_date": today(), + }, + ) + so.submit() + + # Create stock + se = frappe.get_doc( + { + "doctype": "Stock Entry", + "company": self.company, + "stock_entry_type": "Material Receipt", + "posting_date": today(), + "items": [ + {"item_code": self.item, "t_warehouse": self.warehouse_stores, "qty": 5}, + {"item_code": self.item, "t_warehouse": self.warehouse_finished_goods, "qty": 5}, + ], + } + ) + se.submit() + + # Reserve stock on 2 different warehouses + itm = so.items[0] + so.create_stock_reservation_entries( + [ + { + "sales_order_item": itm.name, + "item_code": itm.item_code, + "warehouse": self.warehouse_stores, + "qty_to_reserve": 2, + } + ] + ) + so.create_stock_reservation_entries( + [ + { + "sales_order_item": itm.name, + "item_code": itm.item_code, + "warehouse": self.warehouse_finished_goods, + "qty_to_reserve": 3, + } + ] + ) + + # Delivery note should auto-select warehouse based on reservation + dn = make_delivery_note(so.name, kwargs={"for_reserved_stock": True}) + self.assertEqual(2, len(dn.items)) + self.assertEqual(dn.items[0].qty, 2) + self.assertEqual(dn.items[0].warehouse, self.warehouse_stores) + self.assertEqual(dn.items[1].qty, 3) + self.assertEqual(dn.items[1].warehouse, self.warehouse_finished_goods) + + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + warehouse = create_warehouse("Test Warehouse 1", company=self.company) + + make_stock_entry( + item_code=self.item, + target=warehouse, + qty=5, + company=self.company, + ) + + so = frappe.new_doc("Sales Order") + so.reserve_stock = 1 + so.company = self.company + so.customer = self.customer + so.transaction_date = today() + so.currency = "INR" + so.append( + "items", + { + "item_code": self.item, + "qty": 5, + "rate": 2000, + "warehouse": warehouse, + "delivery_date": today(), + }, + ) + so.submit() + + sres = frappe.get_all( + "Stock Reservation Entry", + filters={"voucher_no": so.name}, + fields=["name"], + ) + + self.assertEqual(len(sres), 1) + sre_doc = frappe.get_doc("Stock Reservation Entry", sres[0].name) + self.assertFalse(sre_doc.status == "Delivered") + + si = make_sales_invoice(so.name) + si.update_stock = 1 + si.submit() + sre_doc.reload() + self.assertTrue(sre_doc.status == "Delivered") + + def test_item_tax_transfer_from_sales_to_purchase(self): + from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order + + item_tax = frappe.new_doc("Item Tax Template") + item_tax.title = "Test Item Tax Template" + item_tax.company = "_Test Company" + item_tax.append("taxes", {"tax_type": "_Test Account Service Tax - _TC", "tax_rate": 2}) + item_tax.save() + + item_group = frappe.get_doc("Item Group", "_Test Item Group") + item_group.append("taxes", {"item_tax_template": "Test Item Tax Template - _TC"}) + item_group.save() + + so = make_sales_order(item_code="_Test Item", qty=1, do_not_submit=1) + so.append( + "taxes", + { + "account_head": "_Test Account Service Tax - _TC", + "charge_type": "On Net Total", + "description": "TDS", + "doctype": "Sales Taxes and Charges", + "rate": 2, + }, + ) + so.submit() + + po = make_purchase_order(so.name, selected_items=so.items) + po.supplier = "_Test Supplier" + po.items[0].rate = 100 + po.submit() + self.assertEqual(po.taxes[0].tax_amount, 2) + +>>>>>>> a393195866 (test: add unit test to validate tax values in Purchase Order from Sales Order) def automatically_fetch_payment_terms(enable=1): accounts_settings = frappe.get_doc("Accounts Settings") From b7cbc66a28fd10269dbcca1c6fafe09913c99a30 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 15 Apr 2025 11:45:17 +0530 Subject: [PATCH 3/3] chore: resolve conflict --- .../doctype/sales_order/test_sales_order.py | 117 ------------------ 1 file changed, 117 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 32c4398b0d9..82a8535a66d 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2160,122 +2160,6 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): self.assertRaises(frappe.ValidationError, so1.update_status, "Draft") -<<<<<<< HEAD -======= - @IntegrationTestCase.change_settings("Stock Settings", {"enable_stock_reservation": True}) - def test_warehouse_mapping_based_on_stock_reservation(self): - self.create_company(company_name="Glass Ceiling", abbr="GC") - self.create_item("Lamy Safari 2", True, self.warehouse_stores, self.company, 2000) - self.create_customer() - self.clear_old_entries() - - so = frappe.new_doc("Sales Order") - so.company = self.company - so.customer = self.customer - so.transaction_date = today() - so.append( - "items", - { - "item_code": self.item, - "qty": 10, - "rate": 2000, - "warehouse": self.warehouse_stores, - "delivery_date": today(), - }, - ) - so.submit() - - # Create stock - se = frappe.get_doc( - { - "doctype": "Stock Entry", - "company": self.company, - "stock_entry_type": "Material Receipt", - "posting_date": today(), - "items": [ - {"item_code": self.item, "t_warehouse": self.warehouse_stores, "qty": 5}, - {"item_code": self.item, "t_warehouse": self.warehouse_finished_goods, "qty": 5}, - ], - } - ) - se.submit() - - # Reserve stock on 2 different warehouses - itm = so.items[0] - so.create_stock_reservation_entries( - [ - { - "sales_order_item": itm.name, - "item_code": itm.item_code, - "warehouse": self.warehouse_stores, - "qty_to_reserve": 2, - } - ] - ) - so.create_stock_reservation_entries( - [ - { - "sales_order_item": itm.name, - "item_code": itm.item_code, - "warehouse": self.warehouse_finished_goods, - "qty_to_reserve": 3, - } - ] - ) - - # Delivery note should auto-select warehouse based on reservation - dn = make_delivery_note(so.name, kwargs={"for_reserved_stock": True}) - self.assertEqual(2, len(dn.items)) - self.assertEqual(dn.items[0].qty, 2) - self.assertEqual(dn.items[0].warehouse, self.warehouse_stores) - self.assertEqual(dn.items[1].qty, 3) - self.assertEqual(dn.items[1].warehouse, self.warehouse_finished_goods) - - from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse - - warehouse = create_warehouse("Test Warehouse 1", company=self.company) - - make_stock_entry( - item_code=self.item, - target=warehouse, - qty=5, - company=self.company, - ) - - so = frappe.new_doc("Sales Order") - so.reserve_stock = 1 - so.company = self.company - so.customer = self.customer - so.transaction_date = today() - so.currency = "INR" - so.append( - "items", - { - "item_code": self.item, - "qty": 5, - "rate": 2000, - "warehouse": warehouse, - "delivery_date": today(), - }, - ) - so.submit() - - sres = frappe.get_all( - "Stock Reservation Entry", - filters={"voucher_no": so.name}, - fields=["name"], - ) - - self.assertEqual(len(sres), 1) - sre_doc = frappe.get_doc("Stock Reservation Entry", sres[0].name) - self.assertFalse(sre_doc.status == "Delivered") - - si = make_sales_invoice(so.name) - si.update_stock = 1 - si.submit() - sre_doc.reload() - self.assertTrue(sre_doc.status == "Delivered") - def test_item_tax_transfer_from_sales_to_purchase(self): from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order @@ -2308,7 +2192,6 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): po.submit() self.assertEqual(po.taxes[0].tax_amount, 2) ->>>>>>> a393195866 (test: add unit test to validate tax values in Purchase Order from Sales Order) def automatically_fetch_payment_terms(enable=1): accounts_settings = frappe.get_doc("Accounts Settings")