django-advanced-report-builder 1.2.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. advanced_report_builder/.DS_Store +0 -0
  2. advanced_report_builder/.ruff_cache/.gitignore +2 -0
  3. advanced_report_builder/.ruff_cache/0.11.9/16555798982502606642 +0 -0
  4. advanced_report_builder/.ruff_cache/CACHEDIR.TAG +1 -0
  5. advanced_report_builder/__init__.py +0 -0
  6. advanced_report_builder/admin.py +264 -0
  7. advanced_report_builder/apps.py +7 -0
  8. advanced_report_builder/column_types.py +26 -0
  9. advanced_report_builder/columns.py +296 -0
  10. advanced_report_builder/customise.py +2 -0
  11. advanced_report_builder/data_merge/__init__.py +0 -0
  12. advanced_report_builder/data_merge/utils.py +112 -0
  13. advanced_report_builder/data_merge/widget.py +30 -0
  14. advanced_report_builder/duplicate.py +171 -0
  15. advanced_report_builder/exceptions.py +9 -0
  16. advanced_report_builder/field_types.py +466 -0
  17. advanced_report_builder/field_utils.py +401 -0
  18. advanced_report_builder/filter_query.py +862 -0
  19. advanced_report_builder/form_utils.py +12 -0
  20. advanced_report_builder/generate_series.py +14 -0
  21. advanced_report_builder/globals.py +276 -0
  22. advanced_report_builder/includes.py +72 -0
  23. advanced_report_builder/migrations/0001_initial.py +246 -0
  24. advanced_report_builder/migrations/0002_auto_20220209_1657.py +23 -0
  25. advanced_report_builder/migrations/0003_auto_20220215_1219.py +42 -0
  26. advanced_report_builder/migrations/0004_customreport.py +27 -0
  27. advanced_report_builder/migrations/0005_auto_20220303_0958.py +84 -0
  28. advanced_report_builder/migrations/0006_auto_20220310_1147.py +32 -0
  29. advanced_report_builder/migrations/0007_auto_20220322_1939.py +23 -0
  30. advanced_report_builder/migrations/0008_auto_20220404_1144.py +28 -0
  31. advanced_report_builder/migrations/0009_auto_20230428_1554.py +53 -0
  32. advanced_report_builder/migrations/0010_auto_20230428_2033.py +23 -0
  33. advanced_report_builder/migrations/0011_auto_20230620_1449.py +23 -0
  34. advanced_report_builder/migrations/0012_auto_20230718_1642.py +24 -0
  35. advanced_report_builder/migrations/0013_reportqueryorder.py +30 -0
  36. advanced_report_builder/migrations/0014_auto_20240706_2207.py +24 -0
  37. advanced_report_builder/migrations/0015_report_user_created_report_user_updated.py +26 -0
  38. advanced_report_builder/migrations/0016_calendarreport_dashboardreport_options_and_more.py +74 -0
  39. advanced_report_builder/migrations/0017_alter_barchartreport_options_and_more.py +57 -0
  40. advanced_report_builder/migrations/0018_reportquery_target_target_period_type.py +24 -0
  41. advanced_report_builder/migrations/0019_multicellstyle_and_more.py +107 -0
  42. advanced_report_builder/migrations/0020_alter_multicellstyle_font_size.py +18 -0
  43. advanced_report_builder/migrations/0021_multivalueheldquery_and_more.py +36 -0
  44. advanced_report_builder/migrations/0022_dashboardreport_show_options_report_template_style_and_more.py +44 -0
  45. advanced_report_builder/migrations/0023_rename_colour_target_default_colour_and_more.py +41 -0
  46. advanced_report_builder/migrations/0024_alter_target_period_type.py +18 -0
  47. advanced_report_builder/migrations/__init__.py +0 -0
  48. advanced_report_builder/models.py +954 -0
  49. advanced_report_builder/report_builder.py +28 -0
  50. advanced_report_builder/signals.py +3 -0
  51. advanced_report_builder/static/.DS_Store +0 -0
  52. advanced_report_builder/static/advanced_report_builder/.DS_Store +0 -0
  53. advanced_report_builder/static/advanced_report_builder/chart-js/js/chart.esm.js +10553 -0
  54. advanced_report_builder/static/advanced_report_builder/chart-js/js/chart.js +13190 -0
  55. advanced_report_builder/static/advanced_report_builder/chart-js/js/chart.min.js +13 -0
  56. advanced_report_builder/static/advanced_report_builder/chart-js/js/chartjs-adapter-moment.min.js +8 -0
  57. advanced_report_builder/static/advanced_report_builder/chart-js/js/chartjs-plugin-datalabels.min.js +7 -0
  58. advanced_report_builder/static/advanced_report_builder/chart-js/js/chunks/helpers.segment.js +2499 -0
  59. advanced_report_builder/static/advanced_report_builder/chart-js/js/helpers.esm.js +7 -0
  60. advanced_report_builder/static/advanced_report_builder/d3/js/d3.js +20196 -0
  61. advanced_report_builder/static/advanced_report_builder/d3/js/d3.min.js +2 -0
  62. advanced_report_builder/static/advanced_report_builder/d3-funnel/js/d3-funnel.js +6087 -0
  63. advanced_report_builder/static/advanced_report_builder/d3-funnel/js/d3-funnel.min.js +2 -0
  64. advanced_report_builder/static/advanced_report_builder/dashboard/js/dashboard.js +19 -0
  65. advanced_report_builder/static/advanced_report_builder/dot/js/.gitignore +31 -0
  66. advanced_report_builder/static/advanced_report_builder/dot/js/.travis.yml +9 -0
  67. advanced_report_builder/static/advanced_report_builder/dot/js/LICENSE-DOT.txt +24 -0
  68. advanced_report_builder/static/advanced_report_builder/dot/js/README.md +90 -0
  69. advanced_report_builder/static/advanced_report_builder/dot/js/bin/dot-packer +52 -0
  70. advanced_report_builder/static/advanced_report_builder/dot/js/bower.json +21 -0
  71. advanced_report_builder/static/advanced_report_builder/dot/js/doT.js +141 -0
  72. advanced_report_builder/static/advanced_report_builder/dot/js/doT.min.js +8 -0
  73. advanced_report_builder/static/advanced_report_builder/dot/js/doU.js +56 -0
  74. advanced_report_builder/static/advanced_report_builder/dot/js/index.js +143 -0
  75. advanced_report_builder/static/advanced_report_builder/dot/js/package.json +46 -0
  76. advanced_report_builder/static/advanced_report_builder/fullcalendar/.DS_Store +0 -0
  77. advanced_report_builder/static/advanced_report_builder/fullcalendar/LICENSE.txt +20 -0
  78. advanced_report_builder/static/advanced_report_builder/fullcalendar/README.md +10 -0
  79. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/LICENSE.txt +20 -0
  80. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/README.md +8 -0
  81. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/af.js +30 -0
  82. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar-dz.js +31 -0
  83. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar-kw.js +31 -0
  84. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar-ly.js +31 -0
  85. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar-ma.js +31 -0
  86. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar-sa.js +31 -0
  87. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar-tn.js +31 -0
  88. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ar.js +31 -0
  89. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/bg.js +31 -0
  90. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/bs.js +32 -0
  91. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ca.js +30 -0
  92. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/cs.js +32 -0
  93. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/da.js +30 -0
  94. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/de.js +33 -0
  95. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/el.js +30 -0
  96. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/en-au.js +17 -0
  97. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/en-gb.js +17 -0
  98. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/en-nz.js +17 -0
  99. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/es-us.js +30 -0
  100. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/es.js +30 -0
  101. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/et.js +32 -0
  102. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/eu.js +30 -0
  103. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/fa.js +33 -0
  104. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/fi.js +30 -0
  105. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/fr-ca.js +27 -0
  106. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/fr-ch.js +31 -0
  107. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/fr.js +31 -0
  108. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/gl.js +30 -0
  109. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/he.js +27 -0
  110. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/hi.js +32 -0
  111. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/hr.js +32 -0
  112. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/hu.js +30 -0
  113. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/id.js +30 -0
  114. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/is.js +30 -0
  115. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/it.js +32 -0
  116. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ja.js +28 -0
  117. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ka.js +32 -0
  118. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/kk.js +32 -0
  119. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ko.js +26 -0
  120. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/lb.js +30 -0
  121. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/lt.js +30 -0
  122. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/lv.js +32 -0
  123. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/mk.js +28 -0
  124. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ms.js +32 -0
  125. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/nb.js +30 -0
  126. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/nl.js +30 -0
  127. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/nn.js +30 -0
  128. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/pl.js +30 -0
  129. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/pt-br.js +28 -0
  130. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/pt.js +30 -0
  131. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ro.js +32 -0
  132. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/ru.js +32 -0
  133. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/sk.js +32 -0
  134. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/sl.js +30 -0
  135. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/sq.js +32 -0
  136. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/sr-cyrl.js +32 -0
  137. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/sr.js +32 -0
  138. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/sv.js +30 -0
  139. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/th.js +25 -0
  140. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/tr.js +30 -0
  141. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/uk.js +32 -0
  142. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/vi.js +32 -0
  143. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/zh-cn.js +33 -0
  144. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales/zh-tw.js +26 -0
  145. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales-all.js +1348 -0
  146. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/locales-all.min.js +1 -0
  147. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/main.css +1052 -0
  148. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/main.d.ts +2730 -0
  149. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/main.esm.js +8558 -0
  150. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/main.js +8717 -0
  151. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/main.min.css +1 -0
  152. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/main.min.js +6 -0
  153. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/core/package.json +30 -0
  154. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/LICENSE.txt +20 -0
  155. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/README.md +8 -0
  156. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/main.css +78 -0
  157. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/main.d.ts +310 -0
  158. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/main.esm.js +1627 -0
  159. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/main.js +1641 -0
  160. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/main.min.css +1 -0
  161. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/main.min.js +6 -0
  162. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/daygrid/package.json +33 -0
  163. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/fullcalendar-yearview/LICENSE +21 -0
  164. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/fullcalendar-yearview/css/main.css +85 -0
  165. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/fullcalendar-yearview/js/main.js +2018 -0
  166. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/LICENSE.txt +20 -0
  167. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/README.md +8 -0
  168. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/main.d.ts +20 -0
  169. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/main.esm.js +162 -0
  170. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/main.js +170 -0
  171. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/main.min.js +6 -0
  172. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/google-calendar/package.json +33 -0
  173. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/LICENSE.txt +20 -0
  174. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/README.md +8 -0
  175. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/main.d.ts +323 -0
  176. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/main.esm.js +2132 -0
  177. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/main.js +2143 -0
  178. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/main.min.js +6 -0
  179. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/interaction/package.json +33 -0
  180. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/LICENSE.txt +20 -0
  181. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/README.md +8 -0
  182. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/main.css +118 -0
  183. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/main.d.ts +33 -0
  184. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/main.esm.js +335 -0
  185. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/main.js +343 -0
  186. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/main.min.css +1 -0
  187. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/main.min.js +6 -0
  188. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/list/package.json +33 -0
  189. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/LICENSE.txt +20 -0
  190. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/README.md +8 -0
  191. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/main.d.ts +14 -0
  192. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/main.esm.js +162 -0
  193. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/main.js +170 -0
  194. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/main.min.js +6 -0
  195. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/luxon/package.json +34 -0
  196. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/LICENSE.txt +20 -0
  197. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/README.md +8 -0
  198. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/main.d.ts +14 -0
  199. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/main.esm.js +102 -0
  200. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/main.js +110 -0
  201. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/main.min.js +6 -0
  202. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment/package.json +34 -0
  203. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/LICENSE.txt +20 -0
  204. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/README.md +8 -0
  205. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/main.d.ts +11 -0
  206. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/main.esm.js +58 -0
  207. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/main.js +64 -0
  208. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/main.min.js +6 -0
  209. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/moment-timezone/package.json +35 -0
  210. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/LICENSE.txt +20 -0
  211. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/README.md +8 -0
  212. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/main.d.ts +9 -0
  213. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/main.esm.js +121 -0
  214. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/main.js +128 -0
  215. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/main.min.js +6 -0
  216. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/rrule/package.json +34 -0
  217. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/LICENSE.txt +20 -0
  218. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/README.md +8 -0
  219. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/main.css +309 -0
  220. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/main.d.ts +220 -0
  221. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/main.esm.js +1345 -0
  222. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/main.js +1357 -0
  223. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/main.min.css +1 -0
  224. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/main.min.js +6 -0
  225. advanced_report_builder/static/advanced_report_builder/fullcalendar/packages/timegrid/package.json +36 -0
  226. advanced_report_builder/static/advanced_report_builder/fullcalendar/vendor/rrule.js +3782 -0
  227. advanced_report_builder/static/advanced_report_builder/jquery_extendext/js/jQuery.extendext.js +132 -0
  228. advanced_report_builder/static/advanced_report_builder/jquery_extendext/js/jQuery.extendext.min.js +9 -0
  229. advanced_report_builder/static/advanced_report_builder/moment/locales.js +9769 -0
  230. advanced_report_builder/static/advanced_report_builder/moment/locales.min.js +1 -0
  231. advanced_report_builder/static/advanced_report_builder/moment/moment-with-locales.js +14289 -0
  232. advanced_report_builder/static/advanced_report_builder/moment/moment-with-locales.min.js +1 -0
  233. advanced_report_builder/static/advanced_report_builder/moment/moment.min.js +1 -0
  234. advanced_report_builder/static/advanced_report_builder/query_builder/.DS_Store +0 -0
  235. advanced_report_builder/static/advanced_report_builder/query_builder/css/.DS_Store +0 -0
  236. advanced_report_builder/static/advanced_report_builder/query_builder/css/query-builder.dark.css +173 -0
  237. advanced_report_builder/static/advanced_report_builder/query_builder/css/query-builder.dark.min.css +6 -0
  238. advanced_report_builder/static/advanced_report_builder/query_builder/css/query-builder.default.css +173 -0
  239. advanced_report_builder/static/advanced_report_builder/query_builder/css/query-builder.default.min.css +6 -0
  240. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.ar.js +80 -0
  241. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.az.js +79 -0
  242. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.bg.js +79 -0
  243. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.cs.js +79 -0
  244. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.da.js +56 -0
  245. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.de.js +76 -0
  246. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.el.js +80 -0
  247. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.en.js +83 -0
  248. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.es.js +81 -0
  249. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.fa-IR.js +79 -0
  250. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.fr.js +83 -0
  251. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.he.js +81 -0
  252. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.it.js +79 -0
  253. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.nl.js +76 -0
  254. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.no.js +54 -0
  255. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.pl.js +80 -0
  256. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.pt-BR.js +80 -0
  257. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.pt-PT.js +75 -0
  258. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.ro.js +54 -0
  259. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.ru.js +77 -0
  260. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.sq.js +78 -0
  261. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.tr.js +82 -0
  262. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.ua.js +79 -0
  263. advanced_report_builder/static/advanced_report_builder/query_builder/i18n/query-builder.zh-CN.js +80 -0
  264. advanced_report_builder/static/advanced_report_builder/query_builder/js/.DS_Store +0 -0
  265. advanced_report_builder/static/advanced_report_builder/query_builder/js/plugins/.DS_Store +0 -0
  266. advanced_report_builder/static/advanced_report_builder/query_builder/js/plugins/currency/plugin.js +30 -0
  267. advanced_report_builder/static/advanced_report_builder/query_builder/js/query-builder.js +6200 -0
  268. advanced_report_builder/static/advanced_report_builder/query_builder/js/query-builder.min.js +7 -0
  269. advanced_report_builder/static/advanced_report_builder/query_builder/js/query-builder.standalone.js +6477 -0
  270. advanced_report_builder/static/advanced_report_builder/query_builder/js/query-builder.standalone.min.js +7 -0
  271. advanced_report_builder/static/advanced_report_builder/query_builder/scss/.DS_Store +0 -0
  272. advanced_report_builder/static/advanced_report_builder/query_builder/scss/dark.scss +19 -0
  273. advanced_report_builder/static/advanced_report_builder/query_builder/scss/default.scss +186 -0
  274. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/_bt-checkbox.scss +12 -0
  275. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/_bt-tooltip-errors.scss +9 -0
  276. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/_filter-description.scss +21 -0
  277. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/_invert.scss +5 -0
  278. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/_sortable.scss +28 -0
  279. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/bt-tooltip-errors.scss +9 -0
  280. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/filter-description.scss +21 -0
  281. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/invert.scss +5 -0
  282. advanced_report_builder/static/advanced_report_builder/query_builder/scss/plugins/sortable.scss +27 -0
  283. advanced_report_builder/template_types.py +34 -0
  284. advanced_report_builder/templates/advanced_report_builder/calendar/description_modal.html +12 -0
  285. advanced_report_builder/templates/advanced_report_builder/calendar/middle.html +33 -0
  286. advanced_report_builder/templates/advanced_report_builder/calendar/modal.html +10 -0
  287. advanced_report_builder/templates/advanced_report_builder/calendar/report.html +80 -0
  288. advanced_report_builder/templates/advanced_report_builder/charts/bar/middle.html +122 -0
  289. advanced_report_builder/templates/advanced_report_builder/charts/funnel/middle.html +46 -0
  290. advanced_report_builder/templates/advanced_report_builder/charts/funnel/report.html +34 -0
  291. advanced_report_builder/templates/advanced_report_builder/charts/line/middle.html +119 -0
  292. advanced_report_builder/templates/advanced_report_builder/charts/modal.html +12 -0
  293. advanced_report_builder/templates/advanced_report_builder/charts/modal_field.html +13 -0
  294. advanced_report_builder/templates/advanced_report_builder/charts/pie/middle.html +58 -0
  295. advanced_report_builder/templates/advanced_report_builder/charts/report.html +33 -0
  296. advanced_report_builder/templates/advanced_report_builder/data_merge/data_merge.html +144 -0
  297. advanced_report_builder/templates/advanced_report_builder/datatables/fields/modal.html +13 -0
  298. advanced_report_builder/templates/advanced_report_builder/datatables/fields/single_query_builder.html +87 -0
  299. advanced_report_builder/templates/advanced_report_builder/datatables/modal.html +13 -0
  300. advanced_report_builder/templates/advanced_report_builder/datatables/onclick_menu.html +14 -0
  301. advanced_report_builder/templates/advanced_report_builder/datatables/report.html +37 -0
  302. advanced_report_builder/templates/advanced_report_builder/datatables/select_pivot.html +199 -0
  303. advanced_report_builder/templates/advanced_report_builder/error.html +21 -0
  304. advanced_report_builder/templates/advanced_report_builder/extra_query_modal.html +13 -0
  305. advanced_report_builder/templates/advanced_report_builder/kanban/description_modal.html +12 -0
  306. advanced_report_builder/templates/advanced_report_builder/kanban/middle.html +63 -0
  307. advanced_report_builder/templates/advanced_report_builder/kanban/modal.html +10 -0
  308. advanced_report_builder/templates/advanced_report_builder/kanban/report.html +71 -0
  309. advanced_report_builder/templates/advanced_report_builder/multi_values/held_modal.html +14 -0
  310. advanced_report_builder/templates/advanced_report_builder/multi_values/middle.html +61 -0
  311. advanced_report_builder/templates/advanced_report_builder/multi_values/modal.html +15 -0
  312. advanced_report_builder/templates/advanced_report_builder/multi_values/report.html +19 -0
  313. advanced_report_builder/templates/advanced_report_builder/query_builder.html +88 -0
  314. advanced_report_builder/templates/advanced_report_builder/query_modal.html +12 -0
  315. advanced_report_builder/templates/advanced_report_builder/select_column.html +230 -0
  316. advanced_report_builder/templates/advanced_report_builder/single_values/gauge_middle.html +143 -0
  317. advanced_report_builder/templates/advanced_report_builder/single_values/middle.html +63 -0
  318. advanced_report_builder/templates/advanced_report_builder/single_values/modal.html +13 -0
  319. advanced_report_builder/templates/advanced_report_builder/single_values/report.html +56 -0
  320. advanced_report_builder/toggle.py +9 -0
  321. advanced_report_builder/urls.py +237 -0
  322. advanced_report_builder/utils.py +171 -0
  323. advanced_report_builder/variable_date.py +670 -0
  324. advanced_report_builder/view_types.py +27 -0
  325. advanced_report_builder/views/.DS_Store +0 -0
  326. advanced_report_builder/views/__init__.py +0 -0
  327. advanced_report_builder/views/bar_charts.py +746 -0
  328. advanced_report_builder/views/calendar.py +745 -0
  329. advanced_report_builder/views/charts_base.py +625 -0
  330. advanced_report_builder/views/custom.py +147 -0
  331. advanced_report_builder/views/dashboard.py +357 -0
  332. advanced_report_builder/views/datatables/__init__.py +0 -0
  333. advanced_report_builder/views/datatables/datatables.py +151 -0
  334. advanced_report_builder/views/datatables/modal.py +1151 -0
  335. advanced_report_builder/views/datatables/utils.py +701 -0
  336. advanced_report_builder/views/error_pod.py +50 -0
  337. advanced_report_builder/views/funnel_charts.py +289 -0
  338. advanced_report_builder/views/helpers.py +22 -0
  339. advanced_report_builder/views/kanban.py +868 -0
  340. advanced_report_builder/views/line_charts.py +415 -0
  341. advanced_report_builder/views/modals_base.py +213 -0
  342. advanced_report_builder/views/multi_value.py +1160 -0
  343. advanced_report_builder/views/pie_charts.py +290 -0
  344. advanced_report_builder/views/query_modal/__init__.py +0 -0
  345. advanced_report_builder/views/query_modal/mixin.py +161 -0
  346. advanced_report_builder/views/query_modal/modal.py +274 -0
  347. advanced_report_builder/views/report.py +241 -0
  348. advanced_report_builder/views/report_utils_mixin.py +312 -0
  349. advanced_report_builder/views/reports.py +154 -0
  350. advanced_report_builder/views/single_values.py +792 -0
  351. advanced_report_builder/views/targets/__init__.py +0 -0
  352. advanced_report_builder/views/targets/utils.py +251 -0
  353. advanced_report_builder/views/targets/views.py +139 -0
  354. advanced_report_builder/views/value_base.py +198 -0
  355. advanced_report_builder/widgets.py +5 -0
  356. django_advanced_report_builder-1.2.9.dist-info/METADATA +35 -0
  357. django_advanced_report_builder-1.2.9.dist-info/RECORD +360 -0
  358. django_advanced_report_builder-1.2.9.dist-info/WHEEL +5 -0
  359. django_advanced_report_builder-1.2.9.dist-info/licenses/LICENSE +21 -0
  360. django_advanced_report_builder-1.2.9.dist-info/top_level.txt +1 -0
@@ -0,0 +1,954 @@
1
+ from django.apps import apps
2
+ from django.conf import settings
3
+ from django.contrib.contenttypes.models import ContentType
4
+ from django.db import models
5
+ from django.forms import ChoiceField
6
+ from django.utils.dates import MONTHS
7
+ from django_datatables.columns import DatatableColumn, ManyToManyColumn
8
+ from django_datatables.model_def import DatatableModel
9
+ from django_modals.model_fields.colour import ColourField
10
+ from django_modals.widgets.select2 import Select2
11
+ from time_stamped_model.models import TimeStampedModel
12
+
13
+ from advanced_report_builder.globals import (
14
+ ANNOTATION_CHART_SCALE,
15
+ ANNOTATION_CHOICE_COUNT,
16
+ ANNOTATION_VALUE_CHOICES,
17
+ ANNOTATIONS_CHOICES,
18
+ CALENDAR_VIEW_TYPE_CHOICES,
19
+ CALENDAR_VIEW_TYPE_DAY,
20
+ CALENDAR_VIEW_TYPE_GRID_WEEK,
21
+ CALENDAR_VIEW_TYPE_LIST_WEEK,
22
+ CALENDAR_VIEW_TYPE_MONTH,
23
+ CALENDAR_VIEW_TYPE_YEAR,
24
+ DISPLAY_OPTION_2_PER_ROW,
25
+ DISPLAY_OPTION_CHOICES,
26
+ DISPLAY_OPTION_CLASSES,
27
+ DISPLAY_OPTION_NONE,
28
+ )
29
+ from advanced_report_builder.signals import model_report_save
30
+
31
+
32
+ class Target(TimeStampedModel):
33
+ class TargetType(models.IntegerChoices):
34
+ COUNT = 1, 'Count'
35
+ MONEY = 2, 'Money'
36
+ PERCENTAGE = 3, 'Percentage'
37
+
38
+ class PeriodType(models.IntegerChoices):
39
+ DAILY = 1, 'Daily'
40
+ WEEKLY = 2, 'Weekly'
41
+ MONTHLY = 3, 'Monthly'
42
+ QUARTER = 4, 'Quarterly'
43
+ YEARLY = 5, 'Yearly'
44
+
45
+ slug = models.SlugField(unique=True)
46
+ name = models.CharField(max_length=64)
47
+ target_type = models.PositiveSmallIntegerField(choices=TargetType.choices)
48
+ period_type = models.PositiveSmallIntegerField(choices=PeriodType.choices, default=PeriodType.MONTHLY)
49
+ default_colour = ColourField(null=True, blank=True, help_text='The colour when it gets displayed on a report')
50
+ default_value = models.IntegerField(blank=True, null=True)
51
+ default_percentage = models.FloatField(blank=True, null=True)
52
+ overridden = models.BooleanField(default=False)
53
+ override_data = models.JSONField(null=True, blank=True)
54
+
55
+ def get_value(self):
56
+ if self.target_type == self.TargetType.PERCENTAGE:
57
+ return self.default_percentage
58
+ return self.default_value
59
+
60
+ def __str__(self):
61
+ return self.name
62
+
63
+ def get_override_data(self):
64
+ override_data = self.override_data if self.override_data else {}
65
+
66
+ ordered_value_dict = {}
67
+
68
+ for year, data in override_data.items():
69
+ if not ordered_value_dict.get(year):
70
+ ordered_value_dict[year] = {}
71
+ for month in MONTHS.values():
72
+ if data.get(str(month)):
73
+ ordered_value_dict[year][month] = data[month]
74
+ else:
75
+ ordered_value_dict[year][month] = self.default_value
76
+
77
+ return ordered_value_dict
78
+
79
+ def add_year(self, year):
80
+ override_data = self.override_data if self.override_data else {}
81
+ if not override_data.get(str(year)):
82
+ override_data[str(year)] = {}
83
+ temp = {}
84
+ # Create a temp dict that has the keys as integers.
85
+ for key, value in override_data.items():
86
+ temp[int(key)] = value
87
+ sorted_dict = {}
88
+ for key in sorted(temp):
89
+ sorted_dict[str(key)] = temp[key]
90
+ if sorted_dict:
91
+ self.override_data = sorted_dict
92
+ self.save()
93
+
94
+ def get_colour_from_percentage(self, percentage):
95
+ """
96
+ Returns a colour based on percentage thresholds.
97
+ Falls back to default_colour if no rule matches.
98
+ """
99
+
100
+ if percentage is None:
101
+ return self.default_colour
102
+
103
+ rule = (
104
+ self.targetcolour_set.filter(percentage__gte=percentage)
105
+ .exclude(colour__isnull=True)
106
+ .order_by('percentage')
107
+ .first()
108
+ )
109
+
110
+ if rule and rule.colour:
111
+ return rule.colour
112
+
113
+ return self.default_colour
114
+
115
+ def save(self, *args, **kwargs):
116
+ """
117
+ Overrides the save so that a new slug is generated
118
+ :param args:
119
+ :param kwargs:
120
+ """
121
+ self.make_new_slug()
122
+ super().save(*args, **kwargs)
123
+
124
+
125
+ class TargetColour(TimeStampedModel):
126
+ target = models.ForeignKey('Target', on_delete=models.CASCADE)
127
+ percentage = models.FloatField(blank=True, null=True, help_text='Less than or equal.')
128
+ colour = ColourField(null=True, blank=True)
129
+
130
+ def __str__(self):
131
+ if self.percentage is None:
132
+ return 'No percentage'
133
+ return f'≤ {self.percentage}%'
134
+
135
+
136
+ class ReportTag(TimeStampedModel):
137
+ name = models.CharField(max_length=128, unique=True)
138
+ slug = models.SlugField(unique=True)
139
+ order = models.PositiveSmallIntegerField()
140
+
141
+ class Meta:
142
+ ordering = ('order',)
143
+
144
+ def __str__(self):
145
+ return self.name
146
+
147
+ def save(self, *args, **kwargs):
148
+ self.make_new_slug(allow_dashes=False, on_edit=True)
149
+ self.set_order_field()
150
+ return super().save(*args, **kwargs)
151
+
152
+
153
+ class ReportType(TimeStampedModel):
154
+ name = models.CharField(max_length=200)
155
+ slug = models.SlugField(unique=True)
156
+ content_type = models.ForeignKey(ContentType, null=False, blank=False, on_delete=models.PROTECT)
157
+ report_builder_class_name = models.CharField(max_length=200)
158
+
159
+ def __str__(self):
160
+ return self.name
161
+
162
+ class Meta:
163
+ ordering = ['name']
164
+
165
+ def save(self, *args, **kwargs):
166
+ self.make_new_slug(allow_dashes=False, on_edit=True)
167
+ return super().save(*args, **kwargs)
168
+
169
+
170
+ class Report(TimeStampedModel):
171
+ report_type_label = 'N/A'
172
+ report_type_icon = '<i class="far fa-file"></i>'
173
+
174
+ def get_child_model_class(self):
175
+ try:
176
+ if '.' in self.instance_type:
177
+ model = apps.get_model(*self.instance_type.split('.'))
178
+ else:
179
+ model = apps.get_model('advanced_report_builder', self.instance_type)
180
+ except LookupError:
181
+ return None
182
+
183
+ return model()
184
+
185
+ def get_output_type_name(self):
186
+ child_model_class = self.get_child_model_class()
187
+ if child_model_class is None:
188
+ return self.report_type_label
189
+ else:
190
+ return child_model_class.report_type_label
191
+
192
+ def get_output_type_icon(self):
193
+ child_model_class = self.get_child_model_class()
194
+ if child_model_class is None:
195
+ return self.report_type_icon
196
+ else:
197
+ return child_model_class.report_type_icon
198
+
199
+ name = models.CharField(max_length=200)
200
+ slug = models.SlugField(unique=True)
201
+ slug_alias = models.SlugField(blank=True, null=True) # used if the slug changes
202
+ report_type = models.ForeignKey(ReportType, null=True, blank=False, on_delete=models.PROTECT)
203
+ instance_type = models.CharField(null=True, max_length=255)
204
+ template_style = models.CharField(blank=True, null=True, max_length=255)
205
+ report_tags = models.ManyToManyField(ReportTag, blank=True)
206
+ notes = models.TextField(null=True, blank=True)
207
+ version = models.PositiveSmallIntegerField(default=0)
208
+ user_created = models.ForeignKey(
209
+ settings.AUTH_USER_MODEL,
210
+ on_delete=models.SET_NULL,
211
+ null=True,
212
+ blank=True,
213
+ related_name='report_user_created_set',
214
+ )
215
+ user_updated = models.ForeignKey(
216
+ settings.AUTH_USER_MODEL,
217
+ on_delete=models.SET_NULL,
218
+ null=True,
219
+ blank=True,
220
+ related_name='report_user_updated_set',
221
+ )
222
+
223
+ def __str__(self):
224
+ return self.name
225
+
226
+ class Meta:
227
+ ordering = ['name']
228
+
229
+ def get_report(self):
230
+ return getattr(self, self.instance_type)
231
+
232
+ def get_title(self):
233
+ return self.name
234
+
235
+ def save(self, *args, **kwargs):
236
+ current_user = getattr(self, '_current_user', None)
237
+ if current_user is not None and current_user.is_authenticated:
238
+ self.user_updated = current_user
239
+ if self.user_created is None:
240
+ self.user_created = current_user
241
+ is_new = self.pk is None
242
+ if self.version is not None:
243
+ self.version += 1
244
+ slug_alias = self.slug
245
+ self.make_new_slug(obj=Report, allow_dashes=False, on_edit=True)
246
+ if slug_alias != self.slug:
247
+ self.slug_alias = slug_alias
248
+ if self.instance_type is None:
249
+ instance_type_data = self._meta.label_lower.split('.')
250
+ if instance_type_data[0] == 'advanced_report_builder':
251
+ self.instance_type = instance_type_data[1]
252
+ else:
253
+ self.instance_type = self._meta.label_lower
254
+ result = super().save(*args, **kwargs)
255
+ model_report_save.send(sender=self.__class__, instance=self, created=is_new, user=current_user)
256
+ return result
257
+
258
+ def get_base_model(self):
259
+ if self.report_type is None:
260
+ return None
261
+ return self.report_type.content_type.model_class()
262
+
263
+ def show_dashboard_query(self):
264
+ return True
265
+
266
+ def show_options(self):
267
+ return True
268
+
269
+ def dashboard_fields(self, form, dashboard_report, layout):
270
+ pass
271
+
272
+ def save_extra_dashboard_fields(self, form, dashboard_report):
273
+ pass
274
+
275
+ class Datatable(DatatableModel):
276
+ class OutputTypeBase(DatatableColumn):
277
+ def setup_results(self, request, all_results):
278
+ if 'type_labels' not in all_results or 'type_icons' not in all_results:
279
+ instance_types = Report.objects.values_list('instance_type', flat=True).distinct()
280
+
281
+ type_labels = {}
282
+ type_icons = {}
283
+
284
+ for instance_type in instance_types:
285
+ report = Report(instance_type=instance_type)
286
+ type_labels[instance_type] = report.get_output_type_name()
287
+ type_icons[instance_type] = report.get_output_type_icon()
288
+
289
+ all_results['type_labels'] = type_labels
290
+ all_results['type_icons'] = type_icons
291
+
292
+ class OutputType(OutputTypeBase):
293
+ def col_setup(self):
294
+ self.field = ['instance_type', 'customreport__output_type']
295
+
296
+ # noinspection PyMethodMayBeStatic
297
+ def row_result(self, data, _page_data):
298
+ instance_type = data[self.model_path + 'instance_type']
299
+ if instance_type == 'customreport':
300
+ output_type = data[self.model_path + 'customreport__output_type']
301
+ if output_type:
302
+ return output_type
303
+ return _page_data['type_labels'].get(instance_type, '')
304
+
305
+ class OutputTypeIcon(OutputTypeBase):
306
+ def __init__(self, **kwargs):
307
+ kwargs['title'] = ''
308
+ kwargs['no_col_search'] = True
309
+ kwargs['column_defs'] = {'orderable': False}
310
+ super().__init__(**kwargs)
311
+
312
+ def col_setup(self):
313
+ self.field = ['instance_type']
314
+
315
+ # noinspection PyMethodMayBeStatic
316
+ def row_result(self, data, _page_data):
317
+ instance_type = data[self.model_path + 'instance_type']
318
+ return _page_data['type_icons'].get(instance_type, '')
319
+
320
+ report_tags_badge = ManyToManyColumn(
321
+ field='report_tags__name',
322
+ html='<span class="badge badge-primary"> %1% </span>',
323
+ title='Tags',
324
+ )
325
+
326
+
327
+ class ReportOption(TimeStampedModel):
328
+ report = models.ForeignKey(Report, on_delete=models.CASCADE)
329
+ slug = models.SlugField()
330
+ name = models.CharField(max_length=256)
331
+ field = models.CharField(max_length=200)
332
+ content_type = models.ForeignKey(ContentType, null=False, blank=False, on_delete=models.PROTECT)
333
+ report_builder_class_name = models.CharField(max_length=200)
334
+ order = models.PositiveSmallIntegerField()
335
+
336
+ class Meta:
337
+ ordering = ['order']
338
+
339
+ def __str__(self):
340
+ return self.name
341
+
342
+ def save(self, *args, **kwargs):
343
+ self.set_order_field(extra_filters={'report': self.report})
344
+ self.make_new_slug(allow_dashes=False, extra_filters={'report': self.report})
345
+ return super().save(*args, **kwargs)
346
+
347
+
348
+ class ReportQuery(TimeStampedModel):
349
+ report = models.ForeignKey(Report, on_delete=models.CASCADE)
350
+ name = models.CharField(max_length=256, default='Standard')
351
+ query = models.JSONField(null=True, blank=True)
352
+ extra_query = models.JSONField(null=True, blank=True) # used for single value Numerator
353
+ target = models.ForeignKey(Target, blank=True, null=True, on_delete=models.SET_NULL)
354
+ order = models.PositiveSmallIntegerField()
355
+
356
+ def save(self, *args, **kwargs):
357
+ self.set_order_field(extra_filters={'report': self.report})
358
+ result = super().save(*args, **kwargs)
359
+ self.report._current_user = getattr(self, '_current_user', None) # this is to update the users
360
+ self.report.save()
361
+ return result
362
+
363
+ class Meta:
364
+ ordering = ['order']
365
+ verbose_name_plural = 'Report queries'
366
+
367
+ def __str__(self):
368
+ return self.name
369
+
370
+
371
+ class ReportQueryOrder(TimeStampedModel):
372
+ report_query = models.ForeignKey(ReportQuery, on_delete=models.CASCADE)
373
+ order_by_field = models.CharField(max_length=200, blank=True, null=True)
374
+ order_by_ascending = models.BooleanField(default=True)
375
+ order = models.PositiveSmallIntegerField()
376
+
377
+ class Meta:
378
+ ordering = ['order']
379
+
380
+ def save(self, *args, **kwargs):
381
+ self.set_order_field(extra_filters={'report_query': self.report_query})
382
+ return super().save(*args, **kwargs)
383
+
384
+
385
+ class TableReport(Report):
386
+ report_type_label = 'Table'
387
+ report_type_icon = '<i class="fas fa-table"></i>'
388
+
389
+ table_fields = models.JSONField(null=True, blank=True)
390
+ has_clickable_rows = models.BooleanField(default=False)
391
+ link_field = models.CharField(max_length=200, blank=True, null=True)
392
+ pivot_fields = models.JSONField(null=True, blank=True)
393
+ order_by_field = models.CharField(max_length=200, blank=True, null=True)
394
+ order_by_ascending = models.BooleanField(default=True)
395
+ page_length = models.PositiveSmallIntegerField(
396
+ choices=(
397
+ (10, '10'),
398
+ (25, '25'),
399
+ (50, '50'),
400
+ (100, '100'),
401
+ (150, '150'),
402
+ (200, '200'),
403
+ ),
404
+ default=100,
405
+ )
406
+
407
+
408
+ class SingleValueReport(Report):
409
+ report_type_label = 'Single Value'
410
+ report_type_icon = '<i class="fas fa-box-open"></i>'
411
+
412
+ class SingleValueType(models.IntegerChoices):
413
+ COUNT = 1, 'Count'
414
+ SUM = 2, 'Sum'
415
+ COUNT_AND_SUM = 3, 'Count & Sum'
416
+ PERCENT = 4, 'Percent'
417
+ PERCENT_FROM_COUNT = 5, 'Percent from Count'
418
+ AVERAGE_SUM_FROM_COUNT = 6, 'Average Sum from Count'
419
+ AVERAGE_SUM_OVER_TIME = 7, 'Average Sum over Time'
420
+ AVERAGE_SUM_OVER_TIME_EXCLUDING_WEEKENDS = 8, 'Average Sum over Time (Excluding Weekends)'
421
+
422
+ @classmethod
423
+ def is_percentage(cls, value):
424
+ return value in {
425
+ cls.PERCENT,
426
+ cls.PERCENT_FROM_COUNT,
427
+ }
428
+
429
+ tile_colour = ColourField(blank=True, null=True)
430
+ font_colour = ColourField(blank=True, null=True)
431
+ field = models.CharField(max_length=200, blank=True, null=True) # denominator
432
+ numerator = models.CharField(max_length=200, blank=True, null=True)
433
+ single_value_type = models.PositiveSmallIntegerField(choices=SingleValueType.choices, default=SingleValueType.COUNT)
434
+ prefix = models.CharField(max_length=64, blank=True, null=True)
435
+ decimal_places = models.IntegerField(default=0)
436
+
437
+ show_breakdown = models.BooleanField(default=False)
438
+ breakdown_fields = models.JSONField(null=True, blank=True)
439
+
440
+ average_scale = models.PositiveSmallIntegerField(choices=ANNOTATION_VALUE_CHOICES, blank=True, null=True)
441
+ average_start_period = models.PositiveSmallIntegerField(blank=True, null=True)
442
+ average_end_period = models.PositiveSmallIntegerField(blank=True, null=True)
443
+
444
+ def is_percentage(self):
445
+ return self.SingleValueType.is_percentage(self.single_value_type)
446
+
447
+
448
+ class BarChartReport(Report):
449
+ report_type_label = 'Bar Chart'
450
+ report_type_icon = '<i class="fas fa-chart-bar"></i>'
451
+
452
+ class BarChartOrientation(models.IntegerChoices):
453
+ VERTICAL = 1, 'Vertical'
454
+ HORIZONTAL = 2, 'Horizontal'
455
+
456
+ DATE_FIELD_SINGLE = 1
457
+ DATE_FIELD_RANGE = 2
458
+
459
+ DATE_FIELD_CHOICES = ((DATE_FIELD_SINGLE, 'Single'), (DATE_FIELD_RANGE, 'Range'))
460
+
461
+ axis_scale = models.PositiveSmallIntegerField(choices=ANNOTATION_VALUE_CHOICES)
462
+
463
+ date_field_type = models.PositiveSmallIntegerField(choices=DATE_FIELD_CHOICES, default=DATE_FIELD_SINGLE)
464
+
465
+ date_field = models.CharField(max_length=200)
466
+ end_date_field = models.CharField(max_length=200, blank=True, null=True)
467
+
468
+ axis_value_type = models.PositiveSmallIntegerField(
469
+ choices=ANNOTATIONS_CHOICES,
470
+ default=ANNOTATION_CHOICE_COUNT,
471
+ null=True,
472
+ blank=True,
473
+ )
474
+ fields = models.JSONField(null=True, blank=True)
475
+ x_label = models.CharField(max_length=200, blank=True, null=True)
476
+ y_label = models.CharField(max_length=200, blank=True, null=True)
477
+
478
+ bar_chart_orientation = models.PositiveSmallIntegerField(
479
+ choices=BarChartOrientation.choices, default=BarChartOrientation.VERTICAL
480
+ )
481
+ stacked = models.BooleanField(default=False)
482
+ show_totals = models.BooleanField(default=False)
483
+ show_blank_dates = models.BooleanField(default=True)
484
+
485
+ show_breakdown = models.BooleanField(default=False)
486
+ breakdown_fields = models.JSONField(null=True, blank=True)
487
+
488
+ def is_orientation_vertical(self):
489
+ return self.bar_chart_orientation == self.BarChartOrientation.VERTICAL
490
+
491
+ def get_chart_scale(self):
492
+ return ANNOTATION_CHART_SCALE[self.axis_scale]
493
+
494
+
495
+ class LineChartReport(Report):
496
+ report_type_label = 'Line Chart'
497
+ report_type_icon = '<i class="fas fa-chart-line"></i>'
498
+
499
+ axis_scale = models.PositiveSmallIntegerField(choices=ANNOTATION_VALUE_CHOICES)
500
+ date_field = models.CharField(max_length=200)
501
+ axis_value_type = models.PositiveSmallIntegerField(
502
+ choices=ANNOTATIONS_CHOICES,
503
+ default=ANNOTATION_CHOICE_COUNT,
504
+ null=True,
505
+ blank=True,
506
+ )
507
+ fields = models.JSONField(null=True, blank=True)
508
+ x_label = models.CharField(max_length=200, blank=True, null=True)
509
+ y_label = models.CharField(max_length=200, blank=True, null=True)
510
+ show_totals = models.BooleanField(default=False)
511
+
512
+ has_targets = models.BooleanField(default=False)
513
+ targets = models.ManyToManyField(Target, blank=True)
514
+
515
+ def get_chart_scale(self):
516
+ return ANNOTATION_CHART_SCALE[self.axis_scale]
517
+
518
+
519
+ class PieChartReport(Report):
520
+ report_type_label = 'Pie Chart'
521
+ report_type_icon = '<i class="fas fa-chart-pie"></i>'
522
+
523
+ class PieChartStyle(models.IntegerChoices):
524
+ PIE = 1, 'Pie'
525
+ DOUGHNUT = 2, 'Doughnut'
526
+
527
+ axis_value_type = models.PositiveSmallIntegerField(
528
+ choices=ANNOTATIONS_CHOICES,
529
+ default=ANNOTATION_CHOICE_COUNT,
530
+ null=True,
531
+ blank=True,
532
+ )
533
+ fields = models.JSONField(null=True, blank=True)
534
+ style = models.PositiveSmallIntegerField(choices=PieChartStyle.choices, default=PieChartStyle.PIE)
535
+
536
+ def is_pie_chart(self):
537
+ return self.style == self.PieChartStyle.PIE
538
+
539
+
540
+ class FunnelChartReport(Report):
541
+ report_type_label = 'Funnel'
542
+ report_type_icon = '<i class="fas fa-filter"></i>'
543
+
544
+ axis_value_type = models.PositiveSmallIntegerField(
545
+ choices=ANNOTATIONS_CHOICES,
546
+ default=ANNOTATION_CHOICE_COUNT,
547
+ null=True,
548
+ blank=True,
549
+ )
550
+ fields = models.JSONField(null=True, blank=True)
551
+
552
+
553
+ class KanbanReport(Report):
554
+ report_type_label = 'Kanban Report'
555
+ report_type_icon = '<i class="fas fa-chart-bar fa-flip-vertical"></i>'
556
+
557
+ def show_dashboard_query(self):
558
+ return False # show queries if true
559
+
560
+
561
+ class KanbanReportDescription(TimeStampedModel):
562
+ kanban_report = models.ForeignKey(KanbanReport, on_delete=models.CASCADE)
563
+ name = models.CharField(max_length=200)
564
+ report_type = models.ForeignKey(ReportType, null=True, blank=False, on_delete=models.PROTECT)
565
+ description = models.TextField(blank=True, null=True)
566
+ order = models.PositiveSmallIntegerField()
567
+
568
+ def save(self, *args, **kwargs):
569
+ self.set_order_field(extra_filters={'kanban_report': self.kanban_report})
570
+ result = super().save(*args, **kwargs)
571
+ self.kanban_report._current_user = getattr(self, '_current_user', None) # this is to update the users
572
+ self.kanban_report.save()
573
+ return result
574
+
575
+ def get_base_model(self):
576
+ return self.report_type.content_type.model_class()
577
+
578
+ def __str__(self):
579
+ return self.name
580
+
581
+ class Meta:
582
+ ordering = ('order',)
583
+
584
+
585
+ class KanbanReportLane(TimeStampedModel):
586
+ MULTIPLE_TYPE_NA = 0
587
+ MULTIPLE_TYPE_DAILY = 1
588
+ MULTIPLE_TYPE_DAILY_WITHIN = 2
589
+ MULTIPLE_TYPE_WEEKLY = 3
590
+ MULTIPLE_TYPE_WEEKLY_WITHIN = 4
591
+ MULTIPLE_TYPE_MONTHLY = 5
592
+ MULTIPLE_TYPE_MONTHLY_WITHIN = 6
593
+
594
+ MULTIPLE_TYPE_CHOICES = [
595
+ (MULTIPLE_TYPE_NA, 'N/A'),
596
+ (MULTIPLE_TYPE_DAILY, 'Daily (single date)'),
597
+ (MULTIPLE_TYPE_DAILY_WITHIN, 'Daily (within two date)'),
598
+ (MULTIPLE_TYPE_WEEKLY, 'Weekly (single date)'),
599
+ (MULTIPLE_TYPE_WEEKLY_WITHIN, 'Weekly (within two date)'),
600
+ (MULTIPLE_TYPE_MONTHLY, 'Monthly (single date)'),
601
+ (MULTIPLE_TYPE_MONTHLY_WITHIN, 'Monthly (within two date)'),
602
+ ]
603
+
604
+ kanban_report = models.ForeignKey(KanbanReport, on_delete=models.CASCADE)
605
+ name = models.CharField(max_length=200)
606
+ order = models.PositiveSmallIntegerField()
607
+ report_type = models.ForeignKey(ReportType, null=True, blank=False, on_delete=models.PROTECT)
608
+ heading_field = models.CharField(max_length=200, blank=True, null=True)
609
+ link_field = models.CharField(max_length=200, blank=True, null=True)
610
+ order_by_field = models.CharField(max_length=200, blank=True, null=True)
611
+ order_by_ascending = models.BooleanField(default=True)
612
+ kanban_report_description = models.ForeignKey(
613
+ KanbanReportDescription, null=True, blank=False, on_delete=models.CASCADE
614
+ )
615
+
616
+ multiple_type = models.PositiveIntegerField(choices=MULTIPLE_TYPE_CHOICES, default=MULTIPLE_TYPE_NA)
617
+ multiple_type_label = models.CharField(max_length=200, blank=True, null=True)
618
+ multiple_type_date_field = models.CharField(max_length=200, blank=True, null=True)
619
+ multiple_type_end_date_field = models.CharField(max_length=200, blank=True, null=True)
620
+
621
+ # this could be choice field from RANGE_TYPE_CHOICES however if one adds a new one it creates a new migration!
622
+ multiple_start_period = models.PositiveSmallIntegerField(blank=True, null=True)
623
+ multiple_end_period = models.PositiveSmallIntegerField(blank=True, null=True)
624
+ background_colour_field = models.CharField(max_length=200, blank=True, null=True)
625
+ heading_colour_field = models.CharField(max_length=200, blank=True, null=True)
626
+
627
+ query_data = models.JSONField(null=True, blank=True)
628
+
629
+ def save(self, *args, **kwargs):
630
+ self.set_order_field(extra_filters={'kanban_report': self.kanban_report})
631
+ result = super().save(*args, **kwargs)
632
+ self.kanban_report._current_user = getattr(self, '_current_user', None) # this is to update the users
633
+ self.kanban_report.save()
634
+ return result
635
+
636
+ def get_base_model(self):
637
+ return self.report_type.content_type.model_class()
638
+
639
+ class Meta:
640
+ ordering = ('order',)
641
+
642
+
643
+ class MultiValueReport(Report):
644
+ report_type_label = 'Multi Values'
645
+ report_type_icon = '<i class="fas fa-grip-horizontal"></i>'
646
+
647
+ rows = models.PositiveSmallIntegerField()
648
+ columns = models.PositiveSmallIntegerField()
649
+ default_multi_cell_style = models.ForeignKey('MultiCellStyle', on_delete=models.PROTECT, null=True, blank=True)
650
+
651
+
652
+ class MultiCellStyle(TimeStampedModel):
653
+ class AlignType(models.IntegerChoices):
654
+ LEFT = 0, 'Left'
655
+ CENTRE = 1, 'Centre'
656
+ RIGHT = 2, 'Right'
657
+
658
+ multi_value_report = models.ForeignKey(MultiValueReport, on_delete=models.CASCADE)
659
+ name = models.CharField(max_length=200)
660
+ align_type = models.IntegerField(choices=AlignType.choices, default=AlignType.LEFT)
661
+ bold = models.BooleanField(default=False)
662
+ italic = models.BooleanField(default=False)
663
+ font_size = models.PositiveSmallIntegerField(null=True, blank=True)
664
+ font_colour = ColourField(null=True, blank=True)
665
+ background_colour = ColourField(null=True, blank=True)
666
+
667
+ def __str__(self):
668
+ return self.name
669
+
670
+ def get_td_class(self):
671
+ results = []
672
+ if self.align_type == self.AlignType.CENTRE:
673
+ results.append('text-center')
674
+ elif self.align_type == self.AlignType.RIGHT:
675
+ results.append('text-right')
676
+ if self.bold:
677
+ results.append('font-weight-bold')
678
+ if self.italic:
679
+ results.append('font-italic')
680
+ return ' '.join(results)
681
+
682
+ def get_td_style(self):
683
+ results = []
684
+ if self.font_size:
685
+ results.append(f'font-size: {self.font_size}px;')
686
+ if self.font_colour:
687
+ results.append(f'color: #{self.font_colour};')
688
+ if self.background_colour:
689
+ results.append(f'background-color: #{self.background_colour};')
690
+ return ';'.join(results)
691
+
692
+
693
+ class MultiValueHeldQuery(TimeStampedModel):
694
+ multi_value_report = models.ForeignKey(MultiValueReport, on_delete=models.CASCADE)
695
+ name = models.CharField(max_length=200)
696
+ report_type = models.ForeignKey(ReportType, null=True, blank=True, on_delete=models.PROTECT)
697
+ query = models.JSONField(null=True, blank=True)
698
+
699
+ def __str__(self):
700
+ return self.name
701
+
702
+
703
+ class MultiValueReportColumn(TimeStampedModel):
704
+ class WidthType(models.IntegerChoices):
705
+ PERCENTAGE = 0, '%'
706
+ PIXELS = 1, 'Pixels'
707
+
708
+ multi_value_report = models.ForeignKey(MultiValueReport, on_delete=models.CASCADE)
709
+ column = models.PositiveSmallIntegerField()
710
+ width_type = models.PositiveSmallIntegerField(choices=WidthType.choices, default=WidthType.PERCENTAGE)
711
+ width = models.PositiveSmallIntegerField()
712
+
713
+ def get_td_style(self):
714
+ if self.width_type == self.WidthType.PERCENTAGE:
715
+ return f'width: {self.width}%'
716
+ elif self.width_type == self.WidthType.PIXELS:
717
+ return f'width: {self.width}px'
718
+ return ''
719
+
720
+
721
+ class MultiValueReportCell(TimeStampedModel):
722
+ class MultiValueType(models.IntegerChoices):
723
+ STATIC_TEXT = 0, 'Static Text'
724
+ COUNT = 1, 'Count'
725
+ SUM = 2, 'Sum'
726
+ PERCENT = 4, 'Percent'
727
+ PERCENT_FROM_COUNT = 5, 'Percent from Count'
728
+ AVERAGE_SUM_FROM_COUNT = 6, 'Average Sum from Count'
729
+ AVERAGE_SUM_OVER_TIME = 7, 'Average Sum over Time'
730
+ AVERAGE_SUM_OVER_TIME_EXCLUDING_WEEKENDS = 8, 'Average Sum over Time (Excluding Weekends)'
731
+ EQUATION = 9, 'Equation'
732
+
733
+ @classmethod
734
+ def is_percentage(cls, value):
735
+ return value in {
736
+ cls.PERCENT,
737
+ cls.PERCENT_FROM_COUNT,
738
+ }
739
+
740
+ multi_value_report = models.ForeignKey(MultiValueReport, on_delete=models.CASCADE)
741
+ row = models.PositiveSmallIntegerField()
742
+ column = models.PositiveSmallIntegerField()
743
+ col_span = models.PositiveSmallIntegerField(default=1)
744
+ row_span = models.PositiveSmallIntegerField(default=1)
745
+ multi_value_type = models.IntegerField(choices=MultiValueType.choices, default=MultiValueType.STATIC_TEXT)
746
+ text = models.TextField(blank=True, null=True)
747
+ multi_cell_style = models.ForeignKey('MultiCellStyle', on_delete=models.SET_NULL, null=True, blank=True)
748
+ report_type = models.ForeignKey(ReportType, null=True, blank=True, on_delete=models.PROTECT)
749
+
750
+ field = models.CharField(max_length=200, blank=True, null=True) # denominator
751
+ numerator = models.CharField(max_length=200, blank=True, null=True)
752
+ prefix = models.CharField(max_length=64, blank=True, null=True)
753
+ decimal_places = models.IntegerField(default=0)
754
+
755
+ show_breakdown = models.BooleanField(default=False)
756
+ breakdown_fields = models.JSONField(null=True, blank=True)
757
+
758
+ average_scale = models.PositiveSmallIntegerField(choices=ANNOTATION_VALUE_CHOICES, blank=True, null=True)
759
+ average_start_period = models.PositiveSmallIntegerField(blank=True, null=True)
760
+ average_end_period = models.PositiveSmallIntegerField(blank=True, null=True)
761
+ label = models.CharField(max_length=256, blank=True, null=True)
762
+
763
+ multi_value_held_query = models.ForeignKey('MultiValueHeldQuery', on_delete=models.SET_NULL, null=True, blank=True)
764
+
765
+ query_data = models.JSONField(null=True, blank=True)
766
+ extra_query_data = models.JSONField(null=True, blank=True) # used for single value Numerator
767
+
768
+ class Meta:
769
+ constraints = [
770
+ models.UniqueConstraint(
771
+ fields=['multi_value_report', 'row', 'column'], name='multi_value_report_cell_unique'
772
+ ),
773
+ ]
774
+
775
+ def get_base_model(self):
776
+ if self.report_type is None:
777
+ return None
778
+ return self.report_type.content_type.model_class()
779
+
780
+
781
+ class CalendarReport(Report):
782
+ report_type_label = 'Calendar'
783
+ report_type_icon = '<i class="fas fa-calendar"></i>'
784
+
785
+ VIEW_TYPE_CODES = {
786
+ CALENDAR_VIEW_TYPE_MONTH: 'dayGridMonth',
787
+ CALENDAR_VIEW_TYPE_GRID_WEEK: 'timeGridWeek',
788
+ CALENDAR_VIEW_TYPE_LIST_WEEK: 'listWeek',
789
+ CALENDAR_VIEW_TYPE_DAY: 'timeGridDay',
790
+ CALENDAR_VIEW_TYPE_YEAR: 'year',
791
+ }
792
+
793
+ height = models.PositiveSmallIntegerField(default=600)
794
+ view_type = models.PositiveSmallIntegerField(
795
+ choices=CALENDAR_VIEW_TYPE_CHOICES,
796
+ default=CALENDAR_VIEW_TYPE_MONTH,
797
+ )
798
+
799
+ def get_view_type_for_calendar(self, view_type=None):
800
+ if view_type is None:
801
+ view_type = self.view_type
802
+ return self.VIEW_TYPE_CODES.get(view_type)
803
+
804
+ def show_dashboard_query(self):
805
+ return False
806
+
807
+ def show_options(self):
808
+ return False
809
+
810
+ def dashboard_fields(self, form, dashboard_report, layout):
811
+ choices = [(0, f'Default ({self.view_type})'), *CALENDAR_VIEW_TYPE_CHOICES]
812
+ calendar_view_type = dashboard_report.options.get('calendar_view_type') if dashboard_report.options else None
813
+ form.fields['calendar_view_type'] = ChoiceField(
814
+ choices=choices, required=False, widget=Select2(), initial=calendar_view_type
815
+ )
816
+ layout.append('calendar_view_type')
817
+
818
+ def save_extra_dashboard_fields(self, form, dashboard_report):
819
+ options = {'calendar_view_type': form.cleaned_data['calendar_view_type']}
820
+ dashboard_report.options = options
821
+
822
+
823
+ class CalendarReportDescription(TimeStampedModel):
824
+ calendar_report = models.ForeignKey(CalendarReport, on_delete=models.CASCADE)
825
+ name = models.CharField(max_length=200)
826
+ report_type = models.ForeignKey(ReportType, null=True, blank=False, on_delete=models.PROTECT)
827
+ description = models.TextField(blank=True, null=True)
828
+ order = models.PositiveSmallIntegerField()
829
+
830
+ def save(self, *args, **kwargs):
831
+ self.set_order_field(extra_filters={'calendar_report': self.calendar_report})
832
+ return super().save(*args, **kwargs)
833
+
834
+ def get_base_model(self):
835
+ return self.report_type.content_type.model_class()
836
+
837
+ def __str__(self):
838
+ return self.name
839
+
840
+ class Meta:
841
+ ordering = ('order',)
842
+
843
+
844
+ class CalendarReportDataSet(TimeStampedModel):
845
+ DISPLAY_TYPE_NAME_AND_DESCRIPTION = 1
846
+ DISPLAY_TYPE_DESCRIPTION_ONLY = 2
847
+ DISPLAY_TYPE_HEADING_ONLY = 3
848
+
849
+ DISPLAY_TYPE_CHOICES = (
850
+ (DISPLAY_TYPE_NAME_AND_DESCRIPTION, 'Name and Description'),
851
+ (DISPLAY_TYPE_DESCRIPTION_ONLY, 'Description Only'),
852
+ (DISPLAY_TYPE_HEADING_ONLY, 'Heading Only'),
853
+ )
854
+
855
+ END_DATE_TYPE_FIELD = 1
856
+ END_DATE_TYPE_DURATION_FIELD = 2
857
+ END_DATE_TYPE_DURATION_FIXED = 3
858
+
859
+ END_DATE_TYPE_CHOICES = (
860
+ (END_DATE_TYPE_FIELD, 'Field'),
861
+ (END_DATE_TYPE_DURATION_FIELD, 'Duration Field'),
862
+ (END_DATE_TYPE_DURATION_FIXED, 'Duration Fixed'),
863
+ )
864
+
865
+ calendar_report = models.ForeignKey(CalendarReport, on_delete=models.CASCADE)
866
+ order = models.PositiveSmallIntegerField()
867
+ report_type = models.ForeignKey(ReportType, null=True, blank=False, on_delete=models.PROTECT)
868
+ heading_field = models.CharField(max_length=200, blank=True, null=True)
869
+ name = models.CharField(max_length=200)
870
+ display_type = models.PositiveSmallIntegerField(
871
+ choices=DISPLAY_TYPE_CHOICES,
872
+ default=DISPLAY_TYPE_NAME_AND_DESCRIPTION,
873
+ )
874
+ start_date_field = models.CharField(max_length=200, blank=True, null=True)
875
+ end_date_type = models.PositiveSmallIntegerField(
876
+ choices=END_DATE_TYPE_CHOICES,
877
+ default=END_DATE_TYPE_FIELD,
878
+ )
879
+ end_date_field = models.CharField(max_length=200, blank=True, null=True)
880
+ end_duration_field = models.CharField(max_length=200, blank=True, null=True)
881
+ end_duration = models.PositiveSmallIntegerField(blank=True, null=True)
882
+ background_colour_field = models.CharField(max_length=200, blank=True, null=True)
883
+ link_field = models.CharField(max_length=200, blank=True, null=True)
884
+ calendar_report_description = models.ForeignKey(
885
+ CalendarReportDescription, null=True, blank=False, on_delete=models.CASCADE
886
+ )
887
+ query_data = models.JSONField(null=True, blank=True)
888
+
889
+ def save(self, *args, **kwargs):
890
+ self.set_order_field(extra_filters={'calendar_report': self.calendar_report})
891
+ return super().save(*args, **kwargs)
892
+
893
+ def get_base_model(self):
894
+ return self.report_type.content_type.model_class()
895
+
896
+ class Meta:
897
+ ordering = ('order',)
898
+
899
+
900
+ class CustomReport(Report):
901
+ report_type_label = 'Custom'
902
+ report_type_icon = '<i class="fas fa-file"></i>'
903
+
904
+ output_type = models.CharField(max_length=200, blank=True, null=True)
905
+ view_name = models.CharField(max_length=200)
906
+ settings = models.JSONField(null=True, blank=True)
907
+
908
+
909
+ class Dashboard(TimeStampedModel):
910
+ slug = models.SlugField(unique=True)
911
+ slug_alias = models.SlugField(blank=True, null=True) # used if the slug changes
912
+ name = models.CharField(max_length=200)
913
+ display_option = models.PositiveIntegerField(choices=DISPLAY_OPTION_CHOICES[1:], default=DISPLAY_OPTION_2_PER_ROW)
914
+
915
+ def __str__(self):
916
+ return self.name
917
+
918
+ def save(self, *args, **kwargs):
919
+ slug_alias = self.slug
920
+ self.make_new_slug(allow_dashes=False, on_edit=True)
921
+ if slug_alias != self.slug:
922
+ self.slug_alias = slug_alias
923
+ return super().save(*args, **kwargs)
924
+
925
+
926
+ class DashboardReport(TimeStampedModel):
927
+ dashboard = models.ForeignKey(Dashboard, on_delete=models.CASCADE)
928
+ order = models.PositiveSmallIntegerField()
929
+ report = models.ForeignKey(Report, on_delete=models.CASCADE)
930
+ top = models.BooleanField(default=False)
931
+ name_override = models.CharField(max_length=200, blank=True, null=True)
932
+ display_option = models.PositiveIntegerField(choices=DISPLAY_OPTION_CHOICES, default=DISPLAY_OPTION_NONE)
933
+ show_versions = models.BooleanField(default=True)
934
+ report_query = models.ForeignKey(ReportQuery, blank=True, null=True, on_delete=models.CASCADE)
935
+ show_options = models.BooleanField(default=True)
936
+ options = models.JSONField(null=True, blank=True)
937
+
938
+ def get_class(self, extra_class_name):
939
+ if self.display_option != DISPLAY_OPTION_NONE:
940
+ class_names = DISPLAY_OPTION_CLASSES.get(self.display_option)
941
+ else:
942
+ class_names = DISPLAY_OPTION_CLASSES.get(self.dashboard.display_option)
943
+
944
+ if extra_class_name:
945
+ class_names += f' {extra_class_name}'
946
+
947
+ return class_names
948
+
949
+ def save(self, *args, **kwargs):
950
+ self.set_order_field(extra_filters={'dashboard': self.dashboard, 'top': self.top})
951
+ return super().save(*args, **kwargs)
952
+
953
+ class Meta:
954
+ ordering = ['order']