fix(inactive_customers): add allowlist for doctype filter and migrate to qb

(cherry picked from commit 2ecf8b0466)

# Conflicts:
#	erpnext/selling/report/inactive_customers/inactive_customers.py
This commit is contained in:
Shllokkk
2026-06-01 21:24:42 +05:30
committed by Mergify
parent 38dd2982f3
commit f43af66246

View File

@@ -4,6 +4,8 @@
import frappe import frappe
from frappe import _ from frappe import _
from frappe.query_builder import Case, CustomFunction
from frappe.query_builder.functions import Count, Max, Sum
from frappe.utils import cint from frappe.utils import cint
@@ -14,7 +16,11 @@ def execute(filters=None):
days_since_last_order = filters.get("days_since_last_order") days_since_last_order = filters.get("days_since_last_order")
doctype = filters.get("doctype") doctype = filters.get("doctype")
<<<<<<< HEAD
if doctype not in ("Sales Order", "Sales Invoice"): if doctype not in ("Sales Order", "Sales Invoice"):
=======
if doctype not in {"Sales Order", "Sales Invoice"}:
>>>>>>> 2ecf8b0466 (fix(inactive_customers): add allowlist for doctype filter and migrate to qb)
frappe.throw(_("Invalid value {0} for 'Doctype'").format(doctype)) frappe.throw(_("Invalid value {0} for 'Doctype'").format(doctype))
if cint(days_since_last_order) <= 0: if cint(days_since_last_order) <= 0:
@@ -24,50 +30,66 @@ def execute(filters=None):
customers = get_sales_details(doctype) customers = get_sales_details(doctype)
data = [] data = []
for cust in customers: for C in customers:
if cint(cust[8]) >= cint(days_since_last_order): if cint(C[8]) >= cint(days_since_last_order):
cust.insert(7, get_last_sales_amt(cust[0], doctype)) C.insert(7, get_last_sales_amt(C[0], doctype))
data.append(cust) data.append(C)
return columns, data return columns, data
def get_sales_details(doctype): def get_sales_details(doctype):
cond = """sum(so.base_net_total) as 'total_order_considered', C = frappe.qb.DocType("Customer")
max(so.posting_date) as 'last_order_date', DT = frappe.qb.DocType(doctype)
DATEDIFF(CURRENT_DATE, max(so.posting_date)) as 'days_since_last_order' """
if doctype == "Sales Order":
cond = """sum(if(so.status = "Stopped",
so.base_net_total * so.per_delivered/100,
so.base_net_total)) as 'total_order_considered',
max(so.transaction_date) as 'last_order_date',
DATEDIFF(CURRENT_DATE, max(so.transaction_date)) as 'days_since_last_order'"""
return frappe.db.sql( DateDiff = CustomFunction("DATEDIFF", ["d1", "d2"])
f"""select CurDate = CustomFunction("CURRENT_DATE", [])
cust.name,
cust.customer_name, if doctype == "Sales Order":
cust.territory, total_considered = Sum(
cust.customer_group, Case()
count(distinct(so.name)) as 'num_of_order', .when(DT.status == "Stopped", DT.base_net_total * DT.per_delivered / 100)
sum(base_net_total) as 'total_order_value', {cond} .else_(DT.base_net_total)
from `tabCustomer` cust, `tab{doctype}` so )
where cust.name = so.customer and so.docstatus = 1 date_col = DT.transaction_date
group by cust.name else:
order by 'days_since_last_order' desc """, total_considered = Sum(DT.base_net_total)
as_list=1, date_col = DT.posting_date
)
last_order_date = Max(date_col)
days_since_last_order = DateDiff(CurDate(), last_order_date)
return (
frappe.qb.from_(C)
.inner_join(DT)
.on(C.name == DT.customer)
.select(
C.name,
C.customer_name,
C.territory,
C.customer_group,
Count(DT.name).distinct().as_("num_of_order"),
Sum(DT.base_net_total).as_("total_order_value"),
total_considered.as_("total_order_considered"),
last_order_date.as_("last_order_date"),
days_since_last_order.as_("days_since_last_order"),
)
.where(DT.docstatus == 1)
.groupby(C.name)
.orderby(days_since_last_order, order=frappe.qb.desc)
).run(as_list=True)
def get_last_sales_amt(customer, doctype): def get_last_sales_amt(customer, doctype):
cond = "posting_date" DT = frappe.qb.DocType(doctype)
if doctype == "Sales Order": date_col = DT.transaction_date if doctype == "Sales Order" else DT.posting_date
cond = "transaction_date"
res = frappe.db.sql( res = (
f"""select base_net_total from `tab{doctype}` frappe.qb.from_(DT)
where customer = %s and docstatus = 1 order by {cond} desc .select(DT.base_net_total)
limit 1""", .where((DT.customer == customer) & (DT.docstatus == 1))
customer, .orderby(date_col, order=frappe.qb.desc)
) .limit(1)
).run()
return res and res[0][0] or 0 return res and res[0][0] or 0