From 1ddfaa7605f710b2fd12ccdfa38824cd086f576d Mon Sep 17 00:00:00 2001 From: Gursheen Kaur Anand <40693548+GursheenK@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:29:20 +0530 Subject: [PATCH 1/8] fix: ignore cancelled gle in voucher-wise balance report (#36417) fix: ignore cancelled gle --- .../accounts/report/voucher_wise_balance/voucher_wise_balance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/report/voucher_wise_balance/voucher_wise_balance.py b/erpnext/accounts/report/voucher_wise_balance/voucher_wise_balance.py index 5ab3611b9a..bd9e9fccad 100644 --- a/erpnext/accounts/report/voucher_wise_balance/voucher_wise_balance.py +++ b/erpnext/accounts/report/voucher_wise_balance/voucher_wise_balance.py @@ -46,6 +46,7 @@ def get_data(filters): .select( gle.voucher_type, gle.voucher_no, Sum(gle.debit).as_("debit"), Sum(gle.credit).as_("credit") ) + .where(gle.is_cancelled == 0) .groupby(gle.voucher_no) ) query = apply_filters(query, filters, gle) From 05b07e098a7f7e5b11f0a18bd62005dc098c5995 Mon Sep 17 00:00:00 2001 From: xdlumertz Date: Mon, 31 Jul 2023 09:04:55 -0300 Subject: [PATCH 2/8] fix: process_owner is not link User (#36420) -Changed "fetch from" since field is not a binding field -Change field "full_name" from Hidden to Read Only --- .../doctype/non_conformance/non_conformance.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.json b/erpnext/quality_management/doctype/non_conformance/non_conformance.json index 8dfe2d6859..e6b87449ce 100644 --- a/erpnext/quality_management/doctype/non_conformance/non_conformance.json +++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.json @@ -62,10 +62,10 @@ "fieldtype": "Column Break" }, { - "fetch_from": "process_owner.full_name", + "fetch_from": "procedure.process_owner_full_name", "fieldname": "full_name", "fieldtype": "Data", - "hidden": 1, + "read_only": 1, "label": "Full Name" }, { @@ -81,7 +81,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-02-26 15:27:47.247814", + "modified": "2023-07-31 08:10:47.247814", "modified_by": "Administrator", "module": "Quality Management", "name": "Non Conformance", From ce36d1f668425539a4937dfca4cefa03dc96648d Mon Sep 17 00:00:00 2001 From: Vimal Date: Mon, 31 Jul 2023 13:21:31 +0100 Subject: [PATCH 3/8] fix: job card suggest holiday as start date (#35958) --- erpnext/manufacturing/doctype/workstation/workstation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py index d5b6d37d67..ac271b7144 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation.py +++ b/erpnext/manufacturing/doctype/workstation/workstation.py @@ -114,7 +114,7 @@ class Workstation(Document): if schedule_date in tuple(get_holidays(self.holiday_list)): schedule_date = add_days(schedule_date, 1) - self.validate_workstation_holiday(schedule_date, skip_holiday_list_check=True) + return self.validate_workstation_holiday(schedule_date, skip_holiday_list_check=True) return schedule_date From 652398fad25d7d6f457ef49667a09d91a8abd8e4 Mon Sep 17 00:00:00 2001 From: xdlumertz Date: Mon, 31 Jul 2023 09:34:33 -0300 Subject: [PATCH 4/8] fix: Defined "Open" Status as default (#36421) Defined "Open" Status as default of the child doctype (Quality Review Objective), because without it the main doctype (Quality Review) has "Passed" status. This happens because in the "set_status" function, the status is updated according to the status of the child records. --- .../quality_review_objective/quality_review_objective.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json index 3a750c21d6..5ddf0f2a0b 100644 --- a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json +++ b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.json @@ -56,6 +56,7 @@ "fieldtype": "Column Break" }, { + "default": "Open", "columns": 2, "fieldname": "status", "fieldtype": "Select", @@ -67,7 +68,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-10-27 16:28:20.908637", + "modified": "2023-07-31 09:20:20.908637", "modified_by": "Administrator", "module": "Quality Management", "name": "Quality Review Objective", @@ -76,4 +77,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} \ No newline at end of file +} From e8eeeb16e26b9885f5ff88d136e8174c3fbd8203 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Mon, 31 Jul 2023 08:47:14 -0400 Subject: [PATCH 5/8] fix: group item reorder by (warehouse, material_request_type) (#35818) * fix: group item reorder by (warehouse, material_request_type) * fix: update reorder error message * chore: linter * fix: correct error message Co-authored-by: s-aga-r * chore: linter --------- Co-authored-by: s-aga-r --- erpnext/stock/doctype/item/item.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index ef4155e48a..aff958738a 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -395,16 +395,16 @@ class Item(Document): def validate_warehouse_for_reorder(self): """Validate Reorder level table for duplicate and conditional mandatory""" - warehouse = [] + warehouse_material_request_type: list[tuple[str, str]] = [] for d in self.get("reorder_levels"): if not d.warehouse_group: d.warehouse_group = d.warehouse - if d.get("warehouse") and d.get("warehouse") not in warehouse: - warehouse += [d.get("warehouse")] + if (d.get("warehouse"), d.get("material_request_type")) not in warehouse_material_request_type: + warehouse_material_request_type += [(d.get("warehouse"), d.get("material_request_type"))] else: frappe.throw( - _("Row {0}: An Reorder entry already exists for this warehouse {1}").format( - d.idx, d.warehouse + _("Row #{0}: A reorder entry already exists for warehouse {1} with reorder type {2}.").format( + d.idx, d.warehouse, d.material_request_type ), DuplicateReorderRows, ) From f83a100a8d41de0c539599394d9bf7260fef847b Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 31 Jul 2023 19:13:23 +0530 Subject: [PATCH 6/8] fix: not able to make material request (#36416) --- .../doctype/sales_order/sales_order.py | 4 ++-- .../doctype/sales_order/test_sales_order.py | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 624dadbc4d..45b3f1ddfe 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -733,7 +733,7 @@ def make_material_request(source_name, target_doc=None): # qty is for packed items, because packed items don't have stock_qty field qty = source.get("qty") target.project = source_parent.project - target.qty = qty - requested_item_qty.get(source.name, 0) - source.delivered_qty + target.qty = qty - requested_item_qty.get(source.name, 0) - flt(source.get("delivered_qty")) target.stock_qty = flt(target.qty) * flt(target.conversion_factor) args = target.as_dict().copy() @@ -767,7 +767,7 @@ def make_material_request(source_name, target_doc=None): "doctype": "Material Request Item", "field_map": {"name": "sales_order_item", "parent": "sales_order"}, "condition": lambda doc: not frappe.db.exists("Product Bundle", doc.item_code) - and (doc.stock_qty - doc.delivered_qty) > requested_item_qty.get(doc.name, 0), + and (doc.stock_qty - flt(doc.get("delivered_qty"))) > requested_item_qty.get(doc.name, 0), "postprocess": update_item, }, }, diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 796e2588ff..c85a4fb2f0 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -549,6 +549,26 @@ class TestSalesOrder(FrappeTestCase): workflow.is_active = 0 workflow.save() + def test_material_request_for_product_bundle(self): + # Create the Material Request from the sales order for the Packing Items + # Check whether the material request has the correct packing item or not. + if not frappe.db.exists("Item", "_Test Product Bundle Item New 1"): + bundle_item = make_item("_Test Product Bundle Item New 1", {"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 2", {"is_stock_item": 1}) + make_product_bundle("_Test Product Bundle Item New 1", ["_Packed Item New 2"], 2) + + so = make_sales_order( + item_code="_Test Product Bundle Item New 1", + ) + + mr = make_material_request(so.name) + self.assertEqual(mr.items[0].item_code, "_Packed Item New 2") + 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"): From f31d07554d05f5b325d8770b90e70e9ee214844b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 31 Jul 2023 22:13:47 +0530 Subject: [PATCH 7/8] perf: avoid full table scan in sle count check (#36428) --- .../batch_wise_balance_history/batch_wise_balance_history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py index bdc9d742c0..176a21566a 100644 --- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py +++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py @@ -17,7 +17,7 @@ def execute(filters=None): if not filters: filters = {} - sle_count = frappe.db.count("Stock Ledger Entry", {"is_cancelled": 0}) + sle_count = frappe.db.count("Stock Ledger Entry") if sle_count > SLE_COUNT_LIMIT and not filters.get("item_code") and not filters.get("warehouse"): frappe.throw(_("Please select either the Item or Warehouse filter to generate the report.")) From 11bd15e58059e2b2d65619437683f030914996f9 Mon Sep 17 00:00:00 2001 From: Gursheen Kaur Anand <40693548+GursheenK@users.noreply.github.com> Date: Mon, 31 Jul 2023 23:27:16 +0530 Subject: [PATCH 8/8] fix: root type in account map for balance sheet (#36303) * fix: root type in account map * fix: fetch gle by root type in consolidated financial statement * refactor: consolidated financial statement gle query * fix: filter accounts by root type --- .../consolidated_financial_statement.py | 75 ++++++++++++------- .../accounts/report/financial_statements.py | 18 ++++- 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index 0b583a1ec6..7c2ebe1d20 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -6,6 +6,7 @@ from collections import defaultdict import frappe from frappe import _ +from frappe.query_builder import Criterion from frappe.utils import flt, getdate import erpnext @@ -359,6 +360,7 @@ def get_data( accounts_by_name, accounts, ignore_closing_entries=False, + root_type=root_type, ) calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year) @@ -603,6 +605,7 @@ def set_gl_entries_by_account( accounts_by_name, accounts, ignore_closing_entries=False, + root_type=None, ): """Returns a dict like { "account": [gl entries], ... }""" @@ -610,7 +613,6 @@ def set_gl_entries_by_account( "Company", filters.get("company"), ["lft", "rgt"] ) - additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters) companies = frappe.db.sql( """ select name, default_currency from `tabCompany` where lft >= %(company_lft)s and rgt <= %(company_rgt)s""", @@ -626,27 +628,42 @@ def set_gl_entries_by_account( ) for d in companies: - gl_entries = frappe.db.sql( - """select gl.posting_date, gl.account, gl.debit, gl.credit, gl.is_opening, gl.company, - gl.fiscal_year, gl.debit_in_account_currency, gl.credit_in_account_currency, gl.account_currency, - acc.account_name, acc.account_number - from `tabGL Entry` gl, `tabAccount` acc where acc.name = gl.account and gl.company = %(company)s and gl.is_cancelled = 0 - {additional_conditions} and gl.posting_date <= %(to_date)s and acc.lft >= %(lft)s and acc.rgt <= %(rgt)s - order by gl.account, gl.posting_date""".format( - additional_conditions=additional_conditions - ), - { - "from_date": from_date, - "to_date": to_date, - "lft": root_lft, - "rgt": root_rgt, - "company": d.name, - "finance_book": filters.get("finance_book"), - "company_fb": frappe.get_cached_value("Company", d.name, "default_finance_book"), - }, - as_dict=True, + gle = frappe.qb.DocType("GL Entry") + account = frappe.qb.DocType("Account") + query = ( + frappe.qb.from_(gle) + .inner_join(account) + .on(account.name == gle.account) + .select( + gle.posting_date, + gle.account, + gle.debit, + gle.credit, + gle.is_opening, + gle.company, + gle.fiscal_year, + gle.debit_in_account_currency, + gle.credit_in_account_currency, + gle.account_currency, + account.account_name, + account.account_number, + ) + .where( + (gle.company == d.name) + & (gle.is_cancelled == 0) + & (gle.posting_date <= to_date) + & (account.lft >= root_lft) + & (account.rgt <= root_rgt) + & (account.root_type <= root_type) + ) + .orderby(gle.account, gle.posting_date) ) + additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters, d) + if additional_conditions: + query = query.where(Criterion.all(additional_conditions)) + gl_entries = query.run(as_dict=True) + if filters and filters.get("presentation_currency") != d.default_currency: currency_info["company"] = d.name currency_info["company_currency"] = d.default_currency @@ -716,23 +733,25 @@ def validate_entries(key, entry, accounts_by_name, accounts): accounts.insert(idx + 1, args) -def get_additional_conditions(from_date, ignore_closing_entries, filters): +def get_additional_conditions(from_date, ignore_closing_entries, filters, d): + gle = frappe.qb.DocType("GL Entry") additional_conditions = [] if ignore_closing_entries: - additional_conditions.append("gl.voucher_type != 'Period Closing Voucher'") + additional_conditions.append((gle.voucher_type != "Period Closing Voucher")) if from_date: - additional_conditions.append("gl.posting_date >= %(from_date)s") + additional_conditions.append(gle.posting_date >= from_date) + + finance_book = filters.get("finance_book") + company_fb = frappe.get_cached_value("Company", d.name, "default_finance_book") if filters.get("include_default_book_entries"): - additional_conditions.append( - "(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)" - ) + additional_conditions.append((gle.finance_book.isin([finance_book, company_fb, "", None]))) else: - additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)") + additional_conditions.append((gle.finance_book.isin([finance_book, "", None]))) - return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else "" + return additional_conditions def add_total_row(out, root_type, balance_must_be, companies, company_currency): diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 26bf315b19..a76dea6a52 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -188,6 +188,7 @@ def get_data( filters, gl_entries_by_account, ignore_closing_entries=ignore_closing_entries, + root_type=root_type, ) calculate_values( @@ -417,13 +418,28 @@ def set_gl_entries_by_account( gl_entries_by_account, ignore_closing_entries=False, ignore_opening_entries=False, + root_type=None, ): """Returns a dict like { "account": [gl entries], ... }""" gl_entries = [] + account_filters = { + "company": company, + "is_group": 0, + "lft": (">=", root_lft), + "rgt": ("<=", root_rgt), + } + + if root_type: + account_filters.update( + { + "root_type": root_type, + } + ) + accounts_list = frappe.db.get_all( "Account", - filters={"company": company, "is_group": 0, "lft": (">=", root_lft), "rgt": ("<=", root_rgt)}, + filters=account_filters, pluck="name", )