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.
- chellow/e/computer.py +22 -19
- chellow/e/views.py +43 -20
- chellow/general_import.py +10 -12
- chellow/models.py +215 -76
- chellow/reports/report_33.py +2 -2
- chellow/reports/report_ecoes_comparison.py +22 -22
- chellow/templates/e/dc_contract_edit.html +48 -60
- chellow/templates/e/dtc_meter_type.html +4 -4
- chellow/templates/e/dtc_meter_types.html +3 -3
- chellow/templates/e/era_edit.html +1 -0
- chellow/templates/e/era_edit_form.html +8 -8
- chellow/templates/e/mop_contract_edit.html +37 -52
- chellow/templates/e/scenario_docs.html +2 -10
- chellow/templates/e/site_add_e_supply.html +1 -0
- chellow/templates/e/site_add_e_supply_form.html +8 -1
- chellow/templates/e/supply_eras.html +6 -3
- chellow/templates/general_imports.html +4 -6
- chellow/templates/macros.html +1 -1
- {chellow-1714470909.0.0.dist-info → chellow-1715252645.0.0.dist-info}/METADATA +1 -1
- {chellow-1714470909.0.0.dist-info → chellow-1715252645.0.0.dist-info}/RECORD +21 -21
- {chellow-1714470909.0.0.dist-info → chellow-1715252645.0.0.dist-info}/WHEEL +0 -0
chellow/e/computer.py
CHANGED
|
@@ -552,6 +552,7 @@ class DataSource:
|
|
|
552
552
|
self.era_map_mop_contracts = self.era_map.get("mop_contracts", {})
|
|
553
553
|
self.era_map_cops = self.era_map.get("cops", {})
|
|
554
554
|
self.era_map_comms = self.era_map.get("comms", {})
|
|
555
|
+
self.era_map_dtc_meter_types = self.era_map.get("dtc_meter_types", {})
|
|
555
556
|
self.era_map_mpan_cores = self.era_map.get("mpan_cores", {})
|
|
556
557
|
self.era_map_dnos = self.era_map.get("dnos", {})
|
|
557
558
|
self.era_map_gsp_groups = self.era_map.get("gsp_groups", {})
|
|
@@ -672,9 +673,16 @@ class SiteSource(DataSource):
|
|
|
672
673
|
else:
|
|
673
674
|
self.sc = era.imp_sc
|
|
674
675
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
676
|
+
if era.dtc_meter_type is None:
|
|
677
|
+
era_dtc_meter_type_code = None
|
|
678
|
+
else:
|
|
679
|
+
era_dtc_meter_type_code = era.dtc_meter_type.code
|
|
680
|
+
if era_dtc_meter_type_code in self.era_map_dtc_meter_types:
|
|
681
|
+
self.dtc_meter_type_code = self.era_map_dtc_meter_types[
|
|
682
|
+
era_dtc_meter_type_code
|
|
683
|
+
]
|
|
684
|
+
else:
|
|
685
|
+
self.dtc_meter_type_code = era_dtc_meter_type_code
|
|
678
686
|
|
|
679
687
|
self.is_import = True
|
|
680
688
|
self.voltage_level_code = self.llfc.voltage_level.code
|
|
@@ -1051,9 +1059,16 @@ class SupplySource(DataSource):
|
|
|
1051
1059
|
else:
|
|
1052
1060
|
self.comm_code = era.comm.code
|
|
1053
1061
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1062
|
+
if era.dtc_meter_type is None:
|
|
1063
|
+
era_dtc_meter_type_code = None
|
|
1064
|
+
else:
|
|
1065
|
+
era_dtc_meter_type_code = era.dtc_meter_type.code
|
|
1066
|
+
if era_dtc_meter_type_code in self.era_map_dtc_meter_types:
|
|
1067
|
+
self.dtc_meter_type_code = self.era_map_dtc_meter_types[
|
|
1068
|
+
era_dtc_meter_type_code
|
|
1069
|
+
]
|
|
1070
|
+
else:
|
|
1071
|
+
self.dtc_meter_type_code = era_dtc_meter_type_code
|
|
1057
1072
|
|
|
1058
1073
|
self.id = self.mpan_core
|
|
1059
1074
|
self.msn = era.msn
|
|
@@ -1632,18 +1647,6 @@ def _read_generator(sess, supply, start, is_forwards, is_prev):
|
|
|
1632
1647
|
if bill.id != r.bill.id:
|
|
1633
1648
|
continue
|
|
1634
1649
|
|
|
1635
|
-
era = supply.find_era_at(sess, dt)
|
|
1636
|
-
if era is None:
|
|
1637
|
-
era_coeff = None
|
|
1638
|
-
else:
|
|
1639
|
-
era_properties = PropDict(
|
|
1640
|
-
chellow.utils.url_root + "eras/" + str(era.id), loads(era.properties)
|
|
1641
|
-
)
|
|
1642
|
-
try:
|
|
1643
|
-
era_coeff = float(era_properties["coefficient"])
|
|
1644
|
-
except KeyError:
|
|
1645
|
-
era_coeff = None
|
|
1646
|
-
|
|
1647
1650
|
reads = {}
|
|
1648
1651
|
coeffs = {}
|
|
1649
1652
|
for coeff, value, tpr_code in sess.query(
|
|
@@ -1656,7 +1659,7 @@ def _read_generator(sess, supply, start, is_forwards, is_prev):
|
|
|
1656
1659
|
r_dt == dt,
|
|
1657
1660
|
):
|
|
1658
1661
|
reads[tpr_code] = value
|
|
1659
|
-
coeffs[tpr_code] = coeff
|
|
1662
|
+
coeffs[tpr_code] = coeff
|
|
1660
1663
|
|
|
1661
1664
|
yield {
|
|
1662
1665
|
"date": dt,
|
chellow/e/views.py
CHANGED
|
@@ -42,6 +42,7 @@ from chellow.models import (
|
|
|
42
42
|
Comm,
|
|
43
43
|
Contract,
|
|
44
44
|
Cop,
|
|
45
|
+
DtcMeterType,
|
|
45
46
|
EnergisationStatus,
|
|
46
47
|
Era,
|
|
47
48
|
GeneratorType,
|
|
@@ -49,7 +50,6 @@ from chellow.models import (
|
|
|
49
50
|
HhDatum,
|
|
50
51
|
Laf,
|
|
51
52
|
Llfc,
|
|
52
|
-
METER_TYPES,
|
|
53
53
|
MarketRole,
|
|
54
54
|
MeasurementRequirement,
|
|
55
55
|
MeterPaymentType,
|
|
@@ -1137,6 +1137,14 @@ def dc_contract_edit_get(dc_contract_id):
|
|
|
1137
1137
|
)
|
|
1138
1138
|
|
|
1139
1139
|
|
|
1140
|
+
@e.route("/dc_contracts/<int:contract_id>/edit", methods=["DELETE"])
|
|
1141
|
+
def dc_contract_edit_delete(contract_id):
|
|
1142
|
+
contract = Contract.get_dc_by_id(g.sess, contract_id)
|
|
1143
|
+
contract.delete(g.sess)
|
|
1144
|
+
g.sess.commit()
|
|
1145
|
+
return hx_redirect("/dc_contracts", 303)
|
|
1146
|
+
|
|
1147
|
+
|
|
1140
1148
|
@e.route("/dc_contracts/<int:contract_id>/edit", methods=["POST"])
|
|
1141
1149
|
def dc_contract_edit_post(contract_id):
|
|
1142
1150
|
contract = None
|
|
@@ -1161,10 +1169,6 @@ def dc_contract_edit_post(contract_id):
|
|
|
1161
1169
|
)
|
|
1162
1170
|
g.sess.commit()
|
|
1163
1171
|
return chellow_redirect(f"/dc_contracts/{contract.id}", 303)
|
|
1164
|
-
elif "delete" in request.form:
|
|
1165
|
-
contract.delete(g.sess)
|
|
1166
|
-
g.sess.commit()
|
|
1167
|
-
return chellow_redirect("/dc_contracts", 303)
|
|
1168
1172
|
else:
|
|
1169
1173
|
party_id = req_int("party_id")
|
|
1170
1174
|
name = req_str("name")
|
|
@@ -1501,15 +1505,14 @@ def dno_get(dno_id):
|
|
|
1501
1505
|
|
|
1502
1506
|
@e.route("/dtc_meter_types")
|
|
1503
1507
|
def dtc_meter_types_get():
|
|
1504
|
-
|
|
1508
|
+
dtc_meter_types = g.sess.scalars(select(DtcMeterType).order_by(DtcMeterType.code))
|
|
1509
|
+
return render_template("dtc_meter_types.html", dtc_meter_types=dtc_meter_types)
|
|
1505
1510
|
|
|
1506
1511
|
|
|
1507
|
-
@e.route("/dtc_meter_types/<
|
|
1508
|
-
def dtc_meter_type_get(
|
|
1509
|
-
|
|
1510
|
-
return render_template(
|
|
1511
|
-
"dtc_meter_type.html", dtc_meter_type_code=code, dtc_meter_type_description=desc
|
|
1512
|
-
)
|
|
1512
|
+
@e.route("/dtc_meter_types/<int:dtc_meter_type_id>")
|
|
1513
|
+
def dtc_meter_type_get(dtc_meter_type_id):
|
|
1514
|
+
dtc_meter_type = DtcMeterType.get_by_id(g.sess, dtc_meter_type_id)
|
|
1515
|
+
return render_template("dtc_meter_type.html", dtc_meter_type=dtc_meter_type)
|
|
1513
1516
|
|
|
1514
1517
|
|
|
1515
1518
|
@e.route("/duration_report")
|
|
@@ -1565,6 +1568,7 @@ def era_edit_get(era_id):
|
|
|
1565
1568
|
cops = g.sess.query(Cop).order_by(Cop.code)
|
|
1566
1569
|
comms = g.sess.query(Comm).order_by(Comm.code)
|
|
1567
1570
|
gsp_groups = g.sess.query(GspGroup).order_by(GspGroup.code)
|
|
1571
|
+
dtc_meter_types = g.sess.scalars(select(DtcMeterType).order_by(DtcMeterType.code))
|
|
1568
1572
|
mop_contracts = (
|
|
1569
1573
|
g.sess.query(Contract)
|
|
1570
1574
|
.join(MarketRole)
|
|
@@ -1598,6 +1602,7 @@ def era_edit_get(era_id):
|
|
|
1598
1602
|
cops=cops,
|
|
1599
1603
|
comms=comms,
|
|
1600
1604
|
gsp_groups=gsp_groups,
|
|
1605
|
+
dtc_meter_types=dtc_meter_types,
|
|
1601
1606
|
mop_contracts=mop_contracts,
|
|
1602
1607
|
dc_contracts=dc_contracts,
|
|
1603
1608
|
supplier_contracts=supplier_contracts,
|
|
@@ -1615,6 +1620,9 @@ def era_edit_form_get(era_id):
|
|
|
1615
1620
|
select(EnergisationStatus).order_by(EnergisationStatus.code)
|
|
1616
1621
|
)
|
|
1617
1622
|
default_energisation_status = EnergisationStatus.get_by_code(g.sess, "E")
|
|
1623
|
+
dtc_meter_types = g.sess.scalars(
|
|
1624
|
+
select(DtcMeterType).order_by(DtcMeterType.code)
|
|
1625
|
+
)
|
|
1618
1626
|
|
|
1619
1627
|
if "start_year" in request.values:
|
|
1620
1628
|
start_date = req_date("start")
|
|
@@ -1934,6 +1942,7 @@ def era_edit_form_get(era_id):
|
|
|
1934
1942
|
start_date=start_date,
|
|
1935
1943
|
imp_llfcs=imp_llfcs,
|
|
1936
1944
|
exp_llfcs=exp_llfcs,
|
|
1945
|
+
dtc_meter_types=dtc_meter_types,
|
|
1937
1946
|
)
|
|
1938
1947
|
except BadRequest as e:
|
|
1939
1948
|
g.sess.rollback()
|
|
@@ -1950,6 +1959,7 @@ def era_edit_form_get(era_id):
|
|
|
1950
1959
|
sscs=sscs,
|
|
1951
1960
|
mtc_participants=mtc_participants,
|
|
1952
1961
|
mtc_participant=mtc_participant,
|
|
1962
|
+
dtc_meter_types=dtc_meter_types,
|
|
1953
1963
|
)
|
|
1954
1964
|
|
|
1955
1965
|
|
|
@@ -2009,7 +2019,11 @@ def era_edit_post(era_id):
|
|
|
2009
2019
|
energisation_status = EnergisationStatus.get_by_id(
|
|
2010
2020
|
g.sess, energisation_status_id
|
|
2011
2021
|
)
|
|
2012
|
-
|
|
2022
|
+
dtc_meter_type_id = req_int_none("dtc_meter_type_id")
|
|
2023
|
+
if dtc_meter_type_id is None:
|
|
2024
|
+
dtc_meter_type = None
|
|
2025
|
+
else:
|
|
2026
|
+
dtc_meter_type = DtcMeterType.get_by_id(g.sess, dtc_meter_type_id)
|
|
2013
2027
|
|
|
2014
2028
|
has_imp_mpan = req_bool("has_imp_mpan")
|
|
2015
2029
|
has_exp_mpan = req_bool("has_exp_mpan")
|
|
@@ -2068,7 +2082,7 @@ def era_edit_post(era_id):
|
|
|
2068
2082
|
comm,
|
|
2069
2083
|
ssc_code,
|
|
2070
2084
|
energisation_status,
|
|
2071
|
-
|
|
2085
|
+
dtc_meter_type,
|
|
2072
2086
|
imp_mpan_core,
|
|
2073
2087
|
imp_llfc_code,
|
|
2074
2088
|
imp_supplier_contract,
|
|
@@ -3059,6 +3073,14 @@ def mop_contract_edit_get(contract_id):
|
|
|
3059
3073
|
)
|
|
3060
3074
|
|
|
3061
3075
|
|
|
3076
|
+
@e.route("/mop_contracts/<int:contract_id>/edit", methods=["DELETE"])
|
|
3077
|
+
def mop_contract_edit_delete(contract_id):
|
|
3078
|
+
contract = Contract.get_mop_by_id(g.sess, contract_id)
|
|
3079
|
+
contract.delete(g.sess)
|
|
3080
|
+
g.sess.commit()
|
|
3081
|
+
return hx_redirect("/mop_contracts", 303)
|
|
3082
|
+
|
|
3083
|
+
|
|
3062
3084
|
@e.route("/mop_contracts/<int:contract_id>/edit", methods=["POST"])
|
|
3063
3085
|
def mop_contract_edit_post(contract_id):
|
|
3064
3086
|
try:
|
|
@@ -3082,10 +3104,6 @@ def mop_contract_edit_post(contract_id):
|
|
|
3082
3104
|
)
|
|
3083
3105
|
g.sess.commit()
|
|
3084
3106
|
return chellow_redirect(f"/mop_contracts/{contract.id}", 303)
|
|
3085
|
-
elif "delete" in request.form:
|
|
3086
|
-
contract.delete(g.sess)
|
|
3087
|
-
g.sess.commit()
|
|
3088
|
-
return chellow_redirect("/mop_contracts", 303)
|
|
3089
3107
|
else:
|
|
3090
3108
|
party_id = req_int("party_id")
|
|
3091
3109
|
name = req_str("name")
|
|
@@ -4618,7 +4636,12 @@ def site_add_e_supply_post(site_id):
|
|
|
4618
4636
|
energisation_status = EnergisationStatus.get_by_id(
|
|
4619
4637
|
g.sess, energisation_status_id
|
|
4620
4638
|
)
|
|
4621
|
-
|
|
4639
|
+
dtc_meter_type_id = req_int_none("dtc_meter_type_id")
|
|
4640
|
+
if dtc_meter_type_id is None:
|
|
4641
|
+
dtc_meter_type = None
|
|
4642
|
+
else:
|
|
4643
|
+
dtc_meter_type = DtcMeterType.get_by_id(g.sess, dtc_meter_type_id)
|
|
4644
|
+
|
|
4622
4645
|
if "generator_type_id" in request.form:
|
|
4623
4646
|
generator_type_id = req_int("generator_type_id")
|
|
4624
4647
|
generator_type = GeneratorType.get_by_id(g.sess, generator_type_id)
|
|
@@ -4695,7 +4718,7 @@ def site_add_e_supply_post(site_id):
|
|
|
4695
4718
|
comm,
|
|
4696
4719
|
None if ssc is None else ssc.code,
|
|
4697
4720
|
energisation_status,
|
|
4698
|
-
|
|
4721
|
+
dtc_meter_type,
|
|
4699
4722
|
imp_mpan_core,
|
|
4700
4723
|
imp_llfc_code,
|
|
4701
4724
|
imp_supplier_contract,
|
chellow/general_import.py
CHANGED
|
@@ -9,7 +9,7 @@ from sqlalchemy.sql.expression import false
|
|
|
9
9
|
|
|
10
10
|
from werkzeug.exceptions import BadRequest
|
|
11
11
|
|
|
12
|
-
from zish import
|
|
12
|
+
from zish import loads
|
|
13
13
|
|
|
14
14
|
from chellow.models import (
|
|
15
15
|
Bill,
|
|
@@ -18,6 +18,7 @@ from chellow.models import (
|
|
|
18
18
|
Comm,
|
|
19
19
|
Contract,
|
|
20
20
|
Cop,
|
|
21
|
+
DtcMeterType,
|
|
21
22
|
EnergisationStatus,
|
|
22
23
|
Era,
|
|
23
24
|
GContract,
|
|
@@ -389,11 +390,11 @@ def general_import_era(sess, action, vals, args):
|
|
|
389
390
|
else:
|
|
390
391
|
energisation_status = EnergisationStatus.get_by_code(sess, es_code)
|
|
391
392
|
|
|
392
|
-
|
|
393
|
-
if
|
|
394
|
-
|
|
393
|
+
dtc_meter_type_code = add_arg(args, "DTC Meter Type", vals, 14)
|
|
394
|
+
if dtc_meter_type_code == NO_CHANGE:
|
|
395
|
+
dtc_meter_type = existing_era.dtc_meter_type
|
|
395
396
|
else:
|
|
396
|
-
|
|
397
|
+
dtc_meter_type = DtcMeterType.get_by_code(sess, dtc_meter_type_code)
|
|
397
398
|
|
|
398
399
|
imp_mpan_core = add_arg(args, "Import MPAN Core", vals, 15)
|
|
399
400
|
if imp_mpan_core == NO_CHANGE:
|
|
@@ -519,7 +520,7 @@ def general_import_era(sess, action, vals, args):
|
|
|
519
520
|
comm,
|
|
520
521
|
ssc_code,
|
|
521
522
|
energisation_status,
|
|
522
|
-
|
|
523
|
+
dtc_meter_type,
|
|
523
524
|
imp_mpan_core,
|
|
524
525
|
imp_llfc_code,
|
|
525
526
|
imp_supplier_contract,
|
|
@@ -1275,11 +1276,8 @@ def general_import_supply(sess, action, vals, args):
|
|
|
1275
1276
|
energisation_status = EnergisationStatus.get_by_code(
|
|
1276
1277
|
sess, energisation_status_code
|
|
1277
1278
|
)
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
properties = loads(properties_str)
|
|
1281
|
-
except ZishException as e:
|
|
1282
|
-
raise BadRequest(f"Can't parse the properties field. {e}")
|
|
1279
|
+
dtc_meter_type_code = add_arg(args, "DTC Meter Type", vals, 19)
|
|
1280
|
+
dtc_meter_type = DtcMeterType.get_by_code(sess, dtc_meter_type_code)
|
|
1283
1281
|
imp_mpan_core = add_arg(args, "Import MPAN Core", vals, 20)
|
|
1284
1282
|
if len(imp_mpan_core) == 0:
|
|
1285
1283
|
imp_mpan_core = None
|
|
@@ -1356,7 +1354,7 @@ def general_import_supply(sess, action, vals, args):
|
|
|
1356
1354
|
comm,
|
|
1357
1355
|
ssc_code,
|
|
1358
1356
|
energisation_status,
|
|
1359
|
-
|
|
1357
|
+
dtc_meter_type,
|
|
1360
1358
|
imp_mpan_core,
|
|
1361
1359
|
imp_llfc_code,
|
|
1362
1360
|
imp_supplier_contract,
|
chellow/models.py
CHANGED
|
@@ -2452,6 +2452,38 @@ class Laf(Base, PersistentClass):
|
|
|
2452
2452
|
self.value = value
|
|
2453
2453
|
|
|
2454
2454
|
|
|
2455
|
+
# J0483 in https://www.electralink.co.uk/data-catalogues/dtc-catalogue/
|
|
2456
|
+
class DtcMeterType(Base, PersistentClass):
|
|
2457
|
+
__tablename__ = "dtc_meter_type"
|
|
2458
|
+
id = Column(Integer, primary_key=True)
|
|
2459
|
+
code = Column(String, nullable=False, unique=True)
|
|
2460
|
+
description = Column(String, nullable=False)
|
|
2461
|
+
eras = relationship("Era", backref="dtc_meter_type")
|
|
2462
|
+
|
|
2463
|
+
def __init__(self, code, description):
|
|
2464
|
+
self.code = code
|
|
2465
|
+
self.description = description
|
|
2466
|
+
|
|
2467
|
+
@classmethod
|
|
2468
|
+
def insert(cls, sess, code, description):
|
|
2469
|
+
dtc_meter_type = cls(code, description)
|
|
2470
|
+
sess.add(dtc_meter_type)
|
|
2471
|
+
return dtc_meter_type
|
|
2472
|
+
|
|
2473
|
+
@staticmethod
|
|
2474
|
+
def find_by_code(sess, code):
|
|
2475
|
+
return sess.execute(
|
|
2476
|
+
select(DtcMeterType).where(DtcMeterType.code == code)
|
|
2477
|
+
).scalar_one_or_none()
|
|
2478
|
+
|
|
2479
|
+
@classmethod
|
|
2480
|
+
def get_by_code(cls, sess, code):
|
|
2481
|
+
dtc_meter_type = cls.find_by_code(sess, code)
|
|
2482
|
+
if dtc_meter_type is None:
|
|
2483
|
+
raise Exception(f"Can't find the DTC meter type with code {code}.")
|
|
2484
|
+
return dtc_meter_type
|
|
2485
|
+
|
|
2486
|
+
|
|
2455
2487
|
class MeterType(Base, PersistentClass):
|
|
2456
2488
|
__tablename__ = "meter_type"
|
|
2457
2489
|
id = Column(Integer, primary_key=True)
|
|
@@ -3234,42 +3266,6 @@ class EnergisationStatus(Base, PersistentClass):
|
|
|
3234
3266
|
return energisation_status
|
|
3235
3267
|
|
|
3236
3268
|
|
|
3237
|
-
METER_TYPES = {
|
|
3238
|
-
"H": "Half Hourly",
|
|
3239
|
-
"K": "Key",
|
|
3240
|
-
"LAG": "Lag",
|
|
3241
|
-
"LEAD": "Lead",
|
|
3242
|
-
"MAIN": "Main",
|
|
3243
|
-
"N": "Non-Half Hourly",
|
|
3244
|
-
"NCAMR": "Non-remotely Configurable Automated Meter Reading",
|
|
3245
|
-
"NSS": "A meter that meets the definition of an ADM but is not compliant "
|
|
3246
|
-
"with any version of SMETS",
|
|
3247
|
-
"RCAMR": "Remotely Configurable Automated Meter Reading without remote "
|
|
3248
|
-
"enable/disable capability",
|
|
3249
|
-
"RCAMY": "Remotely Configurable Automated Meter Reading with remote "
|
|
3250
|
-
"enable/disable capability",
|
|
3251
|
-
"S": "Smartcard Prepayment",
|
|
3252
|
-
"S1": "A meter that is compliant with the Smart Metering Equipment "
|
|
3253
|
-
"Technical Specifications 1 (SMETS1)",
|
|
3254
|
-
"S2A": "A single element meter that is compliant with SMETS2",
|
|
3255
|
-
"S2B": "A twin element meter that is compliant with SMETS2",
|
|
3256
|
-
"S2C": "A polyphase meter that is compliant with SMETS2",
|
|
3257
|
-
"S2AD": "A single element meter with one or more ALCS that is compliant "
|
|
3258
|
-
"with SMETS2",
|
|
3259
|
-
"S2BD": "A twin element meter with one or more ALCS that is compliant "
|
|
3260
|
-
"with SMETS2",
|
|
3261
|
-
"S2CD": "A polyphase meter with one or more ALCS that is compliant with " "SMETS2",
|
|
3262
|
-
"S2ADE": "Single element meter with one or more ALCS and Boost Function "
|
|
3263
|
-
"that is compliant with SMETS2",
|
|
3264
|
-
"S2BDE": "A twin element meter with one or more ALCS and Boost Function "
|
|
3265
|
-
"that is compliant with SMETS2",
|
|
3266
|
-
"S2CDE": "A polyphase meter with one or more ALCS and Boost Function that "
|
|
3267
|
-
"is compliant with SMETS2",
|
|
3268
|
-
"SPECL": "Special",
|
|
3269
|
-
"T": "Token",
|
|
3270
|
-
}
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
3269
|
class Era(Base, PersistentClass):
|
|
3274
3270
|
__tablename__ = "era"
|
|
3275
3271
|
id = Column(Integer, primary_key=True)
|
|
@@ -3298,7 +3294,7 @@ class Era(Base, PersistentClass):
|
|
|
3298
3294
|
energisation_status_id = Column(
|
|
3299
3295
|
Integer, ForeignKey("energisation_status.id"), nullable=False
|
|
3300
3296
|
)
|
|
3301
|
-
|
|
3297
|
+
dtc_meter_type_id = Column(Integer, ForeignKey("dtc_meter_type.id"))
|
|
3302
3298
|
imp_mpan_core = Column(String)
|
|
3303
3299
|
imp_llfc_id = Column(Integer, ForeignKey("llfc.id"))
|
|
3304
3300
|
imp_llfc = relationship("Llfc", primaryjoin="Llfc.id==Era.imp_llfc_id")
|
|
@@ -3441,7 +3437,7 @@ class Era(Base, PersistentClass):
|
|
|
3441
3437
|
self.comm,
|
|
3442
3438
|
None if self.ssc is None else self.ssc.code,
|
|
3443
3439
|
self.energisation_status,
|
|
3444
|
-
|
|
3440
|
+
self.dtc_meter_type,
|
|
3445
3441
|
self.imp_mpan_core,
|
|
3446
3442
|
None if self.imp_llfc is None else self.imp_llfc.code,
|
|
3447
3443
|
self.imp_supplier_contract,
|
|
@@ -3470,7 +3466,7 @@ class Era(Base, PersistentClass):
|
|
|
3470
3466
|
comm,
|
|
3471
3467
|
ssc_code,
|
|
3472
3468
|
energisation_status,
|
|
3473
|
-
|
|
3469
|
+
dtc_meter_type,
|
|
3474
3470
|
imp_mpan_core,
|
|
3475
3471
|
imp_llfc_code,
|
|
3476
3472
|
imp_supplier_contract,
|
|
@@ -3521,22 +3517,7 @@ class Era(Base, PersistentClass):
|
|
|
3521
3517
|
"A NHH supply must have a Standard Settlement Configuration."
|
|
3522
3518
|
)
|
|
3523
3519
|
self.energisation_status = energisation_status
|
|
3524
|
-
|
|
3525
|
-
if isinstance(properties, dict):
|
|
3526
|
-
try:
|
|
3527
|
-
meter_type = properties["meter_type"]
|
|
3528
|
-
if meter_type not in METER_TYPES:
|
|
3529
|
-
raise BadRequest(
|
|
3530
|
-
f"The meter type {meter_type} must be one of {METER_TYPES}."
|
|
3531
|
-
)
|
|
3532
|
-
except KeyError:
|
|
3533
|
-
pass
|
|
3534
|
-
|
|
3535
|
-
self.properties = dumps(properties)
|
|
3536
|
-
else:
|
|
3537
|
-
raise Exception(
|
|
3538
|
-
f"The properties argument must be a dict, rather than {properties}."
|
|
3539
|
-
)
|
|
3520
|
+
self.dtc_meter_type = dtc_meter_type
|
|
3540
3521
|
|
|
3541
3522
|
locs = locals()
|
|
3542
3523
|
voltage_level = None
|
|
@@ -3775,29 +3756,13 @@ class Era(Base, PersistentClass):
|
|
|
3775
3756
|
sess.delete(channel)
|
|
3776
3757
|
sess.flush()
|
|
3777
3758
|
|
|
3778
|
-
@property
|
|
3779
|
-
def props(self):
|
|
3780
|
-
if not hasattr(self, "_props"):
|
|
3781
|
-
self._props = loads(self.properties)
|
|
3782
|
-
return self._props
|
|
3783
|
-
|
|
3784
3759
|
@property
|
|
3785
3760
|
def meter_category(self):
|
|
3786
3761
|
if not hasattr(self, "_meter_category"):
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
except KeyError:
|
|
3791
|
-
if self.pc.code == "00":
|
|
3792
|
-
cat = "hh"
|
|
3793
|
-
elif len(self.channels) > 0:
|
|
3794
|
-
cat = "amr"
|
|
3795
|
-
elif self.mtc_participant.meter_type.code in ["UM", "PH"]:
|
|
3796
|
-
cat = "unmetered"
|
|
3797
|
-
else:
|
|
3798
|
-
cat = "nhh"
|
|
3762
|
+
self._meter_category = METER_CATEGORY[
|
|
3763
|
+
None if self.dtc_meter_type is None else self.dtc_meter_type.code
|
|
3764
|
+
]
|
|
3799
3765
|
|
|
3800
|
-
self._meter_category = cat
|
|
3801
3766
|
return self._meter_category
|
|
3802
3767
|
|
|
3803
3768
|
def get_physical_site(self, sess):
|
|
@@ -3808,7 +3773,42 @@ class Era(Base, PersistentClass):
|
|
|
3808
3773
|
)
|
|
3809
3774
|
|
|
3810
3775
|
|
|
3811
|
-
METER_CATEGORY = {
|
|
3776
|
+
METER_CATEGORY = {
|
|
3777
|
+
None: "unmetered",
|
|
3778
|
+
"CHECK": "hh",
|
|
3779
|
+
"H": "hh",
|
|
3780
|
+
"K": "nhh",
|
|
3781
|
+
"LAG_": "hh",
|
|
3782
|
+
"LEAD_": "hh",
|
|
3783
|
+
"MAIN_": "hh",
|
|
3784
|
+
"N": "nhh",
|
|
3785
|
+
"NCAMR": "amr",
|
|
3786
|
+
"NSS": "amr",
|
|
3787
|
+
"RCAMR": "amr",
|
|
3788
|
+
"RCAMY": "amr",
|
|
3789
|
+
"S": "nhh",
|
|
3790
|
+
"S1": "amr",
|
|
3791
|
+
"S2A": "amr",
|
|
3792
|
+
"S2B": "amr",
|
|
3793
|
+
"S2C": "amr",
|
|
3794
|
+
"S2AD": "amr",
|
|
3795
|
+
"S2BD": "amr",
|
|
3796
|
+
"S2CDE": "amr",
|
|
3797
|
+
"SPECL": "nhh",
|
|
3798
|
+
"T": "nhh",
|
|
3799
|
+
"2ADF": "amr",
|
|
3800
|
+
"2ADEF": "amr",
|
|
3801
|
+
"2AEF": "amr",
|
|
3802
|
+
"2AF": "amr",
|
|
3803
|
+
"2BF": "amr",
|
|
3804
|
+
"2BDF": "amr",
|
|
3805
|
+
"2BDEF": "amr",
|
|
3806
|
+
"2BEF": "amr",
|
|
3807
|
+
"2CDEF": "amr",
|
|
3808
|
+
"2CF": "amr",
|
|
3809
|
+
"2CDF": "amr",
|
|
3810
|
+
"2CEF": "amr",
|
|
3811
|
+
}
|
|
3812
3812
|
|
|
3813
3813
|
|
|
3814
3814
|
class Channel(Base, PersistentClass):
|
|
@@ -4521,7 +4521,7 @@ class Supply(Base, PersistentClass):
|
|
|
4521
4521
|
template_era.comm,
|
|
4522
4522
|
None if template_era.ssc is None else template_era.ssc.code,
|
|
4523
4523
|
template_era.energisation_status,
|
|
4524
|
-
|
|
4524
|
+
template_era.dtc_meter_type,
|
|
4525
4525
|
template_era.imp_mpan_core,
|
|
4526
4526
|
imp_llfc_code,
|
|
4527
4527
|
template_era.imp_supplier_contract,
|
|
@@ -6567,6 +6567,94 @@ def insert_voltage_levels(sess):
|
|
|
6567
6567
|
VoltageLevel.insert(sess, code, desc)
|
|
6568
6568
|
|
|
6569
6569
|
|
|
6570
|
+
def insert_dtc_meter_types(sess):
|
|
6571
|
+
for code, desc in (
|
|
6572
|
+
("CHECK", "Check"),
|
|
6573
|
+
("H", "Half Hourly"),
|
|
6574
|
+
("K", "Key"),
|
|
6575
|
+
("LAG_", "Lag"),
|
|
6576
|
+
("LEAD_", "Lead"),
|
|
6577
|
+
("MAIN_", "Main"),
|
|
6578
|
+
("N", "Non-Half Hourly"),
|
|
6579
|
+
("NCAMR", "Non-remotely Configurable Automated Meter Reading"),
|
|
6580
|
+
(
|
|
6581
|
+
"NSS",
|
|
6582
|
+
"A meter that meets the definition of an ADM but is not compliant with "
|
|
6583
|
+
"any version of SMETS",
|
|
6584
|
+
),
|
|
6585
|
+
(
|
|
6586
|
+
"RCAMR",
|
|
6587
|
+
"Remotely Configurable Automated Meter Reading without remote "
|
|
6588
|
+
"enable/disable capability",
|
|
6589
|
+
),
|
|
6590
|
+
(
|
|
6591
|
+
"RCAMY",
|
|
6592
|
+
"Remotely Configurable Automated Meter Reading with remote "
|
|
6593
|
+
"enable/disable capability",
|
|
6594
|
+
),
|
|
6595
|
+
("S", "Smartcard Prepayment"),
|
|
6596
|
+
(
|
|
6597
|
+
"S1",
|
|
6598
|
+
"A meter that is compliant with the Smart Metering Equipment Technical "
|
|
6599
|
+
"Specifications 1 (SMETS1)",
|
|
6600
|
+
),
|
|
6601
|
+
("S2A", "A single element meter that is compliant with SMETS2"),
|
|
6602
|
+
("S2B", "A twin element meter that is compliant with SMETS2"),
|
|
6603
|
+
("S2C", "A polyphase meter that is compliant with SMETS2"),
|
|
6604
|
+
(
|
|
6605
|
+
"S2AD",
|
|
6606
|
+
"A single element meter with one or more ALCS that is compliant with "
|
|
6607
|
+
"SMETS2",
|
|
6608
|
+
),
|
|
6609
|
+
(
|
|
6610
|
+
"S2BD",
|
|
6611
|
+
"A twin element meter with one or more ALCS that is compliant with "
|
|
6612
|
+
"SMETS2",
|
|
6613
|
+
),
|
|
6614
|
+
(
|
|
6615
|
+
"S2CDE",
|
|
6616
|
+
"A polyphase meter with one or more ALCS and Boost Function that is "
|
|
6617
|
+
"compliant with SMETS2",
|
|
6618
|
+
),
|
|
6619
|
+
("SPECL", "Special"),
|
|
6620
|
+
("T", "Token"),
|
|
6621
|
+
(
|
|
6622
|
+
"2ADF",
|
|
6623
|
+
"Single Element with ALCS and Auxiliary Proportional Controller (APC) "
|
|
6624
|
+
"that is compliant with SMETS2",
|
|
6625
|
+
),
|
|
6626
|
+
(
|
|
6627
|
+
"2ADEF",
|
|
6628
|
+
"Single Element with ALCS, Boost Function and APC that is compliant "
|
|
6629
|
+
"with SMETS2",
|
|
6630
|
+
),
|
|
6631
|
+
(
|
|
6632
|
+
"2AEF",
|
|
6633
|
+
"Single Element with Boost Function and APC that is compliant with SMETS2",
|
|
6634
|
+
),
|
|
6635
|
+
("2AF", "Single Element with APC that is compliant with SMETS2"),
|
|
6636
|
+
("2BF", "Twin Element with APC that is compliant with SMETS2"),
|
|
6637
|
+
("2BDF", "Twin Element with ALCS and APC that is compliant with SMETS2"),
|
|
6638
|
+
(
|
|
6639
|
+
"2BDEF",
|
|
6640
|
+
"Twin Element with ALCS, Boost Function and APC that is compliant with "
|
|
6641
|
+
"SMETS2",
|
|
6642
|
+
),
|
|
6643
|
+
(
|
|
6644
|
+
"2BEF",
|
|
6645
|
+
"Twin Element with Boost Function and APC that is compliant with SMETS2",
|
|
6646
|
+
),
|
|
6647
|
+
(
|
|
6648
|
+
"2CDEF",
|
|
6649
|
+
"Polyphase with ALCS, Boost Function and APC that is compliant with SMETS2",
|
|
6650
|
+
),
|
|
6651
|
+
("2CF", "Polyphase with APC that is compliant with SMETS2"),
|
|
6652
|
+
("2CDF", "Polyphase with ALCS and APC that is compliant with SMETS2"),
|
|
6653
|
+
("2CEF", "Polyphase with Boost Function and APC that is compliant with SMETS2"),
|
|
6654
|
+
):
|
|
6655
|
+
DtcMeterType.insert(sess, code, desc)
|
|
6656
|
+
|
|
6657
|
+
|
|
6570
6658
|
def db_init(sess, root_path):
|
|
6571
6659
|
db_name = config["PGDATABASE"]
|
|
6572
6660
|
log_message("Initializing database.")
|
|
@@ -6658,6 +6746,9 @@ def db_init(sess, root_path):
|
|
|
6658
6746
|
):
|
|
6659
6747
|
Contract.insert_non_core(sess, name, "", properties, last_month_start, None, {})
|
|
6660
6748
|
|
|
6749
|
+
insert_dtc_meter_types(sess)
|
|
6750
|
+
sess.commit()
|
|
6751
|
+
|
|
6661
6752
|
insert_g_read_types(sess)
|
|
6662
6753
|
sess.commit()
|
|
6663
6754
|
|
|
@@ -7295,6 +7386,53 @@ def db_upgrade_45_to_46(sess, root_path):
|
|
|
7295
7386
|
)
|
|
7296
7387
|
|
|
7297
7388
|
|
|
7389
|
+
def db_upgrade_46_to_47(sess, root_path):
|
|
7390
|
+
insert_dtc_meter_types(sess)
|
|
7391
|
+
sess.flush()
|
|
7392
|
+
|
|
7393
|
+
sess.execute(
|
|
7394
|
+
text(
|
|
7395
|
+
"alter table era add dtc_meter_type_id integer references dtc_meter_type "
|
|
7396
|
+
"(id);"
|
|
7397
|
+
)
|
|
7398
|
+
)
|
|
7399
|
+
for era_id, pc_id, era_properties, mtc_participant_id in sess.execute(
|
|
7400
|
+
text("select era.id, era.pc_id, era.properties, mtc_participant_id from era")
|
|
7401
|
+
):
|
|
7402
|
+
dtc_meter_type_id = None
|
|
7403
|
+
props = loads(era_properties)
|
|
7404
|
+
if "meter_type" in props:
|
|
7405
|
+
mt_code = props["meter_type"]
|
|
7406
|
+
dtc_meter_type = DtcMeterType.find_by_code(sess, mt_code)
|
|
7407
|
+
dtc_meter_type_id = dtc_meter_type.id
|
|
7408
|
+
|
|
7409
|
+
if dtc_meter_type_id is None:
|
|
7410
|
+
mtc_participant = MtcParticipant.get_by_id(sess, mtc_participant_id)
|
|
7411
|
+
if mtc_participant.meter_type.code not in ["UM", "PH"]:
|
|
7412
|
+
pc = Pc.get_by_id(sess, pc_id)
|
|
7413
|
+
if pc.code == "00":
|
|
7414
|
+
dtc_meter_type_code = "H"
|
|
7415
|
+
else:
|
|
7416
|
+
channels = sess.scalars(
|
|
7417
|
+
select(Channel).where(Channel.era_id == era_id)
|
|
7418
|
+
).all()
|
|
7419
|
+
if len(channels) > 0:
|
|
7420
|
+
dtc_meter_type_code = "RCAMR"
|
|
7421
|
+
else:
|
|
7422
|
+
dtc_meter_type_code = "N"
|
|
7423
|
+
dtc_meter_type = DtcMeterType.get_by_code(sess, dtc_meter_type_code)
|
|
7424
|
+
dtc_meter_type_id = dtc_meter_type.id
|
|
7425
|
+
|
|
7426
|
+
sess.execute(
|
|
7427
|
+
text(
|
|
7428
|
+
"UPDATE era SET dtc_meter_type_id = :dtc_meter_type_id "
|
|
7429
|
+
"where id = :era_id"
|
|
7430
|
+
),
|
|
7431
|
+
params={"dtc_meter_type_id": dtc_meter_type_id, "era_id": era_id},
|
|
7432
|
+
)
|
|
7433
|
+
sess.execute(text("alter table era drop column properties;"))
|
|
7434
|
+
|
|
7435
|
+
|
|
7298
7436
|
upgrade_funcs = [None] * 18
|
|
7299
7437
|
upgrade_funcs.extend(
|
|
7300
7438
|
[
|
|
@@ -7326,6 +7464,7 @@ upgrade_funcs.extend(
|
|
|
7326
7464
|
db_upgrade_43_to_44,
|
|
7327
7465
|
db_upgrade_44_to_45,
|
|
7328
7466
|
db_upgrade_45_to_46,
|
|
7467
|
+
db_upgrade_46_to_47,
|
|
7329
7468
|
]
|
|
7330
7469
|
)
|
|
7331
7470
|
|