282 lines
9 KiB
Python
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"]}'}
|