From 9e649d852237a54bae334f7c6f413cbdd38f54c5 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 2 Mar 2025 11:29:39 +0530 Subject: [PATCH 01/14] fix: dont update rate of free item when batch is updated (cherry picked from commit a3596f717b6a8145535d4a133d518f565e4ec0c5) # Conflicts: # erpnext/stock/get_item_details.py --- erpnext/stock/get_item_details.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 5c5fe5db276..58f83d7a593 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -221,7 +221,7 @@ def update_stock(ctx, out, doc=None): else: qty -= batch_qty - out.update({"batch_no": batch_no, "actual_batch_qty": qty}) + out.update({"batch_no": batch_no, "actual_batch_qty": batch_qty}) if rate: out.update({"rate": rate, "price_list_rate": rate}) @@ -1051,8 +1051,13 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) +<<<<<<< HEAD if item_price and item_price[0][2] == params.get("uom"): return item_price[0][1] +======= + if item_price and item_price[0].uom == pctx.uom and not pctx.get("items")[0].get("is_free_item"): + return item_price[0].price_list_rate +>>>>>>> a3596f717b (fix: dont update rate of free item when batch is updated) return 0.0 From 61d5680c8daf0b683be3460487711f98ac2d2232 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 2 Mar 2025 12:07:31 +0530 Subject: [PATCH 02/14] fix: error (cherry picked from commit 7c9c0c7776b709005e4abe0edaa2591e3fa1e7cc) # Conflicts: # erpnext/stock/get_item_details.py --- erpnext/stock/get_item_details.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 58f83d7a593..dee4c362363 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1051,11 +1051,15 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) +<<<<<<< HEAD <<<<<<< HEAD if item_price and item_price[0][2] == params.get("uom"): return item_price[0][1] ======= if item_price and item_price[0].uom == pctx.uom and not pctx.get("items")[0].get("is_free_item"): +======= + if item_price and item_price[0].uom == pctx.uom and not pctx.get("items", [{}])[0].get("is_free_item", 0): +>>>>>>> 7c9c0c7776 (fix: error) return item_price[0].price_list_rate >>>>>>> a3596f717b (fix: dont update rate of free item when batch is updated) From 7f4d553201c496cc75bcf370aa84f3fff143a775 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 3 Mar 2025 12:28:06 +0530 Subject: [PATCH 03/14] chore: resolve conflicts --- erpnext/stock/get_item_details.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index dee4c362363..68d4cc85c42 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1051,17 +1051,8 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) -<<<<<<< HEAD -<<<<<<< HEAD - if item_price and item_price[0][2] == params.get("uom"): - return item_price[0][1] -======= - if item_price and item_price[0].uom == pctx.uom and not pctx.get("items")[0].get("is_free_item"): -======= if item_price and item_price[0].uom == pctx.uom and not pctx.get("items", [{}])[0].get("is_free_item", 0): ->>>>>>> 7c9c0c7776 (fix: error) return item_price[0].price_list_rate ->>>>>>> a3596f717b (fix: dont update rate of free item when batch is updated) return 0.0 From 81c7b8c273d1ef7ceab82e00030c7d7a11530415 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 3 Mar 2025 15:05:44 +0530 Subject: [PATCH 04/14] chore: resolve conflicts --- erpnext/stock/get_item_details.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 68d4cc85c42..cd5f7107561 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1051,7 +1051,7 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) - if item_price and item_price[0].uom == pctx.uom and not pctx.get("items", [{}])[0].get("is_free_item", 0): + if item_price and item_price[0].uom == params.uom and not params.get("items", [{}])[0].get("is_free_item", 0): return item_price[0].price_list_rate return 0.0 From cc535b76365325d189d7faee0556a23679bb6bb1 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 3 Mar 2025 15:27:35 +0530 Subject: [PATCH 05/14] fix: syntax error --- erpnext/stock/get_item_details.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index cd5f7107561..f220024e415 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1051,7 +1051,7 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) - if item_price and item_price[0].uom == params.uom and not params.get("items", [{}])[0].get("is_free_item", 0): + if item_price and item_price[0].uom == params.get("uom") and not params.get("items", [{}])[0].get("is_free_item", 0): return item_price[0].price_list_rate return 0.0 From bd48d391e4a9c6e78e0e9896da9ebf8bce64efc5 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 3 Mar 2025 16:40:19 +0530 Subject: [PATCH 06/14] fix: syntax error --- erpnext/stock/get_item_details.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index f220024e415..23e6e003bb0 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1051,8 +1051,8 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) - if item_price and item_price[0].uom == params.get("uom") and not params.get("items", [{}])[0].get("is_free_item", 0): - return item_price[0].price_list_rate + if item_price and item_price[0][2] == params.get("uom") and not params.get("items", [{}])[0].get("is_free_item", 0): + return item_price[0][1] return 0.0 From d10add4b1ecddff754e822d3558b9917117baf17 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 4 Mar 2025 11:48:28 +0530 Subject: [PATCH 07/14] fix: delivery note from sales order uom conversion mistake (cherry picked from commit 49a43d355d346a492d88bb18b3a76e8d5a255abd) # Conflicts: # erpnext/selling/doctype/sales_order/sales_order.py --- erpnext/selling/doctype/sales_order/sales_order.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index effc3f3894d..4e19526c06a 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1044,7 +1044,12 @@ def make_delivery_note(source_name, target_doc=None, kwargs=None): ignore_permissions=True, ) +<<<<<<< HEAD dn_item.qty = flt(sre.reserved_qty) * flt(dn_item.get("conversion_factor", 1)) +======= + dn_item.qty = flt(sre.reserved_qty) / flt(dn_item.get("conversion_factor", 1)) + dn_item.warehouse = sre.warehouse +>>>>>>> 49a43d355d (fix: delivery note from sales order uom conversion mistake) if sre.reservation_based_on == "Serial and Batch" and (sre.has_serial_no or sre.has_batch_no): dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre) From 6b56724436c8200bfa0a4cf6d30c8858b2af2ce6 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Mar 2025 12:46:52 +0530 Subject: [PATCH 08/14] chore: resolve conflicts --- erpnext/selling/doctype/sales_order/sales_order.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 4e19526c06a..74e2328be24 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1044,12 +1044,7 @@ def make_delivery_note(source_name, target_doc=None, kwargs=None): ignore_permissions=True, ) -<<<<<<< HEAD - dn_item.qty = flt(sre.reserved_qty) * flt(dn_item.get("conversion_factor", 1)) -======= dn_item.qty = flt(sre.reserved_qty) / flt(dn_item.get("conversion_factor", 1)) - dn_item.warehouse = sre.warehouse ->>>>>>> 49a43d355d (fix: delivery note from sales order uom conversion mistake) if sre.reservation_based_on == "Serial and Batch" and (sre.has_serial_no or sre.has_batch_no): dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre) From 0b50f1a9c33361bd13603fe1472acfbb608541d7 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Mar 2025 12:57:53 +0530 Subject: [PATCH 09/14] chore: fix pre-commit/linter error --- erpnext/stock/get_item_details.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 23e6e003bb0..ff87d159e36 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1051,7 +1051,11 @@ def get_batch_based_item_price(params, item_code) -> float: if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) - if item_price and item_price[0][2] == params.get("uom") and not params.get("items", [{}])[0].get("is_free_item", 0): + if ( + item_price + and item_price[0][2] == params.get("uom") + and not params.get("items", [{}])[0].get("is_free_item", 0) + ): return item_price[0][1] return 0.0 From 5ae9faab91116fabe663a891d4b343ceffbc65cc Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:11:34 +0530 Subject: [PATCH 10/14] fix: only include submitted docs for internal received quantity validation (backport #46262) (#46304) fix: only include submitted docs for internal received quantity validation (#46262) (cherry picked from commit 88fcdbb81e5aa95fdf29b17d5cdc6f4cc58ccabd) Co-authored-by: Lakshit Jain <108322669+ljain112@users.noreply.github.com> --- erpnext/controllers/stock_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index a8f9976c83b..e892c5d27e2 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1234,7 +1234,7 @@ class StockController(AccountsController): child_tab.item_code, child_tab.qty, ) - .where(parent_tab.docstatus < 2) + .where(parent_tab.docstatus == 1) ) if self.doctype == "Purchase Invoice": From 087dde5873fe64979307856be0a68e38a5f2b445 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:11:45 +0530 Subject: [PATCH 11/14] fix: depreciation and balances report correction (backport #46259) (#46305) fix: depreciation and balances report correction (#46259) (cherry picked from commit 4a542b22a4201f047a9bde553680406bd22960d4) Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> --- .../asset_depreciations_and_balances.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py index bec5d128f0a..5229839bec6 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py @@ -50,6 +50,7 @@ def get_group_by_asset_category_data(filters): flt(row.accumulated_depreciation_as_on_from_date) + flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated_during_the_period) + - flt(row.depreciation_eliminated_via_reversal) ) row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt( @@ -247,6 +248,7 @@ def get_group_by_asset_data(filters): flt(row.accumulated_depreciation_as_on_from_date) + flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated_during_the_period) + - flt(row.depreciation_eliminated_via_reversal) ) row.net_asset_value_as_on_from_date = flt(row.value_as_on_from_date) - flt( @@ -276,6 +278,7 @@ def get_assets_for_grouped_by_category(filters): f""" SELECT results.asset_category, sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date, + sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period from (SELECT a.asset_category, @@ -284,6 +287,11 @@ def get_assets_for_grouped_by_category(filters): else 0 end), 0) as accumulated_depreciation_as_on_from_date, + ifnull(sum(case when gle.posting_date <= %(to_date)s and ifnull(a.disposal_date, 0) = 0 then + gle.credit + else + 0 + end), 0) as depreciation_eliminated_via_reversal, ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then gle.debit @@ -307,7 +315,6 @@ def get_assets_for_grouped_by_category(filters): a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s - and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) {condition} {finance_book_filter} @@ -319,6 +326,7 @@ def get_assets_for_grouped_by_category(filters): else a.opening_accumulated_depreciation end), 0) as accumulated_depreciation_as_on_from_date, + 0 as depreciation_eliminated_via_reversal, ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then a.opening_accumulated_depreciation else @@ -354,6 +362,7 @@ def get_assets_for_grouped_by_asset(filters): f""" SELECT results.name as asset, sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date, + sum(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period from (SELECT a.name as name, @@ -362,6 +371,11 @@ def get_assets_for_grouped_by_asset(filters): else 0 end), 0) as accumulated_depreciation_as_on_from_date, + ifnull(sum(case when gle.posting_date <= %(to_date)s and ifnull(a.disposal_date, 0) = 0 then + gle.credit + else + 0 + end), 0) as depreciation_eliminated_via_reversal, ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then gle.debit @@ -385,7 +399,6 @@ def get_assets_for_grouped_by_asset(filters): a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s - and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) {finance_book_filter} {condition} @@ -397,6 +410,7 @@ def get_assets_for_grouped_by_asset(filters): else a.opening_accumulated_depreciation end), 0) as accumulated_depreciation_as_on_from_date, + 0 as depreciation_as_on_from_date_credit, ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then a.opening_accumulated_depreciation else @@ -503,6 +517,12 @@ def get_columns(filters): "fieldtype": "Currency", "width": 270, }, + { + "label": _("Depreciation eliminated via reversal"), + "fieldname": "depreciation_eliminated_via_reversal", + "fieldtype": "Currency", + "width": 270, + }, { "label": _("Net Asset value as on") + " " + formatdate(filters.day_before_from_date), "fieldname": "net_asset_value_as_on_from_date", From 363129bcd4d674df9762933ec2642330bc862e50 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:11:53 +0530 Subject: [PATCH 12/14] fix(workspace): enable is_query_report on purchase reports (backport #46249) (#46306) fix(workspace): enable is_query_report on purchase reports (#46249) * fix(workspace): enable is_query_report on purchase reports * fix: resolved conflict --------- Co-authored-by: venkat102 (cherry picked from commit 5513e24b001cce2e4011e711cf2474150b77e5ef) Co-authored-by: Nabin Hait --- .../accounts/workspace/payables/payables.json | 14 +++++------ erpnext/patches.txt | 1 + erpnext/patches/v15_0/update_query_report.py | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 erpnext/patches/v15_0/update_query_report.py diff --git a/erpnext/accounts/workspace/payables/payables.json b/erpnext/accounts/workspace/payables/payables.json index f8c85648756..96c626c7291 100644 --- a/erpnext/accounts/workspace/payables/payables.json +++ b/erpnext/accounts/workspace/payables/payables.json @@ -93,7 +93,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Accounts Payable", "link_count": 0, "link_to": "Accounts Payable", @@ -103,7 +103,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Accounts Payable Summary", "link_count": 0, "link_to": "Accounts Payable Summary", @@ -113,7 +113,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Purchase Register", "link_count": 0, "link_to": "Purchase Register", @@ -123,7 +123,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Item-wise Purchase Register", "link_count": 0, "link_to": "Item-wise Purchase Register", @@ -133,7 +133,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Purchase Order Analysis", "link_count": 0, "link_to": "Purchase Order Analysis", @@ -143,7 +143,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Received Items To Be Billed", "link_count": 0, "link_to": "Received Items To Be Billed", @@ -153,7 +153,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Supplier Ledger Summary", "link_count": 0, "link_to": "Supplier Ledger Summary", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index df1b885ad18..f292abfd50a 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -395,3 +395,4 @@ erpnext.patches.v14_0.disable_add_row_in_gross_profit erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment erpnext.patches.v14_0.update_posting_datetime erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes +erpnext.patches.v15_0.update_query_report diff --git a/erpnext/patches/v15_0/update_query_report.py b/erpnext/patches/v15_0/update_query_report.py new file mode 100644 index 00000000000..0efdf8af2c3 --- /dev/null +++ b/erpnext/patches/v15_0/update_query_report.py @@ -0,0 +1,25 @@ +import frappe + + +def execute(): + reports = [ + "Accounts Payable", + "Accounts Payable Summary", + "Purchase Register", + "Item-wise Purchase Register", + "Purchase Order Analysis", + "Received Items To Be Billed", + "Supplier Ledger Summary", + ] + frappe.db.set_value( + "Workspace Link", + { + "parent": "Payables", + "link_type": "Report", + "type": "Link", + "link_to": ["in", reports], + "is_query_report": 0, + }, + "is_query_report", + 1, + ) From 400f4f32adf4e789d692750ff4213a7321c41f39 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:12:09 +0530 Subject: [PATCH 13/14] feat(received items to be billed): add company and date filters (backport #46271) (#46302) feat(received items to be billed): add company and date filters (#46271) * feat(received items to be billed): add company and date filters * feat(delivered to be billed): add company and date filters * feat: add company and date conditions * chore: remove debugger (cherry picked from commit 6117706ab5ad68becd81e967561ddfe0b4f67c73) Co-authored-by: Sudharsanan Ashok <135326972+Sudharsanan11@users.noreply.github.com> --- .../delivered_items_to_be_billed.js | 24 ++++- .../delivered_items_to_be_billed.py | 13 +-- erpnext/accounts/report/non_billed_report.py | 89 +++++++++++-------- .../received_items_to_be_billed.js | 24 ++++- .../received_items_to_be_billed.py | 13 +-- 5 files changed, 104 insertions(+), 59 deletions(-) diff --git a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.js b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.js index f6051d7e04f..1be58ad9d55 100644 --- a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.js +++ b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.js @@ -2,5 +2,27 @@ // For license information, please see license.txt frappe.query_reports["Delivered Items To Be Billed"] = { - filters: [], + filters: [ + { + label: __("Company"), + fieldname: "company", + fieldtype: "Link", + options: "Company", + reqd: 1, + default: frappe.defaults.get_default("Company"), + }, + { + label: __("As on Date"), + fieldname: "posting_date", + fieldtype: "Date", + reqd: 1, + default: frappe.datetime.get_today(), + }, + { + label: __("Delivery Note"), + fieldname: "delivery_note", + fieldtype: "Link", + options: "Delivery Note", + }, + ], }; diff --git a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py index 59914dc29ac..d2e5ff28247 100644 --- a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py +++ b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py @@ -3,6 +3,7 @@ from frappe import _ +from pypika import Order from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data @@ -10,7 +11,7 @@ from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_d def execute(filters=None): columns = get_column() args = get_args() - data = get_ordered_to_be_billed_data(args) + data = get_ordered_to_be_billed_data(args, filters) return columns, data @@ -76,13 +77,6 @@ def get_column(): "options": "Project", "width": 120, }, - { - "label": _("Company"), - "fieldname": "company", - "fieldtype": "Link", - "options": "Company", - "width": 120, - }, ] @@ -92,5 +86,6 @@ def get_args(): "party": "customer", "date": "posting_date", "order": "name", - "order_by": "desc", + "order_by": Order.desc, + "reference_field": "delivery_note", } diff --git a/erpnext/accounts/report/non_billed_report.py b/erpnext/accounts/report/non_billed_report.py index 39c5311cd99..c0ca604cc6d 100644 --- a/erpnext/accounts/report/non_billed_report.py +++ b/erpnext/accounts/report/non_billed_report.py @@ -4,11 +4,12 @@ import frappe from frappe.model.meta import get_field_precision +from frappe.query_builder.functions import IfNull, Round from erpnext import get_default_currency -def get_ordered_to_be_billed_data(args): +def get_ordered_to_be_billed_data(args, filters=None): doctype, party = args.get("doctype"), args.get("party") child_tab = doctype + " Item" precision = ( @@ -18,47 +19,57 @@ def get_ordered_to_be_billed_data(args): or 2 ) - project_field = get_project_field(doctype, party) + doctype = frappe.qb.DocType(doctype) + child_doctype = frappe.qb.DocType(child_tab) - return frappe.db.sql( - """ - Select - `{parent_tab}`.name, `{parent_tab}`.{date_field}, - `{parent_tab}`.{party}, `{parent_tab}`.{party}_name, - `{child_tab}`.item_code, - `{child_tab}`.base_amount, - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)), - (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0)), - (`{child_tab}`.base_amount - - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)) - - (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))), - `{child_tab}`.item_name, `{child_tab}`.description, - {project_field}, `{parent_tab}`.company - from - `{parent_tab}`, `{child_tab}` - where - `{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 - and `{parent_tab}`.status not in ('Closed', 'Completed') - and `{child_tab}`.amount > 0 - and (`{child_tab}`.base_amount - - round(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) - - (`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))) > 0 - order by - `{parent_tab}`.{order} {order_by} - """.format( - parent_tab="tab" + doctype, - child_tab="tab" + child_tab, - precision=precision, - party=party, - date_field=args.get("date"), - project_field=project_field, - order=args.get("order"), - order_by=args.get("order_by"), + docname = filters.get(args.get("reference_field"), None) + project_field = get_project_field(doctype, child_doctype, party) + + query = ( + frappe.qb.from_(doctype) + .inner_join(child_doctype) + .on(doctype.name == child_doctype.parent) + .select( + doctype.name, + doctype[args.get("date")].as_("date"), + doctype[party], + doctype[party + "_name"], + child_doctype.item_code, + child_doctype.base_amount.as_("amount"), + (child_doctype.billed_amt * IfNull(doctype.conversion_rate, 1)).as_("billed_amount"), + (child_doctype.base_rate * IfNull(child_doctype.returned_qty, 0)).as_("returned_amount"), + ( + child_doctype.base_amount + - (child_doctype.billed_amt * IfNull(doctype.conversion_rate, 1)) + - (child_doctype.base_rate * IfNull(child_doctype.returned_qty, 0)) + ).as_("pending_amount"), + child_doctype.item_name, + child_doctype.description, + project_field, ) + .where( + (doctype.docstatus == 1) + & (doctype.status.notin(["Closed", "Completed"])) + & (doctype.company == filters.get("company")) + & (doctype.posting_date <= filters.get("posting_date")) + & (child_doctype.amount > 0) + & ( + child_doctype.base_amount + - Round(child_doctype.billed_amt * IfNull(doctype.conversion_rate, 1), precision) + - (child_doctype.base_rate * IfNull(child_doctype.returned_qty, 0)) + ) + > 0 + ) + .orderby(doctype[args.get("order")], order=args.get("order_by")) ) + if docname: + query = query.where(doctype.name == docname) -def get_project_field(doctype, party): + return query.run(as_dict=True) + + +def get_project_field(doctype, child_doctype, party): if party == "supplier": - doctype = doctype + " Item" - return "`tab%s`.project" % (doctype) + return child_doctype.project + return doctype.project diff --git a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.js b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.js index ad97f270dd3..2577a82ef65 100644 --- a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.js +++ b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.js @@ -2,5 +2,27 @@ // For license information, please see license.txt frappe.query_reports["Received Items To Be Billed"] = { - filters: [], + filters: [ + { + label: __("Company"), + fieldname: "company", + fieldtype: "Link", + options: "Company", + reqd: 1, + default: frappe.defaults.get_default("Company"), + }, + { + label: __("As on Date"), + fieldname: "posting_date", + fieldtype: "Date", + reqd: 1, + default: frappe.datetime.get_today(), + }, + { + label: __("Purchase Receipt"), + fieldname: "purchase_receipt", + fieldtype: "Link", + options: "Purchase Receipt", + }, + ], }; diff --git a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py index 1dcacb97420..87b7b109b99 100644 --- a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py +++ b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py @@ -3,6 +3,7 @@ from frappe import _ +from pypika import Order from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data @@ -10,7 +11,7 @@ from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_d def execute(filters=None): columns = get_column() args = get_args() - data = get_ordered_to_be_billed_data(args) + data = get_ordered_to_be_billed_data(args, filters) return columns, data @@ -76,13 +77,6 @@ def get_column(): "options": "Project", "width": 120, }, - { - "label": _("Company"), - "fieldname": "company", - "fieldtype": "Link", - "options": "Company", - "width": 120, - }, ] @@ -92,5 +86,6 @@ def get_args(): "party": "supplier", "date": "posting_date", "order": "name", - "order_by": "desc", + "order_by": Order.desc, + "reference_field": "purchase_receipt", } From 4f80ddd8348d5004744ba5d39ab1bb73bff8c923 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:12:20 +0530 Subject: [PATCH 14/14] fix: Add company filter at get_invoice method (backport #46238) (#46299) fix: Add company filter at get_invoice method (#46238) (cherry picked from commit a8d1cbc1c34b644ce595e4fb88af961269dcdc3d) Co-authored-by: Kunhi --- .../deferred_revenue_and_expense/deferred_revenue_and_expense.py | 1 + 1 file changed, 1 insertion(+) 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 377777ab2a3..1c85061a551 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 @@ -307,6 +307,7 @@ class Deferred_Revenue_and_Expense_Report: .where( (inv.docstatus == 1) & (deferred_flag_field == 1) + & (inv.company == self.filters.company) & ( ( (self.period_list[0].from_date >= inv_item.service_start_date)