Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions src/bo4e/bo/preisblattmessung.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
Contains PreisblattMessung class and corresponding marshmallow schema for de-/serialization
"""
from typing import List, Optional

import attr
from marshmallow import fields
from marshmallow_enum import EnumField # type:ignore[import]

from bo4e.bo.preisblatt import Preisblatt, PreisblattSchema
from bo4e.com.geraeteeigenschaften import Geraeteeigenschaften, GeraeteeigenschaftenSchema
from bo4e.enum.bilanzierungsmethode import Bilanzierungsmethode
from bo4e.enum.botyp import BoTyp
from bo4e.enum.dienstleistungstyp import Dienstleistungstyp
from bo4e.enum.netzebene import Netzebene


# pylint: disable=too-few-public-methods
@attr.s(auto_attribs=True, kw_only=True)
class PreisblattMessung(Preisblatt):
"""
Variante des Preisblattmodells zur Abbildung der Preise des Messstellenbetriebs und damit verbundener Leistungen
"""

bo_typ: BoTyp = attr.ib(default=BoTyp.PREISBLATTMESSUNG)
# required attributes (additional to those of Preisblatt)
#: Die Preise gelten für Marktlokationen der angebebenen Bilanzierungsmethode
bilanzierungsmethode: Bilanzierungsmethode = attr.ib(validator=attr.validators.instance_of(Bilanzierungsmethode))
#: Die Preise gelten für Messlokationen in der angebebenen Netzebene
messebene: Netzebene = attr.ib(validator=attr.validators.instance_of(Netzebene))

#: Der Preis betrifft den hier angegebenen Zähler, z.B. einen Drehstromzähler
zaehler: Geraeteeigenschaften = attr.ib(validator=attr.validators.instance_of(Geraeteeigenschaften))
# todo: https://github.com/Hochfrequenz/BO4E-python/issues/333

# optional attributes
#: Im Preis sind die hier angegebenen Dienstleistungen enthalten, z.B. Jährliche Ablesung
inklusive_dienstleistungen: Optional[List[Dienstleistungstyp]] = attr.ib(
default=None,
validator=attr.validators.optional(
attr.validators.deep_iterable(
member_validator=attr.validators.instance_of(Dienstleistungstyp),
iterable_validator=attr.validators.instance_of(list),
)
),
)

#: Im Preis sind die hier angebebenen Geräte mit enthalten, z.B. ein Wandler
inklusive_geraete: Optional[List[Geraeteeigenschaften]] = attr.ib(
default=None,
validator=attr.validators.optional(
attr.validators.deep_iterable(
member_validator=attr.validators.instance_of(Geraeteeigenschaften),
iterable_validator=attr.validators.instance_of(list),
)
),
)


class PreisblattMessungSchema(PreisblattSchema):
"""
Schema for de-/serialization of PreisblattMessung
"""

class_name = PreisblattMessung # type:ignore[assignment]
# required attributes
bilanzierungsmethode = EnumField(Bilanzierungsmethode)
messebene = EnumField(Netzebene)
zaehler = fields.Nested(GeraeteeigenschaftenSchema)
# optional attributes
inklusive_dienstleistungen = fields.List(EnumField(Dienstleistungstyp))
inklusive_geraete = fields.List(fields.Nested(GeraeteeigenschaftenSchema))
6 changes: 5 additions & 1 deletion tests/test_geraeteeigenschaften.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
from bo4e.enum.geraetetyp import Geraetetyp
from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import]

example_geraeteeigenschaften = Geraeteeigenschaften(
geraetemerkmal=Geraetemerkmal.GAS_G1000, geraetetyp=Geraetetyp.MULTIPLEXANLAGE
)


class TestGeraeteeigenschaften:
@pytest.mark.parametrize(
"geraeteeigenschaften, expected_json_dict",
[
pytest.param(
Geraeteeigenschaften(geraetemerkmal=Geraetemerkmal.GAS_G1000, geraetetyp=Geraetetyp.MULTIPLEXANLAGE),
example_geraeteeigenschaften,
{"geraetemerkmal": "GAS_G1000", "geraetetyp": "MULTIPLEXANLAGE"},
),
],
Expand Down
46 changes: 46 additions & 0 deletions tests/test_preisblatt_messung.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pytest # type:ignore[import]

from bo4e.bo.preisblattmessung import PreisblattMessung, PreisblattMessungSchema
from bo4e.enum.bilanzierungsmethode import Bilanzierungsmethode
from bo4e.enum.dienstleistungstyp import Dienstleistungstyp
from bo4e.enum.netzebene import Netzebene
from bo4e.enum.preisstatus import Preisstatus
from bo4e.enum.sparte import Sparte
from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import]
from tests.test_geraeteeigenschaften import example_geraeteeigenschaften # type:ignore[import]
from tests.test_marktteilnehmer import example_marktteilnehmer # type:ignore[import]
from tests.test_preisposition import example_preisposition # type:ignore[import]
from tests.test_zeitraum import example_zeitraum # type:ignore[import]


class TestPreisblatt:
@pytest.mark.parametrize(
"preisblatt_messung",
[
pytest.param(
PreisblattMessung(
bezeichnung="foo",
sparte=Sparte.STROM,
preisstatus=Preisstatus.ENDGUELTIG,
preispositionen=[example_preisposition],
gueltigkeit=example_zeitraum,
herausgeber=example_marktteilnehmer,
bilanzierungsmethode=Bilanzierungsmethode.TLP_GEMEINSAM,
messebene=Netzebene.MSP,
inklusive_dienstleistungen=[Dienstleistungstyp.AUSLESUNG_FERNAUSLESUNG_ZUSAETZLICH_MSB],
zaehler=example_geraeteeigenschaften,
inklusive_geraete=[example_geraeteeigenschaften],
)
),
],
)
def test_serialization_roundtrip(self, preisblatt_messung: PreisblattMessung):
"""
Test de-/serialisation
"""
assert_serialization_roundtrip(preisblatt_messung, PreisblattMessungSchema())

def test_missing_required_attribute(self):
with pytest.raises(TypeError) as excinfo:
_ = PreisblattMessung()
assert "missing 8 required" in str(excinfo.value) # 5 from preisblatt + 3 from preisblatt messung