From f81d4a79eab95148a4a6591bb0920cd2db13afed Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 18 Jan 2023 23:21:29 +0530 Subject: [PATCH 01/13] fix: don't add template item in sales/purchase transaction (cherry picked from commit 2c83fff1a1a4aa7053159f58c68d9ed697a73742) # Conflicts: # erpnext/buying/doctype/purchase_order/test_purchase_order.py --- .../purchase_order/test_purchase_order.py | 123 +++++++++++++++++- erpnext/stock/get_item_details.py | 6 +- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 590370e808c..06274af5945 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1239,6 +1239,127 @@ class TestPurchaseOrder(FrappeTestCase): automatically_fetch_payment_terms(enable=0) +<<<<<<< HEAD +======= + def test_internal_transfer_flow(self): + from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( + make_inter_company_purchase_invoice, + ) + from erpnext.selling.doctype.sales_order.sales_order import ( + make_delivery_note, + make_sales_invoice, + ) + from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt + + frappe.db.set_value("Selling Settings", None, "maintain_same_sales_rate", 1) + frappe.db.set_value("Buying Settings", None, "maintain_same_rate", 1) + + prepare_data_for_internal_transfer() + supplier = "_Test Internal Supplier 2" + + mr = make_material_request( + qty=2, company="_Test Company with perpetual inventory", warehouse="Stores - TCP1" + ) + + po = create_purchase_order( + company="_Test Company with perpetual inventory", + supplier=supplier, + warehouse="Stores - TCP1", + from_warehouse="_Test Internal Warehouse New 1 - TCP1", + qty=2, + rate=1, + material_request=mr.name, + material_request_item=mr.items[0].name, + ) + + so = make_inter_company_sales_order(po.name) + so.items[0].delivery_date = today() + self.assertEqual(so.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") + self.assertTrue(so.items[0].purchase_order) + self.assertTrue(so.items[0].purchase_order_item) + so.submit() + + dn = make_delivery_note(so.name) + dn.items[0].target_warehouse = "_Test Internal Warehouse GIT - TCP1" + self.assertEqual(dn.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") + self.assertTrue(dn.items[0].purchase_order) + self.assertTrue(dn.items[0].purchase_order_item) + + self.assertEqual(po.items[0].name, dn.items[0].purchase_order_item) + dn.submit() + + pr = make_inter_company_purchase_receipt(dn.name) + self.assertEqual(pr.items[0].warehouse, "Stores - TCP1") + self.assertTrue(pr.items[0].purchase_order) + self.assertTrue(pr.items[0].purchase_order_item) + self.assertEqual(po.items[0].name, pr.items[0].purchase_order_item) + pr.submit() + + si = make_sales_invoice(so.name) + self.assertEqual(si.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") + self.assertTrue(si.items[0].purchase_order) + self.assertTrue(si.items[0].purchase_order_item) + si.submit() + + pi = make_inter_company_purchase_invoice(si.name) + self.assertTrue(pi.items[0].purchase_order) + self.assertTrue(pi.items[0].po_detail) + pi.submit() + mr.reload() + + po.load_from_db() + self.assertEqual(po.status, "Completed") + self.assertEqual(mr.status, "Received") + + def test_variant_item_po(self): + po = create_purchase_order(item_code="_Test Variant Item", qty=1, rate=100, do_not_save=1) + + self.assertRaises(frappe.ValidationError, po.save) + + +def prepare_data_for_internal_transfer(): + from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier + from erpnext.selling.doctype.customer.test_customer import create_internal_customer + from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + company = "_Test Company with perpetual inventory" + + create_internal_customer( + "_Test Internal Customer 2", + company, + company, + ) + + create_internal_supplier( + "_Test Internal Supplier 2", + company, + company, + ) + + warehouse = create_warehouse("_Test Internal Warehouse New 1", company=company) + + create_warehouse("_Test Internal Warehouse GIT", company=company) + + make_purchase_receipt(company=company, warehouse=warehouse, qty=2, rate=100) + + if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"): + account = "Unrealized Profit and Loss - TCP1" + if not frappe.db.exists("Account", account): + frappe.get_doc( + { + "doctype": "Account", + "account_name": "Unrealized Profit and Loss", + "parent_account": "Direct Income - TCP1", + "company": company, + "is_group": 0, + "account_type": "Income Account", + } + ).insert() + + frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account) + +>>>>>>> 2c83fff1a1 (fix: don't add template item in sales/purchase transaction) def make_pr_against_po(po, received_qty=0): pr = make_purchase_receipt(po) @@ -1342,8 +1463,8 @@ def create_purchase_order(**args): }, ) - po.set_missing_values() if not args.do_not_save: + po.set_missing_values() po.insert() if not args.do_not_submit: if po.is_subcontracted == "Yes": diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 6fb9205d4b9..15d77544236 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -226,8 +226,10 @@ def validate_item_details(args, item): validate_end_of_life(item.name, item.end_of_life, item.disabled) - if args.transaction_type == "selling" and cint(item.has_variants): - throw(_("Item {0} is a template, please select one of its variants").format(item.name)) + if cint(item.has_variants): + msg = f"Item {item.name} is a template, please select one of its variants" + + throw(_(msg), title=_("Template Item Selected")) elif args.transaction_type == "buying" and args.doctype != "Material Request": if args.get("is_subcontracted") == "Yes" and item.is_sub_contracted_item != 1: From 4741ce13c630967e7eb06112c096c2f2349d5027 Mon Sep 17 00:00:00 2001 From: unknown <57280279+SvbZ3r0@users.noreply.github.com> Date: Thu, 12 Jan 2023 07:44:57 +0530 Subject: [PATCH 02/13] fix: rewrite logic for duplicate check in Item Attribute Previously, Item Attribute values were not checked for case-insensitive duplicates, and Item tttribute abbreviations were forced to be uppercase. This commit fixes both problems. (cherry picked from commit 974e12c8378c729647965bdfd65f52f89154609b) --- .../stock/doctype/item_attribute/item_attribute.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py index 391ff06918a..018d5257e1d 100644 --- a/erpnext/stock/doctype/item_attribute/item_attribute.py +++ b/erpnext/stock/doctype/item_attribute/item_attribute.py @@ -74,11 +74,12 @@ class ItemAttribute(Document): def validate_duplication(self): values, abbrs = [], [] for d in self.item_attribute_values: - d.abbr = d.abbr.upper() - if d.attribute_value in values: - frappe.throw(_("{0} must appear only once").format(d.attribute_value)) + if d.attribute_value.lower() in map(str.lower, values): + frappe.throw( + _("Attribute value: {0} must appear only once").format(d.attribute_value.title())) values.append(d.attribute_value) - if d.abbr in abbrs: - frappe.throw(_("{0} must appear only once").format(d.abbr)) + if d.abbr.lower() in map(str.lower, abbrs): + frappe.throw( + _("Abbreviation: {0} must appear only once").format(d.abbr.title())) abbrs.append(d.abbr) From 13906cba9a412a3cc0afd698be932616346f58d7 Mon Sep 17 00:00:00 2001 From: unknown <57280279+SvbZ3r0@users.noreply.github.com> Date: Thu, 12 Jan 2023 20:53:12 +0530 Subject: [PATCH 03/13] fix: linting (cherry picked from commit 2ca4d3fb71587bae26f23f2c748884cc1b27b744) --- erpnext/stock/doctype/item_attribute/item_attribute.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py index 018d5257e1d..ac4c313e28a 100644 --- a/erpnext/stock/doctype/item_attribute/item_attribute.py +++ b/erpnext/stock/doctype/item_attribute/item_attribute.py @@ -75,11 +75,9 @@ class ItemAttribute(Document): values, abbrs = [], [] for d in self.item_attribute_values: if d.attribute_value.lower() in map(str.lower, values): - frappe.throw( - _("Attribute value: {0} must appear only once").format(d.attribute_value.title())) + frappe.throw(_("Attribute value: {0} must appear only once").format(d.attribute_value.title())) values.append(d.attribute_value) if d.abbr.lower() in map(str.lower, abbrs): - frappe.throw( - _("Abbreviation: {0} must appear only once").format(d.abbr.title())) + frappe.throw(_("Abbreviation: {0} must appear only once").format(d.abbr.title())) abbrs.append(d.abbr) From 055f8536c304e750926b6b44c91b83c013dfae24 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 19 Jan 2023 16:57:17 +0530 Subject: [PATCH 04/13] fix: conflicts --- .../purchase_order/test_purchase_order.py | 116 ------------------ 1 file changed, 116 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 06274af5945..2e6df8525cc 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1239,128 +1239,12 @@ class TestPurchaseOrder(FrappeTestCase): automatically_fetch_payment_terms(enable=0) -<<<<<<< HEAD -======= - def test_internal_transfer_flow(self): - from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( - make_inter_company_purchase_invoice, - ) - from erpnext.selling.doctype.sales_order.sales_order import ( - make_delivery_note, - make_sales_invoice, - ) - from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt - - frappe.db.set_value("Selling Settings", None, "maintain_same_sales_rate", 1) - frappe.db.set_value("Buying Settings", None, "maintain_same_rate", 1) - - prepare_data_for_internal_transfer() - supplier = "_Test Internal Supplier 2" - - mr = make_material_request( - qty=2, company="_Test Company with perpetual inventory", warehouse="Stores - TCP1" - ) - - po = create_purchase_order( - company="_Test Company with perpetual inventory", - supplier=supplier, - warehouse="Stores - TCP1", - from_warehouse="_Test Internal Warehouse New 1 - TCP1", - qty=2, - rate=1, - material_request=mr.name, - material_request_item=mr.items[0].name, - ) - - so = make_inter_company_sales_order(po.name) - so.items[0].delivery_date = today() - self.assertEqual(so.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") - self.assertTrue(so.items[0].purchase_order) - self.assertTrue(so.items[0].purchase_order_item) - so.submit() - - dn = make_delivery_note(so.name) - dn.items[0].target_warehouse = "_Test Internal Warehouse GIT - TCP1" - self.assertEqual(dn.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") - self.assertTrue(dn.items[0].purchase_order) - self.assertTrue(dn.items[0].purchase_order_item) - - self.assertEqual(po.items[0].name, dn.items[0].purchase_order_item) - dn.submit() - - pr = make_inter_company_purchase_receipt(dn.name) - self.assertEqual(pr.items[0].warehouse, "Stores - TCP1") - self.assertTrue(pr.items[0].purchase_order) - self.assertTrue(pr.items[0].purchase_order_item) - self.assertEqual(po.items[0].name, pr.items[0].purchase_order_item) - pr.submit() - - si = make_sales_invoice(so.name) - self.assertEqual(si.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") - self.assertTrue(si.items[0].purchase_order) - self.assertTrue(si.items[0].purchase_order_item) - si.submit() - - pi = make_inter_company_purchase_invoice(si.name) - self.assertTrue(pi.items[0].purchase_order) - self.assertTrue(pi.items[0].po_detail) - pi.submit() - mr.reload() - - po.load_from_db() - self.assertEqual(po.status, "Completed") - self.assertEqual(mr.status, "Received") - def test_variant_item_po(self): po = create_purchase_order(item_code="_Test Variant Item", qty=1, rate=100, do_not_save=1) self.assertRaises(frappe.ValidationError, po.save) -def prepare_data_for_internal_transfer(): - from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier - from erpnext.selling.doctype.customer.test_customer import create_internal_customer - from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt - from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse - - company = "_Test Company with perpetual inventory" - - create_internal_customer( - "_Test Internal Customer 2", - company, - company, - ) - - create_internal_supplier( - "_Test Internal Supplier 2", - company, - company, - ) - - warehouse = create_warehouse("_Test Internal Warehouse New 1", company=company) - - create_warehouse("_Test Internal Warehouse GIT", company=company) - - make_purchase_receipt(company=company, warehouse=warehouse, qty=2, rate=100) - - if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"): - account = "Unrealized Profit and Loss - TCP1" - if not frappe.db.exists("Account", account): - frappe.get_doc( - { - "doctype": "Account", - "account_name": "Unrealized Profit and Loss", - "parent_account": "Direct Income - TCP1", - "company": company, - "is_group": 0, - "account_type": "Income Account", - } - ).insert() - - frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account) - ->>>>>>> 2c83fff1a1 (fix: don't add template item in sales/purchase transaction) - def make_pr_against_po(po, received_qty=0): pr = make_purchase_receipt(po) pr.get("items")[0].qty = received_qty or 5 From 1c5c06716b63bbfe9a7e0d56d63473074405c2b6 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 17 Jan 2023 11:32:06 +0530 Subject: [PATCH 05/13] fix: patch item_reposting_for_incorrect_sl_and_gl (cherry picked from commit dbde3a34210bbf63ea5647d46e3fc74c8f69ca97) # Conflicts: # erpnext/patches.txt --- erpnext/patches.txt | 11 +++++++++++ .../v13_0/item_reposting_for_incorrect_sl_and_gl.py | 1 + 2 files changed, 12 insertions(+) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 47277cc48ce..5123b912f5e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -259,8 +259,11 @@ erpnext.patches.v13_0.convert_qi_parameter_to_link_field erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021 erpnext.patches.v13_0.update_payment_terms_outstanding +<<<<<<< HEAD erpnext.patches.v12_0.add_state_code_for_ladakh erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl +======= +>>>>>>> dbde3a3421 (fix: patch item_reposting_for_incorrect_sl_and_gl) erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes erpnext.patches.v13_0.update_vehicle_no_reqd_condition erpnext.patches.v12_0.add_einvoice_status_field #2021-03-17 @@ -352,6 +355,14 @@ erpnext.patches.v13_0.amazon_mws_deprecation_warning erpnext.patches.v13_0.datev_deprecation_warning erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr erpnext.patches.v13_0.update_accounts_in_loan_docs +<<<<<<< HEAD +======= +erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl +erpnext.patches.v14_0.update_batch_valuation_flag +erpnext.patches.v14_0.delete_non_profit_doctypes +erpnext.patches.v13_0.add_cost_center_in_loans +erpnext.patches.v13_0.set_return_against_in_pos_invoice_references +>>>>>>> dbde3a3421 (fix: patch item_reposting_for_incorrect_sl_and_gl) erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 erpnext.patches.v13_0.rename_non_profit_fields erpnext.patches.v13_0.enable_ksa_vat_docs #1 diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py index f6427ca55a6..bf48d3ab04a 100644 --- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py +++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py @@ -7,6 +7,7 @@ from erpnext.stock.stock_ledger import update_entries_after def execute(): doctypes_to_reload = [ + ("setup", "company"), ("stock", "repost_item_valuation"), ("stock", "stock_entry_detail"), ("stock", "purchase_receipt_item"), From d717ca0325a09780212fd1fe63dad5c41a3f456f Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Fri, 20 Jan 2023 14:05:14 +0530 Subject: [PATCH 06/13] fix: conflicts --- erpnext/patches.txt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 5123b912f5e..f49e06675dd 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -259,11 +259,8 @@ erpnext.patches.v13_0.convert_qi_parameter_to_link_field erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021 erpnext.patches.v13_0.update_payment_terms_outstanding -<<<<<<< HEAD erpnext.patches.v12_0.add_state_code_for_ladakh erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl -======= ->>>>>>> dbde3a3421 (fix: patch item_reposting_for_incorrect_sl_and_gl) erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes erpnext.patches.v13_0.update_vehicle_no_reqd_condition erpnext.patches.v12_0.add_einvoice_status_field #2021-03-17 @@ -355,14 +352,6 @@ erpnext.patches.v13_0.amazon_mws_deprecation_warning erpnext.patches.v13_0.datev_deprecation_warning erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr erpnext.patches.v13_0.update_accounts_in_loan_docs -<<<<<<< HEAD -======= -erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl -erpnext.patches.v14_0.update_batch_valuation_flag -erpnext.patches.v14_0.delete_non_profit_doctypes -erpnext.patches.v13_0.add_cost_center_in_loans -erpnext.patches.v13_0.set_return_against_in_pos_invoice_references ->>>>>>> dbde3a3421 (fix: patch item_reposting_for_incorrect_sl_and_gl) erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 erpnext.patches.v13_0.rename_non_profit_fields erpnext.patches.v13_0.enable_ksa_vat_docs #1 @@ -385,4 +374,4 @@ erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair execute:frappe.db.set_value("Naming Series", "Naming Series", {"select_doc_for_series": "", "set_options": "", "prefix": "", "current_value": 0, "user_must_always_select": 0}) -erpnext.patches.v13_0.update_schedule_type_in_loans \ No newline at end of file +erpnext.patches.v13_0.update_schedule_type_in_loans From 2da543ebd4a15ef48d9bdb1c81f456b50bda0137 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 20 Jan 2023 19:26:05 +0530 Subject: [PATCH 07/13] fix(ecommerce): breadcrumb: fallback to `/all-products` (#33718) fix(ecommerce): breadcrumb: fallback to `/all-products` (#33718) * fix(ecommerce): breadcrumb: fallback to `/all-products` * fix(item_group): use `==` instead of `is` * test(ecommerce): breadcrumb (cherry picked from commit a94aa7a79f3569ecb925f0d2d346dd3aa0ede8df) Co-authored-by: Sabu Siyad --- .../e_commerce/doctype/website_item/test_website_item.py | 7 +++++-- erpnext/setup/doctype/item_group/item_group.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/erpnext/e_commerce/doctype/website_item/test_website_item.py b/erpnext/e_commerce/doctype/website_item/test_website_item.py index 18e18dd31a9..ebf01bf43fb 100644 --- a/erpnext/e_commerce/doctype/website_item/test_website_item.py +++ b/erpnext/e_commerce/doctype/website_item/test_website_item.py @@ -173,7 +173,10 @@ class TestWebsiteItem(unittest.TestCase): # Website Item Portal Tests Begin def test_website_item_breadcrumbs(self): - "Check if breadcrumbs include homepage, product listing navigation page, parent item group(s) and item group." + """ + Check if breadcrumbs include homepage, product listing navigation page, + parent item group(s) and item group + """ from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups item_code = "Test Breadcrumb Item" @@ -196,7 +199,7 @@ class TestWebsiteItem(unittest.TestCase): breadcrumbs = get_parent_item_groups(item.item_group) self.assertEqual(breadcrumbs[0]["name"], "Home") - self.assertEqual(breadcrumbs[1]["name"], "Shop by Category") + self.assertEqual(breadcrumbs[1]["name"], "All Products") self.assertEqual(breadcrumbs[2]["name"], "_Test Item Group B") # parent item group self.assertEqual(breadcrumbs[3]["name"], "_Test Item Group B - 1") diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index b0ff1ccfcd7..a11cfc3407a 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -149,12 +149,12 @@ def get_item_for_list_in_html(context): def get_parent_item_groups(item_group_name, from_item=False): - base_nav_page = {"name": _("Shop by Category"), "route": "/shop-by-category"} + base_nav_page = {"name": _("All Products"), "route": "/all-products"} if from_item and frappe.request.environ.get("HTTP_REFERER"): # base page after 'Home' will vary on Item page last_page = frappe.request.environ["HTTP_REFERER"].split("/")[-1].split("?")[0] - if last_page and last_page in ("shop-by-category", "all-products"): + if last_page and last_page == "shop-by-category": base_nav_page_title = " ".join(last_page.split("-")).title() base_nav_page = {"name": _(base_nav_page_title), "route": "/" + last_page} From af3a0e56f6147e8ef816a135f1dcd6a54ebd3d0d Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 20 Jan 2023 18:22:33 +0100 Subject: [PATCH 08/13] chore: bump python version for docs-checker (#33756) --- .github/workflows/docs-checker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-checker.yml b/.github/workflows/docs-checker.yml index db46c5621b2..722c1252ed9 100644 --- a/.github/workflows/docs-checker.yml +++ b/.github/workflows/docs-checker.yml @@ -12,7 +12,7 @@ jobs: - name: 'Setup Environment' uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: '3.10' - name: 'Clone repo' uses: actions/checkout@v2 From d6504320b152629c22b63488a29fb019e78014ea Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 20 Jan 2023 23:38:37 +0530 Subject: [PATCH 09/13] fix: calculate correct amount for qty == 0 (backport #33739) (#33752) fix: calculate correct amount for qty == 0 (#33739) (cherry picked from commit 327b6fdb32c07491058002abe4d06f2d45060061) Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- .../public/js/controllers/taxes_and_totals.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index c75e7b77f70..a9f1ff684f8 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -115,24 +115,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ calculate_item_values: function() { let me = this; if (!this.discount_amount_applied) { - $.each(this.frm.doc["items"] || [], function(i, item) { + for (item of this.frm.doc.items || []) { frappe.model.round_floats_in(item); item.net_rate = item.rate; - - if ((!item.qty) && me.frm.doc.is_return) { - item.amount = flt(item.rate * -1, precision("amount", item)); - } else if ((!item.qty) && me.frm.doc.is_debit_note) { - item.amount = flt(item.rate, precision("amount", item)); - } else { - item.amount = flt(item.rate * item.qty, precision("amount", item)); - } - - item.net_amount = item.amount; + item.qty = item.qty === undefined ? (me.frm.doc.is_return ? -1 : 1) : item.qty; + item.net_amount = item.amount = flt(item.rate * item.qty, precision("amount", item)); item.item_tax_amount = 0.0; item.total_weight = flt(item.weight_per_unit * item.stock_qty); me.set_in_company_currency(item, ["price_list_rate", "rate", "amount", "net_rate", "net_amount"]); - }); + } } }, From 09e13d279c1a4dbaab5924bb4e877c33bfa06984 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 20 Jan 2023 22:38:56 +0530 Subject: [PATCH 10/13] fix: incorrect actual qty for the packed item (cherry picked from commit 02566a02a8a9768d7a48846a9ea49c32daf467a7) --- .../sales_invoice/test_sales_invoice.py | 40 +++++++++++++++++++ erpnext/controllers/selling_controller.py | 2 +- .../doctype/sales_order/test_sales_order.py | 36 +++++++++++++++++ .../delivery_note/test_delivery_note.py | 40 +++++++++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 79a67b83631..6035e86d067 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1117,6 +1117,46 @@ class TestSalesInvoice(unittest.TestCase): frappe.db.sql("delete from `tabPOS Profile`") + def test_bin_details_of_packed_item(self): + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + from erpnext.stock.doctype.item.test_item import make_item + + # test Update Items with product bundle + if not frappe.db.exists("Item", "_Test Product Bundle Item New"): + bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0}) + bundle_item.append( + "item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"} + ) + bundle_item.save(ignore_permissions=True) + + make_item("_Packed Item New 1", {"is_stock_item": 1}) + make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2) + + si = create_sales_invoice( + item_code="_Test Product Bundle Item New", + update_stock=1, + warehouse="_Test Warehouse - _TC", + transaction_date=add_days(nowdate(), -1), + do_not_submit=1, + ) + + make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100) + + bin_details = frappe.db.get_value( + "Bin", + {"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"}, + ["actual_qty", "projected_qty", "ordered_qty"], + as_dict=1, + ) + + si.transaction_date = nowdate() + si.save() + + packed_item = si.packed_items[0] + self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty)) + self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty)) + self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty)) + def test_pos_si_without_payment(self): make_pos_profile() diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 57f8a3e1513..c52a2dfa95b 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -25,7 +25,7 @@ class SellingController(StockController): def onload(self): super(SellingController, self).onload() if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"): - for item in self.get("items"): + for item in self.get("items") + (self.get("packed_items") or []): item.update(get_bin_details(item.item_code, item.warehouse, include_child_warehouses=True)) def validate(self): diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 8bb25d4538c..a1c6cb5cd6c 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -546,6 +546,42 @@ class TestSalesOrder(FrappeTestCase): workflow.is_active = 0 workflow.save() + def test_bin_details_of_packed_item(self): + # test Update Items with product bundle + if not frappe.db.exists("Item", "_Test Product Bundle Item New"): + bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0}) + bundle_item.append( + "item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"} + ) + bundle_item.save(ignore_permissions=True) + + make_item("_Packed Item New 1", {"is_stock_item": 1}) + make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2) + + so = make_sales_order( + item_code="_Test Product Bundle Item New", + warehouse="_Test Warehouse - _TC", + transaction_date=add_days(nowdate(), -1), + do_not_submit=1, + ) + + make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100) + + bin_details = frappe.db.get_value( + "Bin", + {"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"}, + ["actual_qty", "projected_qty", "ordered_qty"], + as_dict=1, + ) + + so.transaction_date = nowdate() + so.save() + + packed_item = so.packed_items[0] + self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty)) + self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty)) + self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty)) + def test_update_child_product_bundle(self): # test Update Items with product bundle if not frappe.db.exists("Item", "_Product Bundle Item"): diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index d747383d6a5..6847c78d7c8 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -490,6 +490,46 @@ class TestDeliveryNote(FrappeTestCase): self.assertEqual(gle_warehouse_amount, 1400) + def test_bin_details_of_packed_item(self): + from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle + from erpnext.stock.doctype.item.test_item import make_item + + # test Update Items with product bundle + if not frappe.db.exists("Item", "_Test Product Bundle Item New"): + bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0}) + bundle_item.append( + "item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"} + ) + bundle_item.save(ignore_permissions=True) + + make_item("_Packed Item New 1", {"is_stock_item": 1}) + make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2) + + si = create_delivery_note( + item_code="_Test Product Bundle Item New", + update_stock=1, + warehouse="_Test Warehouse - _TC", + transaction_date=add_days(nowdate(), -1), + do_not_submit=1, + ) + + make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100) + + bin_details = frappe.db.get_value( + "Bin", + {"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"}, + ["actual_qty", "projected_qty", "ordered_qty"], + as_dict=1, + ) + + si.transaction_date = nowdate() + si.save() + + packed_item = si.packed_items[0] + self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty)) + self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty)) + self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty)) + def test_return_for_serialized_items(self): se = make_serialized_item() serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] From 3daaa021eb618333f51398c44366747c2d8e9904 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 20 Jan 2023 23:41:14 +0530 Subject: [PATCH 11/13] fix: Short closed order, receipt and delivery note status on cancellation (#33743) fix: Short closed order, receipt, and delivery note status on cancellation (#33743) --- erpnext/controllers/status_updater.py | 8 ++++---- erpnext/stock/doctype/delivery_note/test_delivery_note.py | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 62e90ae747d..23dad95fa0d 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -58,7 +58,7 @@ status_map = { "eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed == 100 and self.docstatus == 1", ], ["Cancelled", "eval:self.docstatus==2"], - ["Closed", "eval:self.status=='Closed'"], + ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"], ["On Hold", "eval:self.status=='On Hold'"], ], "Purchase Order": [ @@ -79,7 +79,7 @@ status_map = { ["Delivered", "eval:self.status=='Delivered'"], ["Cancelled", "eval:self.docstatus==2"], ["On Hold", "eval:self.status=='On Hold'"], - ["Closed", "eval:self.status=='Closed'"], + ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"], ], "Delivery Note": [ ["Draft", None], @@ -87,7 +87,7 @@ status_map = { ["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"], - ["Closed", "eval:self.status=='Closed'"], + ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"], ], "Purchase Receipt": [ ["Draft", None], @@ -95,7 +95,7 @@ status_map = { ["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"], - ["Closed", "eval:self.status=='Closed'"], + ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"], ], "Material Request": [ ["Draft", None], diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index d747383d6a5..b2ea0831758 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -650,6 +650,11 @@ class TestDeliveryNote(FrappeTestCase): update_delivery_note_status(dn.name, "Closed") self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed") + # Check cancelling closed delivery note + dn.load_from_db() + dn.cancel() + self.assertEqual(dn.status, "Cancelled") + def test_dn_billing_status_case1(self): # SO -> DN -> SI so = make_sales_order() From 4511d413298738d3d89896bd67350831150f2294 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 21 Jan 2023 12:03:33 +0530 Subject: [PATCH 12/13] Removed an unnecessary check in code which always evaluates to true (#33710) fix: removed an unnecessary check which always evaluates to true --- .../deferred_revenue_and_expense.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py index 1eb257ac853..7d2db26c25f 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py @@ -378,15 +378,14 @@ class Deferred_Revenue_and_Expense_Report(object): ret += [{}] # add total row - if ret is not []: - if self.filters.type == "Revenue": - total_row = frappe._dict({"name": "Total Deferred Income"}) - elif self.filters.type == "Expense": - total_row = frappe._dict({"name": "Total Deferred Expense"}) + if self.filters.type == "Revenue": + total_row = frappe._dict({"name": "Total Deferred Income"}) + elif self.filters.type == "Expense": + total_row = frappe._dict({"name": "Total Deferred Expense"}) - for idx, period in enumerate(self.period_list, 0): - total_row[period.key] = self.period_total[idx].total - ret.append(total_row) + for idx, period in enumerate(self.period_list, 0): + total_row[period.key] = self.period_total[idx].total + ret.append(total_row) return ret From 47e500c2ebf7dd7185e7b4dfc607971d9622e2da Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 21 Jan 2023 15:44:27 +0530 Subject: [PATCH 13/13] fix(minor): Label updates in Statement of Accounts (#33639) fix(minor): Label updates in Statement of Accounts (#33639) --- .../process_statement_of_accounts.html | 1 - erpnext/accounts/report/general_ledger/general_ledger.html | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html index 0da44a464e7..3920d4cf096 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html @@ -49,7 +49,6 @@
{% endif %} - {{ _("Against") }}: {{ row.against }}
{{ _("Remarks") }}: {{ row.remarks }} {% if row.bill_no %}
{{ _("Supplier Invoice No") }}: {{ row.bill_no }} diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html index 378fa3791c1..1aad36ca909 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.html +++ b/erpnext/accounts/report/general_ledger/general_ledger.html @@ -25,8 +25,8 @@ {%= __("Date") %} - {%= __("Ref") %} - {%= __("Party") %} + {%= __("Reference") %} + {%= __("Remarks") %} {%= __("Debit") %} {%= __("Credit") %} {%= __("Balance (Dr - Cr)") %} @@ -45,7 +45,6 @@
{% } %} - {{ __("Against") }}: {%= data[i].against %}
{%= __("Remarks") %}: {%= data[i].remarks %} {% if(data[i].bill_no) { %}
{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}