txn_view.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #
  2. # Copyright (c) Daniel Sheffield 2021
  3. #
  4. # All rights reserved
  5. #
  6. # THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
  7. from psycopg2.sql import (
  8. Identifier,
  9. SQL,
  10. Literal,
  11. Placeholder,
  12. Composed,
  13. )
  14. from collections import (
  15. OrderedDict,
  16. )
  17. select = OrderedDict([
  18. ('id', Identifier('transactions','id')),
  19. ('ts', SQL("""date_part('day',ts)||'/'||date_part('month',ts)||' '||date_part('hour',ts)::int%12""")),
  20. ('store', Identifier('stores', 'name')),
  21. ('code', Identifier('stores', 'code')),
  22. ('description', Identifier('transactions','description')),
  23. ('volume', Identifier('quantity')),
  24. ('unit', Identifier('units', 'name')),
  25. ('price', Identifier('price')),
  26. ('$/unit', SQL("""TRUNC(price/quantity,4)""")),
  27. ('total', SQL("""sum(transactions.price) OVER (PARTITION BY transactions.ts::date ORDER BY transactions.id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)""")),
  28. ('group', Identifier('groups','name')),
  29. ('category', Identifier('categories','name')),
  30. ('product', Identifier('products','name')),
  31. ('organic', Identifier('organic')),
  32. ])
  33. def get_where(date, store, full_name=False, exact_time=False):
  34. where = [ ]
  35. if store is not None:
  36. where.append(SQL(' ').join([
  37. Identifier('stores', 'name' if full_name else 'code'),
  38. SQL('='),
  39. Literal(store)
  40. ]))
  41. where.append(
  42. SQL("{ts} at time zone 'utc' BETWEEN {date}::date AND {date}::date + {interval}::interval").format(
  43. ts=Identifier('ts'),
  44. date=Literal(str(date)),
  45. interval=Literal('23 hours 59 minutes 59 seconds'),
  46. ) if not exact_time else SQL("{ts} at time zone 'utc' = {date}").format(
  47. ts=Identifier('ts'),
  48. date=Literal(str(date)),
  49. )
  50. )
  51. return SQL('').join([
  52. SQL("WHERE"
  53. "\n "),
  54. SQL("\n AND ").join(where),
  55. ])
  56. def get_statement(date, store, full_name=False, exact_time=False):
  57. statement = SQL('\n').join([
  58. SQL('').join([
  59. SQL("SELECT"
  60. "\n "),
  61. SQL(','
  62. "\n ").join([
  63. SQL(' ').join([v, SQL('AS'), Identifier(f'{k}')]) for k, v in select.items()
  64. ])
  65. ]),
  66. SQL('').join([
  67. SQL("FROM"
  68. "\n "),
  69. SQL("\n JOIN ").join([
  70. SQL("transactions"),
  71. SQL("{table} ON {table}.{key} = {index}").format(
  72. table=Identifier('units'),
  73. key=Identifier('id'),
  74. index=Identifier('unit_id'),
  75. ),
  76. SQL("{table} ON {table}.{key} = {index}").format(
  77. table=Identifier('stores'),
  78. key=Identifier('id'),
  79. index=Identifier('store_id')
  80. ),
  81. SQL("{table} ON {table}.{key} = {index}").format(
  82. table=Identifier('products'),
  83. key=Identifier('id'),
  84. index=Identifier('product_id')
  85. ),
  86. SQL("{table} ON {table}.{key} = {index}").format(
  87. table=Identifier('categories'),
  88. key=Identifier('id'),
  89. index=Identifier('category_id')
  90. ),
  91. SQL("{table} ON {table}.{key} = {index}").format(
  92. table=Identifier('groups'),
  93. key=Identifier('id'),
  94. index=Identifier('group_id')
  95. ),
  96. ]),
  97. ]),
  98. get_where(date if exact_time else date.replace(
  99. hour=0, minute=0, second=0, microsecond=0
  100. ), store, full_name=full_name, exact_time=exact_time),
  101. SQL('ORDER BY {_id} DESC').format(_id=Identifier('transactions','id')),
  102. ])
  103. return statement