|
@@ -0,0 +1,158 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+from psycopg2.sql import (
|
|
|
+ Identifier,
|
|
|
+ SQL,
|
|
|
+ Literal,
|
|
|
+ Placeholder,
|
|
|
+ Composed,
|
|
|
+)
|
|
|
+from collections import (
|
|
|
+ OrderedDict,
|
|
|
+)
|
|
|
+
|
|
|
+def get_where(product, unit, organic=None, limit='90 days'):
|
|
|
+ where = [ ]
|
|
|
+ where.append(SQL(' ').join([
|
|
|
+ Identifier('products', 'name'),
|
|
|
+ SQL('='),
|
|
|
+ Literal(product)
|
|
|
+ ]))
|
|
|
+ where.append(SQL(' ').join([
|
|
|
+ Identifier('units', 'name'),
|
|
|
+ SQL('='),
|
|
|
+ Literal(unit),
|
|
|
+ ]))
|
|
|
+ if organic is not None:
|
|
|
+ where.append(SQL(' ').join([
|
|
|
+ Identifier('organic'),
|
|
|
+ SQL('='),
|
|
|
+ Literal(organic),
|
|
|
+ ]))
|
|
|
+ where.append(
|
|
|
+ SQL("{ts} at time zone 'utc' BETWEEN now()::date - {interval} AND now()::date").format(
|
|
|
+ ts=Identifier('ts'),
|
|
|
+ interval=SQL("{literal}::interval").format(literal=Literal(limit))
|
|
|
+ )
|
|
|
+ )
|
|
|
+ return SQL('').join([
|
|
|
+ SQL("WHERE"
|
|
|
+ "\n "),
|
|
|
+ SQL("\n AND ").join(where),
|
|
|
+ ])
|
|
|
+
|
|
|
+def get_historic_prices_statement(sort, product, unit, organic=None, limit='90 days'):
|
|
|
+ partition = f"(PARTITION BY {'organic,' if organic is not None else ''} product_id, unit_id)"
|
|
|
+ organic_sort = f"{'organic,' if organic is not None else ''}"
|
|
|
+ select = OrderedDict([
|
|
|
+ ('id', Identifier('transactions','id')),
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ('date', SQL("""date_part('day',ts)||'/'||date_part('month',ts)||'/'||date_part('year',ts)""")),
|
|
|
+
|
|
|
+ ('code', Identifier('stores', 'code')),
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ('$/unit', SQL("""TRUNC(price/quantity,4)""")),
|
|
|
+ ('avg', SQL(f"""TRUNC(sum(price) OVER {partition} / sum(quantity) OVER {partition}, 4)""")),
|
|
|
+ ('min', SQL(f"""TRUNC(min(price/quantity) OVER {partition}, 4)""")),
|
|
|
+ ('max', SQL(f"""TRUNC(max(price/quantity) OVER {partition}, 4)""")),
|
|
|
+
|
|
|
+ ('group', Identifier('groups','name')),
|
|
|
+ ('category', Identifier('categories','name')),
|
|
|
+ ('product', Identifier('products','name')),
|
|
|
+ ('organic', Identifier('organic')),
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ])
|
|
|
+ statement = SQL('\n').join([
|
|
|
+ SQL('').join([
|
|
|
+ SQL("SELECT"
|
|
|
+ "\n "),
|
|
|
+ SQL(','
|
|
|
+ "\n ").join([
|
|
|
+ SQL(' ').join([v, SQL('AS'), Identifier(f'{k}')]) for k, v in select.items()
|
|
|
+ ])
|
|
|
+ ]),
|
|
|
+ SQL('').join([
|
|
|
+ SQL("FROM"
|
|
|
+ "\n "),
|
|
|
+ SQL("\n JOIN ").join([
|
|
|
+ SQL("transactions"),
|
|
|
+ SQL("{table} ON {table}.{key} = {index}").format(
|
|
|
+ table=Identifier('units'),
|
|
|
+ key=Identifier('id'),
|
|
|
+ index=Identifier('unit_id'),
|
|
|
+ ),
|
|
|
+ SQL("{table} ON {table}.{key} = {index}").format(
|
|
|
+ table=Identifier('stores'),
|
|
|
+ key=Identifier('id'),
|
|
|
+ index=Identifier('store_id')
|
|
|
+ ),
|
|
|
+ SQL("{table} ON {table}.{key} = {index}").format(
|
|
|
+ table=Identifier('products'),
|
|
|
+ key=Identifier('id'),
|
|
|
+ index=Identifier('product_id')
|
|
|
+ ),
|
|
|
+ SQL("{table} ON {table}.{key} = {index}").format(
|
|
|
+ table=Identifier('categories'),
|
|
|
+ key=Identifier('id'),
|
|
|
+ index=Identifier('category_id')
|
|
|
+ ),
|
|
|
+ SQL("{table} ON {table}.{key} = {index}").format(
|
|
|
+ table=Identifier('groups'),
|
|
|
+ key=Identifier('id'),
|
|
|
+ index=Identifier('group_id')
|
|
|
+ ),
|
|
|
+ ]),
|
|
|
+ ]),
|
|
|
+ get_where(product, unit, organic=organic, limit=limit),
|
|
|
+ SQL('ORDER BY {organic_sort} {sort} {direction}, code, "$/unit" ASC, ts DESC').format(
|
|
|
+ sort=Identifier(sort),
|
|
|
+ direction=SQL('DESC' if sort == 'ts' else 'ASC'),
|
|
|
+ organic_sort=SQL(organic_sort),
|
|
|
+ ),
|
|
|
+ ])
|
|
|
+ return statement
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|