From b1e205f4d19d1aa6deca1718a5932cdf56b601b3 Mon Sep 17 00:00:00 2001 From: Ninad1306 Date: Thu, 7 Nov 2024 16:34:14 +0530 Subject: [PATCH 01/20] fix: subcontracting receipt has no reference field for purchase order --- .../buying/doctype/purchase_order/purchase_order_dashboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py index 958d277bb84..3d7102cccae 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py @@ -32,7 +32,7 @@ def get_data(): }, { "label": _("Sub-contracting"), - "items": ["Subcontracting Order", "Subcontracting Receipt", "Stock Entry"], + "items": ["Subcontracting Order", "Stock Entry"], }, {"label": _("Internal"), "items": ["Sales Order"]}, ], From 1446aa3636f3d3814d973036de9c57da03b6d8ee Mon Sep 17 00:00:00 2001 From: "bhaveshkumar.j" Date: Mon, 21 Oct 2024 18:47:20 +0000 Subject: [PATCH 02/20] fix: NoneType while updating ordered_qty in SO for removed items (cherry picked from commit 442cdd7ce49ccbaff855bfac71f3222bc83b7d49) --- erpnext/buying/doctype/purchase_order/purchase_order.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 705e8fd6dd8..a828c117edb 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -456,9 +456,11 @@ class PurchaseOrder(BuyingController): if not self.is_against_so(): return for item in removed_items: - prev_ordered_qty = frappe.get_cached_value( - "Sales Order Item", item.get("sales_order_item"), "ordered_qty" + prev_ordered_qty = ( + frappe.get_cached_value("Sales Order Item", item.get("sales_order_item"), "ordered_qty") + or 0.0 ) + frappe.db.set_value( "Sales Order Item", item.get("sales_order_item"), "ordered_qty", prev_ordered_qty - item.qty ) From 440ada1bdc7f10ce8191a6269e4b583756d09295 Mon Sep 17 00:00:00 2001 From: Ravindu Nethmina <117300601+NethminaHiker360@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:08:32 +0000 Subject: [PATCH 03/20] refactor: add "margin_type" and "margin_rate_or_amount" to no copy (cherry picked from commit 70f090c1ec3be1b904b19801b47dac16ed4a8775) --- 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 293066cde38..9479d4669d0 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1035,6 +1035,8 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t "discount_percentage", "discount_amount", "pricing_rules", + "margin_type", + "margin_rate_or_amount", ], "postprocess": update_item, "condition": lambda doc: doc.ordered_qty < doc.stock_qty From d73cc83b9167905d3bff1712a1586b56018a7c3b Mon Sep 17 00:00:00 2001 From: vishnu Date: Sun, 10 Nov 2024 06:55:16 +0000 Subject: [PATCH 04/20] fix: tyeerror while saving pick list (cherry picked from commit 22de0ecbdcb34ffde91b0788c66e6bb8beb18a17) --- erpnext/stock/doctype/pick_list/pick_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index aa25d625ffe..948437a8287 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -61,7 +61,7 @@ class PickList(Document): "actual_qty", ) - if row.qty > bin_qty: + if row.qty > flt(bin_qty): frappe.throw( _( "At Row #{0}: The picked quantity {1} for the item {2} is greater than available stock {3} in the warehouse {4}." From c12d5f613adcd27ba6865eb3e1a3a108ca8f4064 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:00:43 +0530 Subject: [PATCH 05/20] fix: task path (backport #44073) (#44077) fix: task path (#44073) (cherry picked from commit 8c99acb1b905d57515c42db3e24d480f96048aa1) Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com> --- erpnext/projects/doctype/task/task.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index b051494a651..481c64a39c0 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -118,14 +118,14 @@ class Task(NestedSet): def validate_parent_template_task(self): if self.parent_task: if not frappe.db.get_value("Task", self.parent_task, "is_template"): - parent_task_format = f"""{self.parent_task}""" + parent_task_format = f"""{self.parent_task}""" frappe.throw(_("Parent Task {0} is not a Template Task").format(parent_task_format)) def validate_depends_on_tasks(self): if self.depends_on: for task in self.depends_on: if not frappe.db.get_value("Task", task.task, "is_template"): - dependent_task_format = f"""{task.task}""" + dependent_task_format = f"""{task.task}""" frappe.throw(_("Dependent Task {0} is not a Template Task").format(dependent_task_format)) def validate_completed_on(self): From f2aa71cd6c694e1f82daed0c6d3cb05e740d9f25 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:06:26 +0530 Subject: [PATCH 06/20] chore: update `CODEOWNERS` (backport #44074) (#44080) * chore: update `CODEOWNERS` (#44074) (cherry picked from commit 9a758ea826c091dcd298b19d50d8684e0147beae) # Conflicts: # CODEOWNERS * chore: `conflicts` --------- Co-authored-by: s-aga-r --- CODEOWNERS | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 7f8c4d1ac87..713941e589c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,22 +4,22 @@ # the repo. Unless a later match takes precedence, erpnext/accounts/ @deepeshgarg007 @ruthra-kumar -erpnext/assets/ @anandbaburajan @deepeshgarg007 +erpnext/assets/ @khushi8112 @deepeshgarg007 erpnext/loan_management/ @deepeshgarg007 erpnext/regional @deepeshgarg007 @ruthra-kumar erpnext/selling @deepeshgarg007 @ruthra-kumar erpnext/support/ @deepeshgarg007 pos* -erpnext/buying/ @rohitwaghchaure @s-aga-r -erpnext/maintenance/ @rohitwaghchaure @s-aga-r -erpnext/manufacturing/ @rohitwaghchaure @s-aga-r -erpnext/quality_management/ @rohitwaghchaure @s-aga-r -erpnext/stock/ @rohitwaghchaure @s-aga-r -erpnext/subcontracting @rohitwaghchaure @s-aga-r +erpnext/buying/ @rohitwaghchaure +erpnext/maintenance/ @rohitwaghchaure +erpnext/manufacturing/ @rohitwaghchaure +erpnext/quality_management/ @rohitwaghchaure +erpnext/stock/ @rohitwaghchaure +erpnext/subcontracting @rohitwaghchaure erpnext/controllers/ @deepeshgarg007 @rohitwaghchaure erpnext/patches/ @deepeshgarg007 .github/ @deepeshgarg007 -pyproject.toml @ankush +pyproject.toml @akhilnarang From 6b149f5ddf87b377de0abdff74309454c0dc5f12 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:12:39 +0530 Subject: [PATCH 07/20] fix: populate payment schedule from payment terms (backport #44082) (#44084) fix: populate payment schedule from payment terms (#44082) (cherry picked from commit c81eb6c824b04d8f174ece6900a5669b9a7c9461) Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com> --- erpnext/public/js/controllers/transaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 79e14b9eb5b..dca183cba92 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -2213,7 +2213,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe payment_terms_template() { var me = this; const doc = this.frm.doc; - if(doc.payment_terms_template && doc.doctype !== 'Delivery Note' && doc.is_return == 0) { + if(doc.payment_terms_template && doc.doctype !== 'Delivery Note' && !doc.is_return) { var posting_date = doc.posting_date || doc.transaction_date; frappe.call({ method: "erpnext.controllers.accounts_controller.get_payment_terms", From 599581e09d61622509fc94e29f540c905a69d7c8 Mon Sep 17 00:00:00 2001 From: Vishv-silveroak <108357657+Vishv-024@users.noreply.github.com> Date: Wed, 16 Oct 2024 18:03:40 +0530 Subject: [PATCH 08/20] fix: exception on register reports when filtered on cost center 1 (cherry picked from commit f01e1a8e20d6fa32e48ff22d850e737be5e32e2b) --- erpnext/accounts/report/utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 8ecabaf73ec..5d606f648fa 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -255,7 +255,9 @@ def get_journal_entries(filters, args): ) .orderby(je.posting_date, je.name, order=Order.desc) ) - query = apply_common_conditions(filters, query, doctype="Journal Entry", payments=True) + query = apply_common_conditions( + filters, query, doctype="Journal Entry", child_doctype="Journal Entry Account", payments=True + ) journal_entries = query.run(as_dict=True) return journal_entries @@ -306,7 +308,9 @@ def apply_common_conditions(filters, query, doctype, child_doctype=None, payment query = query.where(parent_doc.posting_date <= filters.to_date) if payments: - if filters.get("cost_center"): + if doctype == "Journal Entry" and filters.get("cost_center"): + query = query.where(child_doc.cost_center == filters.cost_center) + elif filters.get("cost_center"): query = query.where(parent_doc.cost_center == filters.cost_center) else: if filters.get("cost_center"): From a98fe7a72b8adab63cba25891def676e9d2f0ef3 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 8 Nov 2024 12:08:05 +0530 Subject: [PATCH 09/20] test: basic report output (cherry picked from commit 657201b32485cc3471fc91fdb6b20c7d73abdf60) --- .../sales_register/test_sales_register.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 erpnext/accounts/report/sales_register/test_sales_register.py diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py new file mode 100644 index 00000000000..6ed754fa837 --- /dev/null +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -0,0 +1,64 @@ +import frappe +from frappe.tests import IntegrationTestCase +from frappe.utils import getdate, today + +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import execute +from erpnext.accounts.test.accounts_mixin import AccountsTestMixin + + +class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): + def setUp(self): + self.create_company() + self.create_customer() + self.create_item() + + def tearDown(self): + frappe.db.rollback() + + def create_sales_invoice(self, rate=100, do_not_submit=False): + si = create_sales_invoice( + item=self.item, + company=self.company, + customer=self.customer, + debit_to=self.debit_to, + posting_date=today(), + parent_cost_center=self.cost_center, + cost_center=self.cost_center, + rate=rate, + price_list_rate=rate, + do_not_save=1, + ) + si = si.save() + if not do_not_submit: + si = si.submit() + return si + + def test_basic_report_output(self): + si = self.create_sales_invoice(rate=98) + + filters = frappe._dict({"from_date": today(), "to_date": today(), "company": self.company}) + report = execute(filters) + + self.assertEqual(len(report[1]), 1) + + expected_result = { + "item_code": si.items[0].item_code, + "invoice": si.name, + "posting_date": getdate(), + "customer": si.customer, + "debit_to": si.debit_to, + "company": self.company, + "income_account": si.items[0].income_account, + "stock_qty": 1.0, + "stock_uom": si.items[0].stock_uom, + "rate": 98.0, + "amount": 98.0, + "total_tax": 0, + "total_other_charges": 0, + "total": 98.0, + "currency": "INR", + } + + report_output = {k: v for k, v in report[1][0].items() if k in expected_result} + self.assertDictEqual(report_output, expected_result) From 964ac05e74c082b0f7a5c61339d957360011f55a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 11 Nov 2024 12:18:25 +0530 Subject: [PATCH 10/20] test: journals with cost center (cherry picked from commit c255f34eead1cba9210df609b22eb21e643f3d40) --- .../sales_register/test_sales_register.py | 121 +++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index 6ed754fa837..0bd67f39907 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -3,7 +3,7 @@ from frappe.tests import IntegrationTestCase from frappe.utils import getdate, today from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice -from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import execute +from erpnext.accounts.report.sales_register.sales_register import execute from erpnext.accounts.test.accounts_mixin import AccountsTestMixin @@ -12,10 +12,27 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): self.create_company() self.create_customer() self.create_item() + self.create_child_cost_center() def tearDown(self): frappe.db.rollback() + def create_child_cost_center(self): + cc_name = "South Wing" + if frappe.db.exists("Cost Center", cc_name): + cc = frappe.get_doc("Cost Center", cc_name) + else: + cc = frappe.get_doc( + { + "doctype": "Cost Center", + "parent_cost_center": self.cost_center, + "company": self.company, + "is_group": False, + } + ) + cc = cc.save() + self.south_cc = cc.name + def create_sales_invoice(self, rate=100, do_not_submit=False): si = create_sales_invoice( item=self.item, @@ -62,3 +79,105 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): report_output = {k: v for k, v in report[1][0].items() if k in expected_result} self.assertDictEqual(report_output, expected_result) + + def test_journal_with_cost_center_filter(self): + je1 = frappe.get_doc( + { + "doctype": "Journal Entry", + "voucher_type": "Journal Entry", + "company": self.company, + "posting_date": getdate(), + "accounts": [ + { + "account": self.debit_to, + "party_type": "Customer", + "party": self.customer, + "credit_in_account_currency": 77, + "credit": 77, + "is_advance": "Yes", + "cost_center": self.south_cc, + }, + { + "account": self.cash, + "debit_in_account_currency": 77, + "debit": 77, + }, + ], + } + ) + je1.submit() + + je2 = frappe.get_doc( + { + "doctype": "Journal Entry", + "voucher_type": "Journal Entry", + "company": self.company, + "posting_date": getdate(), + "accounts": [ + { + "account": self.debit_to, + "party_type": "Customer", + "party": self.customer, + "credit_in_account_currency": 98, + "credit": 98, + "is_advance": "Yes", + "cost_center": self.cost_center, + }, + { + "account": self.cash, + "debit_in_account_currency": 98, + "debit": 98, + }, + ], + } + ) + je2.submit() + + filters = frappe._dict( + { + "from_date": today(), + "to_date": today(), + "company": self.company, + "include_payments": True, + "customer": self.customer, + "cost_center": self.cost_center, + } + ) + result = [x for x in execute(filters)[1] if x.voucher_no == je1.name] + expected_result = { + "voucher_type": je1.doctype, + "voucher_no": je1.name, + "posting_date": je1.posting_date, + "customer": self.customer, + "receivable_account": self.debit_to, + "net_total": 77, + "cost_center": self.south_cc, + "credit": 77, + } + result_output = {k: v for k, v in result.items() if k in expected_result} + self.assertDictEqual(result_output, expected_result) + + # Without cost center filter + filters = frappe._dict( + { + "from_date": today(), + "to_date": today(), + "company": self.company, + "include_payments": True, + "customer": self.customer, + "cost_center": self.south_cc, + } + ) + result = [x for x in execute(filters)[1] if x.voucher_no == je2.name] + expected_result = { + "voucher_type": je2.doctype, + "voucher_no": je2.name, + "posting_date": je2.posting_date, + "customer": self.customer, + "receivable_account": self.debit_to, + "net_total": 98, + "cost_center": self.south_cc, + "credit": 98, + } + result_output = {k: v for k, v in result.items() if k in expected_result} + self.assertDictEqual(result_output, expected_result) From a8a89f971dc57299eb39243032d71ad710ab381b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 11 Nov 2024 12:34:54 +0530 Subject: [PATCH 11/20] refactor(test): fix incorrect assertion (cherry picked from commit d6030e71121f5c9d7d25c4d11310f4e56cc46833) --- .../sales_register/test_sales_register.py | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index 0bd67f39907..dbb4cd89851 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -60,21 +60,14 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): self.assertEqual(len(report[1]), 1) expected_result = { - "item_code": si.items[0].item_code, - "invoice": si.name, - "posting_date": getdate(), - "customer": si.customer, - "debit_to": si.debit_to, - "company": self.company, - "income_account": si.items[0].income_account, - "stock_qty": 1.0, - "stock_uom": si.items[0].stock_uom, - "rate": 98.0, - "amount": 98.0, - "total_tax": 0, - "total_other_charges": 0, - "total": 98.0, - "currency": "INR", + "voucher_type": si.doctype, + "voucher_no": si.name, + "posting_date": si.posting_date, + "customer": self.customer, + "receivable_account": self.debit_to, + "net_total": 98, + "grand_total": 98, + "credit": 98, } report_output = {k: v for k, v in report[1][0].items() if k in expected_result} @@ -151,13 +144,12 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): "customer": self.customer, "receivable_account": self.debit_to, "net_total": 77, - "cost_center": self.south_cc, + "cost_center": self.cost_center, "credit": 77, } result_output = {k: v for k, v in result.items() if k in expected_result} self.assertDictEqual(result_output, expected_result) - # Without cost center filter filters = frappe._dict( { "from_date": today(), From 4f7d534cab8649e7314f8ce5baab227dcad87ee4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 11 Nov 2024 13:06:09 +0530 Subject: [PATCH 12/20] refactor(test): pass all mandatory fields (cherry picked from commit c53e9637dd1ee39ebfeb713f39e0eaafb414e5c7) --- erpnext/accounts/report/sales_register/test_sales_register.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index dbb4cd89851..cb8f37a4f0f 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -28,6 +28,7 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): "parent_cost_center": self.cost_center, "company": self.company, "is_group": False, + "cost_center_name": cc_name, } ) cc = cc.save() From 71a1e50314eeaf58a928f2b1f62acfabe9e973b2 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 11 Nov 2024 14:16:49 +0530 Subject: [PATCH 13/20] refactor(test): assertion refactoring and exact decimals (cherry picked from commit 1d11131afeef9040ad98647c834daf2faafcb782) --- .../sales_register/test_sales_register.py | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index cb8f37a4f0f..50f12e52e33 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -22,12 +22,13 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): if frappe.db.exists("Cost Center", cc_name): cc = frappe.get_doc("Cost Center", cc_name) else: + parent = frappe.db.get_value("Cost Center", self.cost_center, "parent_cost_center") cc = frappe.get_doc( { "doctype": "Cost Center", - "parent_cost_center": self.cost_center, "company": self.company, "is_group": False, + "parent_cost_center": parent, "cost_center_name": cc_name, } ) @@ -63,12 +64,12 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): expected_result = { "voucher_type": si.doctype, "voucher_no": si.name, - "posting_date": si.posting_date, + "posting_date": getdate(), "customer": self.customer, "receivable_account": self.debit_to, - "net_total": 98, - "grand_total": 98, - "credit": 98, + "net_total": 98.0, + "grand_total": 98.0, + "debit": 98.0, } report_output = {k: v for k, v in report[1][0].items() if k in expected_result} @@ -89,7 +90,7 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): "credit_in_account_currency": 77, "credit": 77, "is_advance": "Yes", - "cost_center": self.south_cc, + "cost_center": self.cost_center, }, { "account": self.cash, @@ -115,7 +116,7 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): "credit_in_account_currency": 98, "credit": 98, "is_advance": "Yes", - "cost_center": self.cost_center, + "cost_center": self.south_cc, }, { "account": self.cash, @@ -137,19 +138,20 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): "cost_center": self.cost_center, } ) - result = [x for x in execute(filters)[1] if x.voucher_no == je1.name] + report_output = execute(filters)[1] + filtered_output = [x for x in report_output if x.get("voucher_no") == je1.name] + self.assertEqual(len(filtered_output), 1) expected_result = { "voucher_type": je1.doctype, "voucher_no": je1.name, "posting_date": je1.posting_date, "customer": self.customer, "receivable_account": self.debit_to, - "net_total": 77, - "cost_center": self.cost_center, - "credit": 77, + "net_total": 77.0, + "credit": 77.0, } - result_output = {k: v for k, v in result.items() if k in expected_result} - self.assertDictEqual(result_output, expected_result) + result_fields = {k: v for k, v in filtered_output[0].items() if k in expected_result} + self.assertDictEqual(result_fields, expected_result) filters = frappe._dict( { @@ -161,16 +163,17 @@ class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): "cost_center": self.south_cc, } ) - result = [x for x in execute(filters)[1] if x.voucher_no == je2.name] + report_output = execute(filters)[1] + filtered_output = [x for x in report_output if x.get("voucher_no") == je2.name] + self.assertEqual(len(filtered_output), 1) expected_result = { "voucher_type": je2.doctype, "voucher_no": je2.name, "posting_date": je2.posting_date, "customer": self.customer, "receivable_account": self.debit_to, - "net_total": 98, - "cost_center": self.south_cc, - "credit": 98, + "net_total": 98.0, + "credit": 98.0, } - result_output = {k: v for k, v in result.items() if k in expected_result} + result_output = {k: v for k, v in filtered_output[0].items() if k in expected_result} self.assertDictEqual(result_output, expected_result) From 558fac68436e7ad8c0af901bf71379f6a6208c89 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 11 Nov 2024 15:07:46 +0530 Subject: [PATCH 14/20] chore: use FrappeTestCase --- erpnext/accounts/report/sales_register/test_sales_register.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index 50f12e52e33..693c33c0ca6 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -1,5 +1,5 @@ import frappe -from frappe.tests import IntegrationTestCase +from frappe.tests.utils import FrappeTestCase from frappe.utils import getdate, today from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice @@ -7,7 +7,7 @@ from erpnext.accounts.report.sales_register.sales_register import execute from erpnext.accounts.test.accounts_mixin import AccountsTestMixin -class TestItemWiseSalesRegister(AccountsTestMixin, IntegrationTestCase): +class TestItemWiseSalesRegister(AccountsTestMixin, FrappeTestCase): def setUp(self): self.create_company() self.create_customer() From fd9fd8f46fe7a37c3d1bbc9ef76e5e0c35953ad4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 11 Nov 2024 16:01:53 +0530 Subject: [PATCH 15/20] chore: filter report output --- erpnext/accounts/report/sales_register/test_sales_register.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index 693c33c0ca6..95aa5add24c 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -59,7 +59,7 @@ class TestItemWiseSalesRegister(AccountsTestMixin, FrappeTestCase): filters = frappe._dict({"from_date": today(), "to_date": today(), "company": self.company}) report = execute(filters) - self.assertEqual(len(report[1]), 1) + res = [x for x in report[1] if x.get("voucher_no") == si.name] expected_result = { "voucher_type": si.doctype, @@ -72,7 +72,7 @@ class TestItemWiseSalesRegister(AccountsTestMixin, FrappeTestCase): "debit": 98.0, } - report_output = {k: v for k, v in report[1][0].items() if k in expected_result} + report_output = {k: v for k, v in res[0].items() if k in expected_result} self.assertDictEqual(report_output, expected_result) def test_journal_with_cost_center_filter(self): From ea38a1f36a66dd62a48111b6c1ea7eb4b1fa9280 Mon Sep 17 00:00:00 2001 From: Nihantra Patel Date: Wed, 13 Nov 2024 14:55:45 +0530 Subject: [PATCH 16/20] fix: Drop Shipping address based on customer shopping address (cherry picked from commit c7499f35285182837570e3aaa1d6b274783d2204) --- erpnext/public/js/controllers/transaction.js | 11 ++++++++--- erpnext/selling/doctype/sales_order/sales_order.py | 14 +++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index dca183cba92..c3ec62c34da 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -822,9 +822,14 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") && ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'].includes(this.frm.doctype)) { - erpnext.utils.get_shipping_address(this.frm, function() { - set_party_account(set_pricing); - }); + let is_drop_ship = me.frm.doc.items.some(item => item.delivered_by_supplier); + + if (!is_drop_ship) { + console.log('get_shipping_address'); + erpnext.utils.get_shipping_address(this.frm, function() { + set_party_account(set_pricing); + }); + } } else { set_party_account(set_pricing); diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 9479d4669d0..34f839b563d 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1090,9 +1090,17 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.payment_schedule = [] if is_drop_ship_order(target): - target.customer = source.customer - target.customer_name = source.customer_name - target.shipping_address = source.shipping_address_name + if source.shipping_address_name: + target.shipping_address = source.shipping_address_name + target.shipping_address_display = source.shipping_address + else: + target.shipping_address = source.customer_address + target.shipping_address_display = source.address_display + + target.customer_contact_person = source.contact_person + target.customer_contact_display = source.contact_display + target.customer_contact_mobile = source.contact_mobile + target.customer_contact_email = source.contact_email else: target.customer = target.customer_name = target.shipping_address = None From 2acee05a0ad8a82bb04b8969a63c000328cdd844 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 13 Nov 2024 16:56:08 +0530 Subject: [PATCH 17/20] refactor: 'Partly Billed' status for Purchase Receipt (cherry picked from commit c58bbd25f2813ac4392877602ca89247127e3623) --- erpnext/stock/doctype/purchase_receipt/purchase_receipt.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index 28c54dab9b2..fabeb74462f 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -885,7 +885,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nTo Bill\nCompleted\nReturn Issued\nCancelled\nClosed", + "options": "\nDraft\nPartly Billed\nTo Bill\nCompleted\nReturn Issued\nCancelled\nClosed", "print_hide": 1, "print_width": "150px", "read_only": 1, @@ -1242,7 +1242,7 @@ "idx": 261, "is_submittable": 1, "links": [], - "modified": "2024-03-20 16:05:31.713453", + "modified": "2024-11-13 16:55:14.129055", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", From 3e2fa16d84efb7ababdcd242a33310574b60dad6 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 29 Jan 2024 19:56:46 +0530 Subject: [PATCH 18/20] feat: Partly billed status in Purchase Receipt (#39543) (cherry picked from commit a673220feb91419f7d9949926fa4b3dd67d63682) --- erpnext/controllers/status_updater.py | 3 ++- .../stock/doctype/purchase_receipt/purchase_receipt_list.js | 4 +++- .../stock/doctype/purchase_receipt/test_purchase_receipt.py | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index dd3fab05ce6..e04618c857f 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -91,7 +91,8 @@ status_map = { ], "Purchase Receipt": [ ["Draft", None], - ["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"], + ["To Bill", "eval:self.per_billed == 0 and self.docstatus == 1"], + ["Partly Billed", "eval:self.per_billed > 0 and self.per_billed < 100 and self.docstatus == 1"], ["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"], ["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"], ["Cancelled", "eval:self.docstatus==2"], diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js index ddc9bb026fb..fc4aabdaa18 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js @@ -17,8 +17,10 @@ frappe.listview_settings["Purchase Receipt"] = { return [__("Closed"), "green", "status,=,Closed"]; } else if (flt(doc.per_returned, 2) === 100) { return [__("Return Issued"), "grey", "per_returned,=,100"]; - } else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) < 100) { + } else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) == 0) { return [__("To Bill"), "orange", "per_billed,<,100"]; + } else if (flt(doc.per_billed, 2) > 0 && flt(doc.per_billed, 2) < 100) { + return [__("Partly Billed"), "yellow", "per_billed,<,100"]; } else if (flt(doc.grand_total) === 0 || flt(doc.per_billed, 2) === 100) { return [__("Completed"), "green", "per_billed,=,100"]; } diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 1c4feedbcfb..2525120cefd 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -595,7 +595,7 @@ class TestPurchaseReceipt(FrappeTestCase): pr2.load_from_db() self.assertEqual(pr2.get("items")[0].billed_amt, 2000) self.assertEqual(pr2.per_billed, 80) - self.assertEqual(pr2.status, "To Bill") + self.assertEqual(pr2.status, "Partly Billed") pr2.cancel() pi2.reload() @@ -1006,7 +1006,7 @@ class TestPurchaseReceipt(FrappeTestCase): pi.load_from_db() pr.load_from_db() - self.assertEqual(pr.status, "To Bill") + self.assertEqual(pr.status, "Partly Billed") self.assertAlmostEqual(pr.per_billed, 50.0, places=2) def test_purchase_receipt_with_exchange_rate_difference(self): From da6c6dcfcbbce9f1f5e1addbf102301f5f51abf3 Mon Sep 17 00:00:00 2001 From: NaviN <118178330+Navin-S-R@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:23:16 +0530 Subject: [PATCH 19/20] fix: update per_billed value in Purchase Receipt while creating Debit Note (#43977) * fix: update per_billed value in Purchase Receipt while creating Debit Note * test: add unit test for validating per_billed value for partial Debit Note (cherry picked from commit 494fd7ceeab3edd56f7f4975101a611e9e8ad391) # Conflicts: # erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py --- .../purchase_receipt/purchase_receipt.py | 11 +- .../purchase_receipt/test_purchase_receipt.py | 279 ++++++++++++++++++ 2 files changed, 288 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 8ed59f452e2..faf305cfe9c 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -883,6 +883,8 @@ def get_billed_amount_against_po(po_items): def update_billing_percentage(pr_doc, update_modified=True, adjust_incoming_rate=False): # Update Billing % based on pending accepted qty + buying_settings = frappe.get_single("Buying Settings") + total_amount, total_billed_amount = 0, 0 item_wise_returned_qty = get_item_wise_returned_qty(pr_doc) @@ -890,10 +892,15 @@ def update_billing_percentage(pr_doc, update_modified=True, adjust_incoming_rate returned_qty = flt(item_wise_returned_qty.get(item.name)) returned_amount = flt(returned_qty) * flt(item.rate) pending_amount = flt(item.amount) - returned_amount - total_billable_amount = pending_amount if item.billed_amt <= pending_amount else item.billed_amt + if buying_settings.bill_for_rejected_quantity_in_purchase_invoice: + pending_amount = flt(item.amount) + + total_billable_amount = abs(flt(item.amount)) + if pending_amount > 0: + total_billable_amount = pending_amount if item.billed_amt <= pending_amount else item.billed_amt total_amount += total_billable_amount - total_billed_amount += flt(item.billed_amt) + total_billed_amount += abs(flt(item.billed_amt)) if pr_doc.get("is_return") and not total_amount and total_billed_amount: total_amount = total_billed_amount diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 2525120cefd..890502c797f 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2683,6 +2683,285 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(pr.items[0].conversion_factor, 1.0) +<<<<<<< HEAD +======= + def test_purchase_receipt_return_valuation_without_use_serial_batch_field(self): + from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return + + batch_item = make_item( + "_Test Purchase Receipt Return Valuation Batch Item", + properties={ + "has_batch_no": 1, + "create_new_batch": 1, + "is_stock_item": 1, + "batch_number_series": "BRTN-TPRBI-.#####", + }, + ).name + + serial_item = make_item( + "_Test Purchase Receipt Return Valuation Serial Item", + properties={"has_serial_no": 1, "is_stock_item": 1, "serial_no_series": "SRTN-TPRSI-.#####"}, + ).name + + rej_warehouse = create_warehouse("_Test Purchase Warehouse For Rejected Qty") + + pr = make_purchase_receipt( + item_code=batch_item, + received_qty=10, + qty=8, + rejected_qty=2, + rejected_warehouse=rej_warehouse, + rate=300, + do_not_submit=1, + use_serial_batch_fields=0, + ) + + pr.append( + "items", + { + "item_code": serial_item, + "qty": 2, + "rate": 100, + "base_rate": 100, + "item_name": serial_item, + "uom": "Nos", + "stock_uom": "Nos", + "conversion_factor": 1, + "rejected_qty": 1, + "warehouse": pr.items[0].warehouse, + "use_serial_batch_fields": 0, + "rejected_warehouse": rej_warehouse, + }, + ) + + pr.save() + pr.submit() + pr.reload() + + batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) + rejected_batch_no = get_batch_from_bundle(pr.items[0].rejected_serial_and_batch_bundle) + + self.assertEqual(batch_no, rejected_batch_no) + + return_entry = make_purchase_return(pr.name) + + return_entry.save() + return_entry.submit() + return_entry.reload() + + for row in return_entry.items: + if row.item_code == batch_item: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 300.00) + else: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 100.00) + + for row in return_entry.items: + if row.item_code == batch_item: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.rejected_serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 0) + else: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.rejected_serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 0) + + def test_purchase_receipt_return_valuation_with_use_serial_batch_field(self): + from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return + + batch_item = make_item( + "_Test Purchase Receipt Return Valuation With Batch Item", + properties={"has_batch_no": 1, "create_new_batch": 1, "is_stock_item": 1}, + ).name + + serial_item = make_item( + "_Test Purchase Receipt Return Valuation With Serial Item", + properties={"has_serial_no": 1, "is_stock_item": 1}, + ).name + + rej_warehouse = create_warehouse("_Test Purchase Warehouse For Rejected Qty") + + batch_no = "BATCH-RTN-BNU-TPRBI-0001" + serial_nos = ["SNU-RTN-TPRSI-0001", "SNU-RTN-TPRSI-0002", "SNU-RTN-TPRSI-0003"] + + if not frappe.db.exists("Batch", batch_no): + frappe.get_doc( + { + "doctype": "Batch", + "batch_id": batch_no, + "item": batch_item, + } + ).insert() + + for serial_no in serial_nos: + if not frappe.db.exists("Serial No", serial_no): + frappe.get_doc( + { + "doctype": "Serial No", + "item_code": serial_item, + "serial_no": serial_no, + } + ).insert() + + pr = make_purchase_receipt( + item_code=batch_item, + received_qty=10, + qty=8, + rejected_qty=2, + rejected_warehouse=rej_warehouse, + batch_no=batch_no, + use_serial_batch_fields=1, + rate=300, + do_not_submit=1, + ) + + pr.append( + "items", + { + "item_code": serial_item, + "qty": 2, + "rate": 100, + "base_rate": 100, + "item_name": serial_item, + "uom": "Nos", + "stock_uom": "Nos", + "conversion_factor": 1, + "rejected_qty": 1, + "warehouse": pr.items[0].warehouse, + "use_serial_batch_fields": 1, + "rejected_warehouse": rej_warehouse, + "serial_no": "\n".join(serial_nos[:2]), + "rejected_serial_no": serial_nos[2], + }, + ) + + pr.save() + pr.submit() + pr.reload() + + batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) + rejected_batch_no = get_batch_from_bundle(pr.items[0].rejected_serial_and_batch_bundle) + + self.assertEqual(batch_no, rejected_batch_no) + + return_entry = make_purchase_return(pr.name) + + return_entry.save() + return_entry.submit() + return_entry.reload() + + for row in return_entry.items: + if row.item_code == batch_item: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 300.00) + else: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 100.00) + + for row in return_entry.items: + if row.item_code == batch_item: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.rejected_serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 0) + else: + bundle_data = frappe.get_all( + "Serial and Batch Entry", + filters={"parent": row.rejected_serial_and_batch_bundle}, + pluck="incoming_rate", + ) + + for incoming_rate in bundle_data: + self.assertEqual(incoming_rate, 0) + + def test_purchase_return_partial_debit_note(self): + pr = make_purchase_receipt( + company="_Test Company with perpetual inventory", + warehouse="Stores - TCP1", + supplier_warehouse="Work In Progress - TCP1", + ) + + return_pr = make_purchase_receipt( + company="_Test Company with perpetual inventory", + warehouse="Stores - TCP1", + supplier_warehouse="Work In Progress - TCP1", + is_return=1, + return_against=pr.name, + qty=-2, + do_not_submit=1, + ) + return_pr.items[0].purchase_receipt_item = pr.items[0].name + return_pr.submit() + + # because new_doc isn't considering is_return portion of status_updater + returned = frappe.get_doc("Purchase Receipt", return_pr.name) + returned.update_prevdoc_status() + pr.load_from_db() + + # Check if Original PR updated + self.assertEqual(pr.items[0].returned_qty, 2) + self.assertEqual(pr.per_returned, 40) + + # Create first partial debit_note + pi_1 = make_purchase_invoice(return_pr.name) + pi_1.items[0].qty = -1 + pi_1.submit() + + # Check if the first partial debit billing percentage got updated + return_pr.reload() + self.assertEqual(return_pr.per_billed, 50) + self.assertEqual(return_pr.status, "Partly Billed") + + # Create second partial debit_note to complete the debit note + pi_2 = make_purchase_invoice(return_pr.name) + pi_2.items[0].qty = -1 + pi_2.submit() + + # Check if the second partial debit note billing percentage got updated + return_pr.reload() + self.assertEqual(return_pr.per_billed, 100) + self.assertEqual(return_pr.status, "Completed") + +>>>>>>> 494fd7ceea (fix: update per_billed value in Purchase Receipt while creating Debit Note (#43977)) def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier From 030df0d7e889c40c9af73cbc1febd981c978dbf4 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 13 Nov 2024 12:25:24 +0530 Subject: [PATCH 20/20] chore: fix conflicts --- .../purchase_receipt/test_purchase_receipt.py | 231 ------------------ 1 file changed, 231 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 890502c797f..adb6e690596 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2683,236 +2683,6 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(pr.items[0].conversion_factor, 1.0) -<<<<<<< HEAD -======= - def test_purchase_receipt_return_valuation_without_use_serial_batch_field(self): - from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return - - batch_item = make_item( - "_Test Purchase Receipt Return Valuation Batch Item", - properties={ - "has_batch_no": 1, - "create_new_batch": 1, - "is_stock_item": 1, - "batch_number_series": "BRTN-TPRBI-.#####", - }, - ).name - - serial_item = make_item( - "_Test Purchase Receipt Return Valuation Serial Item", - properties={"has_serial_no": 1, "is_stock_item": 1, "serial_no_series": "SRTN-TPRSI-.#####"}, - ).name - - rej_warehouse = create_warehouse("_Test Purchase Warehouse For Rejected Qty") - - pr = make_purchase_receipt( - item_code=batch_item, - received_qty=10, - qty=8, - rejected_qty=2, - rejected_warehouse=rej_warehouse, - rate=300, - do_not_submit=1, - use_serial_batch_fields=0, - ) - - pr.append( - "items", - { - "item_code": serial_item, - "qty": 2, - "rate": 100, - "base_rate": 100, - "item_name": serial_item, - "uom": "Nos", - "stock_uom": "Nos", - "conversion_factor": 1, - "rejected_qty": 1, - "warehouse": pr.items[0].warehouse, - "use_serial_batch_fields": 0, - "rejected_warehouse": rej_warehouse, - }, - ) - - pr.save() - pr.submit() - pr.reload() - - batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) - rejected_batch_no = get_batch_from_bundle(pr.items[0].rejected_serial_and_batch_bundle) - - self.assertEqual(batch_no, rejected_batch_no) - - return_entry = make_purchase_return(pr.name) - - return_entry.save() - return_entry.submit() - return_entry.reload() - - for row in return_entry.items: - if row.item_code == batch_item: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 300.00) - else: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 100.00) - - for row in return_entry.items: - if row.item_code == batch_item: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.rejected_serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 0) - else: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.rejected_serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 0) - - def test_purchase_receipt_return_valuation_with_use_serial_batch_field(self): - from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return - - batch_item = make_item( - "_Test Purchase Receipt Return Valuation With Batch Item", - properties={"has_batch_no": 1, "create_new_batch": 1, "is_stock_item": 1}, - ).name - - serial_item = make_item( - "_Test Purchase Receipt Return Valuation With Serial Item", - properties={"has_serial_no": 1, "is_stock_item": 1}, - ).name - - rej_warehouse = create_warehouse("_Test Purchase Warehouse For Rejected Qty") - - batch_no = "BATCH-RTN-BNU-TPRBI-0001" - serial_nos = ["SNU-RTN-TPRSI-0001", "SNU-RTN-TPRSI-0002", "SNU-RTN-TPRSI-0003"] - - if not frappe.db.exists("Batch", batch_no): - frappe.get_doc( - { - "doctype": "Batch", - "batch_id": batch_no, - "item": batch_item, - } - ).insert() - - for serial_no in serial_nos: - if not frappe.db.exists("Serial No", serial_no): - frappe.get_doc( - { - "doctype": "Serial No", - "item_code": serial_item, - "serial_no": serial_no, - } - ).insert() - - pr = make_purchase_receipt( - item_code=batch_item, - received_qty=10, - qty=8, - rejected_qty=2, - rejected_warehouse=rej_warehouse, - batch_no=batch_no, - use_serial_batch_fields=1, - rate=300, - do_not_submit=1, - ) - - pr.append( - "items", - { - "item_code": serial_item, - "qty": 2, - "rate": 100, - "base_rate": 100, - "item_name": serial_item, - "uom": "Nos", - "stock_uom": "Nos", - "conversion_factor": 1, - "rejected_qty": 1, - "warehouse": pr.items[0].warehouse, - "use_serial_batch_fields": 1, - "rejected_warehouse": rej_warehouse, - "serial_no": "\n".join(serial_nos[:2]), - "rejected_serial_no": serial_nos[2], - }, - ) - - pr.save() - pr.submit() - pr.reload() - - batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) - rejected_batch_no = get_batch_from_bundle(pr.items[0].rejected_serial_and_batch_bundle) - - self.assertEqual(batch_no, rejected_batch_no) - - return_entry = make_purchase_return(pr.name) - - return_entry.save() - return_entry.submit() - return_entry.reload() - - for row in return_entry.items: - if row.item_code == batch_item: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 300.00) - else: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 100.00) - - for row in return_entry.items: - if row.item_code == batch_item: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.rejected_serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 0) - else: - bundle_data = frappe.get_all( - "Serial and Batch Entry", - filters={"parent": row.rejected_serial_and_batch_bundle}, - pluck="incoming_rate", - ) - - for incoming_rate in bundle_data: - self.assertEqual(incoming_rate, 0) - def test_purchase_return_partial_debit_note(self): pr = make_purchase_receipt( company="_Test Company with perpetual inventory", @@ -2961,7 +2731,6 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(return_pr.per_billed, 100) self.assertEqual(return_pr.status, "Completed") ->>>>>>> 494fd7ceea (fix: update per_billed value in Purchase Receipt while creating Debit Note (#43977)) def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier