chellow 1746461216.0.0__py3-none-any.whl → 1746689551.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.
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from werkzeug.exceptions import BadRequest
|
|
6
|
+
|
|
7
|
+
from chellow.edi_lib import (
|
|
8
|
+
ct_datetime,
|
|
9
|
+
parse_edi,
|
|
10
|
+
to_date,
|
|
11
|
+
to_decimal,
|
|
12
|
+
to_finish_date,
|
|
13
|
+
to_utc,
|
|
14
|
+
)
|
|
15
|
+
from chellow.utils import HH
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
read_type_map = {
|
|
19
|
+
"00": "N",
|
|
20
|
+
"09": "N3",
|
|
21
|
+
"04": "C",
|
|
22
|
+
"02": "E",
|
|
23
|
+
"11": "E3",
|
|
24
|
+
"01": "EM",
|
|
25
|
+
"03": "W",
|
|
26
|
+
"06": "X",
|
|
27
|
+
"05": "CP",
|
|
28
|
+
"12": "IF",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
TMOD_MAP = {
|
|
33
|
+
"139039": ("aahedc-gbp", "aahedc-rate", "aahedc-kwh"),
|
|
34
|
+
"064305": ("fit-gbp", None, None),
|
|
35
|
+
"590346": ("cfd-operational-gbp", None, None),
|
|
36
|
+
"269100": ("bsuos-gbp", "bsuos-rate", "bsuos-kwh"),
|
|
37
|
+
"422733": ("ccl-gbp", "ccl-rate", "ccl-kwh"),
|
|
38
|
+
"273237": ("cfd-operational-gbp", "cfd-operational-rate", "cfd-operational-kwh"),
|
|
39
|
+
"954379": ("cfd-interim-gbp", "cfd-interim-rate", "cfd-interim-kwh"),
|
|
40
|
+
"538249": ("capaity-gbp", None, None),
|
|
41
|
+
"568307": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
42
|
+
"439724": ("eii-gbp", None, None),
|
|
43
|
+
"247610": ("eii-gbp", None, None),
|
|
44
|
+
"930504": ("eii-gbp", None, None),
|
|
45
|
+
"331201": ("eii-gbp", None, None),
|
|
46
|
+
"307253": ("eii-gbp", "eii-rate", "eii-kwh"),
|
|
47
|
+
"065950": ("eii-gbp", "eii-rate", "eii-kwh"),
|
|
48
|
+
"095469": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
49
|
+
"489920": ("elexon-gbp", "elexon-rate", "elexon-nbp-kwh"),
|
|
50
|
+
"704107": ("fit-gbp", None, None),
|
|
51
|
+
"019090": ("rego-gbp", "rego-rate", "rego-kwh"),
|
|
52
|
+
"033667": ("management-gbp", "management-rate", "management-kwh"),
|
|
53
|
+
"091890": ("shape-gbp", "shape-rate", "shape-kwh"),
|
|
54
|
+
"122568": ("nrg-msp-gbp", "nrg-rate", "nrg-msp-kwh"),
|
|
55
|
+
"716514": ("duos-amber-gbp", "duos-amber-rate", "duos-amber-kwh"),
|
|
56
|
+
"769979": ("duos-red-gbp", "duos-red-rate", "duos-red-kwh"),
|
|
57
|
+
"794486": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
58
|
+
"797790": ("duos-reactive-gbp", "duos-reactive-rate", "duos-reactive-kvarh"),
|
|
59
|
+
"709522": (
|
|
60
|
+
"duos-excess-availability-gbp",
|
|
61
|
+
"duos-excess-availability-rate",
|
|
62
|
+
"duos-excess-availability-kva",
|
|
63
|
+
),
|
|
64
|
+
"644819": ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days"),
|
|
65
|
+
"806318": ("duos-green-gbp", "duos-green-rate", "duos-green-kwh"),
|
|
66
|
+
"209269": ("tnuos-gbp", "tnuos-rate", "tnuos-days"),
|
|
67
|
+
"229128": ("ro-gbp", "ro-rate", "ro-kwh"),
|
|
68
|
+
"012069": ("tnuos-gbp", None, None),
|
|
69
|
+
}
|
|
70
|
+
"""
|
|
71
|
+
"140114": ("reconciliation-gbp", None, None),
|
|
72
|
+
"255204": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
73
|
+
"345065": ("op-weekend-gbp", "op-weekend-rate", "op-weekend-kwh"),
|
|
74
|
+
"350293": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
75
|
+
"425779": ("ro-gbp", "ro-rate", "ro-kwh"),
|
|
76
|
+
"534342": ("reconciliation-gbp", None, None),
|
|
77
|
+
"583174": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
78
|
+
"584867": ("aahedc-gbp", "aahedc-rate", "aahedc-kwh"),
|
|
79
|
+
"946827": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
80
|
+
"989534": ("bsuos-gbp", "bsuos-rate", "bsuos-kwh"),
|
|
81
|
+
"117220": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
82
|
+
"579387": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
83
|
+
"558147": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
84
|
+
"030025": ("ccl-gbp", "ccl-rate", "ccl-kwh"),
|
|
85
|
+
"066540": ("ccl-gbp", "ccl-rate", "ccl-kwh"),
|
|
86
|
+
"154164": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
87
|
+
"281170": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
88
|
+
"342094": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
89
|
+
"378809": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
90
|
+
"574015": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
91
|
+
"810016": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
92
|
+
"839829": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
93
|
+
"649282": ("cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-kwh"),
|
|
94
|
+
"068476": ("day-gbp", "day-rate", "day-kwh"),
|
|
95
|
+
"133186": ("day-gbp", "day-rate", "day-kwh"),
|
|
96
|
+
"400434": ("day-gbp", "day-rate", "day-kwh"),
|
|
97
|
+
"219182": (
|
|
98
|
+
"duos-availability-gbp",
|
|
99
|
+
"duos-availability-rate",
|
|
100
|
+
"duos-availability-kva",
|
|
101
|
+
),
|
|
102
|
+
"144424": (
|
|
103
|
+
"duos-excess-availability-gbp",
|
|
104
|
+
"duos-excess-availability-rate",
|
|
105
|
+
"duos-excess-availability-kva",
|
|
106
|
+
),
|
|
107
|
+
"301541": ("duos-fixed-gbp", None, None),
|
|
108
|
+
"099335": ("duos-fixed-gbp", None, None),
|
|
109
|
+
"873562": ("duos-fixed-gbp", None, None),
|
|
110
|
+
"986159": ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days"),
|
|
111
|
+
"838286": ("duos-reactive-gbp", "duos-reactive-rate", "duos-reactive-kvarh"),
|
|
112
|
+
"242643": ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days"),
|
|
113
|
+
"257304": ("duos-amber-gbp", "duos-amber-rate", "duos-amber-kwh"),
|
|
114
|
+
"661440": ("duos-amber-gbp", "duos-amber-rate", "duos-amber-kwh"),
|
|
115
|
+
"257305": ("duos-green-gbp", "duos-green-rate", "duos-green-kwh"),
|
|
116
|
+
"661441": ("duos-green-gbp", "duos-green-rate", "duos-green-kwh"),
|
|
117
|
+
"257303": ("duos-red-gbp", "duos-red-rate", "duos-red-kwh"),
|
|
118
|
+
"661439": ("duos-red-gbp", "duos-red-rate", "duos-red-kwh"),
|
|
119
|
+
"504364": ("ebrs-gbp", None, "ebrs-kwh"),
|
|
120
|
+
"563023": ("ebrs-gbp", None, "ebrs-kwh"),
|
|
121
|
+
"823408": ("ebrs-gbp", None, "ebrs-kwh"),
|
|
122
|
+
"871593": ("ebrs-gbp", "ebrs-rate", "ebrs-kwh"),
|
|
123
|
+
"873894": ("ebrs-gbp", "ebrs-rate", "ebrs-kwh"),
|
|
124
|
+
"309707": ("fit-gbp", "fit-rate", "fit-kwh"),
|
|
125
|
+
"310129": ("meter-rental-gbp", None, None),
|
|
126
|
+
"452415": ("meter-rental-gbp", None, None),
|
|
127
|
+
"371265": ("meter-rental-gbp", None, None),
|
|
128
|
+
"544936": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
129
|
+
"265091": ("night-gbp", "night-rate", "night-kwh"),
|
|
130
|
+
"483457": ("peak-gbp", "peak-rate", "peak-kwh"),
|
|
131
|
+
"975901": ("peak-shoulder-gbp", "peak-shoulder-rate", "peak-shoulder-kwh"),
|
|
132
|
+
"994483": ("reconciliation-gbp", None, None),
|
|
133
|
+
"637176": ("reconciliation-gbp", None, None),
|
|
134
|
+
"913821": ("reconciliation-gbp", None, None),
|
|
135
|
+
"307660": ("ro-gbp", "ro-rate", "ro-kwh"),
|
|
136
|
+
"364252": ("ro-gbp", "ro-rate", "ro-kwh"),
|
|
137
|
+
"378246": ("ro-gbp", "ro-rate", "ro-kwh"),
|
|
138
|
+
"708848": ("ro-gbp", None, None),
|
|
139
|
+
"632209": ("summer-night-gbp", "summer-night-rate", "summer-night-kwh"),
|
|
140
|
+
"663682": ("summer-weekday-gbp", "summer-weekday-rate", "summer-weekday-kwh"),
|
|
141
|
+
"299992": ("summer-weekend-gbp", "summer-weekend-rate", "summer-weekend-kwh"),
|
|
142
|
+
"211000": ("tnuos-gbp", "tnuos-rate", "tnuos-days"),
|
|
143
|
+
"790618": ("tnuos-gbp", None, None),
|
|
144
|
+
"447769": ("triad-gbp", "triad-rate", "triad-kw"),
|
|
145
|
+
"647721": ("triad-gbp", "triad-rate", "triad-kw"),
|
|
146
|
+
"276631": ("triad-gbp", "triad-rate", "triad-kw"),
|
|
147
|
+
"220894": ("winter-night-gbp", "winter-night-rate", "winter-night-kwh"),
|
|
148
|
+
"264929": ("winter-weekday-gbp", "winter-weekday-rate", "winter-weekday-kwh"),
|
|
149
|
+
"638187": ("winter-weekend-gbp", "winter-weekend-rate", "winter-weekend-kwh"),
|
|
150
|
+
"700285": ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days"),
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
TPR_LOOKUP = {
|
|
154
|
+
"Day": "00043",
|
|
155
|
+
"Off Peak / Weekends": "00210",
|
|
156
|
+
"Night": "00210",
|
|
157
|
+
"Default Rate": "00043",
|
|
158
|
+
"Single": "00210",
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _process_BCD(elements, headers):
|
|
163
|
+
issue_date = to_date(elements["IVDT"][0])
|
|
164
|
+
reference = elements["INVN"][0]
|
|
165
|
+
bill_type_code = elements["BTCD"][0]
|
|
166
|
+
|
|
167
|
+
headers["issue_date"] = issue_date
|
|
168
|
+
headers["bill_type_code"] = bill_type_code
|
|
169
|
+
headers["reference"] = reference
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _process_CCD1(elements, headers):
|
|
173
|
+
tcod = elements["TCOD"]
|
|
174
|
+
pres_read_date = to_finish_date(elements["PRDT"][0])
|
|
175
|
+
|
|
176
|
+
prev_read_date = to_finish_date(elements["PVDT"][0])
|
|
177
|
+
|
|
178
|
+
m = elements["MLOC"][0]
|
|
179
|
+
mpan = " ".join((m[13:15], m[15:18], m[18:], m[:2], m[2:6], m[6:10], m[10:13]))
|
|
180
|
+
|
|
181
|
+
prrd = elements["PRRD"]
|
|
182
|
+
if len(prrd) < 4:
|
|
183
|
+
return
|
|
184
|
+
pres_read_type = read_type_map[prrd[1]]
|
|
185
|
+
prev_read_type = read_type_map[prrd[3]]
|
|
186
|
+
|
|
187
|
+
coefficient = Decimal(elements["ADJF"][1]) / Decimal(100000)
|
|
188
|
+
pres_reading_value = Decimal(prrd[0])
|
|
189
|
+
prev_reading_value = Decimal(prrd[2])
|
|
190
|
+
msn = elements["MTNR"][0]
|
|
191
|
+
tpr_code = elements["TMOD"][0]
|
|
192
|
+
if tpr_code == "kW":
|
|
193
|
+
units = "kW"
|
|
194
|
+
tpr_code = None
|
|
195
|
+
elif tpr_code == "kVA":
|
|
196
|
+
units = "kVA"
|
|
197
|
+
tpr_code = None
|
|
198
|
+
else:
|
|
199
|
+
units = "kWh"
|
|
200
|
+
tpr_code = TPR_LOOKUP[tcod[1]]
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
reads = headers["reads"]
|
|
204
|
+
except KeyError:
|
|
205
|
+
reads = headers["reads"] = []
|
|
206
|
+
|
|
207
|
+
reads.append(
|
|
208
|
+
{
|
|
209
|
+
"msn": msn,
|
|
210
|
+
"mpan": mpan,
|
|
211
|
+
"coefficient": coefficient,
|
|
212
|
+
"units": units,
|
|
213
|
+
"tpr_code": tpr_code,
|
|
214
|
+
"prev_date": prev_read_date,
|
|
215
|
+
"prev_value": prev_reading_value,
|
|
216
|
+
"prev_type_code": prev_read_type,
|
|
217
|
+
"pres_date": pres_read_date,
|
|
218
|
+
"pres_value": pres_reading_value,
|
|
219
|
+
"pres_type_code": pres_read_type,
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _process_CCD2(elements, headers):
|
|
225
|
+
breakdown = defaultdict(int)
|
|
226
|
+
|
|
227
|
+
element_code = elements["TMOD"][0]
|
|
228
|
+
headers["element_code"] = element_code
|
|
229
|
+
try:
|
|
230
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[element_code]
|
|
231
|
+
except KeyError:
|
|
232
|
+
raise BadRequest(f"Can't find the element code {element_code} in the TMOD_MAP.")
|
|
233
|
+
|
|
234
|
+
m = elements["MLOC"][0]
|
|
235
|
+
mpan_core = " ".join((m[:2], m[2:6], m[6:10], m[10:]))
|
|
236
|
+
|
|
237
|
+
cons = elements["CONS"]
|
|
238
|
+
kwh = Decimal("0")
|
|
239
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
240
|
+
el_cons = to_decimal(cons) / Decimal("1000")
|
|
241
|
+
if eln_gbp == "duos-availability-gbp":
|
|
242
|
+
breakdown[eln_cons] = [el_cons]
|
|
243
|
+
else:
|
|
244
|
+
breakdown[eln_cons] = kwh = el_cons
|
|
245
|
+
|
|
246
|
+
if eln_rate is not None:
|
|
247
|
+
rate = to_decimal(elements["BPRI"]) / Decimal("100000")
|
|
248
|
+
breakdown[eln_rate] = [rate]
|
|
249
|
+
|
|
250
|
+
start_date = to_date(elements["CSDT"][0])
|
|
251
|
+
headers["bill_start_date"] = start_date
|
|
252
|
+
|
|
253
|
+
finish_date = to_date(elements["CEDT"][0]) - HH
|
|
254
|
+
headers["bill_finish_date"] = finish_date
|
|
255
|
+
|
|
256
|
+
if "CTOT" in elements:
|
|
257
|
+
net = Decimal("0.00") + to_decimal(elements["CTOT"]) / Decimal("100")
|
|
258
|
+
else:
|
|
259
|
+
net = Decimal("0.00")
|
|
260
|
+
|
|
261
|
+
breakdown[eln_gbp] = net
|
|
262
|
+
|
|
263
|
+
headers["mpan_core"] = mpan_core
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
reads = headers["reads"]
|
|
267
|
+
headers["reads"] = []
|
|
268
|
+
except KeyError:
|
|
269
|
+
reads = []
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
"bill_type_code": headers["bill_type_code"],
|
|
273
|
+
"reference": headers["reference"] + "_" + eln_gbp[:-4],
|
|
274
|
+
"issue_date": headers["issue_date"],
|
|
275
|
+
"mpan_core": mpan_core,
|
|
276
|
+
"account": mpan_core,
|
|
277
|
+
"start_date": start_date,
|
|
278
|
+
"finish_date": finish_date,
|
|
279
|
+
"kwh": kwh if eln_gbp == "ro-gbp" else Decimal("0"),
|
|
280
|
+
"net": net,
|
|
281
|
+
"vat": Decimal("0.00"),
|
|
282
|
+
"gross": net,
|
|
283
|
+
"breakdown": breakdown,
|
|
284
|
+
"reads": reads,
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _process_CCD3(elements, headers):
|
|
289
|
+
breakdown = defaultdict(int)
|
|
290
|
+
|
|
291
|
+
element_code = elements["TMOD"][0]
|
|
292
|
+
headers["element_code"] = element_code
|
|
293
|
+
try:
|
|
294
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[element_code]
|
|
295
|
+
except KeyError:
|
|
296
|
+
raise BadRequest(f"Can't find the element code {element_code} in the TMOD_MAP.")
|
|
297
|
+
|
|
298
|
+
m = elements["MLOC"][0]
|
|
299
|
+
mpan_core = " ".join((m[:2], m[2:6], m[6:10], m[10:]))
|
|
300
|
+
|
|
301
|
+
cons = elements["CONS"]
|
|
302
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
303
|
+
el_cons = to_decimal(cons) / Decimal("1000")
|
|
304
|
+
breakdown[eln_cons] = kwh = el_cons
|
|
305
|
+
else:
|
|
306
|
+
kwh = Decimal("0")
|
|
307
|
+
|
|
308
|
+
if eln_rate is not None:
|
|
309
|
+
rate = to_decimal(elements["BPRI"]) / Decimal("100000")
|
|
310
|
+
breakdown[eln_rate] = [rate]
|
|
311
|
+
|
|
312
|
+
start_date = to_date(elements["CSDT"][0])
|
|
313
|
+
headers["bill_start_date"] = start_date
|
|
314
|
+
|
|
315
|
+
finish_date = to_date(elements["CEDT"][0]) - HH
|
|
316
|
+
headers["bill_finish_date"] = finish_date
|
|
317
|
+
|
|
318
|
+
if "CTOT" in elements:
|
|
319
|
+
net = Decimal("0.00") + to_decimal(elements["CTOT"]) / Decimal("100")
|
|
320
|
+
else:
|
|
321
|
+
net = Decimal("0.00")
|
|
322
|
+
|
|
323
|
+
breakdown[eln_gbp] = net
|
|
324
|
+
|
|
325
|
+
headers["mpan_core"] = mpan_core
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
reads = headers["reads"]
|
|
329
|
+
headers["reads"] = []
|
|
330
|
+
except KeyError:
|
|
331
|
+
reads = []
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
"bill_type_code": headers["bill_type_code"],
|
|
335
|
+
"issue_date": headers["issue_date"],
|
|
336
|
+
"reference": headers["reference"] + "_" + eln_gbp[:-4],
|
|
337
|
+
"mpan_core": mpan_core,
|
|
338
|
+
"account": mpan_core,
|
|
339
|
+
"start_date": start_date,
|
|
340
|
+
"finish_date": finish_date,
|
|
341
|
+
"net": net,
|
|
342
|
+
"kwh": kwh if eln_gbp == "ro-gbp" else Decimal("0"),
|
|
343
|
+
"vat": Decimal("0.00"),
|
|
344
|
+
"gross": net,
|
|
345
|
+
"breakdown": breakdown,
|
|
346
|
+
"reads": reads,
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _process_CCD4(elements, headers):
|
|
351
|
+
breakdown = defaultdict(int)
|
|
352
|
+
|
|
353
|
+
element_code = elements["TMOD"][0]
|
|
354
|
+
headers["element_code"] = element_code
|
|
355
|
+
try:
|
|
356
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[element_code]
|
|
357
|
+
except KeyError:
|
|
358
|
+
raise BadRequest(f"Can't find the element code {element_code} in the TMOD_MAP.")
|
|
359
|
+
|
|
360
|
+
m = elements["MLOC"][0]
|
|
361
|
+
mpan_core = " ".join((m[:2], m[2:6], m[6:10], m[10:]))
|
|
362
|
+
|
|
363
|
+
cons = elements["CONS"]
|
|
364
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
365
|
+
el_cons = to_decimal(cons, "1000")
|
|
366
|
+
breakdown[eln_cons] = kwh = el_cons
|
|
367
|
+
|
|
368
|
+
if eln_rate is not None:
|
|
369
|
+
rate = to_decimal(elements["BPRI"], "100000")
|
|
370
|
+
breakdown[eln_rate] = [rate]
|
|
371
|
+
|
|
372
|
+
start_date = to_date(elements["CSDT"][0])
|
|
373
|
+
headers["bill_start_date"] = start_date
|
|
374
|
+
|
|
375
|
+
finish_date = to_date(elements["CEDT"][0]) - HH
|
|
376
|
+
headers["bill_finish_date"] = finish_date
|
|
377
|
+
|
|
378
|
+
if "CTOT" in elements:
|
|
379
|
+
net = Decimal("0.00") + to_decimal(elements["CTOT"], "100")
|
|
380
|
+
else:
|
|
381
|
+
net = Decimal("0.00")
|
|
382
|
+
|
|
383
|
+
breakdown[eln_gbp] = net
|
|
384
|
+
|
|
385
|
+
headers["mpan_core"] = mpan_core
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
reads = headers["reads"]
|
|
389
|
+
del headers["reads"][:]
|
|
390
|
+
except KeyError:
|
|
391
|
+
reads = []
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
"kwh": kwh if eln_gbp == "ro-gbp" else Decimal("0.00"),
|
|
395
|
+
"reference": headers["reference"] + "_" + eln_gbp[:-4],
|
|
396
|
+
"issue_date": headers["issue_date"],
|
|
397
|
+
"mpan_core": mpan_core,
|
|
398
|
+
"account": mpan_core,
|
|
399
|
+
"start_date": start_date,
|
|
400
|
+
"finish_date": finish_date,
|
|
401
|
+
"net": net,
|
|
402
|
+
"vat": Decimal("0.00"),
|
|
403
|
+
"gross": net,
|
|
404
|
+
"breakdown": breakdown,
|
|
405
|
+
"reads": reads,
|
|
406
|
+
"bill_type_code": headers["bill_type_code"],
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _process_CDT(elements, headers):
|
|
411
|
+
customer_id = elements["CIDN"][0]
|
|
412
|
+
headers["customer_number"] = customer_id
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _process_END(elements, headers):
|
|
416
|
+
pass
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def _process_MHD(elements, headers):
|
|
420
|
+
message_type = elements["TYPE"][0]
|
|
421
|
+
if message_type == "UTLBIL":
|
|
422
|
+
keep_keys = {"customer_number"}
|
|
423
|
+
keep = {k: headers[k] for k in keep_keys}
|
|
424
|
+
headers.clear()
|
|
425
|
+
headers.update(keep)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _process_MTR(elements, headers):
|
|
429
|
+
pass
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _process_VAT(elements, headers):
|
|
433
|
+
vat = Decimal("0.00") + to_decimal(elements["UVTT"]) / Decimal("100")
|
|
434
|
+
vat_percentage = to_decimal(elements["VATP"]) / Decimal("1000")
|
|
435
|
+
vat_net = Decimal("0.00") + to_decimal(elements["UVLA"]) / Decimal("100")
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
"bill_type_code": headers["bill_type_code"],
|
|
439
|
+
"account": headers["mpan_core"],
|
|
440
|
+
"mpan_core": headers["mpan_core"],
|
|
441
|
+
"reference": headers["reference"] + "_vat",
|
|
442
|
+
"issue_date": headers["issue_date"],
|
|
443
|
+
"start_date": headers["bill_start_date"],
|
|
444
|
+
"finish_date": headers["bill_finish_date"],
|
|
445
|
+
"kwh": Decimal("0.00"),
|
|
446
|
+
"net": Decimal("0.00"),
|
|
447
|
+
"vat": vat,
|
|
448
|
+
"gross": vat,
|
|
449
|
+
"breakdown": {"vat": {vat_percentage: {"vat": vat, "net": vat_net}}},
|
|
450
|
+
"reads": [],
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def _process_NOOP(elements, headers):
|
|
455
|
+
pass
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
CODE_FUNCS = {
|
|
459
|
+
"BCD": _process_BCD,
|
|
460
|
+
"BTL": _process_NOOP,
|
|
461
|
+
"CCD1": _process_CCD1,
|
|
462
|
+
"CCD2": _process_CCD2,
|
|
463
|
+
"CCD3": _process_CCD3,
|
|
464
|
+
"CCD4": _process_CCD4,
|
|
465
|
+
"CDT": _process_CDT,
|
|
466
|
+
"CLO": _process_NOOP,
|
|
467
|
+
"DNA": _process_NOOP,
|
|
468
|
+
"END": _process_END,
|
|
469
|
+
"FIL": _process_NOOP,
|
|
470
|
+
"MAN": _process_NOOP,
|
|
471
|
+
"MHD": _process_MHD,
|
|
472
|
+
"MTR": _process_MTR,
|
|
473
|
+
"SDT": _process_NOOP,
|
|
474
|
+
"STX": _process_NOOP,
|
|
475
|
+
"TYP": _process_NOOP,
|
|
476
|
+
"TTL": _process_NOOP,
|
|
477
|
+
"VAT": _process_VAT,
|
|
478
|
+
"VTS": _process_NOOP,
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def _customer_mods(headers, bill):
|
|
483
|
+
if headers["customer_number"] == "WESSEXWAT":
|
|
484
|
+
if (
|
|
485
|
+
headers["element_code"] == "307660"
|
|
486
|
+
and "ro-gbp" in bill["breakdown"]
|
|
487
|
+
and bill["issue_date"] == to_utc(ct_datetime(2023, 4, 14))
|
|
488
|
+
and bill["start_date"] == to_utc(ct_datetime(2023, 3, 1))
|
|
489
|
+
and bill["finish_date"] == to_utc(ct_datetime(2023, 3, 31, 23, 30))
|
|
490
|
+
):
|
|
491
|
+
bill["start_date"] = to_utc(ct_datetime(2021, 4, 1))
|
|
492
|
+
bill["finish_date"] = to_utc(ct_datetime(2022, 3, 31, 23, 30))
|
|
493
|
+
|
|
494
|
+
return bill
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
class Parser:
|
|
498
|
+
def __init__(self, f):
|
|
499
|
+
self.edi_str = str(f.read(), "utf-8", errors="ignore")
|
|
500
|
+
self.line_number = None
|
|
501
|
+
|
|
502
|
+
def make_raw_bills(self):
|
|
503
|
+
bills = []
|
|
504
|
+
headers = {}
|
|
505
|
+
bill = None
|
|
506
|
+
for self.line_number, line, seg_name, elements in parse_edi(self.edi_str):
|
|
507
|
+
try:
|
|
508
|
+
func = CODE_FUNCS[seg_name]
|
|
509
|
+
except KeyError:
|
|
510
|
+
raise BadRequest(f"Code {seg_name} not recognized.")
|
|
511
|
+
|
|
512
|
+
try:
|
|
513
|
+
bill = func(elements, headers)
|
|
514
|
+
except BadRequest as e:
|
|
515
|
+
raise BadRequest(
|
|
516
|
+
f"{e.description} on line {self.line_number} line {line} "
|
|
517
|
+
f"seg_name {seg_name} elements {elements}"
|
|
518
|
+
)
|
|
519
|
+
except BaseException as e:
|
|
520
|
+
raise BadRequest(
|
|
521
|
+
f"{e} on line {self.line_number} line {line} "
|
|
522
|
+
f"seg_name {seg_name} elements {elements}"
|
|
523
|
+
) from e
|
|
524
|
+
|
|
525
|
+
if bill is not None:
|
|
526
|
+
bill["breakdown"]["raw-lines"] = [line]
|
|
527
|
+
bills.append(_customer_mods(headers, bill))
|
|
528
|
+
|
|
529
|
+
return bills
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chellow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 1746689551.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)
|
|
@@ -50,6 +50,7 @@ chellow/e/bill_parsers/activity_mop_stark_xlsx.py,sha256=UgWXDPzQkQghyj_lfgBqoSJ
|
|
|
50
50
|
chellow/e/bill_parsers/annual_mop_stark_xlsx.py,sha256=-HMoIfa_utXYKA44RuC0Xqv3vd2HLeQU_4P0iBUd3WA,4219
|
|
51
51
|
chellow/e/bill_parsers/bgb_edi.py,sha256=GuwHeYbAGk7BVg5n19FcTANFDyKI-y0z3f9niQaPSSw,4828
|
|
52
52
|
chellow/e/bill_parsers/csv.py,sha256=U5zcIaZ6B5QTTpFDAcBnk4G2r8B3j5kJhDPL4AJNkEk,5640
|
|
53
|
+
chellow/e/bill_parsers/drax_edi.py,sha256=HI_P_ot0bJXMJjKSJACCZijsp7_Wla5ZkwgJHmC5A7I,17760
|
|
53
54
|
chellow/e/bill_parsers/edf_export_xlsx.py,sha256=J4lY8epiSTIePZ6D1SGD76TXRoev35KrUC2sjHkNqlE,6632
|
|
54
55
|
chellow/e/bill_parsers/engie_edi.py,sha256=PDMDI0aqUM1lalgzxih1YmMho11n1rMqE0vyL-aEIs8,15840
|
|
55
56
|
chellow/e/bill_parsers/engie_export_xlsx.py,sha256=oZO0qHdDlOxjJ6J5Ate82CkAoX4bxed1EJyUKHxBcpk,4690
|
|
@@ -383,6 +384,6 @@ chellow/templates/g/supply_note_edit.html,sha256=b8mB6_ucBwoljp03iy6AgVaZUhGw3-1
|
|
|
383
384
|
chellow/templates/g/supply_notes.html,sha256=6epNmZ3NKdXZz27fvmRUGeffg_oc1kmwuBeyRzQe3Rg,854
|
|
384
385
|
chellow/templates/g/unit.html,sha256=KouNVU0-i84afANkLQ_heJ0uDfJ9H5A05PuLqb8iCN8,438
|
|
385
386
|
chellow/templates/g/units.html,sha256=p5Nd-lAIboKPEOO6N451hx1bcKxMg4BDODnZ-43MmJc,441
|
|
386
|
-
chellow-
|
|
387
|
-
chellow-
|
|
388
|
-
chellow-
|
|
387
|
+
chellow-1746689551.0.0.dist-info/METADATA,sha256=SvI1m5af2Fx_M8SQUaSDVwNfn-bATlRUwT-maf9y6yA,12238
|
|
388
|
+
chellow-1746689551.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
389
|
+
chellow-1746689551.0.0.dist-info/RECORD,,
|
|
File without changes
|