chellow 1757320031.0.0__py3-none-any.whl → 1759411815.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_importer.py +136 -80
- chellow/e/bill_parsers/activity_mop_stark_xlsx.py +99 -86
- chellow/e/bill_parsers/annual_mop_stark_xlsx.py +78 -61
- chellow/e/bill_parsers/csv.py +139 -101
- chellow/e/bill_parsers/drax_edi.py +65 -89
- chellow/e/bill_parsers/engie_edi.py +187 -255
- chellow/e/bill_parsers/engie_xls.py +153 -167
- chellow/e/bill_parsers/haven_edi.py +189 -228
- chellow/e/bill_parsers/haven_edi_tprs.py +67 -67
- chellow/e/bill_parsers/nonsettlement_dc_stark_xlsx.py +75 -66
- chellow/e/bill_parsers/settlement_dc_stark_xlsx.py +229 -126
- chellow/e/bill_parsers/sse_edi.py +107 -75
- chellow/e/bill_parsers/sww_xls.py +78 -91
- chellow/e/computer.py +1 -1
- chellow/e/views.py +626 -281
- chellow/edi_lib.py +4 -27
- chellow/models.py +92 -3
- chellow/reports/report_111.py +514 -616
- chellow/reports/report_247.py +96 -137
- chellow/templates/e/dc_batch.html +110 -157
- chellow/templates/e/dc_batch_add.html +2 -3
- chellow/templates/e/dc_batch_edit.html +42 -46
- chellow/templates/e/dc_batch_file.html +2 -3
- chellow/templates/e/dc_batch_file_edit.html +28 -40
- chellow/templates/e/dc_batch_upload_file.html +68 -0
- chellow/templates/e/dc_batches.html +2 -1
- chellow/templates/e/dc_batches_edit.html +26 -0
- chellow/templates/e/dc_bill.html +27 -5
- chellow/templates/e/dc_bill_add.html +4 -4
- chellow/templates/e/dc_bill_edit.html +43 -63
- chellow/templates/e/dc_bill_import.html +1 -1
- chellow/templates/e/dc_bill_import_contract.html +130 -0
- chellow/templates/e/dc_contract.html +1 -1
- chellow/templates/e/dc_element.html +41 -0
- chellow/templates/e/dc_element_add.html +36 -0
- chellow/templates/e/dc_element_edit.html +49 -0
- chellow/templates/e/dc_rate_script_edit.html +27 -43
- chellow/templates/e/mop_batch.html +105 -152
- chellow/templates/e/mop_batch_add.html +2 -3
- chellow/templates/e/mop_batch_edit.html +43 -51
- chellow/templates/e/mop_batch_upload_file.html +71 -5
- chellow/templates/e/mop_batches.html +2 -1
- chellow/templates/e/mop_batches_edit.html +26 -0
- chellow/templates/e/mop_bill.html +31 -8
- chellow/templates/e/mop_bill_add.html +7 -27
- chellow/templates/e/mop_bill_import.html +1 -1
- chellow/templates/e/mop_bill_import_contract.html +130 -0
- chellow/templates/e/mop_contract.html +4 -5
- chellow/templates/e/mop_element.html +41 -0
- chellow/templates/e/mop_element_add.html +36 -0
- chellow/templates/e/mop_element_edit.html +49 -0
- chellow/templates/e/supplier_batch.html +3 -7
- chellow/templates/e/supplier_batch_add.html +2 -2
- chellow/templates/e/supplier_batch_edit.html +1 -1
- chellow/templates/e/supplier_batch_file.html +3 -5
- chellow/templates/e/supplier_batch_file_add.html +18 -11
- chellow/templates/e/supplier_batch_upload_file.html +83 -9
- chellow/templates/e/supplier_batches.html +4 -4
- chellow/templates/e/supplier_batches_edit.html +26 -0
- chellow/templates/e/supplier_bill.html +29 -6
- chellow/templates/e/supplier_bill_add.html +3 -3
- chellow/templates/e/supplier_bill_import.html +1 -1
- chellow/templates/e/supplier_bill_import_contract.html +118 -0
- chellow/templates/e/supplier_contract.html +1 -1
- chellow/templates/e/supplier_element.html +45 -0
- chellow/templates/e/supplier_element_add.html +36 -0
- chellow/templates/e/supplier_element_edit.html +51 -0
- chellow/templates/report_run_bill_check.html +137 -179
- chellow/templates/report_run_row_bill_check.html +187 -179
- chellow/views.py +57 -64
- {chellow-1757320031.0.0.dist-info → chellow-1759411815.0.0.dist-info}/METADATA +2 -2
- {chellow-1757320031.0.0.dist-info → chellow-1759411815.0.0.dist-info}/RECORD +73 -60
- chellow/e/bill_parsers/drax_element_edi.py +0 -459
- chellow/templates/e/supplier_bill_imports.html +0 -421
- {chellow-1757320031.0.0.dist-info → chellow-1759411815.0.0.dist-info}/WHEEL +0 -0
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
2
|
from datetime import datetime as Datetime
|
|
3
3
|
from decimal import Decimal, InvalidOperation
|
|
4
|
-
from io import StringIO
|
|
5
4
|
|
|
6
5
|
from dateutil.relativedelta import relativedelta
|
|
7
6
|
|
|
8
7
|
from werkzeug.exceptions import BadRequest
|
|
9
8
|
|
|
10
|
-
from chellow.edi_lib import
|
|
9
|
+
from chellow.edi_lib import parse_edi, to_date, to_gbp
|
|
11
10
|
from chellow.models import Session, Ssc, Supply
|
|
12
11
|
from chellow.utils import HH, parse_mpan_core, to_ct, to_utc
|
|
13
12
|
|
|
@@ -99,11 +98,11 @@ SSC_MAP = {
|
|
|
99
98
|
# None denotes a TPR-based charge
|
|
100
99
|
|
|
101
100
|
TMOD_MAP = {
|
|
102
|
-
"700285": ("standing
|
|
103
|
-
"422733": ("ccl
|
|
104
|
-
"066540": ("ccl
|
|
101
|
+
"700285": ("standing", "rate", "days"),
|
|
102
|
+
"422733": ("ccl", "rate", "kwh"),
|
|
103
|
+
"066540": ("ccl", "rate", "kwh"),
|
|
105
104
|
"453043": None,
|
|
106
|
-
"493988": ("reconciliation
|
|
105
|
+
"493988": ("reconciliation", None, None),
|
|
107
106
|
"068476": None,
|
|
108
107
|
"265091": None,
|
|
109
108
|
"517180": None,
|
|
@@ -114,6 +113,16 @@ TMOD_MAP = {
|
|
|
114
113
|
BillElement = namedtuple("BillElement", ["gbp", "rate", "cons", "titles", "desc"])
|
|
115
114
|
|
|
116
115
|
|
|
116
|
+
def _process_BCD(elements, headers):
|
|
117
|
+
headers["issue_date"] = to_date(elements["IVDT"][0])
|
|
118
|
+
headers["reference"] = elements["INVN"][0]
|
|
119
|
+
headers["bill_type_code"] = elements["BTCD"][0]
|
|
120
|
+
|
|
121
|
+
sumo = elements["SUMO"]
|
|
122
|
+
headers["start_date"] = to_date(sumo[0])
|
|
123
|
+
headers["finish_date"] = to_date(sumo[1]) + relativedelta(days=1) - HH
|
|
124
|
+
|
|
125
|
+
|
|
117
126
|
def _to_date(component):
|
|
118
127
|
return to_utc(to_ct(Datetime.strptime(component, "%y%m%d")))
|
|
119
128
|
|
|
@@ -137,132 +146,11 @@ def _to_decimal(components, divisor=None):
|
|
|
137
146
|
return result
|
|
138
147
|
|
|
139
148
|
|
|
140
|
-
def
|
|
141
|
-
|
|
142
|
-
elem_codes = [m["code"] for m in SEGMENTS[segment_name]["elements"]]
|
|
143
|
-
return dict(zip(elem_codes, elements))
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
class Parser:
|
|
147
|
-
def __init__(self, f):
|
|
148
|
-
self.parser = EdiParser(StringIO(str(f.read(), "utf-8", errors="ignore")))
|
|
149
|
-
self.line_number = None
|
|
150
|
-
|
|
151
|
-
def make_raw_bills(self):
|
|
152
|
-
raw_bills = []
|
|
153
|
-
with Session() as sess:
|
|
154
|
-
headers = {"sess": sess, "errors": []}
|
|
155
|
-
for self.line_number, code in enumerate(self.parser):
|
|
156
|
-
elements = _find_elements(code, self.parser.elements)
|
|
157
|
-
line = self.parser.line
|
|
158
|
-
bill = _process_segment(code, elements, line, headers, self.line_number)
|
|
159
|
-
if bill is not None:
|
|
160
|
-
raw_bills.append(bill)
|
|
161
|
-
|
|
162
|
-
return raw_bills
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def _process_segment(code, elements, line, headers, line_number):
|
|
166
|
-
try:
|
|
167
|
-
if "breakdown" in headers:
|
|
168
|
-
headers["breakdown"]["raw-lines"].append(line)
|
|
169
|
-
|
|
170
|
-
if code == "BCD":
|
|
171
|
-
headers["issue_date"] = _to_date(elements["IVDT"][0])
|
|
172
|
-
headers["reference"] = elements["INVN"][0]
|
|
173
|
-
headers["bill_type_code"] = elements["BTCD"][0]
|
|
174
|
-
|
|
175
|
-
sumo = elements["SUMO"]
|
|
176
|
-
headers["start_date"] = _to_date(sumo[0])
|
|
177
|
-
headers["finish_date"] = _to_date(sumo[1]) + relativedelta(days=1) - HH
|
|
178
|
-
|
|
179
|
-
elif code == "BTL":
|
|
180
|
-
_process_BTL(elements, headers)
|
|
181
|
-
|
|
182
|
-
elif code == "MHD":
|
|
183
|
-
_process_MHD(elements, headers)
|
|
184
|
-
|
|
185
|
-
elif code == "CCD":
|
|
186
|
-
_process_CCD(elements, headers)
|
|
187
|
-
|
|
188
|
-
elif code == "CLO":
|
|
189
|
-
_process_CLO(elements, headers)
|
|
190
|
-
|
|
191
|
-
elif code == "MTR":
|
|
192
|
-
_process_MTR(elements, headers)
|
|
193
|
-
|
|
194
|
-
elif code == "MAN":
|
|
195
|
-
_process_MAN(elements, headers)
|
|
196
|
-
|
|
197
|
-
except BadRequest as e:
|
|
198
|
-
headers["errors"].append(
|
|
199
|
-
f"Can't parse the line number {line_number} {line}: {e.description}"
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
if code == "MTR":
|
|
203
|
-
bill = {}
|
|
204
|
-
|
|
205
|
-
if "message_type" in headers and headers["message_type"] == "UTLBIL":
|
|
206
|
-
for k in (
|
|
207
|
-
"kwh",
|
|
208
|
-
"reference",
|
|
209
|
-
"mpan_core",
|
|
210
|
-
"issue_date",
|
|
211
|
-
"account",
|
|
212
|
-
"start_date",
|
|
213
|
-
"finish_date",
|
|
214
|
-
"net",
|
|
215
|
-
"vat",
|
|
216
|
-
"gross",
|
|
217
|
-
"breakdown",
|
|
218
|
-
"bill_type_code",
|
|
219
|
-
"reads",
|
|
220
|
-
):
|
|
221
|
-
if k in headers:
|
|
222
|
-
bill[k] = headers[k]
|
|
223
|
-
else:
|
|
224
|
-
headers["errors"].append(
|
|
225
|
-
f"The key {k} is missing from the headers at line number "
|
|
226
|
-
f"{line_number}."
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
if len(headers["errors"]) > 0:
|
|
230
|
-
bill["error"] = " ".join(headers["errors"])
|
|
231
|
-
return bill
|
|
232
|
-
|
|
233
|
-
elif len(headers["errors"]) > 0:
|
|
234
|
-
bill["error"] = " ".join(headers["errors"])
|
|
235
|
-
return bill
|
|
149
|
+
def _process_NOOP(elements, headers):
|
|
150
|
+
pass
|
|
236
151
|
|
|
237
152
|
|
|
238
153
|
def _process_BTL(elements, headers):
|
|
239
|
-
headers["net"] = Decimal("0.00") + _to_decimal(elements["UVLT"], "100")
|
|
240
|
-
headers["vat"] = Decimal("0.00") + _to_decimal(elements["UTVA"], "100")
|
|
241
|
-
headers["gross"] = Decimal("0.00") + _to_decimal(elements["TBTL"], "100")
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
def _process_CLO(elements, headers):
|
|
245
|
-
cloc = elements["CLOC"]
|
|
246
|
-
headers["account"] = cloc[1]
|
|
247
|
-
# headers['msn'] = cloc[2] if len(cloc) > 2 else ''
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
def _process_MAN(elements, headers):
|
|
251
|
-
madn = elements["MADN"]
|
|
252
|
-
dno = madn[0]
|
|
253
|
-
unique = madn[1]
|
|
254
|
-
check_digit = madn[2]
|
|
255
|
-
# pc = madn[3]
|
|
256
|
-
# mtc = madn[4]
|
|
257
|
-
# llfc = madn[5]
|
|
258
|
-
|
|
259
|
-
headers["mpan_core"] = parse_mpan_core("".join([dno, unique, check_digit]))
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
def _process_MTR(elements, headers):
|
|
263
|
-
if headers["message_type"] != "UTLBIL":
|
|
264
|
-
return
|
|
265
|
-
|
|
266
154
|
sess = headers["sess"]
|
|
267
155
|
try:
|
|
268
156
|
mpan_core = headers["mpan_core"]
|
|
@@ -273,7 +161,6 @@ def _process_MTR(elements, headers):
|
|
|
273
161
|
reads = headers["reads"]
|
|
274
162
|
supply = Supply.get_by_mpan_core(sess, mpan_core)
|
|
275
163
|
era = supply.find_era_at(sess, start_date)
|
|
276
|
-
bill_elements = []
|
|
277
164
|
if era is None:
|
|
278
165
|
era = supply.find_last_era(sess)
|
|
279
166
|
|
|
@@ -282,7 +169,7 @@ def _process_MTR(elements, headers):
|
|
|
282
169
|
ssc = Ssc.get_by_code(sess, "0393")
|
|
283
170
|
else:
|
|
284
171
|
imp_mpan_core = era.imp_mpan_core
|
|
285
|
-
ssc = Ssc.get_by_code(sess, "0393") if era.ssc is None else era.ssc
|
|
172
|
+
ssc = Ssc.get_by_code(sess, "0393", start_date) if era.ssc is None else era.ssc
|
|
286
173
|
|
|
287
174
|
try:
|
|
288
175
|
ssc_lookup = imp_mpan_core
|
|
@@ -303,68 +190,80 @@ def _process_MTR(elements, headers):
|
|
|
303
190
|
f"The description {desc} isn't in the SSC_MAP for the SSC {ssc_lookup}."
|
|
304
191
|
)
|
|
305
192
|
|
|
193
|
+
elems = []
|
|
306
194
|
for el in headers["bill_elements"]:
|
|
307
|
-
if el.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
gbp = el.gbp / num_mrs
|
|
315
|
-
cons = el.cons / num_mrs
|
|
316
|
-
for mr in mrs:
|
|
317
|
-
tpr_code = mr.tpr.code
|
|
318
|
-
titles = f"{tpr_code}-gbp", f"{tpr_code}-rate", f"{tpr_code}-kwh"
|
|
319
|
-
bill_elements.append(
|
|
320
|
-
BillElement(
|
|
321
|
-
gbp=gbp, rate=el.rate, cons=cons, titles=titles, desc=None
|
|
322
|
-
)
|
|
195
|
+
if el.titles is None:
|
|
196
|
+
try:
|
|
197
|
+
tpr = tpr_map[el.desc]
|
|
198
|
+
except KeyError:
|
|
199
|
+
raise BadRequest(
|
|
200
|
+
f"The billing element description {el.desc} isn't in the "
|
|
201
|
+
f"SSC_MAP for the SSC {ssc_lookup}."
|
|
323
202
|
)
|
|
203
|
+
|
|
204
|
+
elname, elrate, elcons = f"{tpr}", "rate", "kwh"
|
|
324
205
|
else:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
206
|
+
elname, elrate, elcons = el.titles
|
|
207
|
+
|
|
208
|
+
bd = {}
|
|
209
|
+
if elrate is not None and el.rate is not None:
|
|
210
|
+
bd[elrate] = {el.rate}
|
|
211
|
+
if elcons is not None and el.cons is not None:
|
|
212
|
+
bd[elcons] = el.cons
|
|
213
|
+
|
|
214
|
+
if el.gbp is not None:
|
|
215
|
+
elems.append(
|
|
216
|
+
{
|
|
217
|
+
"name": elname,
|
|
218
|
+
"net": el.gbp,
|
|
219
|
+
"breakdown": bd,
|
|
220
|
+
"start_date": headers["start_date"],
|
|
221
|
+
"finish_date": headers["finish_date"],
|
|
222
|
+
}
|
|
342
223
|
)
|
|
343
224
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
225
|
+
bill = {
|
|
226
|
+
"net": to_gbp(elements["UVLT"]),
|
|
227
|
+
"vat": to_gbp(elements["UTVA"]),
|
|
228
|
+
"gross": to_gbp(elements["TBTL"]),
|
|
229
|
+
"elements": elems,
|
|
230
|
+
"mpan_core": headers["mpan_core"],
|
|
231
|
+
"reads": headers["reads"],
|
|
232
|
+
"start_date": headers["start_date"],
|
|
233
|
+
"finish_date": headers["finish_date"],
|
|
234
|
+
"issue_date": headers["issue_date"],
|
|
235
|
+
"breakdown": headers["breakdown"],
|
|
236
|
+
"reference": headers["reference"],
|
|
237
|
+
"kwh": headers["kwh"],
|
|
238
|
+
"bill_type_code": headers["bill_type_code"],
|
|
239
|
+
"account": headers["account"],
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if len(headers["errors"]) > 0:
|
|
243
|
+
bill["error"] = " ".join(headers["errors"])
|
|
244
|
+
return bill
|
|
347
245
|
|
|
348
|
-
try:
|
|
349
|
-
breakdown[eln_gbp] += bill_el.gbp
|
|
350
|
-
except KeyError:
|
|
351
|
-
breakdown[eln_gbp] = bill_el.gbp
|
|
352
246
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
except KeyError:
|
|
358
|
-
rates = breakdown[eln_rate] = set()
|
|
247
|
+
def _process_CLO(elements, headers):
|
|
248
|
+
cloc = elements["CLOC"]
|
|
249
|
+
headers["account"] = cloc[1]
|
|
250
|
+
# headers['msn'] = cloc[2] if len(cloc) > 2 else ''
|
|
359
251
|
|
|
360
|
-
rates.add(rate)
|
|
361
252
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
253
|
+
def _process_MAN(elements, headers):
|
|
254
|
+
madn = elements["MADN"]
|
|
255
|
+
dno = madn[0]
|
|
256
|
+
unique = madn[1]
|
|
257
|
+
check_digit = madn[2]
|
|
258
|
+
# pc = madn[3]
|
|
259
|
+
# mtc = madn[4]
|
|
260
|
+
# llfc = madn[5]
|
|
261
|
+
|
|
262
|
+
headers["mpan_core"] = parse_mpan_core("".join([dno, unique, check_digit]))
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _process_MTR(elements, headers):
|
|
266
|
+
pass
|
|
368
267
|
|
|
369
268
|
|
|
370
269
|
def _process_MHD(elements, headers):
|
|
@@ -381,59 +280,46 @@ def _process_MHD(elements, headers):
|
|
|
381
280
|
headers["message_type"] = message_type
|
|
382
281
|
|
|
383
282
|
|
|
384
|
-
def
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
283
|
+
def _process_CCD4(elements, headers):
|
|
284
|
+
tmod_1 = elements["TMOD"][0]
|
|
285
|
+
try:
|
|
286
|
+
eln_gbp, eln_rate, eln_cons = TMOD_MAP[tmod_1]
|
|
287
|
+
except KeyError:
|
|
288
|
+
raise BadRequest(
|
|
289
|
+
f"Can't find the Tariff Modifer Code 1 {tmod_1} in the TMOD_MAP."
|
|
290
|
+
)
|
|
390
291
|
|
|
391
|
-
|
|
392
|
-
|
|
292
|
+
"""
|
|
293
|
+
m = elements['MLOC'][0]
|
|
294
|
+
mpan_core = ' '.join((m[:2], m[2:6], m[6:10], m[10:]))
|
|
295
|
+
"""
|
|
296
|
+
breakdown = headers["breakdown"]
|
|
393
297
|
|
|
394
|
-
|
|
395
|
-
|
|
298
|
+
cons = elements["CONS"]
|
|
299
|
+
if eln_cons is not None and len(cons[0]) > 0:
|
|
300
|
+
el_cons = _to_decimal(cons, "1000")
|
|
301
|
+
breakdown[eln_cons] = el_cons
|
|
396
302
|
|
|
397
|
-
|
|
398
|
-
|
|
303
|
+
if eln_rate is not None:
|
|
304
|
+
rate = _to_decimal(elements["BPRI"], "100000")
|
|
399
305
|
try:
|
|
400
|
-
|
|
306
|
+
rates = breakdown[eln_rate]
|
|
401
307
|
except KeyError:
|
|
402
|
-
|
|
403
|
-
f"Can't find the Tariff Modifer Code 1 {tmod_1} in the TMOD_MAP."
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
"""
|
|
407
|
-
m = elements['MLOC'][0]
|
|
408
|
-
mpan_core = ' '.join((m[:2], m[2:6], m[6:10], m[10:]))
|
|
409
|
-
"""
|
|
410
|
-
breakdown = headers["breakdown"]
|
|
411
|
-
|
|
412
|
-
cons = elements["CONS"]
|
|
413
|
-
if eln_cons is not None and len(cons[0]) > 0:
|
|
414
|
-
el_cons = _to_decimal(cons, "1000")
|
|
415
|
-
breakdown[eln_cons] = el_cons
|
|
416
|
-
|
|
417
|
-
if eln_rate is not None:
|
|
418
|
-
rate = _to_decimal(elements["BPRI"], "100000")
|
|
419
|
-
try:
|
|
420
|
-
rates = breakdown[eln_rate]
|
|
421
|
-
except KeyError:
|
|
422
|
-
rates = breakdown[eln_rate] = set()
|
|
308
|
+
rates = breakdown[eln_rate] = set()
|
|
423
309
|
|
|
424
|
-
|
|
310
|
+
rates.append(rate)
|
|
425
311
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
312
|
+
"""
|
|
313
|
+
start_date = _to_date(elements['CSDT'][0])
|
|
314
|
+
finish_date = _to_date(elements['CEDT'][0]) - HH
|
|
315
|
+
"""
|
|
430
316
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
317
|
+
if "CTOT" in elements:
|
|
318
|
+
net = Decimal("0.00") + _to_decimal(elements["CTOT"], "100")
|
|
319
|
+
else:
|
|
320
|
+
net = Decimal("0.00")
|
|
435
321
|
|
|
436
|
-
|
|
322
|
+
breakdown[eln_gbp] = net
|
|
437
323
|
|
|
438
324
|
|
|
439
325
|
def _process_CCD1(elements, headers):
|
|
@@ -567,3 +453,78 @@ def _process_CCD3(elements, headers):
|
|
|
567
453
|
headers["bill_elements"].append(
|
|
568
454
|
BillElement(gbp=gbp, rate=rate, cons=consumption, titles=titles, desc=desc)
|
|
569
455
|
)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _process_VAT(elements, header):
|
|
459
|
+
pass
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
CODE_FUNCS = {
|
|
463
|
+
"BCD": _process_BCD,
|
|
464
|
+
"BTL": _process_BTL,
|
|
465
|
+
"CCD1": _process_CCD1,
|
|
466
|
+
"CCD2": _process_CCD2,
|
|
467
|
+
"CCD3": _process_CCD3,
|
|
468
|
+
"CCD4": _process_CCD4,
|
|
469
|
+
"CDA": _process_NOOP,
|
|
470
|
+
"CDT": _process_NOOP,
|
|
471
|
+
"CLO": _process_CLO,
|
|
472
|
+
"DNA": _process_NOOP,
|
|
473
|
+
"END": _process_NOOP,
|
|
474
|
+
"FIL": _process_NOOP,
|
|
475
|
+
"MAN": _process_MAN,
|
|
476
|
+
"MHD": _process_MHD,
|
|
477
|
+
"MTR": _process_MTR,
|
|
478
|
+
"REF": _process_NOOP,
|
|
479
|
+
"SDT": _process_NOOP,
|
|
480
|
+
"STX": _process_NOOP,
|
|
481
|
+
"TYP": _process_NOOP,
|
|
482
|
+
"TTL": _process_NOOP,
|
|
483
|
+
"VAT": _process_VAT,
|
|
484
|
+
"VTS": _process_NOOP,
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def _process_segment(headers, line_number, line, seg_name, elements):
|
|
489
|
+
try:
|
|
490
|
+
func = CODE_FUNCS[seg_name]
|
|
491
|
+
except KeyError:
|
|
492
|
+
raise BadRequest(f"Code {seg_name} not recognized.")
|
|
493
|
+
|
|
494
|
+
try:
|
|
495
|
+
bill = func(elements, headers)
|
|
496
|
+
except BadRequest as e:
|
|
497
|
+
raise BadRequest(
|
|
498
|
+
f"{e.description} on line {line_number} line {line} "
|
|
499
|
+
f"seg_name {seg_name} elements {elements}"
|
|
500
|
+
)
|
|
501
|
+
except BaseException as e:
|
|
502
|
+
raise BadRequest(
|
|
503
|
+
f"Problem on line {line_number} line {line} "
|
|
504
|
+
f"seg_name {seg_name} elements {elements}"
|
|
505
|
+
) from e
|
|
506
|
+
|
|
507
|
+
if "breakdown" in headers:
|
|
508
|
+
headers["breakdown"]["raw-lines"].append(line)
|
|
509
|
+
|
|
510
|
+
return bill
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class Parser:
|
|
514
|
+
def __init__(self, f):
|
|
515
|
+
self.edi_str = str(f.read(), "utf-8", errors="ignore")
|
|
516
|
+
self.line_number = None
|
|
517
|
+
|
|
518
|
+
def make_raw_bills(self):
|
|
519
|
+
bills = []
|
|
520
|
+
bill = None
|
|
521
|
+
with Session() as sess:
|
|
522
|
+
headers = {"sess": sess}
|
|
523
|
+
for self.line_number, line, seg_name, elements in parse_edi(self.edi_str):
|
|
524
|
+
bill = _process_segment(
|
|
525
|
+
headers, self.line_number, line, seg_name, elements
|
|
526
|
+
)
|
|
527
|
+
if bill is not None:
|
|
528
|
+
bills.append(bill)
|
|
529
|
+
|
|
530
|
+
return bills
|