chellow 1727274025.0.0__py3-none-any.whl → 1728660080.0.0__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.
Potentially problematic release.
This version of chellow might be problematic. Click here for more details.
- chellow/__init__.py +2 -0
- chellow/models.py +8 -0
- chellow/reports/report_247.py +95 -41
- chellow/rrun.py +77 -0
- chellow/templates/e/scenario_docs.html +2 -0
- chellow/templates/report_run_monthly_duration_org.html +73 -0
- chellow/templates/report_runs.html +31 -0
- chellow/templates/user.html +23 -52
- chellow/views.py +17 -1
- {chellow-1727274025.0.0.dist-info → chellow-1728660080.0.0.dist-info}/METADATA +1 -1
- {chellow-1727274025.0.0.dist-info → chellow-1728660080.0.0.dist-info}/RECORD +12 -10
- {chellow-1727274025.0.0.dist-info → chellow-1728660080.0.0.dist-info}/WHEEL +0 -0
chellow/__init__.py
CHANGED
|
@@ -25,6 +25,7 @@ import chellow.e.views
|
|
|
25
25
|
import chellow.gas.cv
|
|
26
26
|
import chellow.gas.views
|
|
27
27
|
import chellow.national_grid
|
|
28
|
+
import chellow.rrun
|
|
28
29
|
import chellow.testing
|
|
29
30
|
from chellow.models import (
|
|
30
31
|
Contract,
|
|
@@ -60,6 +61,7 @@ def get_importer_modules():
|
|
|
60
61
|
chellow.e.bmarketidx,
|
|
61
62
|
chellow.national_grid,
|
|
62
63
|
chellow.rate_server,
|
|
64
|
+
chellow.rrun,
|
|
63
65
|
)
|
|
64
66
|
|
|
65
67
|
|
chellow/models.py
CHANGED
|
@@ -6401,6 +6401,14 @@ class ReportRun(Base, PersistentClass):
|
|
|
6401
6401
|
sess.flush()
|
|
6402
6402
|
return report_run
|
|
6403
6403
|
|
|
6404
|
+
@staticmethod
|
|
6405
|
+
def w_insert(name, user_id, title, data):
|
|
6406
|
+
with Session() as wsess:
|
|
6407
|
+
user = User.get_by_id(wsess, user_id)
|
|
6408
|
+
report_run = ReportRun.insert(wsess, name, user, title, data)
|
|
6409
|
+
wsess.commit()
|
|
6410
|
+
return report_run.id
|
|
6411
|
+
|
|
6404
6412
|
@staticmethod
|
|
6405
6413
|
def w_update(report_run_id, state):
|
|
6406
6414
|
with Session() as wsess:
|
chellow/reports/report_247.py
CHANGED
|
@@ -24,6 +24,7 @@ from chellow.models import (
|
|
|
24
24
|
Era,
|
|
25
25
|
MeasurementRequirement,
|
|
26
26
|
RSession,
|
|
27
|
+
ReportRun,
|
|
27
28
|
Scenario,
|
|
28
29
|
Site,
|
|
29
30
|
SiteEra,
|
|
@@ -122,8 +123,10 @@ def _process_site(
|
|
|
122
123
|
now,
|
|
123
124
|
summary_titles,
|
|
124
125
|
title_dict,
|
|
125
|
-
|
|
126
|
+
org_rows,
|
|
126
127
|
site_rows,
|
|
128
|
+
era_rows,
|
|
129
|
+
normal_reads,
|
|
127
130
|
data_source_bill,
|
|
128
131
|
):
|
|
129
132
|
scenario_hh = scenario_props.get("hh_data", {})
|
|
@@ -147,7 +150,6 @@ def _process_site(
|
|
|
147
150
|
|
|
148
151
|
site_category = None
|
|
149
152
|
site_sources = set()
|
|
150
|
-
normal_reads = set()
|
|
151
153
|
site_month_data = defaultdict(int)
|
|
152
154
|
for i, (order, imp_mpan_core, exp_mpan_core, imp_ss, exp_ss) in enumerate(
|
|
153
155
|
sorted(calcs, key=str)
|
|
@@ -155,8 +157,6 @@ def _process_site(
|
|
|
155
157
|
if imp_mpan_core == "displaced":
|
|
156
158
|
month_data = {}
|
|
157
159
|
for sname in (
|
|
158
|
-
"import-grid",
|
|
159
|
-
"export-grid",
|
|
160
160
|
"import-gen",
|
|
161
161
|
"export-gen",
|
|
162
162
|
"import-3rd-party",
|
|
@@ -169,7 +169,11 @@ def _process_site(
|
|
|
169
169
|
for xname in ("kwh", "net-gbp"):
|
|
170
170
|
month_data[f"{sname}-{xname}"] = 0
|
|
171
171
|
month_data["billed-import-kwh"] = 0
|
|
172
|
+
month_data["import-grid-kwh"] = 0
|
|
173
|
+
month_data["export-grid-kwh"] = 0
|
|
172
174
|
for suf in ("net-gbp", "vat-gbp", "gross-gbp"):
|
|
175
|
+
month_data[f"import-grid-{suf}"] = 0
|
|
176
|
+
month_data[f"export-grid-{suf}"] = 0
|
|
173
177
|
month_data[f"billed-import-{suf}"] = 0
|
|
174
178
|
month_data[f"billed-supplier-import-{suf}"] = None
|
|
175
179
|
month_data[f"billed-dc-import-{suf}"] = None
|
|
@@ -240,8 +244,6 @@ def _process_site(
|
|
|
240
244
|
site_sources.add(source_code)
|
|
241
245
|
month_data = {}
|
|
242
246
|
for name in (
|
|
243
|
-
"import-grid",
|
|
244
|
-
"export-grid",
|
|
245
247
|
"import-gen",
|
|
246
248
|
"export-gen",
|
|
247
249
|
"import-3rd-party",
|
|
@@ -255,7 +257,9 @@ def _process_site(
|
|
|
255
257
|
month_data[f"{name}-{sname}"] = 0
|
|
256
258
|
for polarity in ("import", "export"):
|
|
257
259
|
month_data[f"billed-{polarity}-kwh"] = 0
|
|
260
|
+
month_data[f"{polarity}-grid-kwh"] = 0
|
|
258
261
|
for suf in ("net-gbp", "vat-gbp", "gross-gbp"):
|
|
262
|
+
month_data[f"{polarity}-grid-{suf}"] = 0
|
|
259
263
|
month_data[f"billed-{polarity}-{suf}"] = 0
|
|
260
264
|
month_data[f"billed-supplier-{polarity}-{suf}"] = 0
|
|
261
265
|
month_data[f"billed-dc-{polarity}-{suf}"] = 0
|
|
@@ -267,28 +271,32 @@ def _process_site(
|
|
|
267
271
|
kwh = sum(hh["msp-kwh"] for hh in imp_ss.hh_data)
|
|
268
272
|
imp_supplier_bill = imp_ss.supplier_bill
|
|
269
273
|
|
|
270
|
-
|
|
274
|
+
net_gbp = imp_supplier_bill.get("net-gbp", 0)
|
|
275
|
+
vat_gbp = imp_supplier_bill.get("vat-gbp", 0)
|
|
276
|
+
gross_gbp = imp_supplier_bill.get("gross-gbp", 0)
|
|
271
277
|
|
|
272
278
|
if source_code in ("grid", "gen-grid"):
|
|
273
|
-
month_data["import-grid-net-gbp"] +=
|
|
279
|
+
month_data["import-grid-net-gbp"] += net_gbp
|
|
280
|
+
month_data["import-grid-vat-gbp"] += vat_gbp
|
|
281
|
+
month_data["import-grid-gross-gbp"] += gross_gbp
|
|
274
282
|
month_data["import-grid-kwh"] += kwh
|
|
275
|
-
month_data["used-net-gbp"] +=
|
|
283
|
+
month_data["used-net-gbp"] += net_gbp
|
|
276
284
|
month_data["used-kwh"] += kwh
|
|
277
285
|
if source_code == "gen-grid":
|
|
278
286
|
month_data["export-gen-kwh"] += kwh
|
|
279
287
|
elif source_code == "3rd-party":
|
|
280
|
-
month_data["import-3rd-party-net-gbp"] +=
|
|
288
|
+
month_data["import-3rd-party-net-gbp"] += net_gbp
|
|
281
289
|
month_data["import-3rd-party-kwh"] += kwh
|
|
282
|
-
month_data["used-3rd-party-net-gbp"] +=
|
|
290
|
+
month_data["used-3rd-party-net-gbp"] += net_gbp
|
|
283
291
|
month_data["used-3rd-party-kwh"] += kwh
|
|
284
|
-
month_data["used-net-gbp"] +=
|
|
292
|
+
month_data["used-net-gbp"] += net_gbp
|
|
285
293
|
month_data["used-kwh"] += kwh
|
|
286
294
|
elif source_code == "3rd-party-reverse":
|
|
287
|
-
month_data["export-3rd-party-net-gbp"] +=
|
|
295
|
+
month_data["export-3rd-party-net-gbp"] += net_gbp
|
|
288
296
|
month_data["export-3rd-party-kwh"] += kwh
|
|
289
|
-
month_data["used-3rd-party-net-gbp"] -=
|
|
297
|
+
month_data["used-3rd-party-net-gbp"] -= net_gbp
|
|
290
298
|
month_data["used-3rd-party-kwh"] -= kwh
|
|
291
|
-
month_data["used-net-gbp"] -=
|
|
299
|
+
month_data["used-net-gbp"] -= net_gbp
|
|
292
300
|
month_data["used-kwh"] -= kwh
|
|
293
301
|
elif source_code == "gen":
|
|
294
302
|
month_data["import-gen-kwh"] += kwh
|
|
@@ -299,27 +307,31 @@ def _process_site(
|
|
|
299
307
|
kwh = sum(hh["msp-kwh"] for hh in exp_ss.hh_data)
|
|
300
308
|
exp_supplier_bill = exp_ss.supplier_bill
|
|
301
309
|
|
|
302
|
-
|
|
310
|
+
net_gbp = exp_supplier_bill.get("net-gbp", 0)
|
|
311
|
+
vat_gbp = exp_supplier_bill.get("vat-gbp", 0)
|
|
312
|
+
gross_gbp = exp_supplier_bill.get("gross-gbp", 0)
|
|
303
313
|
|
|
304
314
|
if source_code in ("grid", "gen-grid"):
|
|
305
|
-
month_data["export-grid-net-gbp"] +=
|
|
315
|
+
month_data["export-grid-net-gbp"] += net_gbp
|
|
316
|
+
month_data["export-grid-vat-gbp"] += vat_gbp
|
|
317
|
+
month_data["export-grid-gross-gbp"] += gross_gbp
|
|
306
318
|
month_data["export-grid-kwh"] += kwh
|
|
307
319
|
if source_code == "gen-grid":
|
|
308
320
|
month_data["import-gen-kwh"] += kwh
|
|
309
321
|
|
|
310
322
|
elif source_code == "3rd-party":
|
|
311
|
-
month_data["export-3rd-party-net-gbp"] +=
|
|
323
|
+
month_data["export-3rd-party-net-gbp"] += net_gbp
|
|
312
324
|
month_data["export-3rd-party-kwh"] += kwh
|
|
313
|
-
month_data["used-3rd-party-net-gbp"] -=
|
|
325
|
+
month_data["used-3rd-party-net-gbp"] -= net_gbp
|
|
314
326
|
month_data["used-3rd-party-kwh"] -= kwh
|
|
315
|
-
month_data["used-net-gbp"] -=
|
|
327
|
+
month_data["used-net-gbp"] -= net_gbp
|
|
316
328
|
month_data["used-kwh"] -= kwh
|
|
317
329
|
elif source_code == "3rd-party-reverse":
|
|
318
|
-
month_data["import-3rd-party-net-gbp"] +=
|
|
330
|
+
month_data["import-3rd-party-net-gbp"] += net_gbp
|
|
319
331
|
month_data["import-3rd-party-kwh"] += kwh
|
|
320
|
-
month_data["used-3rd-party-net-gbp"] +=
|
|
332
|
+
month_data["used-3rd-party-net-gbp"] += net_gbp
|
|
321
333
|
month_data["used-3rd-party-kwh"] += kwh
|
|
322
|
-
month_data["used-net-gbp"] +=
|
|
334
|
+
month_data["used-net-gbp"] += net_gbp
|
|
323
335
|
month_data["used-kwh"] += kwh
|
|
324
336
|
elif source_code == "gen":
|
|
325
337
|
month_data["export-gen-kwh"] += kwh
|
|
@@ -493,8 +505,6 @@ def _process_site(
|
|
|
493
505
|
if len(bills) > 0:
|
|
494
506
|
month_data = {}
|
|
495
507
|
for name in (
|
|
496
|
-
"import-grid",
|
|
497
|
-
"export-grid",
|
|
498
508
|
"import-gen",
|
|
499
509
|
"export-gen",
|
|
500
510
|
"import-3rd-party",
|
|
@@ -507,7 +517,11 @@ def _process_site(
|
|
|
507
517
|
for sname in ("kwh", "net-gbp"):
|
|
508
518
|
month_data[f"{name}-{sname}"] = 0
|
|
509
519
|
month_data["billed-import-kwh"] = 0
|
|
520
|
+
month_data["import-grid-kwh"] = 0
|
|
521
|
+
month_data["export-grid-kwh"] = 0
|
|
510
522
|
for suf in ("net-gbp", "vat-gbp", "gross-gbp"):
|
|
523
|
+
month_data[f"import-grid-{suf}"] = 0
|
|
524
|
+
month_data[f"export-grid-{suf}"] = 0
|
|
511
525
|
month_data[f"billed-import-{suf}"] = 0
|
|
512
526
|
month_data[f"billed-supplier-import-{suf}"] = 0
|
|
513
527
|
month_data[f"billed-dc-import-{suf}"] = 0
|
|
@@ -610,8 +624,6 @@ def _process_site(
|
|
|
610
624
|
if len(bills) > 0:
|
|
611
625
|
month_data = {}
|
|
612
626
|
for name in (
|
|
613
|
-
"import-grid",
|
|
614
|
-
"export-grid",
|
|
615
627
|
"import-gen",
|
|
616
628
|
"export-gen",
|
|
617
629
|
"import-3rd-party",
|
|
@@ -624,8 +636,12 @@ def _process_site(
|
|
|
624
636
|
for sname in ("kwh", "net-gbp"):
|
|
625
637
|
month_data[f"{name}-{sname}"] = 0
|
|
626
638
|
month_data["billed-import-kwh"] = 0
|
|
639
|
+
month_data["import-grid-kwh"] = 0
|
|
640
|
+
month_data["export-grid-kwh"] = 0
|
|
627
641
|
for suf in ("net-gbp", "vat-gbp", "gross-gbp"):
|
|
628
642
|
month_data[f"billed-import-{suf}"] = 0
|
|
643
|
+
month_data[f"import-grid-{suf}"] = 0
|
|
644
|
+
month_data[f"export-grid-{suf}"] = 0
|
|
629
645
|
month_data[f"billed-supplier-import-{suf}"] = 0
|
|
630
646
|
month_data[f"billed-dc-import-{suf}"] = 0
|
|
631
647
|
month_data[f"billed-mop-import-{suf}"] = 0
|
|
@@ -708,7 +724,7 @@ def _process_site(
|
|
|
708
724
|
] + [site_month_data[k] for k in summary_titles]
|
|
709
725
|
|
|
710
726
|
site_rows.append([make_val(v) for v in site_row])
|
|
711
|
-
return
|
|
727
|
+
return site_month_data
|
|
712
728
|
|
|
713
729
|
|
|
714
730
|
class Object:
|
|
@@ -734,6 +750,7 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
734
750
|
ind_cont = report_context["contract_names"] = {}
|
|
735
751
|
|
|
736
752
|
sess = rf = None
|
|
753
|
+
org_rows = []
|
|
737
754
|
site_rows = []
|
|
738
755
|
era_rows = []
|
|
739
756
|
normal_read_rows = []
|
|
@@ -806,7 +823,8 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
806
823
|
|
|
807
824
|
user = User.get_by_id(sess, user_id)
|
|
808
825
|
|
|
809
|
-
|
|
826
|
+
fname = "_".join(base_name) + ".ods"
|
|
827
|
+
rf = open_file(fname, user, mode="wb")
|
|
810
828
|
|
|
811
829
|
for rate_script in scenario_props.get("rates", []):
|
|
812
830
|
contract_id = rate_script["contract_id"]
|
|
@@ -858,7 +876,21 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
858
876
|
)
|
|
859
877
|
|
|
860
878
|
by_hh = scenario_props.get("by_hh", False)
|
|
879
|
+
org_header_titles = [
|
|
880
|
+
"creation-date",
|
|
881
|
+
"month",
|
|
882
|
+
]
|
|
861
883
|
|
|
884
|
+
site_header_titles = [
|
|
885
|
+
"creation-date",
|
|
886
|
+
"site-id",
|
|
887
|
+
"site-name",
|
|
888
|
+
"associated-site-ids",
|
|
889
|
+
"month",
|
|
890
|
+
"metering-type",
|
|
891
|
+
"sources",
|
|
892
|
+
"generator-types",
|
|
893
|
+
]
|
|
862
894
|
era_header_titles = [
|
|
863
895
|
"creation-date",
|
|
864
896
|
"imp-mpan-core",
|
|
@@ -888,16 +920,6 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
888
920
|
"associated-site-ids",
|
|
889
921
|
"month",
|
|
890
922
|
]
|
|
891
|
-
site_header_titles = [
|
|
892
|
-
"creation-date",
|
|
893
|
-
"site-id",
|
|
894
|
-
"site-name",
|
|
895
|
-
"associated-site-ids",
|
|
896
|
-
"month",
|
|
897
|
-
"metering-type",
|
|
898
|
-
"sources",
|
|
899
|
-
"generator-types",
|
|
900
|
-
]
|
|
901
923
|
summary_titles = [
|
|
902
924
|
"import-grid-kwh",
|
|
903
925
|
"export-grid-kwh",
|
|
@@ -909,7 +931,11 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
909
931
|
"used-kwh",
|
|
910
932
|
"used-3rd-party-kwh",
|
|
911
933
|
"import-grid-net-gbp",
|
|
934
|
+
"import-grid-vat-gbp",
|
|
935
|
+
"import-grid-gross-gbp",
|
|
912
936
|
"export-grid-net-gbp",
|
|
937
|
+
"export-grid-vat-gbp",
|
|
938
|
+
"export-grid-gross-gbp",
|
|
913
939
|
"import-gen-net-gbp",
|
|
914
940
|
"export-gen-net-gbp",
|
|
915
941
|
"import-3rd-party-net-gbp",
|
|
@@ -1003,6 +1029,7 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
1003
1029
|
+ [None]
|
|
1004
1030
|
+ ["exp-supplier-" + t for t in title_dict["exp-supplier"]]
|
|
1005
1031
|
)
|
|
1032
|
+
org_rows.append(org_header_titles + summary_titles)
|
|
1006
1033
|
site_rows.append(site_header_titles + summary_titles)
|
|
1007
1034
|
era_rows.append(era_titles)
|
|
1008
1035
|
|
|
@@ -1016,6 +1043,7 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
1016
1043
|
data_source_bill.finish_date = month_finish
|
|
1017
1044
|
else:
|
|
1018
1045
|
data_source_bill = None
|
|
1046
|
+
org_month_data = defaultdict(int)
|
|
1019
1047
|
for site in sites:
|
|
1020
1048
|
if by_hh:
|
|
1021
1049
|
sf = [
|
|
@@ -1027,7 +1055,7 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
1027
1055
|
|
|
1028
1056
|
for start, finish in sf:
|
|
1029
1057
|
try:
|
|
1030
|
-
|
|
1058
|
+
site_month_data = _process_site(
|
|
1031
1059
|
sess,
|
|
1032
1060
|
report_context,
|
|
1033
1061
|
forecast_from,
|
|
@@ -1039,10 +1067,16 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
1039
1067
|
now,
|
|
1040
1068
|
summary_titles,
|
|
1041
1069
|
title_dict,
|
|
1042
|
-
|
|
1070
|
+
org_rows,
|
|
1043
1071
|
site_rows,
|
|
1072
|
+
era_rows,
|
|
1073
|
+
normal_reads,
|
|
1044
1074
|
data_source_bill,
|
|
1045
1075
|
)
|
|
1076
|
+
for k, v in site_month_data.items():
|
|
1077
|
+
if v is not None:
|
|
1078
|
+
org_month_data[k] += v
|
|
1079
|
+
|
|
1046
1080
|
except BadRequest as e:
|
|
1047
1081
|
raise BadRequest(f"Site Code {site.code}: {e.description}")
|
|
1048
1082
|
|
|
@@ -1053,9 +1087,29 @@ def content(scenario_props, base_name, user_id, compression, now):
|
|
|
1053
1087
|
row = [mpan_core, r.date, r.msn, r.type] + list(r.reads)
|
|
1054
1088
|
normal_read_rows.append(row)
|
|
1055
1089
|
|
|
1090
|
+
org_row = [now, month_start] + [
|
|
1091
|
+
org_month_data[k] for k in summary_titles
|
|
1092
|
+
]
|
|
1093
|
+
org_rows.append([make_val(v) for v in org_row])
|
|
1094
|
+
|
|
1056
1095
|
write_spreadsheet(
|
|
1057
1096
|
rf, compression, site_rows, era_rows, normal_read_rows
|
|
1058
1097
|
)
|
|
1098
|
+
if scenario_props.get("save_report_run", False):
|
|
1099
|
+
report_run_id = ReportRun.w_insert(
|
|
1100
|
+
"monthly_duration", user_id, fname, {"scenario": scenario_props}
|
|
1101
|
+
)
|
|
1102
|
+
for tab, rows in (
|
|
1103
|
+
("org", org_rows),
|
|
1104
|
+
("site", site_rows),
|
|
1105
|
+
("era", era_rows),
|
|
1106
|
+
):
|
|
1107
|
+
titles = rows[0]
|
|
1108
|
+
for row in rows[1:]:
|
|
1109
|
+
values = dict(zip(titles, row))
|
|
1110
|
+
ReportRun.w_insert_row(report_run_id, tab, titles, values, {})
|
|
1111
|
+
ReportRun.w_update(report_run_id, "finished")
|
|
1112
|
+
|
|
1059
1113
|
except BadRequest as e:
|
|
1060
1114
|
msg = e.description + traceback.format_exc()
|
|
1061
1115
|
sys.stderr.write(msg + "\n")
|
chellow/rrun.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import collections
|
|
3
|
+
import threading
|
|
4
|
+
import traceback
|
|
5
|
+
|
|
6
|
+
from dateutil.relativedelta import relativedelta
|
|
7
|
+
|
|
8
|
+
from sqlalchemy import select
|
|
9
|
+
|
|
10
|
+
from chellow.models import ReportRun, Session
|
|
11
|
+
from chellow.utils import utc_datetime_now
|
|
12
|
+
|
|
13
|
+
rrun_deleter = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def startup():
|
|
17
|
+
global rrun_deleter
|
|
18
|
+
|
|
19
|
+
rrun_deleter = ReportRunDeleter()
|
|
20
|
+
rrun_deleter.start()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ReportRunDeleter(threading.Thread):
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super(ReportRunDeleter, self).__init__(name="ReportRun Deleter")
|
|
26
|
+
self.messages = collections.deque(maxlen=1000)
|
|
27
|
+
self.stopped = threading.Event()
|
|
28
|
+
self.going = threading.Event()
|
|
29
|
+
self.global_alert = None
|
|
30
|
+
|
|
31
|
+
def stop(self):
|
|
32
|
+
self.stopped.set()
|
|
33
|
+
self.going.set()
|
|
34
|
+
self.join()
|
|
35
|
+
|
|
36
|
+
def go(self):
|
|
37
|
+
self.going.set()
|
|
38
|
+
|
|
39
|
+
def log(self, message):
|
|
40
|
+
self.messages.appendleft(
|
|
41
|
+
utc_datetime_now().strftime("%Y-%m-%d %H:%M:%S") + " - " + message
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def run(self):
|
|
45
|
+
while not self.stopped.isSet():
|
|
46
|
+
try:
|
|
47
|
+
with Session() as sess:
|
|
48
|
+
now = utc_datetime_now()
|
|
49
|
+
cutoff_date = now - relativedelta(years=1)
|
|
50
|
+
for report_run in sess.scalars(
|
|
51
|
+
select(ReportRun).where(ReportRun.date_created < cutoff_date)
|
|
52
|
+
):
|
|
53
|
+
report_run.delete(sess)
|
|
54
|
+
sess.commit()
|
|
55
|
+
self.log("Deleted report run")
|
|
56
|
+
except BaseException:
|
|
57
|
+
self.log("Outer problem " + traceback.format_exc())
|
|
58
|
+
self.global_alert = (
|
|
59
|
+
"There's a problem with a "
|
|
60
|
+
"<a href='/report_runs'>Report Runs</a>."
|
|
61
|
+
)
|
|
62
|
+
finally:
|
|
63
|
+
self.going.clear()
|
|
64
|
+
self.log("Finished deleting Report Runs.")
|
|
65
|
+
|
|
66
|
+
self.going.wait(24 * 60 * 60)
|
|
67
|
+
self.going.clear()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_importer():
|
|
71
|
+
return rrun_deleter
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@atexit.register
|
|
75
|
+
def shutdown():
|
|
76
|
+
if rrun_deleter is not None:
|
|
77
|
+
rrun_deleter.stop()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}
|
|
4
|
+
» Report Runs » {{run.id}}
|
|
5
|
+
{% endblock %}
|
|
6
|
+
|
|
7
|
+
{% block nav %}
|
|
8
|
+
<a href="/report_runs">Report Runs</a> » {{run.id}}
|
|
9
|
+
{% endblock %}
|
|
10
|
+
|
|
11
|
+
{% block content %}
|
|
12
|
+
{% if request.method == "GET" and request.values.delete %}
|
|
13
|
+
<form method="post" action="/report_runs/{{run.id}}">
|
|
14
|
+
<fieldset>
|
|
15
|
+
<legend>Are you sure you want to delete this report run?</legend>
|
|
16
|
+
<input type="submit" name="delete" value="delete">
|
|
17
|
+
<a href="/report_runs/{{run.id}}">Cancel</a>
|
|
18
|
+
</fieldset>
|
|
19
|
+
</form>
|
|
20
|
+
{% else %}
|
|
21
|
+
<table>
|
|
22
|
+
<caption>Monthly Duration Report</caption>
|
|
23
|
+
<thead>
|
|
24
|
+
<tr>
|
|
25
|
+
<th>Date Created</th>
|
|
26
|
+
<th>Created By</th>
|
|
27
|
+
<th>Title</th>
|
|
28
|
+
<th>State</th>
|
|
29
|
+
<th>Delete</th>
|
|
30
|
+
<th>Download Spreadsheet</th>
|
|
31
|
+
</tr>
|
|
32
|
+
</thead>
|
|
33
|
+
<tbody>
|
|
34
|
+
<tr>
|
|
35
|
+
<td>{{run.date_created|hh_format}}</td>
|
|
36
|
+
<td>{{run.creator}}</td>
|
|
37
|
+
<td>{{run.title}}</td>
|
|
38
|
+
<td>{{run.state}}</td>
|
|
39
|
+
<td>
|
|
40
|
+
<form action="/report_runs/{{run.id}}">
|
|
41
|
+
<fieldset style="border: none;">
|
|
42
|
+
<input type="submit" name="delete" value="Delete">
|
|
43
|
+
</fieldset>
|
|
44
|
+
</form>
|
|
45
|
+
</td>
|
|
46
|
+
<td><a href="/report_runs/{{run.id}}/spreadsheet">Download</a></td>
|
|
47
|
+
</tr>
|
|
48
|
+
</tbody>
|
|
49
|
+
</table>
|
|
50
|
+
|
|
51
|
+
<table class="sticky">
|
|
52
|
+
<caption>
|
|
53
|
+
Organisation Level
|
|
54
|
+
</caption>
|
|
55
|
+
<thead>
|
|
56
|
+
<tr>
|
|
57
|
+
{% for title in org_rows[0].data.titles %}
|
|
58
|
+
<th>{{title}}</th>
|
|
59
|
+
{% endfor %}
|
|
60
|
+
</tr>
|
|
61
|
+
</thead>
|
|
62
|
+
<tbody>
|
|
63
|
+
{% for org_row in org_rows %}
|
|
64
|
+
<tr>
|
|
65
|
+
{% for title in org_row.data.titles %}
|
|
66
|
+
<td>{{org_row.data['values'][title]}}</td>
|
|
67
|
+
{% endfor %}
|
|
68
|
+
</tr>
|
|
69
|
+
{% endfor %}
|
|
70
|
+
</tbody>
|
|
71
|
+
</table>
|
|
72
|
+
{% endif %}
|
|
73
|
+
{% endblock %}
|
|
@@ -35,4 +35,35 @@
|
|
|
35
35
|
{% endfor %}
|
|
36
36
|
</tbody>
|
|
37
37
|
</table>
|
|
38
|
+
|
|
39
|
+
<h2>Report Run Deleter</h2>
|
|
40
|
+
|
|
41
|
+
{% if importer %}
|
|
42
|
+
|
|
43
|
+
<table>
|
|
44
|
+
<tr>
|
|
45
|
+
<th>Is Going?</th>
|
|
46
|
+
<td>{{importer.going.is_set()}}</td>
|
|
47
|
+
</tr>
|
|
48
|
+
{% if importer.going.is_set() %}
|
|
49
|
+
<tr>
|
|
50
|
+
<th>Progress</th>
|
|
51
|
+
<td>{{importer.progress}}</td>
|
|
52
|
+
</tr>
|
|
53
|
+
{% endif %}
|
|
54
|
+
</table>
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
<h4 id="log">Log</h4>
|
|
58
|
+
|
|
59
|
+
<ul>
|
|
60
|
+
{% for message in importer.messages %}
|
|
61
|
+
<li>{{message}}</li>
|
|
62
|
+
{% endfor %}
|
|
63
|
+
</ul>
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
{% else %}
|
|
67
|
+
<p>Deleter not present.</p>
|
|
68
|
+
{% endif %}
|
|
38
69
|
{% endblock %}
|
chellow/templates/user.html
CHANGED
|
@@ -31,62 +31,33 @@
|
|
|
31
31
|
{{ user.email_address }}
|
|
32
32
|
{%- endif -%}">
|
|
33
33
|
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{%- if user.user_role.code == 'editor' %}
|
|
42
|
-
checked
|
|
43
|
-
{%- endif -%}
|
|
44
|
-
{%- endif -%}
|
|
45
|
-
>
|
|
46
|
-
<label>Editor</label>
|
|
47
|
-
<input type="radio" name="user_role_code" value="viewer"
|
|
48
|
-
{% if request.values.user_role_code %}
|
|
49
|
-
{% if request.values.user_role_code == 'viewer' %}
|
|
50
|
-
checked
|
|
51
|
-
{% endif %}
|
|
52
|
-
{% else %}
|
|
53
|
-
{% if user.user_role.code == 'viewer' %}
|
|
54
|
-
checked
|
|
55
|
-
{% endif %}
|
|
56
|
-
{% endif %}
|
|
57
|
-
>
|
|
58
|
-
<label>Viewer</label>
|
|
59
|
-
<input
|
|
60
|
-
type="radio" name="user_role_code"
|
|
61
|
-
value="party-viewer"
|
|
62
|
-
{%- if request.values.user_role_code -%}
|
|
63
|
-
{%- if request.values.user_role_code == 'party-viewer' -%}
|
|
64
|
-
checked
|
|
65
|
-
{%- endif -%}
|
|
66
|
-
{%- else -%}
|
|
67
|
-
{%- if user.user_role.code == 'party-viewer' -%}
|
|
68
|
-
checked
|
|
69
|
-
{% endif %}
|
|
70
|
-
{% endif %}>
|
|
71
|
-
<label>Party Viewer</label>
|
|
72
|
-
<select name="party_id">
|
|
73
|
-
{% for party in parties %}
|
|
74
|
-
<option value="{{ party.id }}"
|
|
75
|
-
{%- if request.values.party_id -%}
|
|
76
|
-
{%- if request.values.party_id == party.id %}
|
|
77
|
-
selected
|
|
34
|
+
<fieldset>
|
|
35
|
+
<legend>Role</legend>
|
|
36
|
+
<label>Editor</label>
|
|
37
|
+
<input type="radio" name="user_role_code" value="editor"
|
|
38
|
+
{%- if request.values.user_role_editor -%}
|
|
39
|
+
{%- if request.values.user_role_editor == 'editor' %}
|
|
40
|
+
checked
|
|
78
41
|
{%- endif -%}
|
|
79
42
|
{%- else -%}
|
|
80
|
-
{%- if user.
|
|
81
|
-
|
|
43
|
+
{%- if user.user_role.code == 'editor' %}
|
|
44
|
+
checked
|
|
82
45
|
{%- endif -%}
|
|
83
46
|
{%- endif -%}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
47
|
+
>
|
|
48
|
+
<label>Viewer</label>
|
|
49
|
+
<input type="radio" name="user_role_code" value="viewer"
|
|
50
|
+
{% if request.values.user_role_code %}
|
|
51
|
+
{% if request.values.user_role_code == 'viewer' %}
|
|
52
|
+
checked
|
|
53
|
+
{% endif %}
|
|
54
|
+
{% else %}
|
|
55
|
+
{% if user.user_role.code == 'viewer' %}
|
|
56
|
+
checked
|
|
57
|
+
{% endif %}
|
|
58
|
+
{% endif %}
|
|
59
|
+
>
|
|
60
|
+
</fieldset>
|
|
90
61
|
<input type="submit" value="Update">
|
|
91
62
|
</fieldset>
|
|
92
63
|
</form>
|
chellow/views.py
CHANGED
|
@@ -1287,8 +1287,9 @@ def download_delete(fname):
|
|
|
1287
1287
|
@home.route("/report_runs")
|
|
1288
1288
|
def report_runs_get():
|
|
1289
1289
|
runs = g.sess.query(ReportRun).order_by(ReportRun.date_created.desc())
|
|
1290
|
+
importer = chellow.rrun.get_importer()
|
|
1290
1291
|
|
|
1291
|
-
return render_template("report_runs.html", runs=runs)
|
|
1292
|
+
return render_template("report_runs.html", runs=runs, importer=importer)
|
|
1292
1293
|
|
|
1293
1294
|
|
|
1294
1295
|
@home.route("/report_runs/<int:run_id>")
|
|
@@ -1375,6 +1376,21 @@ def report_run_get(run_id):
|
|
|
1375
1376
|
run=run,
|
|
1376
1377
|
rows=rows,
|
|
1377
1378
|
)
|
|
1379
|
+
elif run.name == "monthly_duration":
|
|
1380
|
+
org_rows = (
|
|
1381
|
+
g.sess.execute(
|
|
1382
|
+
select(ReportRunRow)
|
|
1383
|
+
.filter(ReportRunRow.report_run == run, ReportRunRow.tab == "org")
|
|
1384
|
+
.order_by(ReportRunRow.data["values"]["month"])
|
|
1385
|
+
)
|
|
1386
|
+
.scalars()
|
|
1387
|
+
.all()
|
|
1388
|
+
)
|
|
1389
|
+
return render_template(
|
|
1390
|
+
"report_run_monthly_duration_org.html",
|
|
1391
|
+
run=run,
|
|
1392
|
+
org_rows=org_rows,
|
|
1393
|
+
)
|
|
1378
1394
|
|
|
1379
1395
|
elif run.name == "ecoes_comparison":
|
|
1380
1396
|
rows = (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: chellow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 1728660080.0.0
|
|
4
4
|
Summary: Web Application for checking UK energy bills.
|
|
5
5
|
Project-URL: Homepage, https://github.com/WessexWater/chellow
|
|
6
6
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
chellow/__init__.py,sha256=
|
|
1
|
+
chellow/__init__.py,sha256=hejB7bPYedSLGaDsHR0_g3UTF7gKfQkdE4zuzoB3A5A,10242
|
|
2
2
|
chellow/api.py,sha256=mk17TfweR76DPFC8lX2SArTjai6y6YshASxqO1w-_-s,11036
|
|
3
3
|
chellow/bank_holidays.py,sha256=T_utYMwe_g1dz5X-aOTdIPryg49SvB7QsWM1yphlqG8,4423
|
|
4
4
|
chellow/commands.py,sha256=ESBe9ZWj1c3vdZgqMZ9gFvYAB3hRag2R1PzOwuw9yFo,1302
|
|
5
5
|
chellow/dloads.py,sha256=dixp-O0MF2_mlwrnKx3D9DH09Qu05BjTo0rZfigTjR4,5534
|
|
6
6
|
chellow/edi_lib.py,sha256=alu20x9ZX06iPfnNI9dEJzuP6RIf4We3Y_M_bl7RrcY,51789
|
|
7
7
|
chellow/general_import.py,sha256=l3EHq9zG9Vfl5Ee6XTVrC1nusXo4YGGB4VBmZ_JaJR8,65798
|
|
8
|
-
chellow/models.py,sha256=
|
|
8
|
+
chellow/models.py,sha256=9LLROzS6gXZGICk0ITXhCyTtKaIY7HW4bMqWg4Mc-xw,244221
|
|
9
9
|
chellow/national_grid.py,sha256=czwIZqzJndSGhEMQ5YzI6hRBhvjkM6VRVYXybf4_KXg,4377
|
|
10
10
|
chellow/proxy.py,sha256=cVXIktPlX3tQ1BYcwxq0nJXKE6r3DtFTtfFHPq55HaM,1351
|
|
11
11
|
chellow/rate_server.py,sha256=fg-Pf_9Hk3bXmC9riPQNGQxBvLvBa_WtNYdwDCjnCSg,5678
|
|
12
|
+
chellow/rrun.py,sha256=1Kt2q_K9UoDG_nsZz-Q6XJiMNKroWqlqFdxn2M6Q8CA,2088
|
|
12
13
|
chellow/testing.py,sha256=Od4HHH6pZrhJ_De118_F55RJEKmAvhUH2S24QE9qFQk,3635
|
|
13
14
|
chellow/utils.py,sha256=32qPWEGzCPKPhSM7ztpzcR6ZG74sVZanScDIdK50Rq4,19308
|
|
14
|
-
chellow/views.py,sha256=
|
|
15
|
+
chellow/views.py,sha256=42IRnCKfU2gKdSjyPnUfmoDX19uUQHvAEPV22xhN3HY,80222
|
|
15
16
|
chellow/e/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
17
|
chellow/e/aahedc.py,sha256=d2usudp7KYWpU6Pk3fal5EQ47EbvkvKeaFGylnb3NWw,606
|
|
17
18
|
chellow/e/bill_importer.py,sha256=7UcnqNlKbJc2GhW9gy8sDp9GuqambJVpZLvbafOZztA,7411
|
|
@@ -79,7 +80,7 @@ chellow/reports/report_219.py,sha256=cA0lfJKnJg41Zc4_gZB1KUXZ9JeJo0TiTlu5jm1bdDM
|
|
|
79
80
|
chellow/reports/report_231.py,sha256=uhO1algP7sibpZVaniqGs56HOCPCQeDO-Y-UfvFQwnI,5311
|
|
80
81
|
chellow/reports/report_233.py,sha256=HJRn4wH7RsYIduD2MNZYjFTbgb5LIu8_-jmUuRc0Q6Y,5016
|
|
81
82
|
chellow/reports/report_241.py,sha256=AlFmSHnfG2HWv_ICmWX7fNpPwLHjq7mo1QtOTjSKO3k,5384
|
|
82
|
-
chellow/reports/report_247.py,sha256=
|
|
83
|
+
chellow/reports/report_247.py,sha256=kIHXNyXnmL0eZe-o8YvgiF0ZnlzdXF7KDz4r0pcHszk,46965
|
|
83
84
|
chellow/reports/report_29.py,sha256=KDFjgrLBv4WbG9efCdu_geMR7gT_QV9N97Wfdt7aDc4,2736
|
|
84
85
|
chellow/reports/report_291.py,sha256=rqBXy6s7hMeYWw-yNX6w_L5t2yz6rNEeos_4xO7wf90,7519
|
|
85
86
|
chellow/reports/report_33.py,sha256=laVz-itDbJTdvC6LxLEeuY0eKpYx43Un4adiExPTEEE,16730
|
|
@@ -137,10 +138,11 @@ chellow/templates/report_run.html,sha256=O_wjIu43S-mKVyZyku3dJJdvyck3rAgEdhw59Ts
|
|
|
137
138
|
chellow/templates/report_run_asset_comparison.html,sha256=VYCCUmIC7Mfe7uuaAHb6ihiK6zsqeTlQbzgtzLqR3zg,2305
|
|
138
139
|
chellow/templates/report_run_bill_check.html,sha256=H2ayoBL7EgKMq2Nwq5VjE_TNvcIKcqeCm0alQWLIw78,5084
|
|
139
140
|
chellow/templates/report_run_ecoes_comparison.html,sha256=VmkT5ypWLP8qZS6NbDTC4yDaG7mnUlxZz7EV8xkHGZw,4086
|
|
141
|
+
chellow/templates/report_run_monthly_duration_org.html,sha256=gGNGJ4Q50q4BtIMi98rhO-7NqRHcsFUmbj2qzeOLejw,1713
|
|
140
142
|
chellow/templates/report_run_row.html,sha256=bmtcdqJaS1CXpL0i8PuqvmeF98jKNYX5-mnQu-OuDKQ,3791
|
|
141
143
|
chellow/templates/report_run_row_bill_check.html,sha256=aC2LMu_6NvmTN3ZdxHJPPPczyxPN6hg0F-PPcqIWUws,4683
|
|
142
144
|
chellow/templates/report_run_supply_contacts.html,sha256=JNzwz9M6qbLRDMkCzFCxxANapUer5klxo7t5a48nAzg,2117
|
|
143
|
-
chellow/templates/report_runs.html,sha256=
|
|
145
|
+
chellow/templates/report_runs.html,sha256=ecoIkl2WtfYtifiTxnslmpMGYYGVQW-CVSBpqhXyiE4,1131
|
|
144
146
|
chellow/templates/site.html,sha256=dj0VgcmjaKJHuTOZDESO2E2MOyluYJtx4YaSOaWOkwU,10024
|
|
145
147
|
chellow/templates/site_add.html,sha256=NxYmOIZQH6X8EBOuJUbhUJ8IYB3t0BukjR1yVRhnJhM,422
|
|
146
148
|
chellow/templates/site_edit.html,sha256=TJ_ZDDkodj-uDB3GPP9Cel3FGZY2oP42KCzHOydPWVc,2909
|
|
@@ -152,7 +154,7 @@ chellow/templates/sites.html,sha256=4ouJ5xYqYHjXCv3cDucTjgbOd_whReFPPHopLBdW6Go,
|
|
|
152
154
|
chellow/templates/supplies.html,sha256=Ie_4K4-KwXqrCBwaUcjWxmV27rYjeESI_DCS9gLUipk,3488
|
|
153
155
|
chellow/templates/system.html,sha256=PP8MN8mieil3AwLS1WlQBcgbl0J61bksN-Cy4toYNqo,1871
|
|
154
156
|
chellow/templates/tester.html,sha256=4DYrtcnFY0y6o3K6_tSmFpPlCRngZj1zo8nJ1NI4pk8,623
|
|
155
|
-
chellow/templates/user.html,sha256=
|
|
157
|
+
chellow/templates/user.html,sha256=tUeE5v-MOayJD_vP1P4g1ruoVMCTcbk-u28fOVTPj84,2412
|
|
156
158
|
chellow/templates/user_roles.html,sha256=Pfjr4uApEmJl8t9s0qJTxigQcAVYw7gpV_ECE8c0Cto,399
|
|
157
159
|
chellow/templates/users.html,sha256=dBB0yOvsoYbY_I9le1XGqZ0SlesUbWMqfRGlZOtOgNs,2244
|
|
158
160
|
chellow/templates/e/asset_comparison.html,sha256=QyN3WMw8YoFaSWUvD2NOnRLdLdB3Kv6m3t8Id8Mb6_A,678
|
|
@@ -275,7 +277,7 @@ chellow/templates/e/read_type.html,sha256=volKteZB79famXrzN_Bgqy9JT9C4a50vXLkuZ0
|
|
|
275
277
|
chellow/templates/e/read_types.html,sha256=CknHXNEkBnsAprqI66ftvnnMFBdR_kqI7o26rxjlrJA,473
|
|
276
278
|
chellow/templates/e/scenario.html,sha256=E8o3WQwAEejzaMPzeuUqyt9fWWNSDtN96qkJz0slDEo,1522
|
|
277
279
|
chellow/templates/e/scenario_add.html,sha256=qQpxvhlrQqrNYiIQTHu_NvSoeSKuRNEJQYwLqRlQ8_U,516
|
|
278
|
-
chellow/templates/e/scenario_docs.html,sha256
|
|
280
|
+
chellow/templates/e/scenario_docs.html,sha256=-aFljSJhiOEKaAb0omOo9kDjnwMarEaFNo-dSYoiwLc,4946
|
|
279
281
|
chellow/templates/e/scenario_edit.html,sha256=Uf64v_qsBP0BxaFEIz214CC_dZXlvro4zvQXH_towhA,1070
|
|
280
282
|
chellow/templates/e/scenarios.html,sha256=zlNhZvQEcuwLgHObVHS-4THur5Lz9Jf1G6xD98-jamI,847
|
|
281
283
|
chellow/templates/e/site_add_e_supply.html,sha256=_gi1ejI4TMTMX9vCW7z2kToR2XKR6qoVh67qp_VrDsM,2731
|
|
@@ -366,6 +368,6 @@ chellow/templates/g/supply_note_edit.html,sha256=b8mB6_ucBwoljp03iy6AgVaZUhGw3-1
|
|
|
366
368
|
chellow/templates/g/supply_notes.html,sha256=6epNmZ3NKdXZz27fvmRUGeffg_oc1kmwuBeyRzQe3Rg,854
|
|
367
369
|
chellow/templates/g/unit.html,sha256=KouNVU0-i84afANkLQ_heJ0uDfJ9H5A05PuLqb8iCN8,438
|
|
368
370
|
chellow/templates/g/units.html,sha256=p5Nd-lAIboKPEOO6N451hx1bcKxMg4BDODnZ-43MmJc,441
|
|
369
|
-
chellow-
|
|
370
|
-
chellow-
|
|
371
|
-
chellow-
|
|
371
|
+
chellow-1728660080.0.0.dist-info/METADATA,sha256=35H6CrEAzoMZ04CzYNyl07FqTrIMfAWt7FBsKZKqzss,12204
|
|
372
|
+
chellow-1728660080.0.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
373
|
+
chellow-1728660080.0.0.dist-info/RECORD,,
|
|
File without changes
|