From a94e362b8ce33144b69afb1fcfc94a261374a551 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 8 Jun 2026 23:08:17 +0530 Subject: [PATCH 1/2] fix: sql injection (cherry picked from commit bd0acf4413fa99a3710e997c2c8dcb75e0286c64) # Conflicts: # erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py --- .../inactive_sales_items.py | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py index df3fc48f9e1..f67214dfe35 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py @@ -4,6 +4,7 @@ import frappe from frappe import _ +from frappe.query_builder import CustomFunction from frappe.utils import cint @@ -94,19 +95,39 @@ def get_data(filters): def get_sales_details(filters): item_details_map = {} +<<<<<<< HEAD date_field = "s.transaction_date" if filters["based_on"] == "Sales Order" else "s.posting_date" +======= + if filters["based_on"] not in ("Sales Order", "Sales Invoice"): + frappe.throw(_("Invalid value {0} for 'Based On'").format(filters["based_on"])) - sales_data = frappe.db.sql( - """ - select s.territory, s.customer, si.item_group, si.item_code, si.qty, {date_field} as last_order_date, - DATEDIFF(CURRENT_DATE, {date_field}) as days_since_last_order - from `tab{doctype}` s, `tab{doctype} Item` si - where s.name = si.parent and s.docstatus = 1 - order by days_since_last_order """.format( # nosec - date_field=date_field, doctype=filters["based_on"] - ), - as_dict=1, - ) + parent = frappe.qb.DocType(filters["based_on"]) + child_doctype = "Sales Order Item" if filters["based_on"] == "Sales Order" else "Sales Invoice Item" + child = frappe.qb.DocType(child_doctype) +>>>>>>> bd0acf4413 (fix: sql injection) + + date_diff = CustomFunction("DATEDIFF", ["d1", "d2"]) + current_date = CustomFunction("CURRENT_DATE", []) + + date_col = parent.transaction_date if filters["based_on"] == "Sales Order" else parent.posting_date + days_since_last_order = date_diff(current_date(), date_col) + + sales_data = ( + frappe.qb.from_(parent) + .inner_join(child) + .on(parent.name == child.parent) + .select( + parent.territory, + parent.customer, + child.item_group, + child.item_code, + child.qty, + date_col.as_("last_order_date"), + days_since_last_order.as_("days_since_last_order"), + ) + .where(parent.docstatus == 1) + .orderby(days_since_last_order) + ).run(as_dict=True) for d in sales_data: item_details_map.setdefault((d.territory, d.item_code), d) From c0f56cd284a1197f66d5ac600c886d45d704e8ce Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 9 Jun 2026 09:31:58 +0530 Subject: [PATCH 2/2] chore: fix conflicts Removed conflicting code related to date_field assignment based on filters. --- .../report/inactive_sales_items/inactive_sales_items.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py index f67214dfe35..6f90cb13398 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py @@ -95,16 +95,12 @@ def get_data(filters): def get_sales_details(filters): item_details_map = {} -<<<<<<< HEAD - date_field = "s.transaction_date" if filters["based_on"] == "Sales Order" else "s.posting_date" -======= if filters["based_on"] not in ("Sales Order", "Sales Invoice"): frappe.throw(_("Invalid value {0} for 'Based On'").format(filters["based_on"])) parent = frappe.qb.DocType(filters["based_on"]) child_doctype = "Sales Order Item" if filters["based_on"] == "Sales Order" else "Sales Invoice Item" child = frappe.qb.DocType(child_doctype) ->>>>>>> bd0acf4413 (fix: sql injection) date_diff = CustomFunction("DATEDIFF", ["d1", "d2"]) current_date = CustomFunction("CURRENT_DATE", [])