chellow 1714470909.0.0__py3-none-any.whl → 1715252645.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.

@@ -375,7 +375,7 @@ limit 3
375
375
  latest_mop_bill_date,
376
376
  supply_start_date,
377
377
  supply_finish_date,
378
- era.properties,
378
+ None if era.dtc_meter_type is None else era.dtc_meter_type.code,
379
379
  imp_tnuos_band,
380
380
  ]
381
381
  + channel_values
@@ -447,7 +447,7 @@ def _process(sess, f, date, supply_id, mpan_cores):
447
447
  "Latest MOP Bill Date",
448
448
  "Supply Start Date",
449
449
  "Supply Finish Date",
450
- "Properties",
450
+ "DTC Meter Type",
451
451
  "tnuos_band",
452
452
  "Import ACTIVE?",
453
453
  "Import REACTIVE_IMPORT?",
@@ -25,7 +25,7 @@ from chellow.models import (
25
25
  Supply,
26
26
  User,
27
27
  )
28
- from chellow.utils import req_bool
28
+ from chellow.utils import csv_make_val, req_bool
29
29
  from chellow.views import chellow_redirect
30
30
 
31
31
 
@@ -236,25 +236,30 @@ def _process(
236
236
  "ecoes_pc",
237
237
  "chellow_pc",
238
238
  "ecoes_mtc",
239
+ "ecoes_mtc_date",
239
240
  "chellow_mtc",
240
241
  "ecoes_llfc",
242
+ "ecoes_llfc_from",
241
243
  "chellow_llfc",
242
244
  "ecoes_ssc",
243
245
  "chellow_ssc",
244
246
  "ecoes_es",
245
247
  "chellow_es",
246
248
  "ecoes_supplier",
249
+ "ecoes_supplier_registration_from",
247
250
  "chellow_supplier",
248
251
  "chellow_supplier_contract_name",
249
252
  "ecoes_dc",
250
253
  "chellow_dc",
251
254
  "ecoes_mop",
255
+ "ecoes_mop_appoint_date",
252
256
  "chellow_mop",
253
257
  "ecoes_gsp_group",
258
+ "ecoes_gsp_effective_from",
254
259
  "chellow_gsp_group",
255
260
  "ecoes_msn",
256
- "chellow_msn",
257
261
  "ecoes_msn_install_date",
262
+ "chellow_msn",
258
263
  "ecoes_meter_type",
259
264
  "chellow_meter_type",
260
265
  "ignored",
@@ -479,7 +484,11 @@ def _process(
479
484
  "serial numbers do match. "
480
485
  )
481
486
 
482
- chellow_meter_type = _meter_type(era)
487
+ chellow_dtc_meter_type = era.dtc_meter_type
488
+ if chellow_dtc_meter_type is None:
489
+ chellow_meter_type = None
490
+ else:
491
+ chellow_meter_type = chellow_dtc_meter_type.code
483
492
 
484
493
  if chellow_meter_type != ecoes["meter-type"]:
485
494
  problem += "The DTC meter types don't match."
@@ -493,8 +502,8 @@ def _process(
493
502
  "ecoes_pc": ecoes["pc"],
494
503
  "chellow_pc": chellow_pc,
495
504
  "ecoes_mtc": ecoes["mtc"],
505
+ "ecoes_mtc_date": _parse_date(ecoes["mtc-date"]),
496
506
  "chellow_mtc": chellow_mtc,
497
- "chellow_mtc_date": _parse_date(ecoes["mtc-date"]),
498
507
  "ecoes_llfc": ecoes["llfc"],
499
508
  "ecoes_llfc_from": _parse_date(ecoes["llfc-from"]),
500
509
  "chellow_llfc": chellow_llfc,
@@ -524,7 +533,7 @@ def _process(
524
533
  "ignored": ignore,
525
534
  "problem": problem,
526
535
  }
527
- writer.writerow(values[t] for t in titles)
536
+ writer.writerow(csv_make_val(values[t]) for t in titles)
528
537
  values["chellow_supplier_contract_id"] = chellow_supplier_contract_id
529
538
  values["chellow_supply_id"] = chellow_supply_id
530
539
  values["diffs"] = diffs
@@ -555,7 +564,8 @@ def _process(
555
564
 
556
565
  msn = "" if era.msn is None else era.msn
557
566
 
558
- meter_type = _meter_type(era)
567
+ dtc_meter_type = era.dtc_meter_type
568
+ meter_type = "" if dtc_meter_type is None else dtc_meter_type.code
559
569
 
560
570
  values = {
561
571
  "mpan_core": mpan_core,
@@ -563,21 +573,26 @@ def _process(
563
573
  "ecoes_pc": "",
564
574
  "chellow_pc": era.pc.code,
565
575
  "ecoes_mtc": "",
576
+ "ecoes_mtc_date": "",
566
577
  "chellow_mtc": era.mtc_participant.mtc.code,
567
578
  "ecoes_llfc": "",
579
+ "ecoes_llfc_from": "",
568
580
  "chellow_llfc": llfc.code,
569
581
  "ecoes_ssc": "",
570
582
  "chellow_ssc": ssc,
571
583
  "ecoes_es": "",
572
584
  "chellow_es": es,
573
585
  "ecoes_supplier": "",
586
+ "ecoes_supplier_registration_from": "",
574
587
  "chellow_supplier": supplier_contract.party.participant.code,
575
588
  "chellow_supplier_contract_name": supplier_contract.name,
576
589
  "ecoes_dc": "",
577
590
  "chellow_dc": dc,
578
591
  "ecoes_mop": "",
592
+ "ecoes_mop_appoint_date": "",
579
593
  "chellow_mop": mop,
580
594
  "ecoes_gsp_group": "",
595
+ "ecoes_gsp_effective_from": "",
581
596
  "chellow_gsp_group": supply.gsp_group.code,
582
597
  "ecoes_msn": "",
583
598
  "chellow_msn": msn,
@@ -587,7 +602,7 @@ def _process(
587
602
  "ignored": False,
588
603
  "problem": "In Chellow, but not in ECOES.",
589
604
  }
590
- writer.writerow(values[t] for t in titles)
605
+ writer.writerow(csv_make_val(values[t]) for t in titles)
591
606
  values["chellow_supplier_contract_id"] = supplier_contract.id
592
607
  values["chellow_supply_id"] = era.supply.id
593
608
  values["diffs"] = []
@@ -595,21 +610,6 @@ def _process(
595
610
  report_run.insert_row(sess, "", titles, values, {})
596
611
 
597
612
 
598
- def _meter_type(era):
599
- props = era.props
600
- try:
601
- return props["meter_type"]
602
- except KeyError:
603
- if era.pc.code == "00":
604
- return "H"
605
- elif len(era.channels) > 0:
606
- return "RCAMR"
607
- elif era.mtc_participant.meter_type.code in ["UM", "PH"]:
608
- return ""
609
- else:
610
- return "N"
611
-
612
-
613
613
  def do_get(sess):
614
614
  show_ignored = req_bool("show_ignored")
615
615
  report_run = ReportRun.insert(
@@ -11,64 +11,52 @@
11
11
  {% endblock %}
12
12
 
13
13
  {% block content %}
14
- {% if request.method == 'GET' and request.values.view == 'confirm_delete' %}
15
- <form method="post" action="/e/dc_contracts/{{dc_contract.id}}/edit">
16
- <fieldset>
17
- <legend>Are you sure you want to delete this contract?</legend>
18
- <input type="submit" name="delete" value="delete">
19
- <a href="/e/dc_contracts/{{dc_contract.id}}/edit">Cancel</a>
20
- </fieldset>
21
- </form>
22
-
23
- {% else %}
24
-
25
- <form action="/e/dc_contracts/{{dc_contract.id}}/edit" method="post">
26
- <fieldset>
27
- <legend>Update Contract</legend>
28
-
29
- <label>Party</label>
30
- <select name="party_id">
31
- {% for party in parties %}
32
- {{ input_option(
33
- 'party_id', party.id,
34
- party.participant.code + ' : ' + party.name,
35
- dc_contract.party.id) }}
36
- {% endfor %}
37
- </select>
38
-
39
- <label>Name</label> {{input_text('name', dc_contract.name)}}
40
-
41
- <label>Charge script</label>
42
- {{input_textarea(
43
- 'charge_script', dc_contract.charge_script, 40, 80)}}
44
-
45
- <input type="submit" value="Update">
46
- </fieldset>
47
- </form>
48
-
49
- <form action="/e/dc_contracts/{{dc_contract.id}}/edit" method="post">
50
- <fieldset>
51
- <legend>Update State</legend>
52
- <label>State</label>
53
- {{input_textarea('state', dc_contract.state, 40, 80)}}
54
- <input type="submit" name="update_state" value="Update">
55
- </fieldset>
56
- </form>
57
-
58
- <form action="/e/dc_contracts/{{dc_contract.id}}/edit">
59
- <fieldset>
60
- <legend>Delete This Contract</legend>
61
- <input type="hidden" name="view" value="confirm_delete">
62
- <input type="submit" value="Delete">
63
- </fieldset>
64
- </form>
65
-
66
- <form method="post" action="/e/dc_contracts/{{dc_contract.id}}/edit">
67
- <fieldset>
68
- <legend>Ignore all snags before</legend>
69
- {{ input_date('ignore', initial_date) }}
70
- <input type="submit" name="ignore_snags" value="Ignore">
71
- </fieldset>
72
- </form>
73
- {% endif %}
14
+ <form action="/e/dc_contracts/{{dc_contract.id}}/edit" method="post">
15
+ <fieldset>
16
+ <legend>Update Contract</legend>
17
+
18
+ <label>Party</label>
19
+ <select name="party_id">
20
+ {% for party in parties %}
21
+ {{ input_option(
22
+ 'party_id', party.id,
23
+ party.participant.code + ' : ' + party.name,
24
+ dc_contract.party.id) }}
25
+ {% endfor %}
26
+ </select>
27
+
28
+ <label>Name</label> {{input_text('name', dc_contract.name)}}
29
+
30
+ <label>Charge script</label>
31
+ {{input_textarea(
32
+ 'charge_script', dc_contract.charge_script, 40, 80)}}
33
+
34
+ <input type="submit" value="Update">
35
+ </fieldset>
36
+ </form>
37
+
38
+ <form action="/e/dc_contracts/{{dc_contract.id}}/edit" method="post">
39
+ <fieldset>
40
+ <legend>Update State</legend>
41
+ <label>State</label>
42
+ {{input_textarea('state', dc_contract.state, 40, 80)}}
43
+ <input type="submit" name="update_state" value="Update">
44
+ </fieldset>
45
+ </form>
46
+
47
+ <form hx-delete="/e/dc_contracts/{{dc_contract.id}}/edit"
48
+ hx-confirm="Are you sure you want to delete this contract?">
49
+ <fieldset>
50
+ <legend>Delete This Contract</legend>
51
+ <input type="submit" value="Delete">
52
+ </fieldset>
53
+ </form>
54
+
55
+ <form method="post" action="/e/dc_contracts/{{dc_contract.id}}/edit">
56
+ <fieldset>
57
+ <legend>Ignore all snags before</legend>
58
+ {{ input_date('ignore', initial_date) }}
59
+ <input type="submit" name="ignore_snags" value="Ignore">
60
+ </fieldset>
61
+ </form>
74
62
  {% endblock %}
@@ -1,11 +1,11 @@
1
1
  {% extends "base.html" %}
2
2
 
3
3
  {% block title %}
4
- &raquo; DTC Meter Types &raquo; {{dtc_meter_type_code}}
4
+ &raquo; DTC Meter Types &raquo; {{dtc_meter_type.code}}
5
5
  {% endblock %}
6
6
 
7
7
  {% block nav %}
8
- <a href="/e/dtc_meter_types">DTC Meter Types</a> &raquo; {{dtc_meter_type_code}}
8
+ <a href="/e/dtc_meter_types">DTC Meter Types</a> &raquo; {{dtc_meter_type.code}}
9
9
  {% endblock %}
10
10
 
11
11
  {% block content %}
@@ -13,11 +13,11 @@
13
13
  <table>
14
14
  <tr>
15
15
  <th>Code</th>
16
- <td>{{dtc_meter_type_code}}</td>
16
+ <td>{{dtc_meter_type.code}}</td>
17
17
  </tr>
18
18
  <tr>
19
19
  <th>Description</th>
20
- <td>{{dtc_meter_type_description}}</td>
20
+ <td>{{dtc_meter_type.description}}</td>
21
21
  </tr>
22
22
  </table>
23
23
 
@@ -18,10 +18,10 @@
18
18
  </tr>
19
19
  </thead>
20
20
  <tbody>
21
- {% for code, desc in dtc_meter_types.items() %}
21
+ {% for dtc_meter_type in dtc_meter_types %}
22
22
  <tr>
23
- <td><a href="/e/dtc_meter_types/{{code}}">{{code}}</a></td>
24
- <td>{{desc}}</td>
23
+ <td><a href="/e/dtc_meter_types/{{dtc_meter_type.id}}">{{dtc_meter_type.code}}</a></td>
24
+ <td>{{dtc_meter_type.description}}</td>
25
25
  </tr>
26
26
  {% endfor %}
27
27
  </tbody>
@@ -80,6 +80,7 @@
80
80
  {{input_hidden('gsp_group_id', initial=era.supply.gsp_group.id)}}
81
81
  {{input_hidden('mtc_participant_id', initial=era.mtc_participant.id)}}
82
82
  {{input_hidden('ssc_id', initial=era.ssc.id)}}
83
+ {{input_hidden('dtc_meter_type_id', initial=era.dtc_meter_type.id)}}
83
84
  {{input_hidden('name', initial=era.name)}}
84
85
  {{input_hidden('msn', initial=era.msn)}}
85
86
  {{input_hidden('mop_contract_id', initial=era.mop_contract_id)}}
@@ -89,14 +89,14 @@
89
89
  {% endfor %}
90
90
  </select>
91
91
 
92
- <label>Properties</label>
93
- <div>
94
- {{input_textarea('properties', era.properties, 10, 80)}}
95
- <p>
96
- The <code>meter_type</code> property contains a
97
- <a href="/e/dtc_meter_types">DTC Meter Type Code</a>.
98
- </p>
99
- </div>
92
+ <label>DTC Meter Type</label>
93
+ <select name="dtc_meter_type_id">
94
+ {{input_option('dtc_meter_type_id', '', 'Unmetered')}}
95
+ {% for dtc_meter_type in dtc_meter_types %}
96
+ {{input_option('dtc_meter_type_id', dtc_meter_type.id,
97
+ dtc_meter_type.code + ' ' + dtc_meter_type.description, era.dtc_meter_type.id)}}
98
+ {% endfor %}
99
+ </select>
100
100
 
101
101
  <label>Has An Import MPAN?</label>
102
102
  {{input_checkbox('has_imp_mpan')}}
@@ -10,38 +10,24 @@
10
10
  {% endblock %}
11
11
 
12
12
  {% block content %}
13
- {% if request.method == 'GET' and request.values.view == 'confirm_delete' %}
14
-
15
- <form method="post">
16
- <fieldset>
17
- <legend>Are you sure you want to delete this contract?</legend>
18
- <input type="hidden" name="mop_contract_id"
19
- value="{{contract.id}}">
20
- <input type="submit" name="delete" value="Delete">
21
- <a href="/e/mop_contracts/{{contract.id}}/edit">Cancel</a>
22
- </fieldset>
23
- </form>
24
-
25
- {% else %}
26
-
27
- <form method="post">
28
- <fieldset>
29
- <legend>Update Contract</legend>
30
- <input type="hidden" name="mop_contract_id" value="{{contract.id}}">
31
- <label>Party</label>
32
- <select name="party_id">
33
- {% for party in parties %}
34
- {{input_option('party_id', party.id,
35
- party.participant.code + ' : ' + party.name, contract.party.id) }}
36
- {% endfor %}
37
- </select>
38
- <label>Name </label> {{input_text('name', contract.name)}}
39
- <label>Charge script</label>
40
- {{input_textarea('charge_script', contract.charge_script, 40, 80)}}
41
- <label>Properties</label>
42
- {{input_textarea('properties', contract.properties, 40, 80)}}
43
- <label>Example</label>
44
- <code><pre>
13
+ <form method="post">
14
+ <fieldset>
15
+ <legend>Update Contract</legend>
16
+ <input type="hidden" name="mop_contract_id" value="{{contract.id}}">
17
+ <label>Party</label>
18
+ <select name="party_id">
19
+ {% for party in parties %}
20
+ {{input_option('party_id', party.id,
21
+ party.participant.code + ' : ' + party.name, contract.party.id) }}
22
+ {% endfor %}
23
+ </select>
24
+ <label>Name </label> {{input_text('name', contract.name)}}
25
+ <label>Charge script</label>
26
+ {{input_textarea('charge_script', contract.charge_script, 40, 80)}}
27
+ <label>Properties</label>
28
+ {{input_textarea('properties', contract.properties, 40, 80)}}
29
+ <label>Example</label>
30
+ <code><pre>
45
31
  has.importer=yes
46
32
  file.type=.df2
47
33
  hostname=example.com
@@ -49,26 +35,25 @@ username=username
49
35
  password=password
50
36
  directory0=downloads1
51
37
  directory1=downloads2
52
- </pre></code>
53
- <input type="submit" value="Update">
54
- </fieldset>
55
- </form>
38
+ </pre></code>
39
+ <input type="submit" value="Update">
40
+ </fieldset>
41
+ </form>
56
42
 
57
- <form action="/e/mop_contracts/{{contract.id}}/edit" method="post">
58
- <fieldset>
59
- <legend>Update State</legend>
60
- <label>State</label>
61
- {{input_textarea('state', contract.state, 40, 80)}}
62
- <input type="submit" name="update_state" value="Update">
63
- </fieldset>
64
- </form>
43
+ <form action="/e/mop_contracts/{{contract.id}}/edit" method="post">
44
+ <fieldset>
45
+ <legend>Update State</legend>
46
+ <label>State</label>
47
+ {{input_textarea('state', contract.state, 40, 80)}}
48
+ <input type="submit" name="update_state" value="Update">
49
+ </fieldset>
50
+ </form>
65
51
 
66
- <form action="/e/mop_contracts/{{contract.id}}/edit" method="post">
67
- <fieldset>
68
- <legend>Delete this contract</legend>
69
- <input type="hidden" name="view" value="confirm_delete">
70
- <input type="submit" value="Delete">
71
- </fieldset>
72
- </form>
73
- {% endif %}
52
+ <form hx-delete="/e/mop_contracts/{{contract.id}}/edit"
53
+ hx-confirm="Are you sure you want to delete this contract?">
54
+ <fieldset>
55
+ <legend>Delete this contract</legend>
56
+ <input type="submit" value="Delete">
57
+ </fieldset>
58
+ </form>
74
59
  {% endblock %}
@@ -94,16 +94,8 @@
94
94
  "*": "_L"
95
95
  },
96
96
 
97
- /* Properties are combined with the existing era properties, with the
98
- ones here overwriting any duplicates */
99
- "properties_overwrite": {
100
- "comms_type": "GSM"
101
- },
102
-
103
- /* Properties are combined with the existing era properties, with the
104
- ones here being overwritten by any duplicates */
105
- "properties_overwritten": {
106
- "meter_type": "H"
97
+ "dtc_meter_types": {
98
+ "*": "H"
107
99
  },
108
100
 
109
101
  /* Use hh data rather than register reads for AMRs */
@@ -20,6 +20,7 @@
20
20
  <input type="hidden" name="energisation_status_id"
21
21
  value="{{request.values.energisation_status_id}}">
22
22
  <input type="hidden" name="pc_id" value="{{request.values.pc_id}}">
23
+ <input type="hidden" name="dtc_meter_type_id" value="{{request.values.dtc_meter_type_id}}">
23
24
  <input type="hidden" name="dno_id" value="{{request.values.dno_id}}">
24
25
  <input type="hidden" name="gsp_group_id" value="{{request.values.gsp_group_id}}">
25
26
  <input type="hidden" name="mtc_participant_id"
@@ -116,7 +116,14 @@
116
116
  {% endfor %}
117
117
  </select>
118
118
 
119
- <label>Properties</label> {{input_textarea('properties', '{}', 10, 80)}}
119
+ <label>DTC Meter Type</label>
120
+ <select name="dtc_meter_type_id">
121
+ {{input_option('dtc_meter_type_id', '', 'Unmetered')}}
122
+ {% for dtc_meter_type in dtc_meter_types %}
123
+ {{input_option( 'dtc_meter_type_id', dtc_meter_type.id,
124
+ dtc_meter_type.code + ' ' + dtc_meter_type.description)}}
125
+ {% endfor %}
126
+ </select>
120
127
 
121
128
  <label>Has An Import MPAN?</label> {{input_checkbox('has_imp_mpan')}}
122
129
 
@@ -21,7 +21,7 @@
21
21
  <th rowspan="2">
22
22
  <span title="Standard Settlement Configuration">SSC</span>
23
23
  </th>
24
- <th rowspan="2"><span title="Properties">Props</span></th>
24
+ <th rowspan="2"><span title="DTC Meter Type">Meter</span></th>
25
25
  <th colspan="2"><span title="Meter Operator">MOP</span></th>
26
26
  <th colspan="2"><span title="Data Collector">DC</span></th>
27
27
  <th rowspan="2">
@@ -75,7 +75,8 @@
75
75
  </td>
76
76
  <td rowspan="4">{{ era.msn }}</td>
77
77
  <td rowspan="4">
78
- <a href="/e/mtc_participants/{{era.mtc_participant.id}}" title="{{era.mtc_participant.description}}">{{era.mtc_participant.mtc.code}}</a>
78
+ <a href="/e/mtc_participants/{{era.mtc_participant.id}}"
79
+ title="{{era.mtc_participant.description}}">{{era.mtc_participant.mtc.code}}</a>
79
80
  </td>
80
81
  <td rowspan="4">
81
82
  <a href="/e/cops/{{era.cop.id}}" title="{{era.cop.description}}">{{era.cop.code}}</a>
@@ -88,7 +89,9 @@
88
89
  <a href="/e/sscs/{{era.ssc.id}}" title="{{era.ssc.description}}">{{era.ssc.code}}</a>
89
90
  {% endif %}
90
91
  </td>
91
- <td rowspan="4">{{era.properties}}</td>
92
+ <td rowspan="4">
93
+ <a href="/e/dtc_meter_types/{{era.dtc_meter_type.id}}">{{era.dtc_meter_type.code}}</a>
94
+ </td>
92
95
  <td rowspan="4">
93
96
  <a href="/e/mop_contracts/{{era.mop_contract.id}}">{{era.mop_contract.name}}</a>
94
97
  </td>
@@ -90,11 +90,9 @@
90
90
  <td>Meter Timeswitch Class</td>
91
91
  <td>CoP</td>
92
92
  <td>Comms Type</td>
93
- <td>
94
- Standard Settlement Configuration (blank for HH supplies)
95
- </td>
93
+ <td>Standard Settlement Configuration (blank for HH supplies)</td>
96
94
  <td>Energisation Status</td>
97
- <td>Properties</td>
95
+ <td>DTC Meter Type</td>
98
96
  <td>Import MPAN Core</td>
99
97
  <td>Import LLFC</td>
100
98
  <td>Import Supply Capacity</td>
@@ -137,7 +135,7 @@
137
135
  <td>Comms Type</td>
138
136
  <td>SSC</td>
139
137
  <td>Energisation Status</td>
140
- <td>Properties</td>
138
+ <td>DTC Meter Type</td>
141
139
  <td>Import MPAN Core</td>
142
140
  <td>Import LLFC</td>
143
141
  <td>Import Supply Capacity</td>
@@ -173,7 +171,7 @@
173
171
  <td>Comms Type</td>
174
172
  <td>SSC</td>
175
173
  <td>Energisation Status</td>
176
- <td>Properties</td>
174
+ <td>DTC Meter Type</td>
177
175
  <td>Import MPAN Core</td>
178
176
  <td>Import LLFC</td>
179
177
  <td>Import Supply Capacity</td>
@@ -31,7 +31,7 @@
31
31
 
32
32
  {%- macro input_option(name, item_id, desc, initial=None) -%}
33
33
  <option value="{{ item_id }}"
34
- {%- if request.values[name] -%}
34
+ {%- if name in request.values -%}
35
35
  {%- if request.values[name] == '' ~ item_id %} selected
36
36
  {%- endif -%}
37
37
  {%- else -%}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: chellow
3
- Version: 1714470909.0.0
3
+ Version: 1715252645.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)