Skip to content

Commit

Permalink
Merge pull request frappe#32520 from s-aga-r/refactor/stock/reports
Browse files Browse the repository at this point in the history
refactor: rewrite stock reports queries in qb
  • Loading branch information
rohitwaghchaure authored Oct 18, 2022
2 parents 7184330 + ae8a638 commit f08c42e
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 273 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import frappe
from frappe import _
from frappe.query_builder.functions import IfNull
from frappe.utils import cint, getdate


Expand Down Expand Up @@ -54,31 +55,28 @@ def get_columns(filters):
return columns


def get_conditions(filters):
conditions = ""
def get_stock_ledger_entries(filters):
if not filters.get("from_date"):
frappe.throw(_("'From Date' is required"))

if filters.get("to_date"):
conditions += " and posting_date <= '%s'" % filters["to_date"]
else:
if not filters.get("to_date"):
frappe.throw(_("'To Date' is required"))

return conditions


def get_stock_ledger_entries(filters):
conditions = get_conditions(filters)
return frappe.db.sql(
"""select item_code, batch_no, warehouse,
posting_date, actual_qty
from `tabStock Ledger Entry`
where is_cancelled = 0
and docstatus < 2 and ifnull(batch_no, '') != '' %s order by item_code, warehouse"""
% conditions,
as_dict=1,
sle = frappe.qb.DocType("Stock Ledger Entry")
query = (
frappe.qb.from_(sle)
.select(sle.item_code, sle.batch_no, sle.warehouse, sle.posting_date, sle.actual_qty)
.where(
(sle.is_cancelled == 0)
& (sle.docstatus < 2)
& (IfNull(sle.batch_no, "") != "")
& (sle.posting_date <= filters["to_date"])
)
.orderby(sle.item_code, sle.warehouse)
)

return query.run(as_dict=True)


def get_item_warehouse_batch_map(filters, float_precision):
sle = get_stock_ledger_entries(filters)
Expand Down Expand Up @@ -112,7 +110,7 @@ def get_item_warehouse_batch_map(filters, float_precision):

def get_item_details(filters):
item_map = {}
for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1):
for d in (frappe.qb.from_("Item").select("name", "item_name", "description")).run(as_dict=True):
item_map.setdefault(d.name, d)

return item_map
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def get_columns(filters):
def get_stock_ledger_entries(filters):
if not filters.get("from_date"):
frappe.throw(_("'From Date' is required"))
if not filters.get("to_date"):
frappe.throw(_("'To Date' is required"))

sle = frappe.qb.DocType("Stock Ledger Entry")
query = (
Expand All @@ -85,18 +87,13 @@ def get_stock_ledger_entries(filters):
.where(
(sle.docstatus < 2)
& (sle.is_cancelled == 0)
& (sle.batch_no.isnotnull())
& (sle.batch_no != "")
& (fn.IfNull(sle.batch_no, "") != "")
& (sle.posting_date <= filters["to_date"])
)
.groupby(sle.voucher_no, sle.batch_no, sle.item_code, sle.warehouse)
.orderby(sle.item_code, sle.warehouse)
)

if to_date := filters.get("to_date"):
query = query.where(sle.posting_date <= to_date)
else:
frappe.throw(_("'To Date' is required"))

query = apply_warehouse_filter(query, sle, filters)
for field in ["item_code", "batch_no", "company"]:
if filters.get(field):
Expand Down Expand Up @@ -136,7 +133,9 @@ def get_item_warehouse_batch_map(filters, float_precision):

def get_item_details(filters):
item_map = {}
for d in frappe.db.sql("select name, item_name, description, stock_uom from tabItem", as_dict=1):
for d in (frappe.qb.from_("Item").select("name", "item_name", "description", "stock_uom")).run(
as_dict=1
):
item_map.setdefault(d.name, d)

return item_map
82 changes: 40 additions & 42 deletions erpnext/stock/report/delayed_item_report/delayed_item_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,54 @@ def run(self):
return self.get_columns(), self.get_data() or []

def get_data(self, consolidated=False):
conditions = ""

doctype = self.filters.get("based_on")
child_doc = "%s Item" % doctype
sales_order_field = "sales_order" if doctype == "Sales Invoice" else "against_sales_order"

parent = frappe.qb.DocType(doctype)
child = frappe.qb.DocType(f"{doctype} Item")

query = (
frappe.qb.from_(child)
.from_(parent)
.select(
child.item_code,
child.item_name,
child.item_group,
child.qty,
child.rate,
child.amount,
child.so_detail,
child[sales_order_field].as_("sales_order"),
parent.shipping_address_name,
parent.po_no,
parent.customer,
parent.posting_date,
parent.name,
parent.grand_total,
)
.where(
(child.parent == parent.name)
& (parent.docstatus == 1)
& (parent.posting_date.between(self.filters.get("from_date"), self.filters.get("to_date")))
& (child[sales_order_field].notnull())
& (child[sales_order_field] != "")
)
)

if doctype == "Sales Invoice":
conditions = " and `tabSales Invoice`.update_stock = 1 and `tabSales Invoice`.is_pos = 0"
query = query.where((parent.update_stock == 1) & (parent.is_pos == 0))

if self.filters.get("item_group"):
conditions += " and `tab%s`.item_group = %s" % (
child_doc,
frappe.db.escape(self.filters.get("item_group")),
)

for field in ["customer", "customer_group", "company"]:
if self.filters.get(field):
conditions += " and `tab%s`.%s = %s" % (
doctype,
field,
frappe.db.escape(self.filters.get(field)),
)

sales_order_field = "against_sales_order"
if doctype == "Sales Invoice":
sales_order_field = "sales_order"
query = query.where(child.item_group == self.filters.get("item_group"))

if self.filters.get("sales_order"):
conditions = " and `tab%s`.%s = '%s'" % (
child_doc,
sales_order_field,
self.filters.get("sales_order"),
)
query = query.where(child[sales_order_field] == self.filters.get("sales_order"))

self.transactions = frappe.db.sql(
""" SELECT `tab{child_doc}`.item_code, `tab{child_doc}`.item_name,
`tab{child_doc}`.item_group, `tab{child_doc}`.qty, `tab{child_doc}`.rate, `tab{child_doc}`.amount,
`tab{child_doc}`.so_detail, `tab{child_doc}`.{so_field} as sales_order,
`tab{doctype}`.shipping_address_name, `tab{doctype}`.po_no, `tab{doctype}`.customer,
`tab{doctype}`.posting_date, `tab{doctype}`.name, `tab{doctype}`.grand_total
FROM `tab{child_doc}`, `tab{doctype}`
WHERE
`tab{child_doc}`.parent = `tab{doctype}`.name and `tab{doctype}`.docstatus = 1 and
`tab{doctype}`.posting_date between %(from_date)s and %(to_date)s and
`tab{child_doc}`.{so_field} is not null and `tab{child_doc}`.{so_field} != '' {cond}
""".format(
cond=conditions, doctype=doctype, child_doc=child_doc, so_field=sales_order_field
),
{"from_date": self.filters.get("from_date"), "to_date": self.filters.get("to_date")},
as_dict=1,
)
for field in ("customer", "customer_group", "company"):
if self.filters.get(field):
query = query.where(parent[field] == self.filters.get(field))

self.transactions = query.run(as_dict=True)

if self.transactions:
self.filter_transactions_data(consolidated)
Expand Down
Loading

0 comments on commit f08c42e

Please sign in to comment.