mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 22:51:49 +00:00
fix: apply user permissions via build_match_conditions
This commit is contained in:
committed by
Vishnu Priya Baskaran
parent
654890dce8
commit
202f52271c
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _, msgprint, qb
|
from frappe import _, msgprint, qb
|
||||||
from frappe.query_builder import Criterion
|
from frappe.desk.reportview import build_match_conditions
|
||||||
|
from frappe.query_builder import Case, Criterion
|
||||||
|
from pypika.terms import LiteralValue
|
||||||
|
|
||||||
from erpnext import get_company_currency
|
from erpnext import get_company_currency
|
||||||
|
|
||||||
@@ -155,84 +157,94 @@ def get_columns(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_entries(filters):
|
def get_entries(filters):
|
||||||
date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
|
doc_type = filters["doc_type"]
|
||||||
if filters["doc_type"] == "Sales Order":
|
|
||||||
qty_field = "delivered_qty"
|
|
||||||
else:
|
|
||||||
qty_field = "qty"
|
|
||||||
conditions, values = get_conditions(filters, date_field)
|
|
||||||
|
|
||||||
entries = frappe.db.sql(
|
date_field = "transaction_date" if doc_type == "Sales Order" else "posting_date"
|
||||||
"""
|
qty_field = "delivered_qty" if doc_type == "Sales Order" else "qty"
|
||||||
SELECT
|
|
||||||
dt.name, dt.customer, dt.territory, dt.{} as posting_date, dt_item.item_code,
|
dt = frappe.qb.DocType(doc_type)
|
||||||
st.sales_person, st.allocated_percentage, dt_item.warehouse,
|
dt_item = frappe.qb.DocType(f"{doc_type} Item")
|
||||||
CASE
|
st = frappe.qb.DocType("Sales Team")
|
||||||
WHEN dt.status = "Closed" THEN dt_item.{} * dt_item.conversion_factor
|
|
||||||
ELSE dt_item.stock_qty
|
calc_qty = dt_item[qty_field] * dt_item.conversion_factor
|
||||||
END as stock_qty,
|
calc_net_amount = dt_item.base_net_rate * calc_qty
|
||||||
CASE
|
|
||||||
WHEN dt.status = "Closed" THEN (dt_item.base_net_rate * dt_item.{} * dt_item.conversion_factor)
|
stock_qty_case = Case().when(dt.status == "Closed", calc_qty).else_(dt_item.stock_qty).as_("stock_qty")
|
||||||
ELSE dt_item.base_net_amount
|
|
||||||
END as base_net_amount,
|
base_net_amount_case = (
|
||||||
CASE
|
Case()
|
||||||
WHEN dt.status = "Closed" THEN ((dt_item.base_net_rate * dt_item.{} * dt_item.conversion_factor) * st.allocated_percentage/100)
|
.when(dt.status == "Closed", calc_net_amount)
|
||||||
ELSE dt_item.base_net_amount * st.allocated_percentage/100
|
.else_(dt_item.base_net_amount)
|
||||||
END as contribution_amt
|
.as_("base_net_amount")
|
||||||
FROM
|
|
||||||
`tab{}` dt, `tab{} Item` dt_item, `tabSales Team` st
|
|
||||||
WHERE
|
|
||||||
st.parent = dt.name and dt.name = dt_item.parent and st.parenttype = {}
|
|
||||||
and dt.docstatus = 1 {} order by st.sales_person, dt.name desc
|
|
||||||
""".format(
|
|
||||||
date_field,
|
|
||||||
qty_field,
|
|
||||||
qty_field,
|
|
||||||
qty_field,
|
|
||||||
filters["doc_type"],
|
|
||||||
filters["doc_type"],
|
|
||||||
"%s",
|
|
||||||
conditions,
|
|
||||||
),
|
|
||||||
tuple([filters["doc_type"], *values]),
|
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return entries
|
contribution_amt_case = (
|
||||||
|
Case()
|
||||||
|
.when(dt.status == "Closed", (calc_net_amount * st.allocated_percentage / 100))
|
||||||
def get_conditions(filters, date_field):
|
.else_(dt_item.base_net_amount * st.allocated_percentage / 100)
|
||||||
conditions = [""]
|
.as_("contribution_amt")
|
||||||
values = []
|
)
|
||||||
|
|
||||||
|
# Only pass valid document-field filters to get_query; report-specific keys such as
|
||||||
|
# doc_type / sales_person / item_group are handled separately below.
|
||||||
|
doc_filters = {"docstatus": 1}
|
||||||
for field in ["company", "customer", "territory"]:
|
for field in ["company", "customer", "territory"]:
|
||||||
if filters.get(field):
|
if filters.get(field):
|
||||||
conditions.append(f"dt.{field}=%s")
|
doc_filters[field] = filters.get(field)
|
||||||
values.append(filters[field])
|
|
||||||
|
if filters.get("from_date") and filters.get("to_date"):
|
||||||
|
doc_filters[date_field] = ["between", [filters.get("from_date"), filters.get("to_date")]]
|
||||||
|
elif filters.get("from_date"):
|
||||||
|
doc_filters[date_field] = [">=", filters.get("from_date")]
|
||||||
|
elif filters.get("to_date"):
|
||||||
|
doc_filters[date_field] = ["<=", filters.get("to_date")]
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.get_query(dt, filters=doc_filters)
|
||||||
|
.join(dt_item)
|
||||||
|
.on(dt.name == dt_item.parent)
|
||||||
|
.join(st)
|
||||||
|
.on(dt.name == st.parent)
|
||||||
|
.select(
|
||||||
|
dt.name,
|
||||||
|
dt.customer,
|
||||||
|
dt.territory,
|
||||||
|
dt[date_field].as_("posting_date"),
|
||||||
|
dt_item.item_code,
|
||||||
|
st.sales_person,
|
||||||
|
st.allocated_percentage,
|
||||||
|
dt_item.warehouse,
|
||||||
|
stock_qty_case,
|
||||||
|
base_net_amount_case,
|
||||||
|
contribution_amt_case,
|
||||||
|
)
|
||||||
|
.where(st.parenttype == doc_type)
|
||||||
|
)
|
||||||
|
|
||||||
if filters.get("sales_person"):
|
if filters.get("sales_person"):
|
||||||
lft, rgt = frappe.get_value("Sales Person", filters.get("sales_person"), ["lft", "rgt"])
|
lft, rgt = frappe.db.get_value("Sales Person", filters.get("sales_person"), ["lft", "rgt"])
|
||||||
conditions.append(
|
sp = frappe.qb.DocType("Sales Person")
|
||||||
f"exists(select name from `tabSales Person` where lft >= {lft} and rgt <= {rgt} and name=st.sales_person)"
|
query = query.where(
|
||||||
|
st.sales_person.isin(frappe.qb.from_(sp).select(sp.name).where((sp.lft >= lft) & (sp.rgt <= rgt)))
|
||||||
)
|
)
|
||||||
|
|
||||||
if filters.get("from_date"):
|
# only resolve items when an item_group/brand filter is set; otherwise get_items
|
||||||
conditions.append(f"dt.{date_field}>=%s")
|
# would return every item in the system and add a huge IN() clause on each run
|
||||||
values.append(filters["from_date"])
|
if filters.get("item_group") or filters.get("brand"):
|
||||||
|
items = get_items(filters)
|
||||||
|
if not items:
|
||||||
|
# the item_group/brand filter matched nothing -> no rows
|
||||||
|
return []
|
||||||
|
query = query.where(dt_item.item_code.isin([d[0] for d in items]))
|
||||||
|
|
||||||
if filters.get("to_date"):
|
query = query.orderby(st.sales_person).orderby(dt.name, order=frappe.qb.desc)
|
||||||
conditions.append(f"dt.{date_field}<=%s")
|
|
||||||
values.append(filters["to_date"])
|
|
||||||
|
|
||||||
items = get_items(filters)
|
# Apply user permissions (v15: ignore_permissions is not available)
|
||||||
if items:
|
match_conditions = build_match_conditions(doc_type)
|
||||||
conditions.append("dt_item.item_code in (%s)" % ", ".join(["%s"] * len(items)))
|
if match_conditions:
|
||||||
values += items
|
query = query.where(LiteralValue(match_conditions))
|
||||||
else:
|
|
||||||
# return empty result, if no items are fetched after filtering on 'item group' and 'brand'
|
|
||||||
conditions.append("dt_item.item_code = Null")
|
|
||||||
|
|
||||||
return " and ".join(conditions), values
|
return query.run(as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
def get_items(filters):
|
def get_items(filters):
|
||||||
@@ -259,8 +271,5 @@ def get_items(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_item_details():
|
def get_item_details():
|
||||||
item_details = {}
|
items = frappe.get_all("Item", fields=["name", "item_group", "brand"])
|
||||||
for d in frappe.db.sql("""SELECT `name`, `item_group`, `brand` FROM `tabItem`""", as_dict=1):
|
return {d.name: d for d in items}
|
||||||
item_details.setdefault(d.name, d)
|
|
||||||
|
|
||||||
return item_details
|
|
||||||
|
|||||||
Reference in New Issue
Block a user