diff --git a/jon/db/get_inventory_report.sql b/jon/db/get_inventory_report.sql index fc1e058..6e9074e 100644 --- a/jon/db/get_inventory_report.sql +++ b/jon/db/get_inventory_report.sql @@ -1,49 +1,43 @@ +-- parameters: +-- +-- location_id: Location to generate the report for + WITH -most_recent_sales AS ( - SELECT DISTINCT ON (inventory_line) - inventory_line, snack_sales_log_id, snack_sales_log_timestamp AS most_recent_sale +sales_by_item_id AS ( + SELECT + inventory_line AS item_id, + max(snack_sales_log_timestamp) AS last_sold, + count(*)::int AS units_sold FROM garfield.snack_sales_log - ORDER BY inventory_line ASC, snack_sales_log_timestamp DESC + WHERE type_id = 'SNACK_BUY' + AND inventory_line IS NOT NULL + AND snack_sales_log_timestamp > NOW() - INTERVAL '120 days' + AND location_id = %(location_id)s + GROUP BY item_id ), -enhanced_overview1 AS ( +sales_by_barcode AS ( SELECT - inventory_items.item_id, - inventory_items.item_barcode, - inventory_items.name, - units_left, - inventory_items.sales_units, - correction_delta, - location_name, - location, - CASE - WHEN snack_sales_log_id IS NULL THEN 0 - ELSE sales / (EXTRACT(EPOCH FROM ( - CASE - WHEN units_left <= 0 THEN most_recent_sale - ELSE NOW() - END - )) - EXTRACT(EPOCH FROM bought)) * 24 * 3600 - END AS per_day - FROM garfield.inventory_item_overview + item_barcode, + max(name) AS name, + sum(units_sold) AS units_sold, + round(avg((units_sold / extract(epoch FROM (CASE WHEN available THEN now() ELSE last_sold END) - bought)) * 86400)::numeric, 2) AS sold_per_day + FROM sales_by_item_id LEFT JOIN garfield.inventory_items USING (item_id) - LEFT JOIN most_recent_sales ON item_id = inventory_line + GROUP BY item_barcode ), -enhanced_overview2 AS ( +current_inventory AS ( SELECT - *, - CASE - WHEN per_day = 0 THEN NULL - ELSE GREATEST(0, units_left / per_day) - END AS days_left - FROM enhanced_overview1 + item_barcode, + sum(units_left)::int AS units_left + FROM all_inventory_item_overview + WHERE available + AND location = %(location_id)s + GROUP BY item_barcode ) SELECT - *, - CASE - WHEN days_left IS NULL THEN NULL - ELSE GREATEST(0, (60 - days_left) * per_day) - END AS for_two_months -FROM enhanced_overview2 -WHERE (%(location_id)s IS NULL OR location = %(location_id)s) -ORDER BY days_left ASC, per_day DESC + sales_by_barcode.*, + COALESCE(current_inventory.units_left, 0)::int AS units_left +FROM sales_by_barcode +LEFT JOIN current_inventory USING (item_barcode) +ORDER BY units_sold DESC diff --git a/jon/inventory.py b/jon/inventory.py index 7fe9254..685cb1f 100644 --- a/jon/inventory.py +++ b/jon/inventory.py @@ -22,11 +22,17 @@ def index(): @bp.get("/report") def read_report(): location = current_user.data.location + + if location is None: + # TODO: Error handling + return "please select a location in order to generate a report", 400 + items = db.run_query("get_inventory_report.sql", { - "location_id": None if location is None else location["location_id"] + "location_id": location["location_id"] }).fetchall() return render_template("inventory/read_report.html", **{ + "location": location, "items": items }) diff --git a/jon/static/jon.css b/jon/static/jon.css index 66dde1c..9c4ac1d 100644 --- a/jon/static/jon.css +++ b/jon/static/jon.css @@ -40,6 +40,9 @@ nav > ul > li + li:before { .--centered { text-align: center; } +.--not-important { + color: #aaa; +} @keyframes wiggle { 0%, 100% { margin-top: 0; } 50% { margin-top: -0.5em; } @@ -55,6 +58,10 @@ th { body { font-size: 8px; } + /* hide the menu when printing */ + header { + display: none; + } } .form-input > label { font-size: .8em; diff --git a/jon/templates/base.html b/jon/templates/base.html index 54a0654..19871d3 100644 --- a/jon/templates/base.html +++ b/jon/templates/base.html @@ -12,6 +12,7 @@