mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-25 07:54:46 +00:00
Merge pull request #49192 from diptanilsaha/sql_qb
fix: improve queries with query builder and input sanitization
This commit is contained in:
@@ -462,9 +462,8 @@ def unset_existing_data(company):
|
|||||||
"Sales Taxes and Charges Template",
|
"Sales Taxes and Charges Template",
|
||||||
"Purchase Taxes and Charges Template",
|
"Purchase Taxes and Charges Template",
|
||||||
]:
|
]:
|
||||||
frappe.db.sql(
|
dt = frappe.qb.DocType(doctype)
|
||||||
f'''delete from `tab{doctype}` where `company`="%s"''' % (company) # nosec
|
frappe.qb.from_(dt).where(dt.company == company).delete().run()
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def set_default_accounts(company):
|
def set_default_accounts(company):
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from frappe.query_builder.functions import Sum
|
||||||
from frappe.utils import flt, today
|
from frappe.utils import flt, today
|
||||||
|
|
||||||
|
|
||||||
@@ -55,22 +56,30 @@ def get_loyalty_details(
|
|||||||
if not expiry_date:
|
if not expiry_date:
|
||||||
expiry_date = today()
|
expiry_date = today()
|
||||||
|
|
||||||
condition = ""
|
LoyaltyPointEntry = frappe.qb.DocType("Loyalty Point Entry")
|
||||||
if company:
|
|
||||||
condition = " and company=%s " % frappe.db.escape(company)
|
|
||||||
if not include_expired_entry:
|
|
||||||
condition += " and expiry_date>='%s' " % expiry_date
|
|
||||||
|
|
||||||
loyalty_point_details = frappe.db.sql(
|
query = (
|
||||||
f"""select sum(loyalty_points) as loyalty_points,
|
frappe.qb.from_(LoyaltyPointEntry)
|
||||||
sum(purchase_amount) as total_spent from `tabLoyalty Point Entry`
|
.select(
|
||||||
where customer=%s and loyalty_program=%s and posting_date <= %s
|
Sum(LoyaltyPointEntry.loyalty_points).as_("loyalty_points"),
|
||||||
{condition}
|
Sum(LoyaltyPointEntry.purchase_amount).as_("total_spent"),
|
||||||
group by customer""",
|
)
|
||||||
(customer, loyalty_program, expiry_date),
|
.where(
|
||||||
as_dict=1,
|
(LoyaltyPointEntry.customer == customer)
|
||||||
|
& (LoyaltyPointEntry.loyalty_program == loyalty_program)
|
||||||
|
& (LoyaltyPointEntry.posting_date <= expiry_date)
|
||||||
|
)
|
||||||
|
.groupby(LoyaltyPointEntry.customer)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if company:
|
||||||
|
query = query.where(LoyaltyPointEntry.company == company)
|
||||||
|
|
||||||
|
if not include_expired_entry:
|
||||||
|
query = query.where(LoyaltyPointEntry.expiry_date >= expiry_date)
|
||||||
|
|
||||||
|
loyalty_point_details = query.run(as_dict=True)
|
||||||
|
|
||||||
if loyalty_point_details:
|
if loyalty_point_details:
|
||||||
return loyalty_point_details[0]
|
return loyalty_point_details[0]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from frappe import _
|
|||||||
from frappe.core.doctype.communication.email import make
|
from frappe.core.doctype.communication.email import make
|
||||||
from frappe.desk.form.load import get_attachments
|
from frappe.desk.form.load import get_attachments
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from frappe.query_builder import Order
|
||||||
from frappe.utils import get_url
|
from frappe.utils import get_url
|
||||||
from frappe.utils.print_format import download_pdf
|
from frappe.utils.print_format import download_pdf
|
||||||
from frappe.utils.user import get_user_fullname
|
from frappe.utils.user import get_user_fullname
|
||||||
@@ -582,35 +583,32 @@ def get_supplier_tag():
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filters):
|
def get_rfq_containing_supplier(doctype, txt, searchfield, start, page_len, filters):
|
||||||
conditions = ""
|
rfq = frappe.qb.DocType("Request for Quotation")
|
||||||
if txt:
|
rfq_supplier = frappe.qb.DocType("Request for Quotation Supplier")
|
||||||
conditions += "and rfq.name like '%%" + txt + "%%' "
|
|
||||||
|
|
||||||
if filters.get("transaction_date"):
|
query = (
|
||||||
conditions += "and rfq.transaction_date = '{}'".format(filters.get("transaction_date"))
|
frappe.qb.from_(rfq)
|
||||||
|
.from_(rfq_supplier)
|
||||||
rfq_data = frappe.db.sql(
|
.select(rfq.name)
|
||||||
f"""
|
.distinct()
|
||||||
select
|
.select(rfq.transaction_date, rfq.company)
|
||||||
distinct rfq.name, rfq.transaction_date,
|
.where(
|
||||||
rfq.company
|
(rfq.name == rfq_supplier.parent)
|
||||||
from
|
& (rfq_supplier.supplier == filters.get("supplier"))
|
||||||
`tabRequest for Quotation` rfq, `tabRequest for Quotation Supplier` rfq_supplier
|
& (rfq.docstatus == 1)
|
||||||
where
|
& (rfq.company == filters.get("company"))
|
||||||
rfq.name = rfq_supplier.parent
|
)
|
||||||
and rfq_supplier.supplier = %(supplier)s
|
.orderby(rfq.transaction_date, order=Order.asc)
|
||||||
and rfq.docstatus = 1
|
.limit(page_len)
|
||||||
and rfq.company = %(company)s
|
.offset(start)
|
||||||
{conditions}
|
|
||||||
order by rfq.transaction_date ASC
|
|
||||||
limit %(page_len)s offset %(start)s """,
|
|
||||||
{
|
|
||||||
"page_len": page_len,
|
|
||||||
"start": start,
|
|
||||||
"company": filters.get("company"),
|
|
||||||
"supplier": filters.get("supplier"),
|
|
||||||
},
|
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if txt:
|
||||||
|
query = query.where(rfq.name.like(f"%%{txt}%%"))
|
||||||
|
|
||||||
|
if filters.get("transaction_date"):
|
||||||
|
query = query.where(rfq.transaction_date == filters.get("transaction_date"))
|
||||||
|
|
||||||
|
rfq_data = query.run(as_dict=1)
|
||||||
|
|
||||||
return rfq_data
|
return rfq_data
|
||||||
|
|||||||
@@ -588,21 +588,27 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
|
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
|
||||||
return frappe.db.sql(
|
bo = frappe.qb.DocType("Blanket Order")
|
||||||
"""select distinct bo.name, bo.blanket_order_type, bo.to_date
|
bo_item = frappe.qb.DocType("Blanket Order Item")
|
||||||
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
|
|
||||||
where
|
blanket_orders = (
|
||||||
boi.parent = bo.name
|
frappe.qb.from_(bo)
|
||||||
and boi.item_code = {item_code}
|
.from_(bo_item)
|
||||||
and bo.blanket_order_type = '{blanket_order_type}'
|
.select(bo.name)
|
||||||
and bo.company = {company}
|
.distinct()
|
||||||
and bo.docstatus = 1""".format(
|
.select(bo.blanket_order_type, bo.to_date)
|
||||||
item_code=frappe.db.escape(filters.get("item")),
|
.where(
|
||||||
blanket_order_type=filters.get("blanket_order_type"),
|
(bo_item.parent == bo.name)
|
||||||
company=frappe.db.escape(filters.get("company")),
|
& (bo_item.item_code == filters.get("item"))
|
||||||
|
& (bo.blanket_order_type == filters.get("blanket_order_type"))
|
||||||
|
& (bo.company == filters.get("company"))
|
||||||
|
& (bo.docstatus == 1)
|
||||||
)
|
)
|
||||||
|
.run()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return blanket_orders
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
@@ -620,7 +626,7 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if filters.get("company"):
|
if filters.get("company"):
|
||||||
condition += "and tabAccount.company = %(company)s"
|
condition += "and tabAccount.company = %(company)s"
|
||||||
|
|
||||||
condition += f"and tabAccount.disabled = {filters.get('disabled', 0)}"
|
condition += " and tabAccount.disabled = %(disabled)s"
|
||||||
|
|
||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
f"""select tabAccount.name from `tabAccount`
|
f"""select tabAccount.name from `tabAccount`
|
||||||
@@ -630,7 +636,11 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
and tabAccount.`{searchfield}` LIKE %(txt)s
|
and tabAccount.`{searchfield}` LIKE %(txt)s
|
||||||
{condition} {get_match_cond(doctype)}
|
{condition} {get_match_cond(doctype)}
|
||||||
order by idx desc, name""",
|
order by idx desc, name""",
|
||||||
{"txt": "%" + txt + "%", "company": filters.get("company", "")},
|
{
|
||||||
|
"txt": "%" + txt + "%",
|
||||||
|
"company": filters.get("company", ""),
|
||||||
|
"disabled": cint(filters.get("disabled", 0)),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -329,12 +329,16 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_timesheet_detail_rate(timelog, currency):
|
def get_timesheet_detail_rate(timelog, currency):
|
||||||
timelog_detail = frappe.db.sql(
|
ts = frappe.qb.DocType("Timesheet")
|
||||||
f"""SELECT tsd.billing_amount as billing_amount,
|
ts_detail = frappe.qb.DocType("Timesheet Detail")
|
||||||
ts.currency as currency FROM `tabTimesheet Detail` tsd
|
|
||||||
INNER JOIN `tabTimesheet` ts ON ts.name=tsd.parent
|
timelog_detail = (
|
||||||
WHERE tsd.name = '{timelog}'""",
|
frappe.qb.from_(ts_detail)
|
||||||
as_dict=1,
|
.inner_join(ts)
|
||||||
|
.on(ts.name == ts_detail.parent)
|
||||||
|
.select(ts_detail.billing_amount.as_("billing_amount"), ts.currency.as_("currency"))
|
||||||
|
.where(ts_detail.name == timelog)
|
||||||
|
.run(as_dict=1)
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
if timelog_detail.currency:
|
if timelog_detail.currency:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import frappe
|
|||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe import _, msgprint
|
from frappe import _, msgprint
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from frappe.query_builder import Order
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
from frappe.utils import cint, cstr, flt, get_link_to_form, getdate, new_line_sep, nowdate
|
from frappe.utils import cint, cstr, flt, get_link_to_form, getdate, new_line_sep, nowdate
|
||||||
|
|
||||||
@@ -624,39 +625,44 @@ def get_items_based_on_default_supplier(supplier):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def get_material_requests_based_on_supplier(doctype, txt, searchfield, start, page_len, filters):
|
def get_material_requests_based_on_supplier(doctype, txt, searchfield, start, page_len, filters):
|
||||||
conditions = ""
|
|
||||||
if txt:
|
|
||||||
conditions += "and mr.name like '%%" + txt + "%%' "
|
|
||||||
|
|
||||||
if filters.get("transaction_date"):
|
|
||||||
date = filters.get("transaction_date")[1]
|
|
||||||
conditions += f"and mr.transaction_date between '{date[0]}' and '{date[1]}' "
|
|
||||||
|
|
||||||
supplier = filters.get("supplier")
|
supplier = filters.get("supplier")
|
||||||
supplier_items = get_items_based_on_default_supplier(supplier)
|
supplier_items = get_items_based_on_default_supplier(supplier)
|
||||||
|
|
||||||
if not supplier_items:
|
if not supplier_items:
|
||||||
frappe.throw(_("{0} is not the default supplier for any items.").format(supplier))
|
frappe.throw(_("{0} is not the default supplier for any items.").format(supplier))
|
||||||
|
|
||||||
material_requests = frappe.db.sql(
|
mr = frappe.qb.DocType("Material Request")
|
||||||
"""select distinct mr.name, transaction_date,company
|
mr_item = frappe.qb.DocType("Material Request Item")
|
||||||
from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
|
|
||||||
where mr.name = mr_item.parent
|
query = (
|
||||||
and mr_item.item_code in ({})
|
frappe.qb.from_(mr)
|
||||||
and mr.material_request_type = 'Purchase'
|
.from_(mr_item)
|
||||||
and mr.per_ordered < 99.99
|
.select(mr.name)
|
||||||
and mr.docstatus = 1
|
.distinct()
|
||||||
and mr.status != 'Stopped'
|
.select(mr.transaction_date, mr.company)
|
||||||
and mr.company = %s
|
.where(
|
||||||
{}
|
(mr.name == mr_item.parent)
|
||||||
order by mr_item.item_code ASC
|
& (mr_item.item_code.isin(supplier_items))
|
||||||
limit {} offset {} """.format(
|
& (mr.material_request_type == "Purchase")
|
||||||
", ".join(["%s"] * len(supplier_items)), conditions, cint(page_len), cint(start)
|
& (mr.per_ordered < 99.99)
|
||||||
),
|
& (mr.docstatus == 1)
|
||||||
(*tuple(supplier_items), filters.get("company")),
|
& (mr.status != "Stopped")
|
||||||
as_dict=1,
|
& (mr.company == filters.get("company"))
|
||||||
|
)
|
||||||
|
.orderby(mr_item.item_code, order=Order.asc)
|
||||||
|
.limit(cint(page_len))
|
||||||
|
.offset(cint(start))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if txt:
|
||||||
|
query = query.where(mr.name.like(f"%%{txt}%%"))
|
||||||
|
|
||||||
|
if filters.get("transaction_date"):
|
||||||
|
date = filters.get("transaction_date")[1]
|
||||||
|
query = query.where(mr.transaction_date[date[0] : date[1]])
|
||||||
|
|
||||||
|
material_requests = query.run(as_dict=True)
|
||||||
|
|
||||||
return material_requests
|
return material_requests
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -126,8 +126,9 @@ def get_stock_balance(
|
|||||||
extra_cond = ""
|
extra_cond = ""
|
||||||
if inventory_dimensions_dict:
|
if inventory_dimensions_dict:
|
||||||
for field, value in inventory_dimensions_dict.items():
|
for field, value in inventory_dimensions_dict.items():
|
||||||
|
column = frappe.utils.sanitize_column(field)
|
||||||
args[field] = value
|
args[field] = value
|
||||||
extra_cond += f" and {field} = %({field})s"
|
extra_cond += f" and {column} = %({field})s"
|
||||||
|
|
||||||
last_entry = get_previous_sle(args, extra_cond=extra_cond)
|
last_entry = get_previous_sle(args, extra_cond=extra_cond)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user