web-app-demos/apps/reporter/queries.py
2025-03-17 16:11:01 -06:00

282 lines
9 KiB
Python

from decimal import Decimal
import datetime
from dateutil.relativedelta import relativedelta
async def orders_by_employee(cursor, options):
errors = {}
if options["date"]["from"] == '' or options["date"]["to"] == '':
errors["date"] = "Please enter order date range."
if "category" not in options:
errors["category"] = "Please choose at least one product category."
if len(errors) > 0:
return {'status': 'error', 'errors': errors}
query = """\
SELECT
CONCAT(E.firstname, ' ', E.lastname) AS name,
O.orderid,
O.orderdate,
C.customername,
inter.value
FROM employees AS E
INNER JOIN orders AS O ON E.employeeid = O.employeeid
LEFT JOIN customers AS C on O.customerid = C.customerid
INNER JOIN (
SELECT
OD.orderid,
SUM(OD.quantity * P.price) AS value
FROM orderdetails AS OD
LEFT JOIN products AS P ON OD.productid = P.productid
WHERE P.categoryid IN ({})
GROUP BY OD.orderid
) AS inter ON o.orderid = inter.orderid
WHERE O.orderdate BETWEEN %s AND %s;""".format(",".join(['%s'] * len(options["category"])))
await cursor.execute(query, [*options["category"].keys(), options["date"]["from"], options["date"]["to"]])
rows = await cursor.fetchall()
results = []
for row in rows:
row = list(row)
row[2] = row[2].date().strftime('%Y-%m-%d')
results.append(row)
return {'status': 'ok', 'rows': results, 'period': f'{options["date"]["from"]} - {options["date"]["to"]}'}
async def orders_by_location(cursor, options):
errors = {}
if "location" not in options:
errors["location"] = "Please choose how to group locations."
if options["date"]["from"] == '' or options["date"]["to"] == '':
errors["date"] = "Please enter order date range."
if "category" not in options:
errors["category"] = "Please choose at least one product category."
if len(errors) > 0:
return {'status': 'error', 'errors': errors}
location_query = {
'city': "CONCAT(C.country, ' - ', C.city)",
'country': "C.country"
}
query = """\
SELECT
{},
C.customername,
O.orderid,
O.orderdate,
inter.value
FROM orders AS O
LEFT JOIN customers AS C on O.customerid = C.customerid
INNER JOIN (
SELECT
OD.orderid,
SUM(OD.quantity * P.price) AS value
FROM orderdetails AS OD
LEFT JOIN products AS P ON OD.productid = P.productid
WHERE P.categoryid IN ({})
GROUP BY OD.orderid
) AS inter ON o.orderid = inter.orderid
WHERE O.orderdate BETWEEN %s AND %s;\
""".format(location_query[options["location"]], ",".join(['%s'] * len(options["category"])))
await cursor.execute(query, [*options["category"].keys(), options["date"]["from"], options["date"]["to"]])
rows = await cursor.fetchall()
results = []
for row in rows:
row = list(row)
row[3] = row[3].date().strftime('%Y-%m-%d')
results.append(row)
return {'status': 'ok', 'rows': results, 'period': f'{options["date"]["from"]} - {options["date"]["to"]}'}
async def orders_by_product(cursor, options):
errors = {}
if options["date"]["from"] == '' or options["date"]["to"] == '':
errors["date"] = "Please enter order date range."
if "category" not in options:
errors["category"] = "Please choose at least one product category."
if len(errors) > 0:
return {'status': 'error', 'errors': errors}
query = """\
SELECT
P.productname,
C.customername,
O.orderid,
O.orderdate,
OD.quantity,
OD.quantity * P.price AS value
FROM orderdetails AS OD
LEFT JOIN orders AS O ON OD.orderid = O.orderid
LEFT JOIN products AS P ON OD.productid = P.productid
LEFT JOIN customers AS C ON O.customerid = C.customerid
WHERE P.categoryid IN ({})
AND O.orderdate BETWEEN %s AND %s;\
""".format(",".join(['%s'] * len(options["category"])))
await cursor.execute(query, [*options["category"].keys(), options["date"]["from"], options["date"]["to"]])
rows = await cursor.fetchall()
results = []
for row in rows:
row = list(row)
row[3] = row[3].date().strftime('%Y-%m-%d')
results.append(row)
return {'status': 'ok', 'rows': results, 'period': f'{options["date"]["from"]} - {options["date"]["to"]}'}
async def orders_by_supplier(cursor, options):
errors = {}
if options["date"]["from"] == '' or options["date"]["to"] == '':
errors["date"] = "Please enter order date range."
if "category" not in options:
errors["category"] = "Please choose at least one product category."
if len(errors) > 0:
return {'status': 'error', 'errors': errors}
query = """\
SELECT
S.suppliername,
P.productname,
C.customername,
O.orderid,
O.orderdate,
OD.quantity,
OD.quantity * P.price AS value
FROM orderdetails AS OD
LEFT JOIN orders AS O ON OD.orderid = O.orderid
LEFT JOIN products AS P ON OD.productid = P.productid
LEFT JOIN customers AS C ON O.customerid = C.customerid
LEFT JOIN suppliers AS S ON P.supplierid = S.supplierid
WHERE P.categoryid IN ({})
AND O.orderdate BETWEEN %s AND %s;\
""".format(",".join(['%s'] * len(options["category"])))
await cursor.execute(query, [*options["category"].keys(), options["date"]["from"], options["date"]["to"]])
rows = await cursor.fetchall()
results = []
for row in rows:
row = list(row)
row[4] = row[4].date().strftime('%Y-%m-%d')
results.append(row)
return {'status': 'ok', 'rows': results, 'period': f'{options["date"]["from"]} - {options["date"]["to"]}'}
async def pivot_table(cursor, options):
errors = {}
valid_rows = set(['month', 'year', 'employee', 'shipper', 'customer', 'supplier', 'category', 'product'])
valid_columns = set(['month', 'year', 'employee', 'shipper', 'category'])
valid_values = set(['sales', 'qty'])
if options["date"]["from"] == '' or options["date"]["to"] == '':
errors["date"] = "Please enter order date range."
if "category" not in options:
errors["category"] = "Please choose at least one product category."
if options["rows"] not in valid_rows:
errors["rows"] = "Please choose the data to display as rows."
if options["columns"] not in valid_columns:
options["columns"] = "none"
if options["rows"] == options["columns"]:
errors["columns"] = "Columns and Rows should be different."
if options["values"] not in valid_values:
errors["values"] = "Value selection invalid."
if len(errors) > 0:
return {'status': 'error', 'errors': errors}
# SELECT, GROUP BY, JOIN
parts = {
'none' : ("", "", ""),
'month' : ("CONCAT(YEAR(o.orderdate), '-', LPAD(MONTH(o.orderdate), 2, '0')) AS month", "month", ""),
'year' : ("YEAR(o.orderdate) AS year", "year", ""),
'employee': ("CONCAT(E.firstname, ' ', E.lastname) AS employeename",
"employeename",
"LEFT JOIN employees AS E ON O.employeeid = E.employeeid"),
'shipper' : ("SH.shippername",
"SH.shippername",
"LEFT JOIN shippers AS SH ON O.shipperid = SH.shipperid"),
'customer': ("C.customername",
"C.customername",
"LEFT JOIN customers AS C ON O.customerid = C.customerid"),
'supplier': ("S.suppliername",
"S.suppliername",
"LEFT JOIN suppliers AS S ON P.supplierid = S.supplierid"),
'category': ("CA.categoryname",
"CA.categoryname",
"LEFT JOIN categories AS CA ON P.categoryid = CA.categoryid"),
'product' : ("P.productname", "P.productname", "")
}
values = {
'sales' : 'SUM(OD.quantity * P.price)',
'qty' : 'SUM(OD.quantity)'
}
query = """
SELECT
{rows} {columns} {values}
FROM orderdetails AS OD
LEFT JOIN orders AS O ON OD.orderid = O.orderid
LEFT JOIN products AS P ON OD.productid = P.productid
{joins}
WHERE P.categoryid IN ({categories})
AND O.orderdate BETWEEN %s AND %s
GROUP BY {grouprows}{groupcols}
""".format(
rows=f"{parts[options['rows']][0]},",
columns=f"{parts[options['columns']][0]}," if options["columns"] != 'none' else '',
values=f"{values[options['values']]}",
joins=f"{parts[options['rows']][2]} {parts[options['columns']][2]}",
categories=",".join(['%s'] * len(options["category"])),
grouprows=parts[options['rows']][1],
groupcols=', '+parts[options['columns']][1] if options["columns"] != 'none' else ''
)
await cursor.execute(query, [*options["category"].keys(), options["date"]["from"], options["date"]["to"]])
response = await cursor.fetchall()
if options["columns"] == 'none':
results = [ list(row) for row in response ]
value_lookup = {'sales': 'Order Value', 'qty': 'Item Quantity'}
rv = {'status': 'ok', 'rows': results, 'columns': [{'name': options['rows'].capitalize()}, {'name': value_lookup[options["values"]], 'format': '$'}]}
return rv
else:
results = []
intermediate = {}
cols = set()
for row in response:
if row[0] is None:
continue
cols.add(row[1])
if row[0] not in intermediate:
intermediate[row[0]] = {'Total': 0}
assert row[1] not in intermediate[row[0]]
intermediate[row[0]][row[1]] = row[2]
intermediate[row[0]]['Total'] += row[2]
cols = list(sorted(cols)) + ['Total']
for row in sorted(intermediate):
values = [row] + [ intermediate[row].get(col, '') for col in cols ]
results.append(values)
headings = [{'name': options['rows'].capitalize(), 'frozen': True}] + [ {'name': col, 'format': '$'} for col in cols ]
headings[-1]['frozen'] = True
return {'status': 'ok', 'rows': results, 'columns': headings, 'period': f'{options["date"]["from"]} - {options["date"]["to"]}'}