Implement some more python features

This commit is contained in:
Paul Brinkmeier 2023-06-06 16:51:28 +02:00
parent b886d71a0b
commit bbd51978cb
11 changed files with 133 additions and 69 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
.setjonpass .setjonpass
elm-stuff elm-stuff
static/jon.js static/jon.js
__pycache__
*.swp

View File

@ -10,6 +10,7 @@ def get_db():
# TODO: Make this configurable and use a default that works # TODO: Make this configurable and use a default that works
# on the pool computers. # on the pool computers.
g.db = psycopg2.connect("host=localhost dbname=garfield") g.db = psycopg2.connect("host=localhost dbname=garfield")
run_query_on(g.db, "add_views.sql", None)
return g.db return g.db
@ -25,8 +26,10 @@ def init_app(app):
def run_query(query_name, params=None): def run_query(query_name, params=None):
db = get_db() return run_query_on(get_db(), query_name, params)
def run_query_on(db, query_name, params):
query = (Path(__file__).parent / Path(query_name)).read_text() query = (Path(__file__).parent / Path(query_name)).read_text()
cursor = db.cursor(cursor_factory=RealDictCursor) cursor = db.cursor(cursor_factory=RealDictCursor)

59
py/jon/db/add_views.sql Normal file
View File

@ -0,0 +1,59 @@
-- Modified version of garfield.inventory_item_overview.
CREATE TEMPORARY VIEW all_inventory_item_overview AS
SELECT
item_id,
inventory_items.item_barcode,
inventory_items.bought,
inventory_items.name,
inventory_items.sales_units,
inventory_items.unit_price,
inventory_items.available,
inventory_items.item_group,
inventory_items.location,
inventory_item_groups.group_name,
COALESCE(b.sales::numeric, 0::numeric) - COALESCE(cancel.count::numeric, 0::numeric) AS sales,
inventory_items.sales_units::numeric - COALESCE(b.sales, 0::bigint)::numeric + COALESCE(c.delta, 0::numeric) + COALESCE(cancel.count::numeric, 0::numeric) AS units_left,
COALESCE(c.delta, 0::numeric) AS correction_delta,
COALESCE(m.mappings::numeric, 0::numeric) AS active_mappings,
m.mappings_array AS active_mappings_array,
locations.location_name
FROM garfield.inventory_items
JOIN garfield.locations ON inventory_items.location = locations.location_id
LEFT JOIN garfield.inventory_item_groups ON inventory_item_groups.group_id = inventory_items.item_group
LEFT JOIN (
SELECT
snack_sales_log.inventory_line AS item_id,
count(*) AS sales
FROM garfield.snack_sales_log
WHERE snack_sales_log.inventory_line IS NOT NULL
AND snack_sales_log.type_id::text = 'SNACK_BUY'::text
GROUP BY snack_sales_log.inventory_line
) b USING (item_id)
LEFT JOIN (
SELECT
snack_sales_log.inventory_line AS item_id,
count(*) AS count
FROM garfield.snack_sales_log
WHERE snack_sales_log.inventory_line IS NOT NULL
AND snack_sales_log.type_id::text = 'SNACK_CANCEL'::text
GROUP BY snack_sales_log.inventory_line
) cancel USING (item_id)
LEFT JOIN (
SELECT
inventory_correction.item_id,
sum(inventory_correction.delta) AS delta
FROM garfield.inventory_correction
GROUP BY inventory_correction.item_id
) c USING (item_id)
LEFT JOIN (
SELECT
count(inventory_map.snack_id) AS mappings,
array_agg(inventory_map.snack_id) AS mappings_array,
inventory_map.inventory_id AS item_id
FROM garfield.inventory_map
JOIN garfield.snacks_available ON snacks_available.snack_available AND snacks_available.snack_id = inventory_map.snack_id
GROUP BY inventory_map.inventory_id
) m USING (item_id)
ORDER BY inventory_items.name;

View File

@ -1,19 +1,8 @@
SELECT SELECT
inventory_items.item_id, *
inventory_items.item_barcode, FROM all_inventory_item_overview
inventory_items.name, WHERE (%(location_id)s IS NULL OR location = %(location_id)s)
inventory_items.unit_price, AND available
inventory_items.bought,
inventory_item_overview.group_name,
inventory_item_overview.units_left,
inventory_item_overview.correction_delta,
inventory_item_overview.sales_units,
inventory_item_overview.active_mappings,
inventory_item_overview.location_name
FROM garfield.inventory_item_overview
LEFT JOIN garfield.inventory_items USING (item_id)
WHERE
(%(location_id)s IS NULL OR inventory_items.location = %(location_id)s)
ORDER BY ORDER BY
name ASC, name ASC,
item_barcode DESC, item_barcode DESC,

View File

@ -1,18 +1,4 @@
SELECT SELECT
inventory_items.item_id, *
inventory_items.available, FROM all_inventory_item_overview
inventory_items.item_barcode,
inventory_items.name,
inventory_items.unit_price,
inventory_items.bought,
inventory_items.item_group,
inventory_items.location,
inventory_item_overview.group_name,
inventory_item_overview.units_left,
inventory_item_overview.correction_delta,
inventory_item_overview.sales_units,
inventory_item_overview.active_mappings,
inventory_item_overview.location_name
FROM garfield.inventory_item_overview
LEFT JOIN garfield.inventory_items USING (item_id)
WHERE item_id = %(item_id)s WHERE item_id = %(item_id)s

View File

@ -1,9 +1,6 @@
SELECT SELECT
* *
FROM garfield.inventory_item_overview FROM all_inventory_item_overview
LEFT JOIN garfield.inventory_items USING (item_id)
LEFT JOIN garfield.locations ON location = location_id
LEFT JOIN garfield.inventory_item_groups ON item_group = group_id
WHERE item_barcode = %(item_barcode)s WHERE item_barcode = %(item_barcode)s
AND location = %(location_id)s AND location = %(location_id)s
ORDER BY available DESC, bought DESC ORDER BY available DESC, bought DESC

View File

@ -6,3 +6,6 @@ LEFT JOIN garfield.snacks_available USING (snack_id)
LEFT JOIN garfield.tax_groups USING (tax_group_id) LEFT JOIN garfield.tax_groups USING (tax_group_id)
LEFT JOIN garfield.locations USING (location_id) LEFT JOIN garfield.locations USING (location_id)
WHERE inventory_id = %(item_id)s WHERE inventory_id = %(item_id)s
ORDER BY
snack_available DESC,
snack_timestamp DESC

View File

@ -4,6 +4,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>jon</title> <title>jon</title>
<style> <style>
html {
font-family: Helvetica, sans-serif;
}
h1 { h1 {
margin: 0; margin: 0;
} }
@ -34,9 +37,15 @@
animation: wiggle 0.8s ease-in-out 0s infinite; animation: wiggle 0.8s ease-in-out 0s infinite;
/* animation-direction: alternate; */ /* animation-direction: alternate; */
} }
.number-column { .--align-left {
text-align: left;
}
.--align-right {
text-align: right; text-align: right;
} }
.--centered {
text-align: center;
}
@keyframes wiggle { @keyframes wiggle {
0%, 100% { margin-top: 0; } 0%, 100% { margin-top: 0; }
50% { margin-top: -0.5em; } 50% { margin-top: -0.5em; }

View File

@ -9,10 +9,10 @@
<th>Preis (Netto)</th> <th>Preis (Netto)</th>
<th>Kaufdatum</th> <th>Kaufdatum</th>
<th>Gruppe</th> <th>Gruppe</th>
<th>Inventar</th>
<th title="Korrekturen">Korr.</th>
<th>Eingekauft</th> <th>Eingekauft</th>
<th title="Aktive Snackeinträge">AS</th> <th title="Korrekturen">Korr.</th>
<th>Inventar</th>
<th title="Anzahl aktiver Snackeinträge">#AS</th>
<th>Raum</th> <th>Raum</th>
</tr> </tr>
{% for item in items %} {% for item in items %}
@ -20,13 +20,13 @@
<td><a href="/inventory/{{ item.item_id }}">{{ item.item_id }}</a></td> <td><a href="/inventory/{{ item.item_id }}">{{ item.item_id }}</a></td>
<td><code>{{ item.item_barcode }}</code></td> <td><code>{{ item.item_barcode }}</code></td>
<td>{{ item.name }}</td> <td>{{ item.name }}</td>
<td class="number-column">{{ format_currency(item.unit_price) }}</td> <td class="--align-right">{{ format_currency(item.unit_price) }}</td>
<td>{{ format_date(item.bought) }}</td> <td>{{ format_date(item.bought) }}</td>
<td>{{ item.group_name }}</td> <td>{{ item.group_name }} ({{ item.item_group }})</td>
<td class="number-column">{{ item.units_left }}</td> <td class="--align-right">{{ item.sales_units }}</td>
<td class="number-column">{{ item.correction_delta }}</td> <td class="--align-right">{% if item.correction_delta > 0 %}+{% endif %}{{ item.correction_delta }}</td>
<td class="number-column">{{ item.sales_units }}</td> <td class="--align-right">{{ item.units_left }}</td>
<td class="number-column">{{ item.active_mappings }}</td> <td class="--align-right">{{ item.active_mappings }}</td>
<td>{{ item.location_name }}</td> <td>{{ item.location_name }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -7,47 +7,47 @@
<legend>Inventareintrag {{ item.item_id }}</legend> <legend>Inventareintrag {{ item.item_id }}</legend>
<table> <table>
<tr> <tr>
<th style="text-align: left;">ID</th> <th class="--align-left">ID</th>
<td>{{ item.item_id }}</td> <td>{{ item.item_id }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Barcode</th> <th class="--align-left">Barcode</th>
<td><code>{{ item.item_barcode }}</code></td> <td><code>{{ item.item_barcode }}</code></td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Name</th> <th class="--align-left">Name</th>
<td>{{ item.name }}</td> <td>{{ item.name }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Einkaufspreis (Netto)</th> <th class="--align-left">Einkaufspreis (Netto)</th>
<td>{{ format_currency(item.unit_price) }}</td> <td>{{ format_currency(item.unit_price) }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Kaufdatum</th> <th class="--align-left">Kaufdatum</th>
<td>{{ format_date(item.bought) }}</td> <td>{{ format_date(item.bought) }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Gruppe</th> <th class="--align-left">Gruppe</th>
<td>{{ item.group_name }} ({{ item.item_group }})</td> <td>{{ item.group_name }} ({{ item.item_group }})</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Inventar</th> <th class="--align-left">Inventar</th>
<td>{{ item.units_left }}</td> <td>{{ item.units_left }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Korrekturen</th> <th class="--align-left">Korrekturen</th>
<td>{{ item.correction_delta }}</td> <td>{{ item.correction_delta }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Eingekauft</th> <th class="--align-left">Eingekauft</th>
<td>{{ item.sales_units }}</td> <td>{{ item.sales_units }}</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Raum</th> <th class="--align-left">Raum</th>
<td>{{ item.location_name }} ({{ item.location }})</td> <td>{{ item.location_name }} ({{ item.location }})</td>
</tr> </tr>
<tr> <tr>
<th style="text-align: left;">Aktiv?</th> <th class="--align-left">Aktiv?</th>
<td>{{ format_bool(item.available) }}</td> <td>{{ format_bool(item.available) }}</td>
</tr> </tr>
</table> </table>
@ -72,18 +72,18 @@
<td>{{ snack.snack_id }}</td> <td>{{ snack.snack_id }}</td>
<td><code>{{ snack.snack_barcode }}</code></td> <td><code>{{ snack.snack_barcode }}</code></td>
<td>{{ snack.snack_name }}</td> <td>{{ snack.snack_name }}</td>
<td>{{ format_currency(snack.snack_price) }}</td> <td class="--align-right">{{ format_currency(snack.snack_price) }}</td>
<td>{{ format_date(snack.snack_timestamp) }}</td> <td>{{ format_date(snack.snack_timestamp) }}</td>
<td>{{ snack.description }} ({{ snack.tax_group_id }})</td> <td>{{ snack.description }} ({{ snack.tax_group_id }})</td>
<td>{{ snack.location_name }} ({{ snack.location_id }})</td> <td>{{ snack.location_name }} ({{ snack.location_id }})</td>
<td>{{ format_bool(snack.active) }}</td> <td>{{ format_bool(snack.snack_available) }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Aktive Inventareinträge mit Barcode <code>{{ item.item_barcode }}</code> in {{ item.location_name }}</legend> <legend>Inventareinträge mit Barcode <code>{{ item.item_barcode }}</code> in {{ item.location_name }}</legend>
<table> <table>
<tr> <tr>
@ -93,23 +93,31 @@
<th>Einkaufspreis (Netto)</th> <th>Einkaufspreis (Netto)</th>
<th>Kaufdatum</th> <th>Kaufdatum</th>
<th>Gruppe</th> <th>Gruppe</th>
<th>Inventar</th>
<th>Korrekturen</th>
<th>Eingekauft</th> <th>Eingekauft</th>
<th>Raum</th> <th>Korrekturen</th>
<th>Inventar</th>
<th title="Aktive Snackeinträge">AS</th>
<th>Aktiv?</th>
</tr> </tr>
{% for item in same_barcode_items %} {% for item in same_barcode_items %}
<tr> <tr>
<td><a href="/inventory/{{ item.item_id }}">{{ item.item_id }}</a></td> <td><a href="/inventory/{{ item.item_id }}">{{ item.item_id }}</a></td>
<td><code>{{ item.item_barcode }}</code></td> <td><code>{{ item.item_barcode }}</code></td>
<td>{{ item.name }}</td> <td>{{ item.name }}</td>
<td>{{ format_currency(item.unit_price) }}</td> <td class="--align-right">{{ format_currency(item.unit_price) }}</td>
<td>{{ format_date(item.bought) }}</td> <td>{{ format_date(item.bought) }}</td>
<td>{{ item.group_name }} ({{ item.item_group }})</td> <td>{{ item.group_name }} ({{ item.item_group }})</td>
<td>{{ item.units_left }}</td> <td class="--align-right">{{ item.sales_units }}</td>
<td>{{ item.correction_delta }}</td> <td class="--align-right">{% if item.correction_delta > 0 %}+{% endif %}{{ item.correction_delta }}</td>
<td>{{ item.sales_units }}</td> <td class="--align-right">{{ item.units_left }}</td>
<td>{{ item.location_name }} ({{ item.location }})</td> <td class="--centered">
{% if item.active_mappings != 0 %}
{{ item.active_mappings_array | join(", ") }}
{% else %}
-
{% endif %}
</td>
<td class="--centered">{{ format_bool(item.available) }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -21,3 +21,11 @@ th, td {
tr:not(:first-child):hover, tbody tr:hover { tr:not(:first-child):hover, tbody tr:hover {
background-color: lightblue; background-color: lightblue;
} }
@media print {
.noprint { display: none; }
body > div + div {
display: none !important;
}
}