1
0

4 Коммиты b1a320eb7a ... 628f37e0f6

Автор SHA1 Сообщение Дата
  Pi 628f37e0f6 do not limit the transaction view, and fix the timezone 1 месяц назад
  Pi e1892a9ab7 group trending chart by date 1 месяц назад
  Pi 90b133c21d add statistics page 1 месяц назад
  Pi 2eb2f2e0d7 fix DNS resolution broken 7 месяцев назад

+ 6 - 2
docker-compose.yml

@@ -11,7 +11,9 @@ services:
       - 6772
     restart: unless-stopped
     networks:
-      - priv
+      priv:
+        aliases:
+          - grocery-web
 
   db:
     image: docker.io/library/postgres:17-alpine
@@ -31,7 +33,9 @@ services:
     volumes:
       - ./data:/var/lib/postgresql/data
     networks:
-      - priv
+      priv:
+        aliases:
+          - grocery-db
 
 networks:
   priv:

+ 1 - 1
sqlpage/sqlpage/data/transactions.sql

@@ -56,5 +56,5 @@ AND
     )
   ) OR $tags IS NULL)
 ORDER BY ts DESC
-LIMIT 1000);
+);
 GRANT SELECT ON sqlpage_txn TO PUBLIC;

+ 2 - 1
sqlpage/sqlpage/internal/entry.sql

@@ -41,7 +41,8 @@ END;
 SET page = CASE
   WHEN $title IN (
     'Products', 'Categories', 'Groups', 'Tags', 'Transactions',
-    'Trend', 'Volume'
+    'Trend', 'Volume',
+    'Statistics'
   )
   THEN $title||'.sql'
   ELSE NULL

+ 4 - 0
sqlpage/sqlpage/migrations/001_schema-add-statistics.sql

@@ -0,0 +1,4 @@
+INSERT INTO sqlpage_pages
+SELECT UNNEST(ARRAY[
+  'Statistics'
+]);

+ 142 - 0
sqlpage/sqlpage/pages/Statistics.sql

@@ -0,0 +1,142 @@
+SET ":ago" = COALESCE(:ago, '90 days');
+--SELECT 'form' AS component;
+--SELECT 'ago' AS name
+--, 'Period' AS label
+--, 'input' AS type
+--, :ago AS value
+--;
+--SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/internal/cookie.sql') AS properties;
+--SET products = sqlpage.cookie('products')::json;
+--SET categories = sqlpage.cookie('categories')::json;
+--SET groups = sqlpage.cookie('groups')::json;
+--SET tags = sqlpage.cookie('tags')::json;
+--SET start = sqlpage.cookie('start');
+--SET end = sqlpage.cookie('end');
+--SET unit_volume = sqlpage.cookie('unit_volume');
+--SET unit_mass = sqlpage.cookie('unit_mass');
+--SET unit_count = sqlpage.cookie('unit_count')::json;
+--SET log_scale = sqlpage.cookie('log_scale');
+SELECT 'table' AS component
+, TRUE AS search
+, TRUE AS striped_rows
+, TRUE AS small
+;
+WITH mass(
+	"group",
+       	name,
+	organic,
+       	price,
+       	oz,
+       	lb
+) AS (
+	SELECT g.name
+	, p.name
+	, t.organic
+	, t.price
+	, t.quantity*convert_unit(u.name, 'oz', p.name) oz
+	, t.quantity*convert_unit(u.name, 'lb', p.name) lb
+	FROM transactions t, products p, units u, unit_types ut, categories c, groups g
+	WHERE t.unit_id = u.id AND u.unit_type_id = ut.id AND t.product_id = p.id AND c.id = category_id AND g.id = group_id
+	AND ut.name = 'Mass' --AND ts > CURRENT_TIMESTAMP - :ago::interval
+	AND
+	  (p.name IN (SELECT v#>>'{}' FROM json_array_elements($products::json) j(v)) OR $products IS NULL)
+	AND
+	  (c.name IN (SELECT v#>>'{}' FROM json_array_elements($categories::json) j(v)) OR $categories IS NULL)
+	AND
+	  (g.name IN (SELECT v#>>'{}' FROM json_array_elements($groups::json) j(v)) OR $groups IS NULL)
+	AND
+	  --((ts AT TIME ZONE 'UTC') AT TIME ZONE 'Pacific/Auckland')::date
+	  ((ts AT TIME ZONE 'UTC') AT TIME ZONE 'US/Eastern')::date
+	  BETWEEN $start::date AND $end::date
+), vol(
+	"group",
+       	name,
+	organic,
+       	price,
+	floz,
+       	gal
+) AS (
+	SELECT g.name
+	, p.name
+	, t.organic
+	, t.price
+	, t.quantity*convert_unit(u.name, 'fl. oz.', p.name) floz
+	, t.quantity*convert_unit(u.name, 'gal', p.name) gal
+	FROM transactions t, products p, units u, unit_types ut, categories c, groups g
+	WHERE t.unit_id = u.id AND u.unit_type_id = ut.id AND t.product_id = p.id AND c.id = category_id AND g.id = group_id
+	AND ut.name = 'Volume' --AND ts > CURRENT_TIMESTAMP - :ago::interval
+	AND
+	  (p.name IN (SELECT v#>>'{}' FROM json_array_elements($products::json) j(v)) OR $products IS NULL)
+	AND
+	  (c.name IN (SELECT v#>>'{}' FROM json_array_elements($categories::json) j(v)) OR $categories IS NULL)
+	AND
+	  (g.name IN (SELECT v#>>'{}' FROM json_array_elements($groups::json) j(v)) OR $groups IS NULL)
+	AND
+	  --((ts AT TIME ZONE 'UTC') AT TIME ZONE 'Pacific/Auckland')::date
+	  ((ts AT TIME ZONE 'UTC') AT TIME ZONE 'US/Eastern')::date
+	  BETWEEN $start::date AND $end::date
+), piece(
+	"group",
+       	name,
+	organic,
+       	price,
+       	pieces,
+	ksheets
+) AS (
+	SELECT g.name
+	, p.name
+	, t.organic
+	, t.price
+	, t.quantity*convert_unit(u.name, 'Pieces', p.name) pieces
+	, t.quantity*convert_unit(u.name, 'kSheets', p.name) ksheets
+	FROM transactions t, products p, units u, unit_types ut, categories c, groups g
+	WHERE t.unit_id = u.id AND u.unit_type_id = ut.id AND t.product_id = p.id AND c.id = category_id AND g.id = group_id
+	AND ut.name = 'Count' --AND ts > CURRENT_TIMESTAMP - :ago::interval
+	AND
+	  (p.name IN (SELECT v#>>'{}' FROM json_array_elements($products::json) j(v)) OR $products IS NULL)
+	AND
+	  (c.name IN (SELECT v#>>'{}' FROM json_array_elements($categories::json) j(v)) OR $categories IS NULL)
+	AND
+	  (g.name IN (SELECT v#>>'{}' FROM json_array_elements($groups::json) j(v)) OR $groups IS NULL)
+	AND
+	  --((ts AT TIME ZONE 'UTC') AT TIME ZONE 'Pacific/Auckland')::date
+	  ((ts AT TIME ZONE 'UTC') AT TIME ZONE 'US/Eastern')::date
+	  BETWEEN $start::date AND $end::date
+)
+SELECT "group", name, organic org, 'oz' "by", round(min(price/oz), 2) min, round(sum(price)/sum(oz), 2) avg, round(max(price/oz), 2) max
+FROM mass
+GROUP BY "group", name, organic
+UNION
+SELECT "group", name, organic org, 'lb' "by", round(min(price/lb), 2) min, round(sum(price)/sum(lb), 2) avg, round(max(price/lb), 2) max
+FROM mass
+GROUP BY "group", name, organic
+--ORDER BY "group", name, "by";
+--;
+--
+--SELECT 'table' AS component
+--, TRUE AS search
+--;
+UNION
+SELECT "group", name, organic org, 'fl. oz.' "by", round(min(price/floz), 2) min, round(sum(price)/sum(floz), 2) avg, round(max(price/floz), 2) max
+FROM vol
+GROUP BY "group", name, organic
+UNION
+SELECT "group", name, organic org, 'gal' "by", round(min(price/gal), 2) min, round(sum(price)/sum(gal), 2) avg, round(max(price/gal), 2) max
+FROM vol
+GROUP BY "group", name, organic
+--ORDER BY "group", name, "by"
+--;
+--
+--SELECT 'table' AS component
+--, TRUE AS search
+--;
+UNION
+SELECT "group", name, organic org, 'Pieces' "by", round(min(price/pieces), 2) min, round(sum(CASE WHEN pieces IS NOT NULL THEN price ELSE NULL END)/sum(pieces), 2) avg, round(max(price/pieces), 2) max
+FROM piece
+GROUP BY "group", name, organic
+UNION
+SELECT "group", name, organic org, 'kSheets' "by", round(min(price/ksheets), 2) min, round(sum(CASE WHEN ksheets IS NOT NULL THEN price ELSE NULL END)/sum(ksheets), 2) avg, round(max(price/ksheets), 2) max
+FROM piece
+GROUP BY "group", name, organic
+ORDER BY "group", name, org, "by"
+;

+ 5 - 2
sqlpage/sqlpage/pages/Transactions.sql

@@ -11,7 +11,8 @@ SELECT
 ;
 SELECT
   to_char(ts
-     AT TIME ZONE 'Pacific/Auckland', --COALESCE('$ParameterTZ', 'Pacific/Auckland'),
+     --AT TIME ZONE 'Pacific/Auckland', --COALESCE('$ParameterTZ', 'Pacific/Auckland'),
+     AT TIME ZONE 'US/Eastern', --COALESCE('$ParameterTZ', 'Pacific/Auckland'),
     'Mon DD HH24:MI:SS'
   ) AS "Time",
   description AS "Description",
@@ -23,7 +24,9 @@ SELECT
   to_char(price, 'FM999999999.00') AS "Price",
   to_char(quantity, 'FM999999999.000') AS "Quantity",
   unit AS "Unit"
-FROM sqlpage_txn;
+FROM sqlpage_txn
+ORDER BY ts DESC
+;
 
 SELECT '# No Data' AS "Notice"
 WHERE NOT EXISTS(SELECT * FROM sqlpage_txn LIMIT 1);

+ 27 - 0
sqlpage/statistics.sql

@@ -0,0 +1,27 @@
+SET ":title" = 'Statistics';
+SET ":page" = 'Statistics.sql';
+SET filter_config = '[
+  {"name": "products[]", "width": 4},
+  {"name": "categories[]", "width": 4},
+  {"name": "groups[]", "width": 4},
+  {"name": "tags[]", "type": "hidden"},
+  {"name": "log_scale", "type": "hidden"},
+  {"name": "unit_mass", "type": "hidden"},
+  {"name": "unit_volume", "type": "hidden"},
+  {"name": "unit_count[]", "type": "hidden"}
+]';
+SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/internal/entry.sql') AS properties;
+--SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/internal/theme.sql') AS properties;
+--
+--SELECT 'tab' AS component, TRUE AS center;
+--SELECT title
+--, lower(title) AS id
+--, $title = title AS active
+--, lower(title)||'.sql' AS link
+--FROM (
+--  SELECT name FROM sqlpage_pages
+--) AS tabs(title)
+--;
+--
+--
+--SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/pages/'||:page) AS properties;

+ 4 - 3
sqlpage/trend/Quantity.sql

@@ -40,9 +40,10 @@ SELECT 'chart' AS component
 , :marker AS marker
 ;
 SELECT product AS series
-, ts AS x
-, to_char(price/quantity, 'FM999999999.000') AS y
+, ts::date AS x
+, to_char(sum(price)/sum(quantity), 'FM999999999.000') AS y
 FROM sqlpage_txn
 WHERE unit = :unit
-ORDER BY ts
+GROUP BY product, ts::date
+ORDER BY x
 ;

+ 3 - 3
sqlpage/trend/Store.sql

@@ -45,10 +45,10 @@ SELECT 'chart' AS component
 , :marker AS marker
 ;
 SELECT code AS series
-, ts AS x
+, ts::date AS x
 , to_char(sum(price)/sum(quantity), 'FM999999999.000') AS y
 FROM sqlpage_txn
 WHERE unit = :unit
-GROUP BY code, ts
-ORDER BY ts
+GROUP BY code, ts::date
+ORDER BY x
 ;