chellow 1750675713.0.0__py3-none-any.whl → 1751459327.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/e/bill_parsers/drax_edi.py +210 -225
- chellow/e/bill_parsers/drax_element_edi.py +459 -0
- chellow/e/views.py +72 -51
- chellow/gas/bill_parser_bgs_xlsx.py +41 -56
- chellow/general_import.py +72 -0
- chellow/templates/g/bill_import.html +4 -4
- chellow/templates/general_imports.html +18 -0
- chellow/views.py +3 -1
- {chellow-1750675713.0.0.dist-info → chellow-1751459327.0.0.dist-info}/METADATA +2 -2
- {chellow-1750675713.0.0.dist-info → chellow-1751459327.0.0.dist-info}/RECORD +11 -10
- {chellow-1750675713.0.0.dist-info → chellow-1751459327.0.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,459 @@
|
|
|
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, parse_mpan_core
|
|
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
|
+
"020330": ("eii-gbp", None, None),
|
|
43
|
+
"439724": ("eii-gbp", None, None),
|
|
44
|
+
"247610": ("eii-gbp", None, None),
|
|
45
|
+
"930504": ("eii-gbp", None, None),
|
|
46
|
+
"331201": ("eii-gbp", None, None),
|
|
47
|
+
"307253": ("eii-gbp", "eii-rate", "eii-kwh"),
|
|
48
|
+
"065950": ("eii-gbp", "eii-rate", "eii-kwh"),
|
|
49
|
+
"095469": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
50
|
+
"637050": ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days"),
|
|
51
|
+
"489920": ("elexon-gbp", "elexon-rate", "elexon-nbp-kwh"),
|
|
52
|
+
"704107": ("fit-gbp", None, None),
|
|
53
|
+
"019090": ("rego-gbp", "rego-rate", "rego-kwh"),
|
|
54
|
+
"033667": ("management-gbp", "management-rate", "management-kwh"),
|
|
55
|
+
"091890": ("shape-gbp", "shape-rate", "shape-kwh"),
|
|
56
|
+
"122568": ("nrg-msp-gbp", "nrg-rate", "nrg-msp-kwh"),
|
|
57
|
+
"716514": ("duos-amber-gbp", "duos-amber-rate", "duos-amber-kwh"),
|
|
58
|
+
"769979": ("duos-red-gbp", "duos-red-rate", "duos-red-kwh"),
|
|
59
|
+
"794486": ("capacity-gbp", "capacity-rate", "capacity-kwh"),
|
|
60
|
+
"797790": ("duos-reactive-gbp", "duos-reactive-rate", "duos-reactive-kvarh"),
|
|
61
|
+
"709522": (
|
|
62
|
+
"duos-excess-availability-gbp",
|
|
63
|
+
"duos-excess-availability-rate",
|
|
64
|
+
"duos-excess-availability-kva",
|
|
65
|
+
),
|
|
66
|
+
"644819": ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days"),
|
|
67
|
+
"806318": ("duos-green-gbp", "duos-green-rate", "duos-green-kwh"),
|
|
68
|
+
"209269": ("tnuos-gbp", "tnuos-rate", "tnuos-days"),
|
|
69
|
+
"229128": ("ro-gbp", "ro-rate", "ro-kwh"),
|
|
70
|
+
"012069": ("tnuos-gbp", None, None),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
TPR_LOOKUP = {
|
|
74
|
+
"Day": "00043",
|
|
75
|
+
"Off Peak / Weekends": "00210",
|
|
76
|
+
"Night": "00210",
|
|
77
|
+
"Default Rate": "00043",
|
|
78
|
+
"Single": "00210",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _process_BCD(elements, headers):
|
|
83
|
+
issue_date = to_date(elements["IVDT"][0])
|
|
84
|
+
reference = elements["INVN"][0]
|
|
85
|
+
bill_type_code = elements["BTCD"][0]
|
|
86
|
+
|
|
87
|
+
headers["issue_date"] = issue_date
|
|
88
|
+
headers["bill_type_code"] = bill_type_code
|
|
89
|
+
headers["reference"] = reference
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _process_BTL(elements, headers):
|
|
93
|
+
for bill in headers["bills"]:
|
|
94
|
+
bill["mpan_core"] = headers["mpan_core"]
|
|
95
|
+
bill["account"] = headers["account"]
|
|
96
|
+
_customer_mods(headers, bill)
|
|
97
|
+
return headers["bills"]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _process_CCD1(elements, headers):
|
|
101
|
+
tcod = elements["TCOD"]
|
|
102
|
+
pres_read_date = to_finish_date(elements["PRDT"][0])
|
|
103
|
+
|
|
104
|
+
prev_read_date = to_finish_date(elements["PVDT"][0])
|
|
105
|
+
|
|
106
|
+
m = elements["MLOC"][0]
|
|
107
|
+
mpan = " ".join((m[13:15], m[15:18], m[18:], m[:2], m[2:6], m[6:10], m[10:13]))
|
|
108
|
+
|
|
109
|
+
prrd = elements["PRRD"]
|
|
110
|
+
if len(prrd) < 4:
|
|
111
|
+
return
|
|
112
|
+
pres_read_type = read_type_map[prrd[1]]
|
|
113
|
+
prev_read_type = read_type_map[prrd[3]]
|
|
114
|
+
|
|
115
|
+
coefficient = Decimal(elements["ADJF"][1]) / Decimal(100000)
|
|
116
|
+
pres_reading_value = Decimal(prrd[0])
|
|
117
|
+
prev_reading_value = Decimal(prrd[2])
|
|
118
|
+
msn = elements["MTNR"][0]
|
|
119
|
+
tpr_code = elements["TMOD"][0]
|
|
120
|
+
if tpr_code == "kW":
|
|
121
|
+
units = "kW"
|
|
122
|
+
tpr_code = None
|
|
123
|
+
elif tpr_code == "kVA":
|
|
124
|
+
units = "kVA"
|
|
125
|
+
tpr_code = None
|
|
126
|
+
else:
|
|
127
|
+
units = "kWh"
|
|
128
|
+
tpr_code = TPR_LOOKUP[tcod[1]]
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
reads = headers["reads"]
|
|
132
|
+
except KeyError:
|
|
133
|
+
reads = headers["reads"] = []
|
|
134
|
+
|
|
135
|
+
reads.append(
|
|
136
|
+
{
|
|
137
|
+
"msn": msn,
|
|
138
|
+
"mpan": mpan,
|
|
139
|
+
"coefficient": coefficient,
|
|
140
|
+
"units": units,
|
|
141
|
+
"tpr_code": tpr_code,
|
|
142
|
+
"prev_date": prev_read_date,
|
|
143
|
+
"prev_value": prev_reading_value,
|
|
144
|
+
"prev_type_code": prev_read_type,
|
|
145
|
+
"pres_date": pres_read_date,
|
|
146
|
+
"pres_value": pres_reading_value,
|
|
147
|
+
"pres_type_code": pres_read_type,
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _process_CCD2(elements, headers):
|
|
153
|
+
breakdown = defaultdict(int)
|
|
154
|
+
|
|
155
|
+
element_code = elements["TMOD"][0]
|
|
156
|
+
headers["element_code"] = element_code
|
|
157
|
+
try:
|
|
158
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[element_code]
|
|
159
|
+
except KeyError:
|
|
160
|
+
raise BadRequest(f"Can't find the element code {element_code} in the TMOD_MAP.")
|
|
161
|
+
|
|
162
|
+
cons = elements["CONS"]
|
|
163
|
+
kwh = Decimal("0")
|
|
164
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
165
|
+
el_cons = to_decimal(cons) / Decimal("1000")
|
|
166
|
+
if eln_gbp == "duos-availability-gbp":
|
|
167
|
+
breakdown[eln_cons] = [el_cons]
|
|
168
|
+
else:
|
|
169
|
+
breakdown[eln_cons] = kwh = el_cons
|
|
170
|
+
|
|
171
|
+
if eln_rate is not None:
|
|
172
|
+
rate = to_decimal(elements["BPRI"]) / Decimal("100000")
|
|
173
|
+
breakdown[eln_rate] = [rate]
|
|
174
|
+
|
|
175
|
+
start_date = to_date(elements["CSDT"][0])
|
|
176
|
+
headers["bill_start_date"] = start_date
|
|
177
|
+
|
|
178
|
+
finish_date = to_date(elements["CEDT"][0]) - HH
|
|
179
|
+
headers["bill_finish_date"] = finish_date
|
|
180
|
+
|
|
181
|
+
if "CTOT" in elements:
|
|
182
|
+
net = Decimal("0.00") + to_decimal(elements["CTOT"]) / Decimal("100")
|
|
183
|
+
else:
|
|
184
|
+
net = Decimal("0.00")
|
|
185
|
+
|
|
186
|
+
breakdown[eln_gbp] = net
|
|
187
|
+
breakdown["raw-lines"] = [headers["line"]]
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
reads = headers["reads"]
|
|
191
|
+
headers["reads"] = []
|
|
192
|
+
except KeyError:
|
|
193
|
+
reads = []
|
|
194
|
+
|
|
195
|
+
bill = {
|
|
196
|
+
"bill_type_code": headers["bill_type_code"],
|
|
197
|
+
"reference": headers["reference"] + "_" + eln_gbp[:-4],
|
|
198
|
+
"issue_date": headers["issue_date"],
|
|
199
|
+
"start_date": start_date,
|
|
200
|
+
"finish_date": finish_date,
|
|
201
|
+
"kwh": kwh if eln_gbp == "ro-gbp" else Decimal("0"),
|
|
202
|
+
"net": net,
|
|
203
|
+
"vat": Decimal("0.00"),
|
|
204
|
+
"gross": net,
|
|
205
|
+
"breakdown": breakdown,
|
|
206
|
+
"reads": reads,
|
|
207
|
+
}
|
|
208
|
+
headers["bills"].append(bill)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _process_CCD3(elements, headers):
|
|
212
|
+
breakdown = defaultdict(int)
|
|
213
|
+
|
|
214
|
+
element_code = elements["TMOD"][0]
|
|
215
|
+
headers["element_code"] = element_code
|
|
216
|
+
try:
|
|
217
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[element_code]
|
|
218
|
+
except KeyError:
|
|
219
|
+
raise BadRequest(f"Can't find the element code {element_code} in the TMOD_MAP.")
|
|
220
|
+
|
|
221
|
+
cons = elements["CONS"]
|
|
222
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
223
|
+
el_cons = to_decimal(cons) / Decimal("1000")
|
|
224
|
+
breakdown[eln_cons] = kwh = el_cons
|
|
225
|
+
else:
|
|
226
|
+
kwh = Decimal("0")
|
|
227
|
+
|
|
228
|
+
bpri = elements["BPRI"]
|
|
229
|
+
if len(bpri[0]) > 0:
|
|
230
|
+
rate = to_decimal(bpri) / Decimal("100000")
|
|
231
|
+
breakdown[eln_rate] = [rate]
|
|
232
|
+
|
|
233
|
+
start_date = to_date(elements["CSDT"][0])
|
|
234
|
+
headers["bill_start_date"] = start_date
|
|
235
|
+
|
|
236
|
+
finish_date = to_date(elements["CEDT"][0]) - HH
|
|
237
|
+
headers["bill_finish_date"] = finish_date
|
|
238
|
+
|
|
239
|
+
if "CTOT" in elements:
|
|
240
|
+
net = Decimal("0.00") + to_decimal(elements["CTOT"]) / Decimal("100")
|
|
241
|
+
else:
|
|
242
|
+
net = Decimal("0.00")
|
|
243
|
+
|
|
244
|
+
breakdown[eln_gbp] = net
|
|
245
|
+
breakdown["raw-lines"] = [headers["line"]]
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
reads = headers["reads"]
|
|
249
|
+
headers["reads"] = []
|
|
250
|
+
except KeyError:
|
|
251
|
+
reads = []
|
|
252
|
+
|
|
253
|
+
bill = {
|
|
254
|
+
"bill_type_code": headers["bill_type_code"],
|
|
255
|
+
"issue_date": headers["issue_date"],
|
|
256
|
+
"reference": headers["reference"] + "_" + eln_gbp[:-4],
|
|
257
|
+
"start_date": start_date,
|
|
258
|
+
"finish_date": finish_date,
|
|
259
|
+
"net": net,
|
|
260
|
+
"kwh": kwh if eln_gbp == "ro-gbp" else Decimal("0"),
|
|
261
|
+
"vat": Decimal("0.00"),
|
|
262
|
+
"gross": net,
|
|
263
|
+
"breakdown": breakdown,
|
|
264
|
+
"reads": reads,
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
headers["bills"].append(bill)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _process_CCD4(elements, headers):
|
|
271
|
+
breakdown = defaultdict(int)
|
|
272
|
+
|
|
273
|
+
element_code = elements["TMOD"][0]
|
|
274
|
+
headers["element_code"] = element_code
|
|
275
|
+
try:
|
|
276
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[element_code]
|
|
277
|
+
except KeyError:
|
|
278
|
+
raise BadRequest(f"Can't find the element code {element_code} in the TMOD_MAP.")
|
|
279
|
+
|
|
280
|
+
cons = elements["CONS"]
|
|
281
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
282
|
+
el_cons = to_decimal(cons, "1000")
|
|
283
|
+
breakdown[eln_cons] = kwh = el_cons
|
|
284
|
+
|
|
285
|
+
if eln_rate is not None:
|
|
286
|
+
rate = to_decimal(elements["BPRI"], "100000")
|
|
287
|
+
breakdown[eln_rate] = [rate]
|
|
288
|
+
|
|
289
|
+
start_date = to_date(elements["CSDT"][0])
|
|
290
|
+
headers["bill_start_date"] = start_date
|
|
291
|
+
|
|
292
|
+
finish_date = to_date(elements["CEDT"][0]) - HH
|
|
293
|
+
headers["bill_finish_date"] = finish_date
|
|
294
|
+
|
|
295
|
+
if "CTOT" in elements:
|
|
296
|
+
net = Decimal("0.00") + to_decimal(elements["CTOT"], "100")
|
|
297
|
+
else:
|
|
298
|
+
net = Decimal("0.00")
|
|
299
|
+
|
|
300
|
+
breakdown[eln_gbp] = net
|
|
301
|
+
breakdown["raw-lines"] = [headers["line"]]
|
|
302
|
+
|
|
303
|
+
try:
|
|
304
|
+
reads = headers["reads"]
|
|
305
|
+
del headers["reads"][:]
|
|
306
|
+
except KeyError:
|
|
307
|
+
reads = []
|
|
308
|
+
|
|
309
|
+
bill = {
|
|
310
|
+
"kwh": kwh if eln_gbp == "ro-gbp" else Decimal("0.00"),
|
|
311
|
+
"reference": headers["reference"] + "_" + eln_gbp[:-4],
|
|
312
|
+
"issue_date": headers["issue_date"],
|
|
313
|
+
"start_date": start_date,
|
|
314
|
+
"finish_date": finish_date,
|
|
315
|
+
"net": net,
|
|
316
|
+
"vat": Decimal("0.00"),
|
|
317
|
+
"gross": net,
|
|
318
|
+
"breakdown": breakdown,
|
|
319
|
+
"reads": reads,
|
|
320
|
+
"bill_type_code": headers["bill_type_code"],
|
|
321
|
+
}
|
|
322
|
+
headers["bills"].append(bill)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _process_CDT(elements, headers):
|
|
326
|
+
customer_id = elements["CIDN"][0]
|
|
327
|
+
headers["customer_number"] = customer_id
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _process_CLO(elements, headers):
|
|
331
|
+
cloc = elements["CLOC"]
|
|
332
|
+
headers["account"] = cloc[1]
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _process_END(elements, headers):
|
|
336
|
+
pass
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _process_MAN(elements, headers):
|
|
340
|
+
madn = elements["MADN"]
|
|
341
|
+
|
|
342
|
+
headers["mpan_core"] = parse_mpan_core("".join(madn[0:3]))
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def _process_MHD(elements, headers):
|
|
346
|
+
message_type = elements["TYPE"][0]
|
|
347
|
+
if message_type == "UTLBIL":
|
|
348
|
+
keep_keys = {"customer_number"}
|
|
349
|
+
keep = {k: headers[k] for k in keep_keys}
|
|
350
|
+
headers.clear()
|
|
351
|
+
headers.update(keep)
|
|
352
|
+
headers["bills"] = []
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def _process_MTR(elements, headers):
|
|
356
|
+
pass
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _process_VAT(elements, headers):
|
|
360
|
+
vat = Decimal("0.00") + to_decimal(elements["UVTT"]) / Decimal("100")
|
|
361
|
+
vat_percentage = to_decimal(elements["VATP"]) / Decimal("1000")
|
|
362
|
+
vat_net = Decimal("0.00") + to_decimal(elements["UVLA"]) / Decimal("100")
|
|
363
|
+
|
|
364
|
+
bill = {
|
|
365
|
+
"bill_type_code": headers["bill_type_code"],
|
|
366
|
+
"account": headers["account"],
|
|
367
|
+
"mpan_core": headers["mpan_core"],
|
|
368
|
+
"reference": headers["reference"] + "_vat",
|
|
369
|
+
"issue_date": headers["issue_date"],
|
|
370
|
+
"start_date": headers["bill_start_date"],
|
|
371
|
+
"finish_date": headers["bill_finish_date"],
|
|
372
|
+
"kwh": Decimal("0.00"),
|
|
373
|
+
"net": Decimal("0.00"),
|
|
374
|
+
"vat": vat,
|
|
375
|
+
"gross": vat,
|
|
376
|
+
"breakdown": {
|
|
377
|
+
"raw-lines": [headers["line"]],
|
|
378
|
+
"vat": {vat_percentage: {"vat": vat, "net": vat_net}},
|
|
379
|
+
},
|
|
380
|
+
"reads": [],
|
|
381
|
+
}
|
|
382
|
+
headers["bills"].append(bill)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def _process_NOOP(elements, headers):
|
|
386
|
+
pass
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
CODE_FUNCS = {
|
|
390
|
+
"BCD": _process_BCD,
|
|
391
|
+
"BTL": _process_BTL,
|
|
392
|
+
"CCD1": _process_CCD1,
|
|
393
|
+
"CCD2": _process_CCD2,
|
|
394
|
+
"CCD3": _process_CCD3,
|
|
395
|
+
"CCD4": _process_CCD4,
|
|
396
|
+
"CDT": _process_CDT,
|
|
397
|
+
"CLO": _process_CLO,
|
|
398
|
+
"DNA": _process_NOOP,
|
|
399
|
+
"END": _process_END,
|
|
400
|
+
"FIL": _process_NOOP,
|
|
401
|
+
"MAN": _process_MAN,
|
|
402
|
+
"MHD": _process_MHD,
|
|
403
|
+
"MTR": _process_MTR,
|
|
404
|
+
"SDT": _process_NOOP,
|
|
405
|
+
"STX": _process_NOOP,
|
|
406
|
+
"TYP": _process_NOOP,
|
|
407
|
+
"TTL": _process_NOOP,
|
|
408
|
+
"VAT": _process_VAT,
|
|
409
|
+
"VTS": _process_NOOP,
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _customer_mods(headers, bill):
|
|
414
|
+
if headers["customer_number"] == "WESSEXWAT":
|
|
415
|
+
if (
|
|
416
|
+
headers["element_code"] == "307660"
|
|
417
|
+
and "ro-gbp" in bill["breakdown"]
|
|
418
|
+
and bill["issue_date"] == to_utc(ct_datetime(2023, 4, 14))
|
|
419
|
+
and bill["start_date"] == to_utc(ct_datetime(2023, 3, 1))
|
|
420
|
+
and bill["finish_date"] == to_utc(ct_datetime(2023, 3, 31, 23, 30))
|
|
421
|
+
):
|
|
422
|
+
bill["start_date"] = to_utc(ct_datetime(2021, 4, 1))
|
|
423
|
+
bill["finish_date"] = to_utc(ct_datetime(2022, 3, 31, 23, 30))
|
|
424
|
+
|
|
425
|
+
return bill
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
class Parser:
|
|
429
|
+
def __init__(self, f):
|
|
430
|
+
self.edi_str = str(f.read(), "utf-8", errors="ignore")
|
|
431
|
+
self.line_number = None
|
|
432
|
+
|
|
433
|
+
def make_raw_bills(self):
|
|
434
|
+
bills = []
|
|
435
|
+
headers = {"bills": []}
|
|
436
|
+
for self.line_number, line, seg_name, elements in parse_edi(self.edi_str):
|
|
437
|
+
headers["line"] = line
|
|
438
|
+
try:
|
|
439
|
+
func = CODE_FUNCS[seg_name]
|
|
440
|
+
except KeyError:
|
|
441
|
+
raise BadRequest(f"Code {seg_name} not recognized.")
|
|
442
|
+
|
|
443
|
+
try:
|
|
444
|
+
bills_chunk = func(elements, headers)
|
|
445
|
+
except BadRequest as e:
|
|
446
|
+
raise BadRequest(
|
|
447
|
+
f"{e.description} on line {self.line_number} line {line} "
|
|
448
|
+
f"seg_name {seg_name} elements {elements}"
|
|
449
|
+
)
|
|
450
|
+
except BaseException as e:
|
|
451
|
+
raise BadRequest(
|
|
452
|
+
f"{e} on line {self.line_number} line {line} "
|
|
453
|
+
f"seg_name {seg_name} elements {elements}"
|
|
454
|
+
) from e
|
|
455
|
+
|
|
456
|
+
if bills_chunk is not None:
|
|
457
|
+
bills.extend(bills_chunk)
|
|
458
|
+
|
|
459
|
+
return bills
|
chellow/e/views.py
CHANGED
|
@@ -28,7 +28,7 @@ from sqlalchemy.orm import aliased, joinedload
|
|
|
28
28
|
|
|
29
29
|
from werkzeug.exceptions import BadRequest
|
|
30
30
|
|
|
31
|
-
from zish import dumps, loads
|
|
31
|
+
from zish import ZishException, dumps, loads
|
|
32
32
|
|
|
33
33
|
import chellow.e.dno_rate_parser
|
|
34
34
|
import chellow.e.lcc
|
|
@@ -4910,62 +4910,83 @@ def supplier_batches_get():
|
|
|
4910
4910
|
@e.route("/supplier_batches/<int:batch_id>")
|
|
4911
4911
|
def supplier_batch_get(batch_id):
|
|
4912
4912
|
batch = Batch.get_by_id(g.sess, batch_id)
|
|
4913
|
-
|
|
4914
4913
|
num_bills = sum_net_gbp = sum_vat_gbp = sum_gross_gbp = sum_kwh = 0
|
|
4915
4914
|
vat_breakdown = {}
|
|
4916
|
-
bills = (
|
|
4917
|
-
g.sess.execute(
|
|
4918
|
-
select(Bill)
|
|
4919
|
-
.where(Bill.batch == batch)
|
|
4920
|
-
.order_by(Bill.reference)
|
|
4921
|
-
.options(joinedload(Bill.bill_type))
|
|
4922
|
-
)
|
|
4923
|
-
.scalars()
|
|
4924
|
-
.all()
|
|
4925
|
-
)
|
|
4926
|
-
for bill in bills:
|
|
4927
|
-
num_bills += 1
|
|
4928
|
-
sum_net_gbp += bill.net
|
|
4929
|
-
sum_vat_gbp += bill.vat
|
|
4930
|
-
sum_gross_gbp += bill.gross
|
|
4931
|
-
sum_kwh += bill.kwh
|
|
4932
4915
|
|
|
4933
|
-
|
|
4934
|
-
if "vat" in bd:
|
|
4935
|
-
for vat_percentage, vat_vals in bd["vat"].items():
|
|
4936
|
-
try:
|
|
4937
|
-
vbd = vat_breakdown[vat_percentage]
|
|
4938
|
-
except KeyError:
|
|
4939
|
-
vbd = vat_breakdown[vat_percentage] = defaultdict(int)
|
|
4916
|
+
try:
|
|
4940
4917
|
|
|
4941
|
-
|
|
4942
|
-
|
|
4918
|
+
bills = (
|
|
4919
|
+
g.sess.execute(
|
|
4920
|
+
select(Bill)
|
|
4921
|
+
.where(Bill.batch == batch)
|
|
4922
|
+
.order_by(Bill.reference)
|
|
4923
|
+
.options(joinedload(Bill.bill_type))
|
|
4924
|
+
)
|
|
4925
|
+
.scalars()
|
|
4926
|
+
.all()
|
|
4927
|
+
)
|
|
4928
|
+
for bill in bills:
|
|
4929
|
+
num_bills += 1
|
|
4930
|
+
sum_net_gbp += bill.net
|
|
4931
|
+
sum_vat_gbp += bill.vat
|
|
4932
|
+
sum_gross_gbp += bill.gross
|
|
4933
|
+
sum_kwh += bill.kwh
|
|
4943
4934
|
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
if "batch_reports" in properties:
|
|
4947
|
-
batch_reports = []
|
|
4948
|
-
for report_id in properties["batch_reports"]:
|
|
4949
|
-
batch_reports.append(Report.get_by_id(g.sess, report_id))
|
|
4950
|
-
else:
|
|
4951
|
-
batch_reports = None
|
|
4935
|
+
try:
|
|
4936
|
+
bd = bill.bd
|
|
4952
4937
|
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4938
|
+
if "vat" in bd:
|
|
4939
|
+
for vat_percentage, vat_vals in bd["vat"].items():
|
|
4940
|
+
try:
|
|
4941
|
+
vbd = vat_breakdown[vat_percentage]
|
|
4942
|
+
except KeyError:
|
|
4943
|
+
vbd = vat_breakdown[vat_percentage] = defaultdict(int)
|
|
4944
|
+
|
|
4945
|
+
vbd["vat"] += vat_vals["vat"]
|
|
4946
|
+
vbd["net"] += vat_vals["net"]
|
|
4947
|
+
except ZishException as e:
|
|
4948
|
+
raise BadRequest(f"Problem with bill {bill.id}") from e
|
|
4949
|
+
|
|
4950
|
+
config_contract = Contract.get_non_core_by_name(g.sess, "configuration")
|
|
4951
|
+
properties = config_contract.make_properties()
|
|
4952
|
+
if "batch_reports" in properties:
|
|
4953
|
+
batch_reports = []
|
|
4954
|
+
for report_id in properties["batch_reports"]:
|
|
4955
|
+
batch_reports.append(Report.get_by_id(g.sess, report_id))
|
|
4956
|
+
else:
|
|
4957
|
+
batch_reports = None
|
|
4958
|
+
|
|
4959
|
+
importer_ids = sorted(
|
|
4960
|
+
chellow.e.bill_importer.get_bill_import_ids(batch), reverse=True
|
|
4961
|
+
)
|
|
4962
|
+
return render_template(
|
|
4963
|
+
"supplier_batch.html",
|
|
4964
|
+
batch=batch,
|
|
4965
|
+
bills=bills,
|
|
4966
|
+
batch_reports=batch_reports,
|
|
4967
|
+
num_bills=num_bills,
|
|
4968
|
+
sum_net_gbp=sum_net_gbp,
|
|
4969
|
+
sum_vat_gbp=sum_vat_gbp,
|
|
4970
|
+
sum_gross_gbp=sum_gross_gbp,
|
|
4971
|
+
sum_kwh=sum_kwh,
|
|
4972
|
+
vat_breakdown=vat_breakdown,
|
|
4973
|
+
importer_ids=importer_ids,
|
|
4974
|
+
)
|
|
4975
|
+
except BadRequest as e:
|
|
4976
|
+
flash(e.description)
|
|
4977
|
+
return make_response(
|
|
4978
|
+
render_template(
|
|
4979
|
+
"supplier_batch.html",
|
|
4980
|
+
batch=batch,
|
|
4981
|
+
num_bills=num_bills,
|
|
4982
|
+
sum_net_gbp=sum_net_gbp,
|
|
4983
|
+
sum_vat_gbp=sum_vat_gbp,
|
|
4984
|
+
vat_breakdown=vat_breakdown,
|
|
4985
|
+
sum_gross_gbp=sum_gross_gbp,
|
|
4986
|
+
sum_kwh=sum_kwh,
|
|
4987
|
+
),
|
|
4988
|
+
400,
|
|
4989
|
+
)
|
|
4969
4990
|
|
|
4970
4991
|
|
|
4971
4992
|
@e.route("/supplier_batches/<int:batch_id>/edit")
|