chellow 1760028799.0.0__py3-none-any.whl → 1761297878.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/dloads.py +2 -2
- chellow/e/views.py +30 -16
- chellow/reports/report_247.py +1 -4
- chellow/reports/report_channel_snags.py +294 -0
- chellow/templates/e/channel_snags.html +32 -100
- chellow/templates/e/supplier_contract_edit.html +24 -36
- chellow/templates/e/supplier_rate_script_edit.html +28 -43
- chellow/templates/macros.html +14 -4
- chellow/templates/reports/channel_snags.html +91 -0
- chellow/utils.py +14 -3
- {chellow-1760028799.0.0.dist-info → chellow-1761297878.0.0.dist-info}/METADATA +12 -14
- {chellow-1760028799.0.0.dist-info → chellow-1761297878.0.0.dist-info}/RECORD +13 -13
- chellow/commands.py +0 -52
- chellow/reports/report_233.py +0 -150
- {chellow-1760028799.0.0.dist-info → chellow-1761297878.0.0.dist-info}/WHEEL +0 -0
chellow/dloads.py
CHANGED
|
@@ -91,7 +91,7 @@ class DloadFile:
|
|
|
91
91
|
def open_file(base, user, mode="r", newline=None, is_zip=False):
|
|
92
92
|
global download_id
|
|
93
93
|
|
|
94
|
-
base =
|
|
94
|
+
base = "".join(x if (x.isalnum() or x in "_.") else "_" for x in base)
|
|
95
95
|
try:
|
|
96
96
|
lock.acquire()
|
|
97
97
|
if len(list(download_path.iterdir())) == 0:
|
|
@@ -108,7 +108,7 @@ def open_file(base, user, mode="r", newline=None, is_zip=False):
|
|
|
108
108
|
un = user.proxy_username
|
|
109
109
|
else:
|
|
110
110
|
un = user.email_address
|
|
111
|
-
uname =
|
|
111
|
+
uname = "".join(x if (x.isalnum() or x in "_") else "_" for x in un)
|
|
112
112
|
|
|
113
113
|
names = tuple("_".join((serial, v, uname, base)) for v in ("RUNNING", "FINISHED"))
|
|
114
114
|
running_name, finished_name = tuple(download_path / name for name in names)
|
chellow/e/views.py
CHANGED
|
@@ -381,7 +381,7 @@ def channel_snags_get():
|
|
|
381
381
|
total_snags_q = total_snags_q.where(Era.dc_contract == contract)
|
|
382
382
|
snags_q = snags_q.where(Era.dc_contract == contract)
|
|
383
383
|
|
|
384
|
-
total_snags = g.sess.
|
|
384
|
+
total_snags = g.sess.scalars(total_snags_q).one()
|
|
385
385
|
|
|
386
386
|
snag_groups = []
|
|
387
387
|
prev_snag = None
|
|
@@ -5711,7 +5711,7 @@ def supplier_contract_edit_delete(contract_id):
|
|
|
5711
5711
|
contract = Contract.get_supplier_by_id(g.sess, contract_id)
|
|
5712
5712
|
contract.delete(g.sess)
|
|
5713
5713
|
g.sess.commit()
|
|
5714
|
-
return
|
|
5714
|
+
return hx_redirect("/supplier_contracts", 303)
|
|
5715
5715
|
except BadRequest as e:
|
|
5716
5716
|
g.sess.rollback()
|
|
5717
5717
|
description = e.description
|
|
@@ -5882,25 +5882,39 @@ def supplier_rate_script_edit_get(rate_script_id):
|
|
|
5882
5882
|
)
|
|
5883
5883
|
|
|
5884
5884
|
|
|
5885
|
+
@e.route("/supplier_rate_scripts/<int:rate_script_id>/edit", methods=["DELETE"])
|
|
5886
|
+
def supplier_rate_script_edit_delete(rate_script_id):
|
|
5887
|
+
try:
|
|
5888
|
+
rate_script = RateScript.get_supplier_by_id(g.sess, rate_script_id)
|
|
5889
|
+
contract = rate_script.contract
|
|
5890
|
+
contract.delete_rate_script(g.sess, rate_script)
|
|
5891
|
+
g.sess.commit()
|
|
5892
|
+
return hx_redirect(f"/supplier_contracts/{contract.id}", 303)
|
|
5893
|
+
except BadRequest as e:
|
|
5894
|
+
g.sess.rollback()
|
|
5895
|
+
flash(e.description)
|
|
5896
|
+
return make_response(
|
|
5897
|
+
render_template(
|
|
5898
|
+
"supplier_rate_script_edit.html", supplier_rate_script=rate_script
|
|
5899
|
+
),
|
|
5900
|
+
400,
|
|
5901
|
+
)
|
|
5902
|
+
|
|
5903
|
+
|
|
5885
5904
|
@e.route("/supplier_rate_scripts/<int:rate_script_id>/edit", methods=["POST"])
|
|
5886
5905
|
def supplier_rate_script_edit_post(rate_script_id):
|
|
5887
5906
|
try:
|
|
5888
5907
|
rate_script = RateScript.get_supplier_by_id(g.sess, rate_script_id)
|
|
5889
5908
|
contract = rate_script.contract
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
contract.update_rate_script(
|
|
5900
|
-
g.sess, rate_script, start_date, finish_date, script
|
|
5901
|
-
)
|
|
5902
|
-
g.sess.commit()
|
|
5903
|
-
return chellow_redirect(f"/supplier_rate_scripts/{rate_script.id}", 303)
|
|
5909
|
+
script = req_zish("script")
|
|
5910
|
+
start_date = req_date("start")
|
|
5911
|
+
has_finished = req_bool("has_finished")
|
|
5912
|
+
finish_date = req_date("finish") if has_finished else None
|
|
5913
|
+
contract.update_rate_script(
|
|
5914
|
+
g.sess, rate_script, start_date, finish_date, script
|
|
5915
|
+
)
|
|
5916
|
+
g.sess.commit()
|
|
5917
|
+
return chellow_redirect(f"/supplier_rate_scripts/{rate_script.id}", 303)
|
|
5904
5918
|
except BadRequest as e:
|
|
5905
5919
|
g.sess.rollback()
|
|
5906
5920
|
flash(e.description)
|
chellow/reports/report_247.py
CHANGED
|
@@ -1116,10 +1116,7 @@ def do_post(sess):
|
|
|
1116
1116
|
exp_mpan_core if imp_mpan_core is None else imp_mpan_core
|
|
1117
1117
|
]
|
|
1118
1118
|
|
|
1119
|
-
|
|
1120
|
-
compression = req_bool("compression")
|
|
1121
|
-
else:
|
|
1122
|
-
compression = True
|
|
1119
|
+
compression = req_bool("compression")
|
|
1123
1120
|
|
|
1124
1121
|
user = g.user
|
|
1125
1122
|
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import sys
|
|
3
|
+
import threading
|
|
4
|
+
import traceback
|
|
5
|
+
|
|
6
|
+
from dateutil.relativedelta import relativedelta
|
|
7
|
+
|
|
8
|
+
from flask import g, redirect, render_template, request
|
|
9
|
+
|
|
10
|
+
from sqlalchemy.orm import joinedload
|
|
11
|
+
from sqlalchemy.sql.expression import false, select, true
|
|
12
|
+
|
|
13
|
+
from werkzeug.exceptions import BadRequest
|
|
14
|
+
|
|
15
|
+
from chellow.dloads import open_file
|
|
16
|
+
from chellow.models import (
|
|
17
|
+
Channel,
|
|
18
|
+
Contract,
|
|
19
|
+
Era,
|
|
20
|
+
Party,
|
|
21
|
+
RSession,
|
|
22
|
+
Site,
|
|
23
|
+
SiteEra,
|
|
24
|
+
Snag,
|
|
25
|
+
Supply,
|
|
26
|
+
User,
|
|
27
|
+
)
|
|
28
|
+
from chellow.utils import (
|
|
29
|
+
csv_make_val,
|
|
30
|
+
hh_before,
|
|
31
|
+
req_bool,
|
|
32
|
+
req_date,
|
|
33
|
+
req_int,
|
|
34
|
+
req_int_none,
|
|
35
|
+
req_str,
|
|
36
|
+
utc_datetime_now,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _make_rows(
|
|
41
|
+
sess,
|
|
42
|
+
now,
|
|
43
|
+
contract,
|
|
44
|
+
days_hidden,
|
|
45
|
+
is_ignored,
|
|
46
|
+
show_settlement,
|
|
47
|
+
only_ongoing,
|
|
48
|
+
days_long_hidden,
|
|
49
|
+
limit=None,
|
|
50
|
+
):
|
|
51
|
+
cutoff_date = now - relativedelta(days=days_hidden)
|
|
52
|
+
q = (
|
|
53
|
+
select(Snag, Channel, Era, Supply, SiteEra, Site, Contract)
|
|
54
|
+
.join(Channel, Snag.channel_id == Channel.id)
|
|
55
|
+
.join(Era, Channel.era_id == Era.id)
|
|
56
|
+
.join(Supply, Era.supply_id == Supply.id)
|
|
57
|
+
.join(SiteEra, Era.site_eras)
|
|
58
|
+
.join(Site, SiteEra.site_id == Site.id)
|
|
59
|
+
.join(Contract, Era.dc_contract_id == Contract.id)
|
|
60
|
+
.where(
|
|
61
|
+
SiteEra.is_physical == true(),
|
|
62
|
+
Snag.start_date < cutoff_date,
|
|
63
|
+
)
|
|
64
|
+
.order_by(
|
|
65
|
+
Site.code,
|
|
66
|
+
Supply.id,
|
|
67
|
+
Channel.imp_related,
|
|
68
|
+
Channel.channel_type,
|
|
69
|
+
Snag.description,
|
|
70
|
+
Snag.start_date,
|
|
71
|
+
Snag.id,
|
|
72
|
+
)
|
|
73
|
+
.options(joinedload(Era.dc_contract))
|
|
74
|
+
)
|
|
75
|
+
if contract is not None:
|
|
76
|
+
q = q.where(Era.dc_contract == contract)
|
|
77
|
+
|
|
78
|
+
if not is_ignored:
|
|
79
|
+
q = q.where(Snag.is_ignored == false())
|
|
80
|
+
|
|
81
|
+
if show_settlement == "yes":
|
|
82
|
+
q = q.join(Party, Supply.dno_id == Party.id).where(Party.dno_code != "99")
|
|
83
|
+
elif show_settlement == "no":
|
|
84
|
+
q = q.join(Party, Supply.dno_id == Party.id).where(Party.dno_code == "99")
|
|
85
|
+
elif show_settlement == "both":
|
|
86
|
+
pass
|
|
87
|
+
else:
|
|
88
|
+
raise BadRequest("show_settlement must be 'yes', 'no' or 'both'.")
|
|
89
|
+
|
|
90
|
+
snag_groups = []
|
|
91
|
+
prev_snag = None
|
|
92
|
+
for snag, channel, era, supply, site_era, site, contract in sess.execute(q):
|
|
93
|
+
snag_start = snag.start_date
|
|
94
|
+
snag_finish = snag.finish_date
|
|
95
|
+
|
|
96
|
+
if snag_finish is None:
|
|
97
|
+
duration = now - snag_start
|
|
98
|
+
age_of_snag = None
|
|
99
|
+
else:
|
|
100
|
+
duration = snag_finish - snag_start
|
|
101
|
+
if hh_before(cutoff_date, snag_finish):
|
|
102
|
+
age_of_snag = None
|
|
103
|
+
else:
|
|
104
|
+
delta = now - snag_finish
|
|
105
|
+
age_of_snag = delta.days
|
|
106
|
+
|
|
107
|
+
if only_ongoing and age_of_snag is not None:
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
if days_long_hidden is not None and duration < days_long_hidden:
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
if (
|
|
114
|
+
prev_snag is None
|
|
115
|
+
or channel.era != prev_snag.channel.era
|
|
116
|
+
or snag.start_date != prev_snag.start_date
|
|
117
|
+
or snag.finish_date != prev_snag.finish_date
|
|
118
|
+
or snag.description != prev_snag.description
|
|
119
|
+
):
|
|
120
|
+
if limit is not None and len(snag_groups) > limit:
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
snag_group = {
|
|
124
|
+
"snags": [],
|
|
125
|
+
"site": site,
|
|
126
|
+
"era": era,
|
|
127
|
+
"supply": supply,
|
|
128
|
+
"description": snag.description,
|
|
129
|
+
"start_date": snag.start_date,
|
|
130
|
+
"finish_date": snag.finish_date,
|
|
131
|
+
"contract": contract,
|
|
132
|
+
"contract_name": contract.name,
|
|
133
|
+
"hidden_days": days_hidden,
|
|
134
|
+
"chellow_id": snag.id,
|
|
135
|
+
"imp_mpan_core": era.imp_mpan_core,
|
|
136
|
+
"exp_mpan_core": era.exp_mpan_core,
|
|
137
|
+
"site_code": site.code,
|
|
138
|
+
"site_name": site.name,
|
|
139
|
+
"snag_description": snag.description,
|
|
140
|
+
"channel_type": channel.channel_type,
|
|
141
|
+
"is_ignored": snag.is_ignored,
|
|
142
|
+
"days_since_finished": age_of_snag,
|
|
143
|
+
"duration": duration.days,
|
|
144
|
+
}
|
|
145
|
+
snag_groups.append(snag_group)
|
|
146
|
+
snag_group["snags"].append(snag)
|
|
147
|
+
prev_snag = snag
|
|
148
|
+
|
|
149
|
+
def make_key(item):
|
|
150
|
+
return item["duration"]
|
|
151
|
+
|
|
152
|
+
snag_groups.sort(key=make_key, reverse=True)
|
|
153
|
+
return snag_groups
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def content(
|
|
157
|
+
contract_id,
|
|
158
|
+
days_hidden,
|
|
159
|
+
is_ignored,
|
|
160
|
+
user_id,
|
|
161
|
+
only_ongoing,
|
|
162
|
+
show_settlement,
|
|
163
|
+
days_long_hidden,
|
|
164
|
+
now,
|
|
165
|
+
):
|
|
166
|
+
f = writer = None
|
|
167
|
+
try:
|
|
168
|
+
with RSession() as sess:
|
|
169
|
+
user = User.get_by_id(sess, user_id)
|
|
170
|
+
if contract_id is None:
|
|
171
|
+
contract = None
|
|
172
|
+
namef = "all"
|
|
173
|
+
else:
|
|
174
|
+
contract = Contract.get_dc_by_id(sess, contract_id)
|
|
175
|
+
namef = contract.name
|
|
176
|
+
|
|
177
|
+
f = open_file(f"channel_snags_{namef}.csv", user, mode="w", newline="")
|
|
178
|
+
writer = csv.writer(f, lineterminator="\n")
|
|
179
|
+
titles = (
|
|
180
|
+
"contract",
|
|
181
|
+
"hidden_days",
|
|
182
|
+
"chellow_ids",
|
|
183
|
+
"imp_mpan_core",
|
|
184
|
+
"exp_mpan_core",
|
|
185
|
+
"site_code",
|
|
186
|
+
"site_name",
|
|
187
|
+
"snag_description",
|
|
188
|
+
"channel_types",
|
|
189
|
+
"start_date",
|
|
190
|
+
"finish_date",
|
|
191
|
+
"is_ignored",
|
|
192
|
+
"days_since_finished",
|
|
193
|
+
"duration",
|
|
194
|
+
)
|
|
195
|
+
writer.writerow(titles)
|
|
196
|
+
|
|
197
|
+
for snag_group in _make_rows(
|
|
198
|
+
sess,
|
|
199
|
+
now,
|
|
200
|
+
contract,
|
|
201
|
+
days_hidden,
|
|
202
|
+
is_ignored,
|
|
203
|
+
show_settlement,
|
|
204
|
+
only_ongoing,
|
|
205
|
+
days_long_hidden,
|
|
206
|
+
):
|
|
207
|
+
|
|
208
|
+
vals = {
|
|
209
|
+
"contract": snag_group["contract"].name,
|
|
210
|
+
"hidden_days": days_hidden,
|
|
211
|
+
"chellow_ids": [snag.id for snag in snag_group["snags"]],
|
|
212
|
+
"imp_mpan_core": snag_group["imp_mpan_core"],
|
|
213
|
+
"exp_mpan_core": snag_group["exp_mpan_core"],
|
|
214
|
+
"site": snag_group["site"],
|
|
215
|
+
"site_code": snag_group["site"].code,
|
|
216
|
+
"site_name": snag_group["site"].name,
|
|
217
|
+
"snag_description": snag_group["description"],
|
|
218
|
+
"channel_types": [
|
|
219
|
+
f"{s.channel.imp_related}_{s.channel.channel_type}"
|
|
220
|
+
for s in snag_group["snags"]
|
|
221
|
+
],
|
|
222
|
+
"start_date": snag_group["start_date"],
|
|
223
|
+
"finish_date": snag_group["finish_date"],
|
|
224
|
+
"is_ignored": snag_group["is_ignored"],
|
|
225
|
+
"days_since_finished": snag_group["days_since_finished"],
|
|
226
|
+
"duration": snag_group["duration"],
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
writer.writerow(csv_make_val(vals[t]) for t in titles)
|
|
230
|
+
except BaseException:
|
|
231
|
+
msg = traceback.format_exc()
|
|
232
|
+
sys.stderr.write(msg)
|
|
233
|
+
writer.writerow([msg])
|
|
234
|
+
finally:
|
|
235
|
+
if f is not None:
|
|
236
|
+
f.close()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
LIMIT = 200
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def do_get(sess):
|
|
243
|
+
contract_id = req_int_none("dc_contract_id")
|
|
244
|
+
days_hidden = req_int("days_hidden")
|
|
245
|
+
is_ignored = req_bool("is_ignored")
|
|
246
|
+
only_ongoing = req_bool("only_ongoing")
|
|
247
|
+
show_settlement = req_str("show_settlement")
|
|
248
|
+
as_csv = req_bool("as_csv")
|
|
249
|
+
days_long_hidden = req_int_none("days_long_hidden")
|
|
250
|
+
if "now_year" in request.values:
|
|
251
|
+
now = req_date("now")
|
|
252
|
+
else:
|
|
253
|
+
now = utc_datetime_now()
|
|
254
|
+
|
|
255
|
+
if as_csv:
|
|
256
|
+
args = (
|
|
257
|
+
contract_id,
|
|
258
|
+
days_hidden,
|
|
259
|
+
is_ignored,
|
|
260
|
+
g.user.id,
|
|
261
|
+
only_ongoing,
|
|
262
|
+
show_settlement,
|
|
263
|
+
now,
|
|
264
|
+
)
|
|
265
|
+
threading.Thread(target=content, args=args).start()
|
|
266
|
+
return redirect("/downloads", 303)
|
|
267
|
+
else:
|
|
268
|
+
if contract_id is None:
|
|
269
|
+
contract = None
|
|
270
|
+
else:
|
|
271
|
+
contract = Contract.get_dc_by_id(sess, contract_id)
|
|
272
|
+
now = utc_datetime_now()
|
|
273
|
+
snag_groups = _make_rows(
|
|
274
|
+
sess,
|
|
275
|
+
now,
|
|
276
|
+
contract,
|
|
277
|
+
days_hidden,
|
|
278
|
+
is_ignored,
|
|
279
|
+
show_settlement,
|
|
280
|
+
only_ongoing,
|
|
281
|
+
days_long_hidden,
|
|
282
|
+
limit=LIMIT,
|
|
283
|
+
)
|
|
284
|
+
return render_template(
|
|
285
|
+
"reports/channel_snags.html",
|
|
286
|
+
contract=contract,
|
|
287
|
+
limit=LIMIT,
|
|
288
|
+
snag_groups=snag_groups,
|
|
289
|
+
days_hidden=days_hidden,
|
|
290
|
+
is_ignored=is_ignored,
|
|
291
|
+
only_ongoing=only_ongoing,
|
|
292
|
+
show_settlement=show_settlement,
|
|
293
|
+
days_long_hidden=days_long_hidden,
|
|
294
|
+
)
|
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
Channel Snags
|
|
9
9
|
{% endblock %}
|
|
10
10
|
|
|
11
|
+
{% block inside_head %}
|
|
12
|
+
<style>
|
|
13
|
+
#snags.htmx-swapping {
|
|
14
|
+
opacity: 0;
|
|
15
|
+
transition: opacity 1s ease-out;
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
18
|
+
{% endblock %}
|
|
19
|
+
|
|
11
20
|
{% block nav %}
|
|
12
21
|
<a href="/e/dc_contracts">DC Contracts</a> »
|
|
13
22
|
{% if contract %}
|
|
@@ -17,113 +26,36 @@
|
|
|
17
26
|
{% endblock %}
|
|
18
27
|
|
|
19
28
|
{% block content %}
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
<form hx-get="/reports/channel_snags" hx-params="*" hx-include="this" hx-trigger="load, change"
|
|
30
|
+
hx-target="#snags" hx-swap="outerHTML swap:1s">
|
|
22
31
|
<fieldset>
|
|
23
|
-
<legend>
|
|
32
|
+
<legend>Filters</legend>
|
|
24
33
|
<input type="hidden" name="dc_contract_id" value="{{contract.id}}">
|
|
25
34
|
<label>Hide snags < days old</label>
|
|
26
|
-
|
|
35
|
+
{{input_text('days_hidden', initial='5', size=3, maxlength=3)}}
|
|
27
36
|
<label>Include ignored snags</label> {{input_checkbox('is_ignored', False)}}
|
|
28
|
-
<input type="submit" value="Download">
|
|
29
|
-
</fieldset>
|
|
30
|
-
</form>
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
finish date is 'ongoing' or if it finished less than 'Days Hidden' ago).
|
|
35
|
-
</p>
|
|
38
|
+
<label>Only show ongoing snags</label>
|
|
39
|
+
{{input_checkbox('only_ongoing', initial=True)}}
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
">
|
|
45
|
-
<label>Hide snags < days old</label>
|
|
46
|
-
{{input_text('days_hidden', '0', 3, 3)}}
|
|
47
|
-
<label>Include ignored snags</label> {{input_checkbox('is_ignored', False)}}
|
|
48
|
-
<input type="submit" value="Show">
|
|
49
|
-
</fieldset>
|
|
50
|
-
</form>
|
|
41
|
+
<fieldset>
|
|
42
|
+
|
|
43
|
+
<label>Show settlement only</label>
|
|
44
|
+
{{input_radio('show_settlement', 'yes', initial=False)}}
|
|
45
|
+
|
|
46
|
+
<label>Show non-settlement only</label>
|
|
47
|
+
{{input_radio('show_settlement', 'no', initial=False)}}
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{%- if not is_ignored %}
|
|
55
|
-
that aren't ignored
|
|
56
|
-
{%- endif -%}.
|
|
57
|
-
</p>
|
|
49
|
+
<label>Show both</label>
|
|
50
|
+
{{input_radio('show_settlement', 'both', initial=True)}}
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
<th>Export MPAN Core</th>
|
|
67
|
-
<th>Sites</th>
|
|
68
|
-
<th>Snag Description</th>
|
|
69
|
-
<th>Channels</th>
|
|
70
|
-
<th>Duration</th>
|
|
71
|
-
</tr>
|
|
72
|
-
</thead>
|
|
73
|
-
<tbody>
|
|
74
|
-
{% for snag_group in snag_groups %}
|
|
75
|
-
<tr>
|
|
76
|
-
<td>
|
|
77
|
-
<ul>
|
|
78
|
-
{% for snag in snag_group.snags %}
|
|
79
|
-
<li>
|
|
80
|
-
<a href="/e/channel_snags/{{snag.id}}">view</a>
|
|
81
|
-
[<a href="/e/channel_snags/{{snag.id}}/edit">edit</a>]
|
|
82
|
-
{% if snag.is_ignored %} ignored{% endif %}
|
|
83
|
-
</li>
|
|
84
|
-
{% endfor %}
|
|
85
|
-
</ul>
|
|
86
|
-
</td>
|
|
87
|
-
<td>{{snag_group.era.dc_contract.name}}</td>
|
|
88
|
-
<td>
|
|
89
|
-
{% if snag_group.era.imp_mpan_core %}
|
|
90
|
-
{{snag_group.era.imp_mpan_core}}
|
|
91
|
-
{% endif %}
|
|
92
|
-
</td>
|
|
93
|
-
<td>
|
|
94
|
-
{% if snag_group.era.exp_mpan_core %}
|
|
95
|
-
{{snag_group.era.exp_mpan_core}}
|
|
96
|
-
{% endif %}
|
|
97
|
-
</td>
|
|
98
|
-
<td>
|
|
99
|
-
<ul>
|
|
100
|
-
{% for site in snag_group.sites %}
|
|
101
|
-
<li>{{site.code}} {{site.name}}</li>
|
|
102
|
-
{% endfor %}
|
|
103
|
-
</ul>
|
|
104
|
-
</td>
|
|
105
|
-
<td>{{snag_group.description}}</td>
|
|
106
|
-
<td>
|
|
107
|
-
<ul>
|
|
108
|
-
{% for snag in snag_group.snags %}
|
|
109
|
-
<li>
|
|
110
|
-
{% if snag.channel.imp_related %}
|
|
111
|
-
Import
|
|
112
|
-
{% else %}
|
|
113
|
-
Export
|
|
114
|
-
{% endif %}
|
|
115
|
-
{{snag.channel.channel_type}}
|
|
116
|
-
</li>
|
|
117
|
-
{% endfor %}
|
|
118
|
-
</ul>
|
|
119
|
-
</td>
|
|
120
|
-
<td>
|
|
121
|
-
{{snag_group.start_date|hh_format}} to
|
|
122
|
-
{{snag_group.finish_date|hh_format}}
|
|
123
|
-
</td>
|
|
124
|
-
</tr>
|
|
125
|
-
{% endfor %}
|
|
126
|
-
</tbody>
|
|
127
|
-
</table>
|
|
52
|
+
</fieldset>
|
|
53
|
+
|
|
54
|
+
<label>Hide snags < days long</label>
|
|
55
|
+
{{input_text('days_long_hidden', initial='', size=3, maxlength=3)}}
|
|
56
|
+
|
|
57
|
+
</fieldset>
|
|
58
|
+
</form>
|
|
128
59
|
|
|
60
|
+
<div id="snags"></div>
|
|
129
61
|
{% endblock %}
|
|
@@ -12,41 +12,29 @@
|
|
|
12
12
|
|
|
13
13
|
{% block content %}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{% endfor %}
|
|
34
|
-
</select>
|
|
35
|
-
<label>Name</label>
|
|
36
|
-
{{input_text('name', contract.name)}}
|
|
37
|
-
<label>Charge script</label>
|
|
38
|
-
{{input_textarea('charge_script', contract.charge_script, 40, 80)}}
|
|
39
|
-
<label>Properties</label>
|
|
40
|
-
{{input_textarea('properties', contract.properties, 20, 80)}}
|
|
41
|
-
<input type="submit" value="Update">
|
|
42
|
-
</fieldset>
|
|
43
|
-
</form>
|
|
15
|
+
<form method="post">
|
|
16
|
+
<fieldset>
|
|
17
|
+
<legend>Update Contract</legend>
|
|
18
|
+
<label>Party</label>
|
|
19
|
+
<select name="party_id">
|
|
20
|
+
{% for party in parties %}
|
|
21
|
+
{{ input_option('party_id', party.id, party.participant.code + ' : ' + party.name, contract.party.id) }}
|
|
22
|
+
{% endfor %}
|
|
23
|
+
</select>
|
|
24
|
+
<label>Name</label>
|
|
25
|
+
{{input_text('name', contract.name)}}
|
|
26
|
+
<label>Charge script</label>
|
|
27
|
+
{{input_textarea('charge_script', contract.charge_script, 40, 80, show_pos=True)}}
|
|
28
|
+
<label>Properties</label>
|
|
29
|
+
{{input_textarea('properties', contract.properties, 20, 80)}}
|
|
30
|
+
<input type="submit" value="Update">
|
|
31
|
+
</fieldset>
|
|
32
|
+
</form>
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{% endif %}
|
|
34
|
+
<form hx-delete="/e/supplier_contracts/{{contract.id}}/edit" hx-confirm="Are you sure you want to delete this contract?">
|
|
35
|
+
<fieldset>
|
|
36
|
+
<legend>Delete this contract</legend>
|
|
37
|
+
<input type="submit" name="delete" value="Delete">
|
|
38
|
+
</fieldset>
|
|
39
|
+
</form>
|
|
52
40
|
{% endblock %}
|
|
@@ -14,52 +14,37 @@
|
|
|
14
14
|
{% endblock %}
|
|
15
15
|
|
|
16
16
|
{% block content %}
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
action="/e/supplier_rate_scripts/{{supplier_rate_script.id}}/edit">
|
|
21
|
-
<fieldset>
|
|
22
|
-
<legend>Are you sure you want to delete this rate script?</legend>
|
|
23
|
-
<input type="submit" name="delete" value="Delete">
|
|
24
|
-
<a href="/supplier_rate_scripts/{{supplier_rate_script.id}}/edit">Cancel</a>
|
|
25
|
-
</fieldset>
|
|
26
|
-
</form>
|
|
27
|
-
|
|
28
|
-
{% else %}
|
|
29
|
-
|
|
30
|
-
<form action="" method="post">
|
|
17
|
+
<form action="/e/supplier_rate_scripts/{{supplier_rate_script.id}}/edit" method="post">
|
|
18
|
+
<fieldset>
|
|
19
|
+
<legend>Update Rate Script</legend>
|
|
31
20
|
<fieldset>
|
|
32
|
-
<legend>
|
|
33
|
-
|
|
34
|
-
<legend>Start date</legend>
|
|
35
|
-
{{ input_date('start', supplier_rate_script.start_date) }}
|
|
36
|
-
</fieldset>
|
|
37
|
-
<fieldset>
|
|
38
|
-
<legend>Finish date</legend>
|
|
39
|
-
<label>
|
|
40
|
-
Ended?
|
|
41
|
-
{{input_checkbox('has_finished', supplier_rate_script.finish_date != None)}}
|
|
42
|
-
</label>
|
|
43
|
-
{{ input_date('finish', supplier_rate_script.finish_date) }}
|
|
44
|
-
</fieldset>
|
|
45
|
-
<label>Script</label>
|
|
46
|
-
{{ input_textarea(
|
|
47
|
-
'script', supplier_rate_script.script, 40, 80, show_pos=True) }}
|
|
48
|
-
<input type="submit" value="Update">
|
|
21
|
+
<legend>Start date</legend>
|
|
22
|
+
{{ input_date('start', supplier_rate_script.start_date) }}
|
|
49
23
|
</fieldset>
|
|
50
|
-
</form>
|
|
51
|
-
|
|
52
|
-
{% if rate_script_example %}
|
|
53
|
-
<h4>Example</h4>
|
|
54
|
-
<pre>{{rate_script_example}}</pre>
|
|
55
|
-
{% endif %}
|
|
56
|
-
|
|
57
|
-
<form>
|
|
58
24
|
<fieldset>
|
|
59
|
-
<legend>
|
|
60
|
-
<
|
|
25
|
+
<legend>Finish date</legend>
|
|
26
|
+
<label>
|
|
27
|
+
Ended?
|
|
28
|
+
{{input_checkbox('has_finished', supplier_rate_script.finish_date != None)}}
|
|
29
|
+
</label>
|
|
30
|
+
{{ input_date('finish', supplier_rate_script.finish_date) }}
|
|
61
31
|
</fieldset>
|
|
62
|
-
|
|
63
|
-
|
|
32
|
+
<label>Script</label>
|
|
33
|
+
{{ input_textarea(
|
|
34
|
+
'script', supplier_rate_script.script, 40, 80, show_pos=True) }}
|
|
35
|
+
<input type="submit" value="Update">
|
|
36
|
+
</fieldset>
|
|
37
|
+
</form>
|
|
38
|
+
|
|
39
|
+
{% if rate_script_example %}
|
|
40
|
+
<h4>Example</h4>
|
|
41
|
+
<pre>{{rate_script_example}}</pre>
|
|
64
42
|
{% endif %}
|
|
43
|
+
|
|
44
|
+
<form hx-delete="/e/supplier_rate_scripts/{{supplier_rate_script.id}}/edit" hx-confirm="Are you sure you want to delete this rate script?">
|
|
45
|
+
<fieldset>
|
|
46
|
+
<legend>Delete this Rate Script</legend>
|
|
47
|
+
<input type="submit" name="delete" value="Delete">
|
|
48
|
+
</fieldset>
|
|
49
|
+
</form>
|
|
65
50
|
{% endblock %}
|
chellow/templates/macros.html
CHANGED
|
@@ -124,13 +124,23 @@
|
|
|
124
124
|
</div>
|
|
125
125
|
{%- endmacro -%}
|
|
126
126
|
|
|
127
|
-
{%- macro input_checkbox(name, initial) %}
|
|
128
|
-
<input type="checkbox" name="{{ name }}" value="
|
|
127
|
+
{%- macro input_checkbox(name, initial=False, value='true') %}
|
|
128
|
+
<input type="checkbox" name="{{ name }}" value="{{value}}"
|
|
129
129
|
{%- if request.values[name] -%}
|
|
130
|
-
{%- if request.values[name] ==
|
|
130
|
+
{%- if request.values[name] == value %} checked
|
|
131
131
|
{%- endif -%}
|
|
132
132
|
{%- else -%}
|
|
133
|
-
{%- if initial
|
|
133
|
+
{%- if initial %} checked{% endif -%}
|
|
134
|
+
{%- endif -%}>
|
|
135
|
+
{%- endmacro -%}
|
|
136
|
+
|
|
137
|
+
{%- macro input_radio(name, value, initial=False) %}
|
|
138
|
+
<input type="radio" name="{{ name }}" value="{{value}}"
|
|
139
|
+
{%- if request.values[name] -%}
|
|
140
|
+
{%- if request.values[name] == value %} checked
|
|
141
|
+
{%- endif -%}
|
|
142
|
+
{%- else -%}
|
|
143
|
+
{%- if initial %} checked{% endif -%}
|
|
134
144
|
{%- endif -%}>
|
|
135
145
|
{%- endmacro -%}
|
|
136
146
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{% extends "macros.html" %}
|
|
2
|
+
|
|
3
|
+
{% block html %}
|
|
4
|
+
<table class="sticky" id="snags">
|
|
5
|
+
<caption>
|
|
6
|
+
Snags (truncated after 200)
|
|
7
|
+
<a href="/reports/channel_snags?dc_contract_id={{contract.id}}&days_hidden={{days_hidden}}&is_ignored={{is_ignored}}&only_ongoing={{only_ongoing}}&show_settlement={{show_settlement}}&as_csv=true">Download as CSV</a>
|
|
8
|
+
</caption>
|
|
9
|
+
<thead>
|
|
10
|
+
<tr>
|
|
11
|
+
<th>View</th>
|
|
12
|
+
<th>Contract</th>
|
|
13
|
+
<th>Import MPAN Core</th>
|
|
14
|
+
<th>Export MPAN Core</th>
|
|
15
|
+
<th>Site</th>
|
|
16
|
+
<th>Description</th>
|
|
17
|
+
<th>Channels</th>
|
|
18
|
+
<th>Start Date</th>
|
|
19
|
+
<th>Finish Date</th>
|
|
20
|
+
<th>
|
|
21
|
+
<span title="Blank if the snag is ongoing (ie. if the finish date is 'ongoing' or if it finished less than 'Days Hidden' ago).">Days Since Finished</span>
|
|
22
|
+
</th>
|
|
23
|
+
<th>Duration</th>
|
|
24
|
+
<th>Comm</th>
|
|
25
|
+
</tr>
|
|
26
|
+
</thead>
|
|
27
|
+
<tbody>
|
|
28
|
+
{% for snag_group in snag_groups %}
|
|
29
|
+
<tr>
|
|
30
|
+
<td>
|
|
31
|
+
<ul>
|
|
32
|
+
{% for snag in snag_group.snags %}
|
|
33
|
+
<li>
|
|
34
|
+
<a href="/e/channel_snags/{{snag.id}}">view</a>
|
|
35
|
+
[<a href="/e/channel_snags/{{snag.id}}/edit">edit</a>]
|
|
36
|
+
{% if snag.is_ignored %} ignored{% endif %}
|
|
37
|
+
</li>
|
|
38
|
+
{% endfor %}
|
|
39
|
+
</ul>
|
|
40
|
+
</td>
|
|
41
|
+
<td>
|
|
42
|
+
<a href="/e/dc_contracts/{{snag_group.contract.id}}">{{snag_group.contract.name}}</a>
|
|
43
|
+
</td>
|
|
44
|
+
<td>
|
|
45
|
+
{% if snag_group.era.imp_mpan_core %}
|
|
46
|
+
<a href="/e/supplies/{{snag_group.supply.id}}">{{snag_group.era.imp_mpan_core}}</a>
|
|
47
|
+
{% endif %}
|
|
48
|
+
</td>
|
|
49
|
+
<td>
|
|
50
|
+
{% if snag_group.era.exp_mpan_core %}
|
|
51
|
+
<a href="/e/supplies/{{snag_group.supply.id}}">{{snag_group.era.exp_mpan_core}}</a>
|
|
52
|
+
{% endif %}
|
|
53
|
+
</td>
|
|
54
|
+
<td>
|
|
55
|
+
<a href="/sites/{{snag_group.site.id}}">{{snag_group.site.code}} {{snag_group.site.name}}</a>
|
|
56
|
+
</td>
|
|
57
|
+
<td>{{snag_group.description}}</td>
|
|
58
|
+
<td>
|
|
59
|
+
<ul>
|
|
60
|
+
{% for snag in snag_group.snags %}
|
|
61
|
+
<li>
|
|
62
|
+
{% if snag.channel.imp_related %}
|
|
63
|
+
Import
|
|
64
|
+
{% else %}
|
|
65
|
+
Export
|
|
66
|
+
{% endif %}
|
|
67
|
+
{{snag.channel.channel_type}}
|
|
68
|
+
</li>
|
|
69
|
+
{% endfor %}
|
|
70
|
+
</ul>
|
|
71
|
+
</td>
|
|
72
|
+
<td>
|
|
73
|
+
{{snag_group.start_date|hh_format}}
|
|
74
|
+
</td>
|
|
75
|
+
<td>
|
|
76
|
+
{{snag_group.finish_date|hh_format}}
|
|
77
|
+
</td>
|
|
78
|
+
<td>
|
|
79
|
+
{% if snag_group.days_since_finished %}
|
|
80
|
+
{{snag_group.days_since_finished}}
|
|
81
|
+
{% endif %}
|
|
82
|
+
</td>
|
|
83
|
+
<td>{{snag_group.duration}}</td>
|
|
84
|
+
<td>
|
|
85
|
+
<a href="/e/comms/{{snag_group.era.comm.id}}" title="{{snag_group.era.comm.description}}">{{snag_group.era.comm.code}}</a>
|
|
86
|
+
</td>
|
|
87
|
+
</tr>
|
|
88
|
+
{% endfor %}
|
|
89
|
+
</tbody>
|
|
90
|
+
</table>
|
|
91
|
+
{% endblock %}
|
chellow/utils.py
CHANGED
|
@@ -29,11 +29,15 @@ def req_str(name):
|
|
|
29
29
|
raise BadRequest(f"The field {name} is required.")
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def req_strs(name):
|
|
33
33
|
try:
|
|
34
|
-
return request.values
|
|
34
|
+
return request.values.getlist(name)
|
|
35
35
|
except KeyError:
|
|
36
|
-
|
|
36
|
+
raise BadRequest(f"The field {name} is required.")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def req_bool(name):
|
|
40
|
+
return name in request.values
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
def req_int(name):
|
|
@@ -43,6 +47,13 @@ def req_int(name):
|
|
|
43
47
|
raise BadRequest(f"Problem parsing the field {name} as an integer: {e}")
|
|
44
48
|
|
|
45
49
|
|
|
50
|
+
def req_ints(name):
|
|
51
|
+
try:
|
|
52
|
+
return [int(v) for v in req_strs(name)]
|
|
53
|
+
except ValueError as e:
|
|
54
|
+
raise BadRequest(f"Problem parsing the field {name} as an integer: {e}")
|
|
55
|
+
|
|
56
|
+
|
|
46
57
|
def req_int_none(name):
|
|
47
58
|
val = req_str(name)
|
|
48
59
|
if val == "":
|
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chellow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 1761297878.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)
|
|
7
7
|
Classifier: Operating System :: OS Independent
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Requires-Python: >=3.11
|
|
10
|
-
Requires-Dist: flask-restx==1.3.
|
|
11
|
-
Requires-Dist: flask==3.1.
|
|
12
|
-
Requires-Dist: jsonschema==4.17.3
|
|
10
|
+
Requires-Dist: flask-restx==1.3.2
|
|
11
|
+
Requires-Dist: flask==3.1.2
|
|
13
12
|
Requires-Dist: odio==0.0.23
|
|
14
13
|
Requires-Dist: openpyxl==3.1.5
|
|
15
|
-
Requires-Dist: paramiko==
|
|
16
|
-
Requires-Dist: pep3143daemon==0.1.0
|
|
14
|
+
Requires-Dist: paramiko==4.0.0
|
|
17
15
|
Requires-Dist: pg8000==1.31.5
|
|
18
16
|
Requires-Dist: pip>=9.0.1
|
|
19
|
-
Requires-Dist: psutil==
|
|
20
|
-
Requires-Dist: pympler==1.
|
|
21
|
-
Requires-Dist: pypdf==6.
|
|
17
|
+
Requires-Dist: psutil==7.1.1
|
|
18
|
+
Requires-Dist: pympler==1.1
|
|
19
|
+
Requires-Dist: pypdf==6.1.3
|
|
22
20
|
Requires-Dist: python-dateutil==2.8.2
|
|
23
|
-
Requires-Dist: pytz==
|
|
24
|
-
Requires-Dist: requests==2.32.
|
|
25
|
-
Requires-Dist: sqlalchemy==2.0.
|
|
26
|
-
Requires-Dist: waitress==3.0.
|
|
27
|
-
Requires-Dist: xlrd==2.0.
|
|
21
|
+
Requires-Dist: pytz==2025.2
|
|
22
|
+
Requires-Dist: requests==2.32.5
|
|
23
|
+
Requires-Dist: sqlalchemy==2.0.44
|
|
24
|
+
Requires-Dist: waitress==3.0.2
|
|
25
|
+
Requires-Dist: xlrd==2.0.2
|
|
28
26
|
Requires-Dist: zish==0.1.12
|
|
29
27
|
Description-Content-Type: text/markdown
|
|
30
28
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
chellow/__init__.py,sha256=9aoSbGmHCIHwzI_c_TLSg5CeKwqAq0I6kKaMvTrTMqg,10936
|
|
2
2
|
chellow/api.py,sha256=mk17TfweR76DPFC8lX2SArTjai6y6YshASxqO1w-_-s,11036
|
|
3
3
|
chellow/bank_holidays.py,sha256=T_utYMwe_g1dz5X-aOTdIPryg49SvB7QsWM1yphlqG8,4423
|
|
4
|
-
chellow/
|
|
5
|
-
chellow/dloads.py,sha256=dixp-O0MF2_mlwrnKx3D9DH09Qu05BjTo0rZfigTjR4,5534
|
|
4
|
+
chellow/dloads.py,sha256=sNAPMe4LeHqfisEubGXvraDsUS0F-ujI3WG0Md8DywM,5565
|
|
6
5
|
chellow/edi_lib.py,sha256=Lq70TUJuogoP5KGrphzUEUfyfgftEclg_iA3mpNAaDI,51324
|
|
7
6
|
chellow/fake_batch_updater.py,sha256=khAmvSUn9qN04w8C92kRg1UeyQvfLztE7QXv9tUz6nE,11611
|
|
8
7
|
chellow/general_import.py,sha256=ghybbden66VT4q5J0vYwiNg-6G2vg71EgCN_x3fvhW0,69200
|
|
@@ -12,7 +11,7 @@ chellow/proxy.py,sha256=cVXIktPlX3tQ1BYcwxq0nJXKE6r3DtFTtfFHPq55HaM,1351
|
|
|
12
11
|
chellow/rate_server.py,sha256=RwJo-AzBIdzxx7PAtboZEUH1nUjAeJckw0bk06-9oyM,5672
|
|
13
12
|
chellow/rrun.py,sha256=sWm_tuJ_6xH3T28TY1w63k1Q44N_S_p_pYF5YCeztqU,2226
|
|
14
13
|
chellow/testing.py,sha256=Dj2c1NX8lVlygueOrh2eyYawLW6qKEHxNhXVVUaNRO0,3637
|
|
15
|
-
chellow/utils.py,sha256=
|
|
14
|
+
chellow/utils.py,sha256=x6yReQkhFaFGnsuhs6PqrEkE1OfZSPrrC7IqstRXKKU,19701
|
|
16
15
|
chellow/views.py,sha256=9IUUbYjqEmQQzbYQB4w-ygCo25gecIxYVbxTXRF-YfY,86078
|
|
17
16
|
chellow/e/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
17
|
chellow/e/aahedc.py,sha256=d2usudp7KYWpU6Pk3fal5EQ47EbvkvKeaFGylnb3NWw,606
|
|
@@ -45,7 +44,7 @@ chellow/e/system_price.py,sha256=6w5J7bzwFAZubE2zdOFRiS8IIrVP8hkoIOaG2yCt-Ic,623
|
|
|
45
44
|
chellow/e/tlms.py,sha256=pyL32hPiYd09FbpXVMnBjHsWFEQHs-Az945V7EShGiY,9116
|
|
46
45
|
chellow/e/tnuos.py,sha256=NBmc-f3oezrl4gviAKobljHfICTpBKxxxEGBGJi_lRk,4927
|
|
47
46
|
chellow/e/triad.py,sha256=uQIngSrz8irBXQ0Rp_s8nAUzu-y2Ms7aj4B38_Ff8y8,13720
|
|
48
|
-
chellow/e/views.py,sha256=
|
|
47
|
+
chellow/e/views.py,sha256=Duvdp5ZjtCHnOrAyk7uZZJr0jZcg0F2h3g1XNN25HtU,234669
|
|
49
48
|
chellow/e/bill_parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
49
|
chellow/e/bill_parsers/activity_mop_stark_xlsx.py,sha256=hcbjxqLOe7qkDjS7enCpmfyGwm3d-pq3u5VQIaUmVTw,3796
|
|
51
50
|
chellow/e/bill_parsers/annual_mop_stark_xlsx.py,sha256=yoEGQS0qcrv3TWFfxELIIi8f1CyKcIzh0xVaPoz2w2s,4191
|
|
@@ -86,9 +85,8 @@ chellow/reports/report_183.py,sha256=fGONpKEIXTqIT_3dE5jZKBIesWPgLq-chHO6X22dIv0
|
|
|
86
85
|
chellow/reports/report_187.py,sha256=RCvxDnkfRu7ocKUPEX0qtVphGOBEl9RULy790uteXcQ,9915
|
|
87
86
|
chellow/reports/report_219.py,sha256=3Zs16ka6dWWY_lCDoA-ZFrlPb4vHk1LQoa2yrlTMntA,7117
|
|
88
87
|
chellow/reports/report_231.py,sha256=WARLztV2HzBFSi5_xvY_DTXVyuBBbBYiU0RazfjKw-Y,5270
|
|
89
|
-
chellow/reports/report_233.py,sha256=qJdPFuBgQAWD24BsljgGJ44L_RGdHOA1RqsxGjTWhFc,4975
|
|
90
88
|
chellow/reports/report_241.py,sha256=lfivElRkV_CZAhck0rxAuhqzgponj3aWwmwGMNQvUxg,5343
|
|
91
|
-
chellow/reports/report_247.py,sha256=
|
|
89
|
+
chellow/reports/report_247.py,sha256=pbWfM-fUeuakZxH1Ovlx7-XfUg6SL9t51swK3yMc1lc,43253
|
|
92
90
|
chellow/reports/report_29.py,sha256=ZXnq6Kg5on-IPquUsH4bn46mBVESY_WhwqDWZPXOJwo,2695
|
|
93
91
|
chellow/reports/report_291.py,sha256=BnWtxe0eWN2QKKWpwjs5-RI5LbReBKL119QbkrkNhV8,7478
|
|
94
92
|
chellow/reports/report_33.py,sha256=lt1EN_LNx6u-AgdaS3YRkPMZA33JgMcELolHF4oJUMw,16689
|
|
@@ -101,6 +99,7 @@ chellow/reports/report_87.py,sha256=udzbCuXcckWD-OHmfJCT6bwg_paYhm4vfDWlL8WM-jA,
|
|
|
101
99
|
chellow/reports/report_asset_comparison.py,sha256=Cl2NgvbclqhOVvKuUu3sajTVO2JupMfzK3bV0_K8eNs,6077
|
|
102
100
|
chellow/reports/report_batches.py,sha256=MoCv2dE-JgaJzaMjMA-kZrPkYR13uDoXer5UuF12OYc,4757
|
|
103
101
|
chellow/reports/report_bills.py,sha256=LP7XDxzO0Fp10c8xDE67e4tHTEc7nN74ESQBy762Nx4,3401
|
|
102
|
+
chellow/reports/report_channel_snags.py,sha256=qBVmw0q588izKJr6dDOn7jjdFvSa-Ldd2uqtVETqijY,8748
|
|
104
103
|
chellow/reports/report_csv_llfcs.py,sha256=mMB06b6Jems5kcQU4H4Le_fyKgVr8THP8BCx3pkvg5E,1903
|
|
105
104
|
chellow/reports/report_csv_site_hh_data.py,sha256=ik0OkGVo1bfTXLdcT3gPUHnxSkSdorzZheP3qgnOR5c,4331
|
|
106
105
|
chellow/reports/report_csv_site_snags.py,sha256=AuAy6vjL0g7vwPPAZhBqxOyITL9_jnyFj012MnUcxxk,2627
|
|
@@ -134,7 +133,7 @@ chellow/templates/home.html,sha256=7xiD6QLju3ugALzMlzTJosRyMUmQGWPK6jDF7oZbnAQ,5
|
|
|
134
133
|
chellow/templates/input_date.html,sha256=rpgB5n0LfN8Y5djN_ZiuSxqdskxzCoKrEqI7hyJkVQo,1248
|
|
135
134
|
chellow/templates/local_report.html,sha256=pV7_0QwyQ-D3OS9LXrly5pq3qprZnwTCoq6vCnMTkS4,1332
|
|
136
135
|
chellow/templates/local_reports.html,sha256=4wbfVkY4wUfSSfWjxqIsvCpIsa9k7H_dGAjznrG5jNM,701
|
|
137
|
-
chellow/templates/macros.html,sha256=
|
|
136
|
+
chellow/templates/macros.html,sha256=FlRTl9W2avRXErnS3vzeOxciGXJYoKptiR08iVmSpfw,5353
|
|
138
137
|
chellow/templates/national_grid.html,sha256=8W92tsjlqPSB0J--nyFIi-wzFae9CyDr6fODXLZp8ic,991
|
|
139
138
|
chellow/templates/non_core_auto_importer.html,sha256=s9SluRN1bHTHjd8GP6uFhk6LrZYG8dqBG3y94zUKe5Q,944
|
|
140
139
|
chellow/templates/non_core_contract.html,sha256=BdGtxErTvw4DwXLb6B2vimuU6ode3fFA-90kBmHCwYc,1754
|
|
@@ -181,7 +180,7 @@ chellow/templates/e/channel_add.html,sha256=szwQJBHx2kAoSFomXDHD0N_7PSd4drqOoAWh
|
|
|
181
180
|
chellow/templates/e/channel_edit.html,sha256=OUkdiS2NBQ_w4gmxRxXAcRToM5BT8DWWJrtQMFs-GUU,2198
|
|
182
181
|
chellow/templates/e/channel_snag.html,sha256=wBJ5KBfeJdAeRmaB0qu0AD9Z4nM5fn6tJ_8bNqTWtoo,1477
|
|
183
182
|
chellow/templates/e/channel_snag_edit.html,sha256=sUFI4Ml3F1B35x8_t_Pz3hWuQN9Xtxr3kt4u8hdxNwY,1911
|
|
184
|
-
chellow/templates/e/channel_snags.html,sha256=
|
|
183
|
+
chellow/templates/e/channel_snags.html,sha256=TgRhS6DcOMyoAowwrCjPtq9iuX6lpvG3uchcd3g80kk,1593
|
|
185
184
|
chellow/templates/e/comm.html,sha256=DSlAaDg1r4KYq9VUgDtt2lgW6apZjZvwhMujIJINmps,383
|
|
186
185
|
chellow/templates/e/comms.html,sha256=bUXZePnMfpKk1E71qLGOSkx8r3GxdPPD_-MosIXXq4s,434
|
|
187
186
|
chellow/templates/e/cop.html,sha256=ULv7ALFJHMUgPX96hQNm2irc3edtKYHS6fYAxvmzj8M,376
|
|
@@ -336,14 +335,14 @@ chellow/templates/e/supplier_bill_import.html,sha256=RXvRkKoH-s1F_Wz---WygiNCmAm
|
|
|
336
335
|
chellow/templates/e/supplier_bill_import_contract.html,sha256=HySas6Q-1Pi6aZaEZNhKeK4c3d8MFbBIMh0PJ4zvKWQ,3117
|
|
337
336
|
chellow/templates/e/supplier_contract.html,sha256=jz3_2q5HuJaxQhJPaM_dcukigYyI6UmhVYC6nPHY7Ng,3243
|
|
338
337
|
chellow/templates/e/supplier_contract_add.html,sha256=gsozEtF24lzYi_Bb4LTenvh62tCt7dQ4CwaIz7rFck4,899
|
|
339
|
-
chellow/templates/e/supplier_contract_edit.html,sha256=
|
|
338
|
+
chellow/templates/e/supplier_contract_edit.html,sha256=PciQ91n1PB2-Z8vK4HIRiAc4tH3zwV17tnA-T6sRJu0,1226
|
|
340
339
|
chellow/templates/e/supplier_contracts.html,sha256=VwWD4q88Fynz7vioFSAsyH6RR_1SyQQl6bQwzL-W1m0,1508
|
|
341
340
|
chellow/templates/e/supplier_element.html,sha256=XQXvSVFISC3ZwCRurfpZbppFJgMhzbhqcwDYFT50bok,1370
|
|
342
341
|
chellow/templates/e/supplier_element_add.html,sha256=gSdn3X2BPUclPwbsuvQC-yIejaLykKFhJl_sC1kLB4s,1220
|
|
343
342
|
chellow/templates/e/supplier_element_edit.html,sha256=NrW51twKITht7w4qi8xrxivU3h-jcGpYySBuxq-L5XU,1846
|
|
344
343
|
chellow/templates/e/supplier_rate_script.html,sha256=tjWeCUAgNip3VLHzbXqe19Msiasys3Wm5Vra936qJjI,1245
|
|
345
344
|
chellow/templates/e/supplier_rate_script_add.html,sha256=Yf2LZEIHbL7qT6oxBCtPf0ZX7vJsSo_ZeOKJhJoVh3o,690
|
|
346
|
-
chellow/templates/e/supplier_rate_script_edit.html,sha256=
|
|
345
|
+
chellow/templates/e/supplier_rate_script_edit.html,sha256=Nt2bg78DCXiQpl2SAxIWjJx2nqljOtcqKVDkUnmO9_k,1695
|
|
347
346
|
chellow/templates/e/supply.html,sha256=kFyYPIzMgRZz7tHY_TfmjYzUkc1zXyaJses6X372Ozg,8427
|
|
348
347
|
chellow/templates/e/supply_edit.html,sha256=2BRGU35nb0ZpUHKCi_fgAPMU6SlHI7ve3_Ne8LXHtms,2333
|
|
349
348
|
chellow/templates/e/supply_eras.html,sha256=5lB7_oC-sTWRQoASuPgBWj5XSZa9ajR0s6V6xKHvf6E,19996
|
|
@@ -400,6 +399,7 @@ chellow/templates/g/supply_note_edit.html,sha256=b8mB6_ucBwoljp03iy6AgVaZUhGw3-1
|
|
|
400
399
|
chellow/templates/g/supply_notes.html,sha256=6epNmZ3NKdXZz27fvmRUGeffg_oc1kmwuBeyRzQe3Rg,854
|
|
401
400
|
chellow/templates/g/unit.html,sha256=KouNVU0-i84afANkLQ_heJ0uDfJ9H5A05PuLqb8iCN8,438
|
|
402
401
|
chellow/templates/g/units.html,sha256=p5Nd-lAIboKPEOO6N451hx1bcKxMg4BDODnZ-43MmJc,441
|
|
403
|
-
chellow
|
|
404
|
-
chellow-
|
|
405
|
-
chellow-
|
|
402
|
+
chellow/templates/reports/channel_snags.html,sha256=_aAgFgMlTkK2HuKFU8YisAIcUYfg6Hqhgyf5MZpdK8c,2629
|
|
403
|
+
chellow-1761297878.0.0.dist-info/METADATA,sha256=YJWJBO0S9POBAD-RG5IFnGyCsyecRLSoNm_xWroFfrw,12428
|
|
404
|
+
chellow-1761297878.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
405
|
+
chellow-1761297878.0.0.dist-info/RECORD,,
|
chellow/commands.py
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import os.path
|
|
3
|
-
import signal
|
|
4
|
-
import sys
|
|
5
|
-
import time
|
|
6
|
-
from os import environ
|
|
7
|
-
|
|
8
|
-
from pep3143daemon import DaemonContext, PidFile
|
|
9
|
-
|
|
10
|
-
import waitress
|
|
11
|
-
|
|
12
|
-
from chellow import create_app
|
|
13
|
-
|
|
14
|
-
app = create_app()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def chellow_start(daemon):
|
|
18
|
-
chellow_port = environ["CHELLOW_PORT"] if "CHELLOW_PORT" in environ else 80
|
|
19
|
-
daemon.open()
|
|
20
|
-
waitress.serve(app, host="0.0.0.0", port=chellow_port)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def chellow_stop(pidfile_path):
|
|
24
|
-
with open(pidfile_path) as pidfile:
|
|
25
|
-
pid = int(pidfile.read())
|
|
26
|
-
os.kill(pid, signal.SIGTERM)
|
|
27
|
-
while os.path.exists(pidfile_path):
|
|
28
|
-
time.sleep(1)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def chellow_command():
|
|
32
|
-
parser = argparse.ArgumentParser()
|
|
33
|
-
parser.add_argument("action", choices=["start", "stop", "restart"])
|
|
34
|
-
args = parser.parse_args()
|
|
35
|
-
|
|
36
|
-
try:
|
|
37
|
-
os.makedirs(app.instance_path)
|
|
38
|
-
except BaseException:
|
|
39
|
-
pass
|
|
40
|
-
pidfile_path = os.path.join(app.instance_path, "chellow.pid")
|
|
41
|
-
pidfile = PidFile(pidfile_path)
|
|
42
|
-
daemon = DaemonContext(
|
|
43
|
-
pidfile=pidfile, stdin=sys.stdin, stderr=sys.stderr, stdout=sys.stdout
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
if args.action == "start":
|
|
47
|
-
chellow_start(daemon)
|
|
48
|
-
elif args.action == "stop":
|
|
49
|
-
chellow_stop(pidfile_path)
|
|
50
|
-
elif args.action == "restart":
|
|
51
|
-
chellow_stop(pidfile_path)
|
|
52
|
-
chellow_start(daemon)
|
chellow/reports/report_233.py
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import csv
|
|
2
|
-
import sys
|
|
3
|
-
import threading
|
|
4
|
-
import traceback
|
|
5
|
-
|
|
6
|
-
from dateutil.relativedelta import relativedelta
|
|
7
|
-
|
|
8
|
-
from flask import g, redirect
|
|
9
|
-
|
|
10
|
-
from sqlalchemy.orm import joinedload
|
|
11
|
-
from sqlalchemy.sql.expression import false, select, true
|
|
12
|
-
|
|
13
|
-
from chellow.dloads import open_file
|
|
14
|
-
from chellow.models import (
|
|
15
|
-
Channel,
|
|
16
|
-
Contract,
|
|
17
|
-
Era,
|
|
18
|
-
Session,
|
|
19
|
-
Site,
|
|
20
|
-
SiteEra,
|
|
21
|
-
Snag,
|
|
22
|
-
Supply,
|
|
23
|
-
User,
|
|
24
|
-
)
|
|
25
|
-
from chellow.utils import (
|
|
26
|
-
csv_make_val,
|
|
27
|
-
hh_before,
|
|
28
|
-
req_bool,
|
|
29
|
-
req_int,
|
|
30
|
-
req_int_none,
|
|
31
|
-
utc_datetime_now,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def content(contract_id, days_hidden, is_ignored, user_id):
|
|
36
|
-
f = writer = None
|
|
37
|
-
try:
|
|
38
|
-
with Session() as sess:
|
|
39
|
-
user = User.get_by_id(sess, user_id)
|
|
40
|
-
if contract_id is None:
|
|
41
|
-
contract = None
|
|
42
|
-
namef = "all"
|
|
43
|
-
else:
|
|
44
|
-
contract = Contract.get_dc_by_id(sess, contract_id)
|
|
45
|
-
namef = "".join(x if x.isalnum() else "_" for x in contract.name)
|
|
46
|
-
|
|
47
|
-
f = open_file(f"channel_snags_{namef}.csv", user, mode="w", newline="")
|
|
48
|
-
writer = csv.writer(f, lineterminator="\n")
|
|
49
|
-
titles = (
|
|
50
|
-
"contract",
|
|
51
|
-
"Hidden Days",
|
|
52
|
-
"Chellow Id",
|
|
53
|
-
"Imp MPAN Core",
|
|
54
|
-
"Exp MPAN Core",
|
|
55
|
-
"Site Code",
|
|
56
|
-
"Site Name",
|
|
57
|
-
"Snag Description",
|
|
58
|
-
"Import Related?",
|
|
59
|
-
"Channel Type",
|
|
60
|
-
"Start Date",
|
|
61
|
-
"Finish Date",
|
|
62
|
-
"Is Ignored?",
|
|
63
|
-
"Days Since Snag Finished",
|
|
64
|
-
"Duration Of Snag (Days)",
|
|
65
|
-
)
|
|
66
|
-
writer.writerow(titles)
|
|
67
|
-
|
|
68
|
-
now = utc_datetime_now()
|
|
69
|
-
cutoff_date = now - relativedelta(days=days_hidden)
|
|
70
|
-
q = (
|
|
71
|
-
select(Snag, Channel, Era, Supply, SiteEra, Site)
|
|
72
|
-
.join(Channel, Snag.channel_id == Channel.id)
|
|
73
|
-
.join(Era, Channel.era_id == Era.id)
|
|
74
|
-
.join(Supply, Era.supply_id == Supply.id)
|
|
75
|
-
.join(SiteEra, Era.site_eras)
|
|
76
|
-
.join(Site, SiteEra.site_id == Site.id)
|
|
77
|
-
.where(
|
|
78
|
-
SiteEra.is_physical == true(),
|
|
79
|
-
Snag.start_date < cutoff_date,
|
|
80
|
-
)
|
|
81
|
-
.order_by(
|
|
82
|
-
Site.code,
|
|
83
|
-
Supply.id,
|
|
84
|
-
Channel.imp_related,
|
|
85
|
-
Channel.channel_type,
|
|
86
|
-
Snag.description,
|
|
87
|
-
Snag.start_date,
|
|
88
|
-
Snag.id,
|
|
89
|
-
)
|
|
90
|
-
.options(joinedload(Era.dc_contract))
|
|
91
|
-
)
|
|
92
|
-
if contract is not None:
|
|
93
|
-
q = q.where(Era.dc_contract == contract)
|
|
94
|
-
|
|
95
|
-
if not is_ignored:
|
|
96
|
-
q = q.where(Snag.is_ignored == false())
|
|
97
|
-
|
|
98
|
-
for snag, channel, era, supply, site_era, site in sess.execute(q):
|
|
99
|
-
snag_start = snag.start_date
|
|
100
|
-
snag_finish = snag.finish_date
|
|
101
|
-
imp_mc = "" if era.imp_mpan_core is None else era.imp_mpan_core
|
|
102
|
-
exp_mc = "" if era.exp_mpan_core is None else era.exp_mpan_core
|
|
103
|
-
|
|
104
|
-
if snag_finish is None:
|
|
105
|
-
duration = now - snag_start
|
|
106
|
-
age_of_snag = None
|
|
107
|
-
else:
|
|
108
|
-
duration = snag_finish - snag_start
|
|
109
|
-
if hh_before(cutoff_date, snag_finish):
|
|
110
|
-
age_of_snag = None
|
|
111
|
-
else:
|
|
112
|
-
delta = now - snag_finish
|
|
113
|
-
age_of_snag = delta.days
|
|
114
|
-
|
|
115
|
-
vals = {
|
|
116
|
-
"contract": era.dc_contract.name,
|
|
117
|
-
"Hidden Days": days_hidden,
|
|
118
|
-
"Chellow Id": snag.id,
|
|
119
|
-
"Imp MPAN Core": imp_mc,
|
|
120
|
-
"Exp MPAN Core": exp_mc,
|
|
121
|
-
"Site Code": site.code,
|
|
122
|
-
"Site Name": site.name,
|
|
123
|
-
"Snag Description": snag.description,
|
|
124
|
-
"Import Related?": channel.imp_related,
|
|
125
|
-
"Channel Type": channel.channel_type,
|
|
126
|
-
"Start Date": snag_start,
|
|
127
|
-
"Finish Date": snag_finish,
|
|
128
|
-
"Is Ignored?": snag.is_ignored,
|
|
129
|
-
"Days Since Snag Finished": age_of_snag,
|
|
130
|
-
"Duration Of Snag (Days)": duration.days,
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
writer.writerow(csv_make_val(vals[t]) for t in titles)
|
|
134
|
-
except BaseException:
|
|
135
|
-
msg = traceback.format_exc()
|
|
136
|
-
sys.stderr.write(msg)
|
|
137
|
-
writer.writerow([msg])
|
|
138
|
-
finally:
|
|
139
|
-
if f is not None:
|
|
140
|
-
f.close()
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def do_get(sess):
|
|
144
|
-
contract_id = req_int_none("dc_contract_id")
|
|
145
|
-
days_hidden = req_int("days_hidden")
|
|
146
|
-
is_ignored = req_bool("is_ignored")
|
|
147
|
-
|
|
148
|
-
args = contract_id, days_hidden, is_ignored, g.user.id
|
|
149
|
-
threading.Thread(target=content, args=args).start()
|
|
150
|
-
return redirect("/downloads", 303)
|
|
File without changes
|