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.

Files changed (75) hide show
  1. chellow/e/bill_importer.py +136 -80
  2. chellow/e/bill_parsers/activity_mop_stark_xlsx.py +99 -86
  3. chellow/e/bill_parsers/annual_mop_stark_xlsx.py +78 -61
  4. chellow/e/bill_parsers/csv.py +139 -101
  5. chellow/e/bill_parsers/drax_edi.py +65 -89
  6. chellow/e/bill_parsers/engie_edi.py +187 -255
  7. chellow/e/bill_parsers/engie_xls.py +153 -167
  8. chellow/e/bill_parsers/haven_edi.py +189 -228
  9. chellow/e/bill_parsers/haven_edi_tprs.py +67 -67
  10. chellow/e/bill_parsers/nonsettlement_dc_stark_xlsx.py +75 -66
  11. chellow/e/bill_parsers/settlement_dc_stark_xlsx.py +229 -126
  12. chellow/e/bill_parsers/sse_edi.py +107 -75
  13. chellow/e/bill_parsers/sww_xls.py +78 -91
  14. chellow/e/computer.py +1 -1
  15. chellow/e/views.py +626 -281
  16. chellow/edi_lib.py +4 -27
  17. chellow/models.py +92 -3
  18. chellow/reports/report_111.py +514 -616
  19. chellow/reports/report_247.py +96 -137
  20. chellow/templates/e/dc_batch.html +110 -157
  21. chellow/templates/e/dc_batch_add.html +2 -3
  22. chellow/templates/e/dc_batch_edit.html +42 -46
  23. chellow/templates/e/dc_batch_file.html +2 -3
  24. chellow/templates/e/dc_batch_file_edit.html +28 -40
  25. chellow/templates/e/dc_batch_upload_file.html +68 -0
  26. chellow/templates/e/dc_batches.html +2 -1
  27. chellow/templates/e/dc_batches_edit.html +26 -0
  28. chellow/templates/e/dc_bill.html +27 -5
  29. chellow/templates/e/dc_bill_add.html +4 -4
  30. chellow/templates/e/dc_bill_edit.html +43 -63
  31. chellow/templates/e/dc_bill_import.html +1 -1
  32. chellow/templates/e/dc_bill_import_contract.html +130 -0
  33. chellow/templates/e/dc_contract.html +1 -1
  34. chellow/templates/e/dc_element.html +41 -0
  35. chellow/templates/e/dc_element_add.html +36 -0
  36. chellow/templates/e/dc_element_edit.html +49 -0
  37. chellow/templates/e/dc_rate_script_edit.html +27 -43
  38. chellow/templates/e/mop_batch.html +105 -152
  39. chellow/templates/e/mop_batch_add.html +2 -3
  40. chellow/templates/e/mop_batch_edit.html +43 -51
  41. chellow/templates/e/mop_batch_upload_file.html +71 -5
  42. chellow/templates/e/mop_batches.html +2 -1
  43. chellow/templates/e/mop_batches_edit.html +26 -0
  44. chellow/templates/e/mop_bill.html +31 -8
  45. chellow/templates/e/mop_bill_add.html +7 -27
  46. chellow/templates/e/mop_bill_import.html +1 -1
  47. chellow/templates/e/mop_bill_import_contract.html +130 -0
  48. chellow/templates/e/mop_contract.html +4 -5
  49. chellow/templates/e/mop_element.html +41 -0
  50. chellow/templates/e/mop_element_add.html +36 -0
  51. chellow/templates/e/mop_element_edit.html +49 -0
  52. chellow/templates/e/supplier_batch.html +3 -7
  53. chellow/templates/e/supplier_batch_add.html +2 -2
  54. chellow/templates/e/supplier_batch_edit.html +1 -1
  55. chellow/templates/e/supplier_batch_file.html +3 -5
  56. chellow/templates/e/supplier_batch_file_add.html +18 -11
  57. chellow/templates/e/supplier_batch_upload_file.html +83 -9
  58. chellow/templates/e/supplier_batches.html +4 -4
  59. chellow/templates/e/supplier_batches_edit.html +26 -0
  60. chellow/templates/e/supplier_bill.html +29 -6
  61. chellow/templates/e/supplier_bill_add.html +3 -3
  62. chellow/templates/e/supplier_bill_import.html +1 -1
  63. chellow/templates/e/supplier_bill_import_contract.html +118 -0
  64. chellow/templates/e/supplier_contract.html +1 -1
  65. chellow/templates/e/supplier_element.html +45 -0
  66. chellow/templates/e/supplier_element_add.html +36 -0
  67. chellow/templates/e/supplier_element_edit.html +51 -0
  68. chellow/templates/report_run_bill_check.html +137 -179
  69. chellow/templates/report_run_row_bill_check.html +187 -179
  70. chellow/views.py +57 -64
  71. {chellow-1757320031.0.0.dist-info → chellow-1759411815.0.0.dist-info}/METADATA +2 -2
  72. {chellow-1757320031.0.0.dist-info → chellow-1759411815.0.0.dist-info}/RECORD +73 -60
  73. chellow/e/bill_parsers/drax_element_edi.py +0 -459
  74. chellow/templates/e/supplier_bill_imports.html +0 -421
  75. {chellow-1757320031.0.0.dist-info → chellow-1759411815.0.0.dist-info}/WHEEL +0 -0
@@ -14,134 +14,105 @@ from chellow.utils import HH, parse_mpan_core, to_ct, to_utc
14
14
 
15
15
 
16
16
  ELEM_MAP = {
17
- None: None,
18
- "Charge - Recurring": {
19
- None: ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days")
17
+ None: {
18
+ None: None,
19
+ "OOC MOP": {None: "meter-rental"},
20
20
  },
21
+ "Charge - Recurring": {None: "duos-fixed"},
21
22
  "Meter - Standard": {
22
- "Energy Bill Relief Scheme": {None: ["ebrs-gbp", "ebrs-msp-kwh"]},
23
- "Energy Bill Relief Scheme Discount": {None: ["ebrs-gbp", "ebrs-msp-kwh"]},
24
- "Energy Bill Discount Scheme": {None: ["ebrs-gbp", "ebrs-msp-kwh"]},
25
- },
26
- "Meter - UK Electricity - AAHEDC Pass-Thru": {
27
- None: ["aahedc-gbp", "aahedc-rate", "aahedc-gsp-kwh"]
28
- },
29
- "Meter - UK Electricity - BSUoS Pass-Thru": {
30
- None: ["bsuos-gbp", "bsuos-rate", "bsuos-nbp-kwh"]
23
+ "Energy Bill Relief Scheme": {None: "ebrs"},
24
+ "Energy Bill Relief Scheme Discount": {None: "ebrs"},
25
+ "Energy Bill Discount Scheme": {None: "ebrs"},
31
26
  },
27
+ "Meter - UK Electricity - AAHEDC Pass-Thru": {None: "aahedc"},
28
+ "Meter - UK Electricity - BSUoS Pass-Thru": {None: "bsuos"},
32
29
  "Meter - UK Electricity - Capacity Market Pass-Thru": {
33
- None: ["capacity-gbp", "capacity-rate", "capacity-kwh"],
34
- "Reverse Capacity Market Estimate": {None: ["capacity-gbp"]},
35
- },
36
- "Meter - UK Electricity - CfD FiT Pass-Thru": {
37
- None: ["cfd-fit-gbp", "cfd-fit-rate", "cfd-fit-nbp-kwh"]
30
+ None: "capacity",
31
+ "Reverse Capacity Market Estimate": {None: "capacity"},
38
32
  },
33
+ "Meter - UK Electricity - CfD FiT Pass-Thru": {None: "cfd-fit"},
39
34
  "Meter - UK Electricity - CCL": {
40
- None: ["ccl-gbp", "ccl-rate", "ccl-kwh"],
41
- "CCL": {None: ["ccl-gbp", "ccl-rate", "ccl-kwh"]},
42
- "Levy Exempt Energy": {None: ["lec-gbp", "lec-rate", "lec-kwh"]},
35
+ None: "ccl",
36
+ "CCL": {None: "ccl"},
37
+ "Levy Exempt Energy": {None: "lec"},
43
38
  },
44
39
  "Meter - UK Electricity - DUoS": {
45
40
  None: None,
46
41
  "DUoS Unit Rate 3": {
47
- None: ("duos-green-gbp", "duos-green-rate", "duos-green-kwh")
42
+ None: "duos-green",
48
43
  },
49
44
  "DUoS Unit Charge 3": {
50
- None: ("duos-green-gbp", "duos-green-rate", "duos-green-kwh")
45
+ None: "duos-green",
51
46
  },
52
47
  "DUoS Unit Charge 2": {
53
- None: ("duos-amber-gbp", "duos-amber-rate", "duos-amber-kwh")
48
+ None: "duos-amber",
54
49
  },
55
50
  "DUoS Unit Rate 2": {
56
- None: ("duos-amber-gbp", "duos-amber-rate", "duos-amber-kwh")
51
+ None: "duos-amber",
57
52
  },
58
- "DUoS Unit Charge 1": {None: ("duos-red-gbp", "duos-red-kwh", "duos-red-rate")},
59
- "DUoS Unit Rate 1": {None: ("duos-red-gbp", "duos-red-kwh", "duos-red-rate")},
60
- "DUoS Standing Charge": {
61
- None: ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days")
62
- },
63
- "DUoS Fixed": {None: ("duos-fixed-gbp", "duos-fixed-rate", "duos-fixed-days")},
53
+ "DUoS Unit Charge 1": {None: "duos-red"},
54
+ "DUoS Unit Rate 1": {None: "duos-red"},
55
+ "DUoS Standing Charge": {None: "duos-fixed"},
56
+ "DUoS Fixed": {None: "duos-fixed"},
64
57
  "DUoS Reactive": {
65
- None: ("duos-reactive-gbp", "duos-reactive-rate", "duos-reactive-kvarh")
58
+ None: "duos-reactive",
66
59
  },
67
60
  },
68
61
  "Meter - UK Electricity - FiT Pass-Thru": {
69
- None: ("fit-gbp", "fit-rate", "fit-msp-kwh")
62
+ None: "fit",
70
63
  },
71
64
  "Pass Thru - UK Electricity Cost Component": {
72
- None: ("meter-rental-gbp", "meter-rental-rate", "meter-rental-days")
73
- },
74
- "Meter - UK Electricity - RO Pass-Thru": {
75
- None: ("ro-gbp", "ro-rate", "ro-msp-kwh")
65
+ None: "meter-rental",
76
66
  },
67
+ "Meter - UK Electricity - RO Pass-Thru": {None: "ro"},
77
68
  "Meter - UK Electricity - TUoS": {
78
- None: ("triad-gbp", "triad-rate", "triad-gsp-kw"),
69
+ None: "triad",
79
70
  "TNUoS Fixed": {
80
- None: ("tnuos-gbp", "tnuos-rate", "tnuos-days"),
71
+ None: "tnuos",
81
72
  },
82
73
  },
83
74
  "Meter - UK Electricity - Standard": {
84
75
  None: None,
85
76
  "Unit Rate": {
86
77
  "Summer Weekday": {
87
- None: (
88
- "summer-weekday-gbp",
89
- "summer-weekday-rate",
90
- "summer-weekday-gsp-kwh",
91
- )
78
+ None: "summer-weekday",
92
79
  },
93
- "Peak": {None: ("peak-gbp", "peak-rate", "peak-gsp-kwh")},
80
+ "Peak": {None: "peak"},
94
81
  "Peak Shoulder": {
95
- None: (
96
- "peak-shoulder-gbp",
97
- "peak-shoulder-gsp-kwh",
98
- "peak-shoulder-rate",
99
- )
82
+ None: "peak-shoulder",
100
83
  },
101
84
  "Summer Night": {
102
- None: ("summer-night-gbp", "summer-night-rate", "summer-night-gsp-kwh")
85
+ None: "summer-night",
103
86
  },
104
87
  "Summer Weekend & Bank Holiday": {
105
- None: (
106
- "summer-weekend-gbp",
107
- "summer-weekend-rate",
108
- "summer-weekend-gsp-kwh",
109
- )
88
+ None: "summer-weekend",
110
89
  },
111
- "Night": {None: ("night-gbp", "night-rate", "night-gsp-kwh")},
90
+ "Night": {None: "night"},
112
91
  "Winter Weekday": {
113
- None: (
114
- "winter-weekday-gbp",
115
- "winter-weekday-rate",
116
- "winter-weekday-gsp-kwh",
117
- )
92
+ None: "winter-weekday",
118
93
  },
119
94
  "Winter Weekend & Bank Holiday": {
120
- None: (
121
- "winter-weekend-gbp",
122
- "winter-weekend-rate",
123
- "winter-weekend-gsp-kwh",
124
- )
95
+ None: "winter-weekend",
125
96
  },
126
97
  "Winter Night": {
127
- None: ("winter-night-gbp", "winter-night-rate", "winter-night-gsp-kwh")
98
+ None: "winter-night",
128
99
  },
129
- "Day": {None: ("day-gbp", "day-rate", "day-gsp-kwh")},
130
- "Single": {None: ("day-gbp", "day-rate", "day-gsp-kwh")},
131
- "Off Peak / Weekends": {None: ("day-gbp", "day-rate", "day-gsp-kwh")},
100
+ "Day": {None: "day"},
101
+ "Single": {None: "day"},
102
+ "Off Peak / Weekends": {None: "day"},
132
103
  },
133
104
  "Reverse BSUoS in Unit Rate": {
134
- None: ("bsuos-reverse-gbp", "bsuos-reverse-rate", "bsuos-reverse-nbp-kwh")
105
+ None: "bsuos-reverse",
135
106
  },
136
107
  },
137
- "Meter - UK Gas - CCL": {None: ("ccl-gbp", "ccl-rate", "ccl-kwh")},
108
+ "Meter - UK Gas - CCL": {None: "ccl"},
138
109
  }
139
110
 
140
111
 
141
- def _find_names(tree, path):
112
+ def _find_name(tree, path):
142
113
  if len(path) > 0:
143
114
  try:
144
- return _find_names(tree[path[0]], path[1:])
115
+ return _find_name(tree[path[0]], path[1:])
145
116
  except KeyError:
146
117
  pass
147
118
 
@@ -219,23 +190,23 @@ def get_dec(row, name):
219
190
  return None
220
191
 
221
192
 
222
- def _bd_add(bd, el_name, val):
223
- if el_name.split("-")[-1] in ("rate", "kva"):
224
- if el_name not in bd:
225
- bd[el_name] = set()
226
- bd[el_name].add(val)
193
+ def _get_vat_values(bd, percentage):
194
+ if "vat" in bd:
195
+ vat_breakdown = bd["vat"]
227
196
  else:
228
- if el_name not in bd:
229
- bd[el_name] = 0
230
- try:
231
- bd[el_name] += val
232
- except TypeError as e:
233
- raise BadRequest(
234
- f"Problem with element name {el_name} and value '{val}': {e}"
235
- )
197
+ vat_breakdown = bd["vat"] = {}
198
+
199
+ try:
200
+ vat_values = vat_breakdown[percentage]
201
+ except KeyError:
202
+ vat_values = vat_breakdown[percentage] = {
203
+ "vat": Decimal("0.00"),
204
+ "net": Decimal("0.00"),
205
+ }
206
+ return vat_values
236
207
 
237
208
 
238
- def _parse_row(row, row_index, datemode, title_row):
209
+ def _parse_row(bills, row, row_index, datemode, title_row):
239
210
  val = get_value(row, "Meter Point")
240
211
  try:
241
212
  mpan_core = parse_mpan_core(str(int(val)))
@@ -245,6 +216,11 @@ def _parse_row(row, row_index, datemode, title_row):
245
216
  f"{e}"
246
217
  )
247
218
 
219
+ try:
220
+ mc = bills[mpan_core]
221
+ except KeyError:
222
+ mc = bills[mpan_core] = {}
223
+
248
224
  bill_period = get_value(row, "Bill Period")
249
225
  if "-" in bill_period:
250
226
  period_start_naive, period_finish_naive = [
@@ -255,6 +231,26 @@ def _parse_row(row, row_index, datemode, title_row):
255
231
  else:
256
232
  period_start, period_finish = None, None
257
233
 
234
+ issue_date = get_date(row, "Bill Date", datemode)
235
+
236
+ try:
237
+ bill = mc[bill_period]
238
+ except KeyError:
239
+ bill = mc[bill_period] = {
240
+ "bill_type_code": "N",
241
+ "kwh": Decimal(0),
242
+ "vat": Decimal("0.00"),
243
+ "net": Decimal("0.00"),
244
+ "reads": [],
245
+ "breakdown": {"raw_lines": [str(title_row)]},
246
+ "account": mpan_core,
247
+ "issue_date": issue_date,
248
+ "start_date": period_start,
249
+ "finish_date": period_finish,
250
+ "mpan_core": mpan_core,
251
+ "elements": [],
252
+ }
253
+
258
254
  from_date = get_date(row, "From Date", datemode)
259
255
  if from_date is None:
260
256
  if period_start is None:
@@ -272,25 +268,11 @@ def _parse_row(row, row_index, datemode, title_row):
272
268
  else:
273
269
  to_date = to_utc(to_ct(to_date_naive + relativedelta(days=1) - HH))
274
270
 
275
- issue_date = get_date(row, "Bill Date", datemode)
276
271
  bill_number = get_value(row, "Bill Number")
277
- bill = {
278
- "bill_type_code": "N",
279
- "kwh": Decimal(0),
280
- "vat": Decimal("0.00"),
281
- "net": Decimal("0.00"),
282
- "reads": [],
283
- "breakdown": {"raw_lines": [str(title_row)]},
284
- "account": mpan_core,
285
- "issue_date": issue_date,
286
- "start_date": from_date,
287
- "finish_date": to_date,
288
- "mpan_core": mpan_core,
289
- }
290
272
  bd = bill["breakdown"]
291
273
 
292
274
  usage = get_dec(row, "Usage")
293
- # usage_units = get_value(row, 'Usage Unit')
275
+ usage_units = get_value(row, "Usage Unit")
294
276
  price = get_dec(row, "Price")
295
277
  amount = get_dec(row, "Amount")
296
278
  product_item_name = get_value(row, "Product Item Name")
@@ -299,92 +281,96 @@ def _parse_row(row, row_index, datemode, title_row):
299
281
  bill["kwh"] += round(usage, 2)
300
282
  description = get_value(row, "Description")
301
283
  product_class = get_value(row, "Product Item Class")
284
+
302
285
  if description in ("Standard VAT@20%", "Reduced VAT@5%"):
303
- bill["vat"] += round(amount, 2)
286
+ vat_gbp = round(amount, 2)
287
+ bill["vat"] += vat_gbp
304
288
  if description.endswith("20%"):
305
289
  vat_percentage = Decimal("20")
306
290
  else:
307
291
  vat_percentage = Decimal("5")
308
292
  bd["vat_percentage"] = vat_percentage
293
+
294
+ if "vat-rate" in bd:
295
+ vat_rate = bd["vat-rate"]
296
+ else:
297
+ vat_rate = bd["vat-rate"] = set()
298
+
299
+ vat_rate.add(vat_percentage / Decimal("100"))
300
+
301
+ vat_values = _get_vat_values(bd, vat_percentage)
302
+ vat_values["vat"] += vat_gbp
309
303
  else:
310
- bill["net"] += round(amount, 2)
304
+ net = round(amount, 2)
305
+ bill["net"] += net
311
306
 
312
- path = [product_class, description, rate_name]
313
- names = _find_names(ELEM_MAP, path)
307
+ sales_tax_rate = get_value(row, "Sales Tax Rate")
308
+ if sales_tax_rate == "Commercial UK Energy VAT":
309
+ vat_values = _get_vat_values(bd, 20)
310
+ vat_values["net"] += net
314
311
 
312
+ path = [product_class, description, rate_name]
313
+ elname = _find_name(ELEM_MAP, path)
314
+ ebd = {}
315
315
  duos_avail_prefix = "DUoS Availability ("
316
316
  duos_excess_avail_prefix = "DUoS Excess Availability ("
317
317
 
318
- if description.startswith("DUoS Availability Adjustment "):
319
- _bd_add(bd, "duos-availability-gbp", amount)
320
- elif description.startswith("DUoS Availability"):
321
- if description.startswith(duos_avail_prefix):
322
- _bd_add(
323
- bd,
324
- "duos-availability-kva",
325
- int(description[len(duos_avail_prefix) : -5]),
326
- )
327
- _bd_add(bd, "duos-availability-days", usage)
328
- _bd_add(bd, "duos-availability-rate", price)
329
- _bd_add(bd, "duos-availability-gbp", amount)
330
- elif description.startswith("DUoS Excess Availability"):
331
- if description.startswith(duos_excess_avail_prefix):
332
- kva = int(description[len(duos_excess_avail_prefix) : -5])
333
- _bd_add(bd, "duos-excess-availability-kva", kva)
334
- _bd_add(bd, "duos-excess-availability-days", usage)
335
- _bd_add(bd, "duos-excess-availability-rate", price)
336
- _bd_add(bd, "duos-excess-availability-gbp", amount)
337
- elif description.startswith("BSUoS Black Start "):
338
- _bd_add(bd, "black-start-gbp", amount)
339
- elif description.startswith("BSUoS Reconciliation - "):
340
- if usage is not None:
341
- _bd_add(bd, "bsuos-nbp-kwh", usage)
342
- if price is not None:
343
- _bd_add(bd, "bsuos-rate", price)
344
- _bd_add(bd, "bsuos-gbp", amount)
345
- elif description.startswith("FiT Rec - "):
346
- _bd_add(bd, "fit-gbp", amount)
347
- elif description.startswith("FiT Reconciliation "):
348
- _bd_add(bd, "fit-gbp", amount)
349
- elif description.startswith("CfD FiT Rec - ") or description.startswith(
350
- "CfD FiT Reconciliation"
318
+ for prefix, name in (
319
+ ("DUoS Availability Adjustment ", "duos-availability"),
320
+ ("DUoS Availability", "duos-availability"),
321
+ ("DUoS Excess Availability", "duos-excess-availability"),
322
+ ("BSUoS Black Start ", "black-start"),
323
+ ("BSUoS Reconciliation - ", "bsuos"),
324
+ ("FiT Rec - ", "fit"),
325
+ ("FiT Reconciliation ", "fit"),
326
+ ("CfD FiT Rec - ", "cfd-fit"),
327
+ ("CfD FiT Reconciliation", "cfd-fit"),
328
+ ("Flex", "reconciliation"),
329
+ ("Legacy TNUoS Reversal ", "triad"),
330
+ ("Hand Held Read -", "meter-rental"),
331
+ ("RO Mutualisation ", "ro"),
332
+ ("OOC MOP - ", "meter-rental"),
333
+ ("KVa Adjustment ", "duos-availability"),
351
334
  ):
352
- _bd_add(bd, "cfd-fit-gbp", amount)
353
- elif description.startswith("Flex"):
354
- _bd_add(bd, "reconciliation-gbp", amount)
355
- elif description.startswith("Legacy TNUoS Reversal "):
356
- _bd_add(bd, "triad-gbp", amount)
357
- elif description.startswith("Hand Held Read -"):
358
- _bd_add(bd, "meter-rental-gbp", amount)
359
- elif description.startswith("RO Mutualisation "):
360
- _bd_add(bd, "ro-gbp", amount)
361
- elif description.startswith("OOC MOP - "):
362
- _bd_add(bd, "meter-rental-gbp", amount)
363
- elif description.startswith("KVa Adjustment "):
364
- _bd_add(bd, "duos-availability-gbp", amount)
365
- elif names is not None:
366
- for elem_k, elem_v in zip(names, (amount, price, usage)):
367
- if elem_k is not None:
368
- _bd_add(bd, elem_k, elem_v)
369
- else:
335
+ if description.startswith(prefix):
336
+ elname = name
337
+ if description.startswith(duos_excess_avail_prefix):
338
+ ebd["kva"] = int(description[len(duos_excess_avail_prefix) : -5])
339
+ elif description.startswith(duos_avail_prefix):
340
+ ebd["kva"] = int(description[len(duos_avail_prefix) : -5])
341
+ break
342
+
343
+ if elname is None:
370
344
  raise BadRequest(
371
345
  f"For the path {path} the parser can't work out the element."
372
346
  )
373
347
 
348
+ if usage is not None:
349
+ if isinstance(usage_units, str) and usage_units != "":
350
+ units = usage_units.lower()
351
+ else:
352
+ units = "kwh"
353
+ ebd[units] = usage
354
+ if price is not None:
355
+ ebd["rate"] = price
356
+ bill["elements"].append(
357
+ {
358
+ "start_date": from_date,
359
+ "finish_date": to_date,
360
+ "name": elname,
361
+ "net": net,
362
+ "breakdown": ebd,
363
+ }
364
+ )
365
+
374
366
  reference = str(bill_number) + "_" + str(row_index + 1)
375
- for k, v in tuple(bd.items()):
376
- if isinstance(v, set):
377
- bd[k] = list(v)
378
- elif k.endswith("-gbp"):
379
- reference += "_" + k[:-4]
380
367
 
381
368
  bill["reference"] = reference
382
369
  bill["gross"] = bill["net"] + bill["vat"]
383
- return bill
384
370
 
385
371
 
386
372
  def _make_raw_bills(sheet, datemode):
387
- bills = []
373
+ bills = {}
388
374
  title_row = sheet.row(0)
389
375
  for row_index in range(1, sheet.nrows):
390
376
  row = sheet.row(row_index)
@@ -392,11 +378,11 @@ def _make_raw_bills(sheet, datemode):
392
378
  val = row[21].value
393
379
  if val not in (None, ""):
394
380
  try:
395
- bills.append(_parse_row(row, row_index, datemode, title_row))
381
+ _parse_row(bills, row, row_index, datemode, title_row)
396
382
  except BadRequest as e:
397
383
  raise BadRequest(f"On row {row_index + 1}: {e.description}")
398
384
 
399
- return bills
385
+ return [b for mc in bills.values() for b in mc.values()]
400
386
 
401
387
 
402
388
  class Parser: