From 2033cb06da6ae3b791d4c00cc283d963b3992f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Annika=20Schl=C3=B6gl?= Date: Fri, 21 Jan 2022 18:20:13 +0100 Subject: [PATCH 01/20] =?UTF-8?q?=E2=9C=A8Implement=20BO=20Regionaltarif?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bo4e/bo/regionaltarif.py | 86 ++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/bo4e/bo/regionaltarif.py diff --git a/src/bo4e/bo/regionaltarif.py b/src/bo4e/bo/regionaltarif.py new file mode 100644 index 000000000..e550b10b9 --- /dev/null +++ b/src/bo4e/bo/regionaltarif.py @@ -0,0 +1,86 @@ +""" +Contains Regionaltarif class and corresponding marshmallow schema for de-/serialization +""" + +from datetime import datetime +from typing import List, Optional + +import attr +from marshmallow import fields + +from bo4e.bo.tarifinfo import Tarifinfo, TarifinfoSchema +from bo4e.com.regionalepreisgarantie import RegionalePreisgarantie, RegionalePreisgarantieSchema +from bo4e.com.regionaleraufabschlag import RegionalerAufAbschlag, RegionalerAufAbschlagSchema +from bo4e.com.regionaletarifpreisposition import RegionaleTarifpreisposition, RegionaleTarifpreispositionSchema +from bo4e.com.tarifberechnungsparameter import Tarifberechnungsparameter, TarifberechnungsparameterSchema +from bo4e.com.tarifeinschraenkung import Tarifeinschraenkung, TarifeinschraenkungSchema +from bo4e.enum.botyp import BoTyp +from bo4e.validators import check_list_length_at_least_one + + +# pylint: disable=too-few-public-methods, empty-docstring +@attr.s(auto_attribs=True, kw_only=True) +class Regionaltarif(Tarifinfo): + # no description in the official docs. + # https://github.com/Hochfrequenz/BO4E-python/issues/338 + """ """ + + bo_typ: BoTyp = attr.ib(default=BoTyp.REGIONALTARIF) + # required attributes + #: Gibt an, wann der Preis zuletzt angepasst wurde + preisstand: datetime = attr.ib(validator=attr.validators.instance_of(datetime)) + #: Für die Berechnung der Kosten sind die hier abgebildeten Parameter heranzuziehen + berechnungsparameter: Tarifberechnungsparameter = attr.ib( + validator=attr.validators.instance_of(Tarifberechnungsparameter) + ) + #: Die festgelegten Preise mit regionaler Eingrenzung, z.B. für Arbeitspreis, Grundpreis etc. + tarifpreise: List[RegionaleTarifpreisposition] = attr.ib( + validator=attr.validators.deep_iterable( + member_validator=attr.validators.instance_of(RegionaleTarifpreisposition), + iterable_validator=check_list_length_at_least_one, + ) + ) + + # optional attributes + #: Auf- und Abschläge auf die Preise oder Kosten mit regionaler Eingrenzung + tarif_auf_abschlaege: Optional[List[RegionalerAufAbschlag]] = attr.ib( + default=None, + validator=attr.validators.optional( + attr.validators.deep_iterable( + member_validator=attr.validators.instance_of(RegionalerAufAbschlag), + iterable_validator=attr.validators.instance_of(list), + ) + ), + ) + #: Festlegung von Garantien für bestimmte Preisanteile + preisgarantien: Optional[List[RegionalePreisgarantie]] = attr.ib( + default=None, + validator=attr.validators.optional( + attr.validators.deep_iterable( + member_validator=attr.validators.instance_of(RegionalePreisgarantie), + iterable_validator=attr.validators.instance_of(list), + ) + ), + ) + #: Die Bedingungen und Einschränkungen unter denen ein Tarif angewendet werden kann + tarifeinschraenkungen: Optional[Tarifeinschraenkung] = attr.ib( + default=None, validator=attr.validators.optional(attr.validators.instance_of(Tarifeinschraenkung)) + ) + + +class RegionaltarifSchema(TarifinfoSchema): + """ + Schema for de-/serialization of Regionaltarif + """ + + class_name = Regionaltarif # type:ignore[assignment] + + # required attributes + preisstand = fields.DateTime() + berechnungsparameter = fields.Nested(TarifberechnungsparameterSchema) + tarifpreise = fields.List(fields.Nested(RegionaleTarifpreispositionSchema)) + + # optional attributes + tarif_auf_abschlaege = fields.List(fields.Nested(RegionalerAufAbschlagSchema), allow_none=True) + preisgarantien = fields.List(fields.Nested(RegionalePreisgarantieSchema), allow_none=True) + tarifeinschraenkungen = fields.Nested(TarifeinschraenkungSchema, allow_none=True) From 073ec876938d77f32474a61261d9c2c72409e33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Annika=20Schl=C3=B6gl?= Date: Fri, 21 Jan 2022 18:20:32 +0100 Subject: [PATCH 02/20] =?UTF-8?q?=E2=9C=85=20Add=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_regionalepreisgarantie.py | 24 +++--- tests/test_regionaleraufabschlag.py | 36 +++++---- tests/test_regionaletarifpreisposition.py | 40 +++++----- tests/test_regionaltarif.py | 96 +++++++++++++++++++++++ tests/test_tarifberechnungsparameter.py | 26 +++--- tests/test_tarifeinschraenkung.py | 19 +++++ 6 files changed, 181 insertions(+), 60 deletions(-) create mode 100644 tests/test_regionaltarif.py diff --git a/tests/test_regionalepreisgarantie.py b/tests/test_regionalepreisgarantie.py index e3a2883a1..8be9277aa 100644 --- a/tests/test_regionalepreisgarantie.py +++ b/tests/test_regionalepreisgarantie.py @@ -11,23 +11,25 @@ from bo4e.enum.tarifregionskriterium import Tarifregionskriterium from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +example_regionale_preisgarantie = RegionalePreisgarantie( + preisgarantietyp=Preisgarantietyp.NUR_ENERGIEPREIS, + zeitliche_gueltigkeit=Zeitraum( + startzeitpunkt=datetime(2011, 2, 5, 16, 43, tzinfo=timezone.utc), + endzeitpunkt=datetime(2021, 7, 30, tzinfo=timezone.utc), + ), + regionale_gueltigkeit=RegionaleGueltigkeit( + gueltigkeitstyp=Gueltigkeitstyp.NUR_IN, + kriteriums_werte=[KriteriumWert(kriterium=Tarifregionskriterium.POSTLEITZAHL, wert="01069")], + ), +) + class TestRegionalePreisgarantie: @pytest.mark.parametrize( "regionale_preisgarantie, expected_json_dict", [ pytest.param( - RegionalePreisgarantie( - preisgarantietyp=Preisgarantietyp.NUR_ENERGIEPREIS, - zeitliche_gueltigkeit=Zeitraum( - startzeitpunkt=datetime(2011, 2, 5, 16, 43, tzinfo=timezone.utc), - endzeitpunkt=datetime(2021, 7, 30, tzinfo=timezone.utc), - ), - regionale_gueltigkeit=RegionaleGueltigkeit( - gueltigkeitstyp=Gueltigkeitstyp.NUR_IN, - kriteriums_werte=[KriteriumWert(kriterium=Tarifregionskriterium.POSTLEITZAHL, wert="01069")], - ), - ), + example_regionale_preisgarantie, { "beschreibung": None, "preisgarantietyp": "NUR_ENERGIEPREIS", diff --git a/tests/test_regionaleraufabschlag.py b/tests/test_regionaleraufabschlag.py index c4b0bbc5a..1dd0cbb5a 100644 --- a/tests/test_regionaleraufabschlag.py +++ b/tests/test_regionaleraufabschlag.py @@ -12,29 +12,31 @@ from tests.test_vertragskonditionen import example_vertragskonditionen # type:ignore[import] from tests.test_zeitraum import example_zeitraum # type:ignore[import] +example_regionaler_auf_abschlag = RegionalerAufAbschlag( + bezeichnung="Foo", + beschreibung="Bar", + auf_abschlagstyp=AufAbschlagstyp.RELATIV, + auf_abschlagsziel=AufAbschlagsziel.ARBEITSPREIS_HT, + einheit=Waehrungseinheit.CT, + website="https://www.hochfrequenz.de", + zusatzprodukte=["ein standmixer", "ein thermomix"], + voraussetzungen=["lecker essen", "mit ökostrom gekocht"], + tarifnamensaenderungen="Super-Duper Tarif", + staffeln=[example_regionale_preisstaffel], + gueltigkeitszeitraum=example_zeitraum, + energiemixaenderung=example_energiemix, + vertagskonditionsaenderung=example_vertragskonditionen, + garantieaenderung=example_preisgarantie, + einschraenkungsaenderung=Tarifeinschraenkung(), +) + class TestRegionalerAufAbschlag: @pytest.mark.parametrize( "regionaler_auf_abschlag", [ pytest.param( - RegionalerAufAbschlag( - bezeichnung="Foo", - beschreibung="Bar", - auf_abschlagstyp=AufAbschlagstyp.RELATIV, - auf_abschlagsziel=AufAbschlagsziel.ARBEITSPREIS_HT, - einheit=Waehrungseinheit.CT, - website="https://www.hochfrequenz.de", - zusatzprodukte=["ein standmixer", "ein thermomix"], - voraussetzungen=["lecker essen", "mit ökostrom gekocht"], - tarifnamensaenderungen="Super-Duper Tarif", - staffeln=[example_regionale_preisstaffel], - gueltigkeitszeitraum=example_zeitraum, - energiemixaenderung=example_energiemix, - vertagskonditionsaenderung=example_vertragskonditionen, - garantieaenderung=example_preisgarantie, - einschraenkungsaenderung=Tarifeinschraenkung(), - ), + example_regionaler_auf_abschlag, id="maximal attributes", ), ], diff --git a/tests/test_regionaletarifpreisposition.py b/tests/test_regionaletarifpreisposition.py index 9b2d1a811..769476ed8 100644 --- a/tests/test_regionaletarifpreisposition.py +++ b/tests/test_regionaletarifpreisposition.py @@ -14,32 +14,32 @@ from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] from tests.test_sigmoidparameter import example_sigmoidparameter # type:ignore[import] +example_regionale_tarifpreisposition = RegionaleTarifpreisposition( + preistyp=Preistyp.ARBEITSPREIS_NT, + einheit=Waehrungseinheit.EUR, + bezugseinheit=Mengeneinheit.KWH, + mengeneinheitstaffel=Mengeneinheit.WH, + preisstaffeln=[ + RegionalePreisstaffel( + einheitspreis=Decimal(40.0), + staffelgrenze_von=Decimal(12.5), + staffelgrenze_bis=Decimal(25.0), + sigmoidparameter=example_sigmoidparameter, + regionale_gueltigkeit=RegionaleGueltigkeit( + gueltigkeitstyp=Gueltigkeitstyp.NUR_IN, + kriteriums_werte=[KriteriumWert(kriterium=Tarifregionskriterium.POSTLEITZAHL, wert="01069")], + ), + ), + ], +) + class TestRegionaleTarifpreisPosition: @pytest.mark.parametrize( "regionale_tarifpreis_position, expected_json_dict", [ pytest.param( - RegionaleTarifpreisposition( - preistyp=Preistyp.ARBEITSPREIS_NT, - einheit=Waehrungseinheit.EUR, - bezugseinheit=Mengeneinheit.KWH, - mengeneinheitstaffel=Mengeneinheit.WH, - preisstaffeln=[ - RegionalePreisstaffel( - einheitspreis=Decimal(40.0), - staffelgrenze_von=Decimal(12.5), - staffelgrenze_bis=Decimal(25.0), - sigmoidparameter=example_sigmoidparameter, - regionale_gueltigkeit=RegionaleGueltigkeit( - gueltigkeitstyp=Gueltigkeitstyp.NUR_IN, - kriteriums_werte=[ - KriteriumWert(kriterium=Tarifregionskriterium.POSTLEITZAHL, wert="01069") - ], - ), - ), - ], - ), + example_regionale_tarifpreisposition, { "bezugseinheit": "KWH", "preisstaffeln": [ diff --git a/tests/test_regionaltarif.py b/tests/test_regionaltarif.py new file mode 100644 index 000000000..e51ea9bd5 --- /dev/null +++ b/tests/test_regionaltarif.py @@ -0,0 +1,96 @@ +from datetime import datetime, timezone + +import pytest # type:ignore[import] + +from bo4e.bo.regionaltarif import Regionaltarif, RegionaltarifSchema +from bo4e.enum.kundentyp import Kundentyp +from bo4e.enum.sparte import Sparte +from bo4e.enum.tarifart import Tarifart +from bo4e.enum.tarifmerkmal import Tarifmerkmal +from bo4e.enum.tariftyp import Tariftyp +from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +from tests.test_energiemix import example_energiemix # type:ignore[import] +from tests.test_marktteilnehmer import example_marktteilnehmer # type:ignore[import] +from tests.test_regionalepreisgarantie import example_regionale_preisgarantie # type:ignore[import] +from tests.test_regionaleraufabschlag import example_regionaler_auf_abschlag # type:ignore[import] +from tests.test_regionaletarifpreisposition import example_regionale_tarifpreisposition # type:ignore[import] +from tests.test_tarifberechnungsparameter import example_tarifberechnungsparameter # type:ignore[import] +from tests.test_tarifeinschraenkung import example_tarifeinschraenkung # type:ignore[import] +from tests.test_vertragskonditionen import example_vertragskonditionen # type:ignore[import] +from tests.test_zeitraum import example_zeitraum # type:ignore[import] + + +class TestRegionaltarif: + @pytest.mark.parametrize( + "regionaltarif", + [ + pytest.param( + Regionaltarif( + preisstand=datetime(2022, 2, 1, 0, 0, 0, tzinfo=timezone.utc), + berechnungsparameter=example_tarifberechnungsparameter, + tarif_auf_abschlaege=[example_regionaler_auf_abschlag], + tarifpreise=[example_regionale_tarifpreisposition], + preisgarantien=[example_regionale_preisgarantie], + tarifeinschraenkungen=example_tarifeinschraenkung, + bezeichnung="foo", + anbietername="der beste stromanbieter", + sparte=Sparte.STROM, + kundentypen=[Kundentyp.PRIVAT, Kundentyp.GEWERBE], + tarifart=Tarifart.MEHRTARIF, + tariftyp=Tariftyp.GRUND_ERSATZVERSORGUNG, + tarifmerkmale=[Tarifmerkmal.HEIZSTROM], + website="https://foo.inv", + bemerkung="super billig aber auch super dreckig", + vertragskonditionen=example_vertragskonditionen, + zeitliche_gueltigkeit=example_zeitraum, + energiemix=example_energiemix, + anbieter=example_marktteilnehmer, + ), + id="required and optional attributes", + ), + pytest.param( + Regionaltarif( + preisstand=datetime(2022, 2, 1, 0, 0, 0, tzinfo=timezone.utc), + berechnungsparameter=example_tarifberechnungsparameter, + tarifpreise=[example_regionale_tarifpreisposition], + bezeichnung="foo", + anbietername="der beste stromanbieter", + sparte=Sparte.STROM, + kundentypen=[Kundentyp.PRIVAT, Kundentyp.GEWERBE], + tarifart=Tarifart.MEHRTARIF, + tariftyp=Tariftyp.GRUND_ERSATZVERSORGUNG, + tarifmerkmale=[Tarifmerkmal.HEIZSTROM], + anbieter=example_marktteilnehmer, + ), + id="required attributes", + ), + ], + ) + def test_serialization_roundtrip(self, regionaltarif: Regionaltarif): + """ + Test de-/serialisation + """ + assert_serialization_roundtrip(regionaltarif, RegionaltarifSchema()) + + def test_missing_required_attribute(self): + with pytest.raises(TypeError) as excinfo: + _ = Regionaltarif() + assert "missing 11 required" in str(excinfo.value) # 3 from regionaltarif + 8 from tarifinfo + + def test_failing_validation_list_length_at_least_one(self): + with pytest.raises(ValueError) as excinfo: + _ = Regionaltarif( + preisstand=datetime(2022, 2, 1, 0, 0, 0, tzinfo=timezone.utc), + berechnungsparameter=example_tarifberechnungsparameter, + tarifpreise=[], + bezeichnung="foo", + anbietername="der beste stromanbieter", + sparte=Sparte.STROM, + kundentypen=[Kundentyp.PRIVAT, Kundentyp.GEWERBE], + tarifart=Tarifart.MEHRTARIF, + tariftyp=Tariftyp.GRUND_ERSATZVERSORGUNG, + tarifmerkmale=[Tarifmerkmal.HEIZSTROM], + anbieter=example_marktteilnehmer, + ) + + assert "List tarifpreise must not be empty." in str(excinfo.value) diff --git a/tests/test_tarifberechnungsparameter.py b/tests/test_tarifberechnungsparameter.py index 1a6210ffc..c5ab04a71 100644 --- a/tests/test_tarifberechnungsparameter.py +++ b/tests/test_tarifberechnungsparameter.py @@ -10,24 +10,26 @@ from tests.test_preis import example_preis # type:ignore[import] from tests.test_tarifpreis import example_tarifpreis # type:ignore[import] +example_tarifberechnungsparameter = Tarifberechnungsparameter( + berechnungsmethode=Tarifkalkulationsmethode.ZONEN, + messpreis_in_gp_enthalten=True, + kw_inklusive=Decimal(12.5), + kw_weitere_mengen=Decimal(12.5), + messpreistyp=Messpreistyp.MESSPREIS_G6, + messpreis_beruecksichtigen=True, + hoechstpreis_h_t=example_preis, + hoechstpreis_n_t=example_preis, + mindestpreis=example_preis, + zusatzpreise=[example_tarifpreis], +) + class TestFremdkostenposition: @pytest.mark.parametrize( "tarifberechnungsparameter", [ pytest.param( - Tarifberechnungsparameter( - berechnungsmethode=Tarifkalkulationsmethode.ZONEN, - messpreis_in_gp_enthalten=True, - kw_inklusive=Decimal(12.5), - kw_weitere_mengen=Decimal(12.5), - messpreistyp=Messpreistyp.MESSPREIS_G6, - messpreis_beruecksichtigen=True, - hoechstpreis_h_t=example_preis, - hoechstpreis_n_t=example_preis, - mindestpreis=example_preis, - zusatzpreise=[example_tarifpreis], - ), + example_tarifberechnungsparameter, id="maximal attributes", ), ], diff --git a/tests/test_tarifeinschraenkung.py b/tests/test_tarifeinschraenkung.py index 3fd4fc513..bcf698464 100644 --- a/tests/test_tarifeinschraenkung.py +++ b/tests/test_tarifeinschraenkung.py @@ -12,6 +12,25 @@ from bo4e.enum.voraussetzungen import Voraussetzungen from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +example_tarifeinschraenkung = Tarifeinschraenkung( + zusatzprodukte=["foo", "bar"], + voraussetzungen=[Voraussetzungen.ALTVERTRAG, Voraussetzungen.DIREKTVERTRIEB], + einschraenkungzaehler=[ + Geraet( + geraetenummer="0815", + geraeteeigenschaften=Geraeteeigenschaften( + geraetemerkmal=Geraetemerkmal.GAS_G1000, + geraetetyp=Geraetetyp.MULTIPLEXANLAGE, + ), + ), + Geraet(geraetenummer="197foo"), + ], + einschraenkungleistung=[ + Menge(wert=Decimal(12.5), einheit=Mengeneinheit.MWH), + Menge(wert=Decimal(30), einheit=Mengeneinheit.KWH), + ], +) + class TestTarifeinschraenkung: @pytest.mark.parametrize( From cf051327e53d29508e3bbbb9817667330dd7fcab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Annika=20Schl=C3=B6gl?= Date: Fri, 21 Jan 2022 18:20:39 +0100 Subject: [PATCH 03/20] =?UTF-8?q?=F0=9F=93=A6=F0=9F=93=9DGenerated=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api/bo4e.bo.rst | 112 +++++++++++++++++++++++++++++++++++++++++ docs/api/bo4e.com.rst | 112 +++++++++++++++++++++++++++++++++++++++++ docs/api/bo4e.enum.rst | 8 +++ 3 files changed, 232 insertions(+) diff --git a/docs/api/bo4e.bo.rst b/docs/api/bo4e.bo.rst index b19c699d7..24f6048b9 100644 --- a/docs/api/bo4e.bo.rst +++ b/docs/api/bo4e.bo.rst @@ -12,6 +12,22 @@ bo4e.bo.ansprechpartner module :undoc-members: :show-inheritance: +bo4e.bo.buendelvertrag module +----------------------------- + +.. automodule:: bo4e.bo.buendelvertrag + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.energiemenge module +--------------------------- + +.. automodule:: bo4e.bo.energiemenge + :members: + :undoc-members: + :show-inheritance: + bo4e.bo.geschaeftsobjekt module ------------------------------- @@ -28,6 +44,22 @@ bo4e.bo.geschaeftspartner module :undoc-members: :show-inheritance: +bo4e.bo.kosten module +--------------------- + +.. automodule:: bo4e.bo.kosten + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.lastgang module +----------------------- + +.. automodule:: bo4e.bo.lastgang + :members: + :undoc-members: + :show-inheritance: + bo4e.bo.marktlokation module ---------------------------- @@ -52,6 +84,78 @@ bo4e.bo.messlokation module :undoc-members: :show-inheritance: +bo4e.bo.preisblatt module +------------------------- + +.. automodule:: bo4e.bo.preisblatt + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.preisblattkonzessionsabgabe module +------------------------------------------ + +.. automodule:: bo4e.bo.preisblattkonzessionsabgabe + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.preisblattmessung module +-------------------------------- + +.. automodule:: bo4e.bo.preisblattmessung + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.preisblattnetznutzung module +------------------------------------ + +.. automodule:: bo4e.bo.preisblattnetznutzung + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.region module +--------------------- + +.. automodule:: bo4e.bo.region + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.regionaltarif module +---------------------------- + +.. automodule:: bo4e.bo.regionaltarif + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.standorteigenschaften module +------------------------------------ + +.. automodule:: bo4e.bo.standorteigenschaften + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.tarifinfo module +------------------------ + +.. automodule:: bo4e.bo.tarifinfo + :members: + :undoc-members: + :show-inheritance: + +bo4e.bo.tarifkosten module +-------------------------- + +.. automodule:: bo4e.bo.tarifkosten + :members: + :undoc-members: + :show-inheritance: + bo4e.bo.vertrag module ---------------------- @@ -68,6 +172,14 @@ bo4e.bo.zaehler module :undoc-members: :show-inheritance: +bo4e.bo.zeitreihe module +------------------------ + +.. automodule:: bo4e.bo.zeitreihe + :members: + :undoc-members: + :show-inheritance: + Module contents --------------- diff --git a/docs/api/bo4e.com.rst b/docs/api/bo4e.com.rst index 8624b0e6a..a0ae8ade8 100644 --- a/docs/api/bo4e.com.rst +++ b/docs/api/bo4e.com.rst @@ -28,6 +28,14 @@ bo4e.com.angebotsteil module :undoc-members: :show-inheritance: +bo4e.com.angebotsvariante module +-------------------------------- + +.. automodule:: bo4e.com.angebotsvariante + :members: + :undoc-members: + :show-inheritance: + bo4e.com.aufabschlag module --------------------------- @@ -68,6 +76,14 @@ bo4e.com.ausschreibungsdetail module :undoc-members: :show-inheritance: +bo4e.com.ausschreibungslos module +--------------------------------- + +.. automodule:: bo4e.com.ausschreibungslos + :members: + :undoc-members: + :show-inheritance: + bo4e.com.betrag module ---------------------- @@ -116,6 +132,14 @@ bo4e.com.externereferenz module :undoc-members: :show-inheritance: +bo4e.com.fremdkostenblock module +-------------------------------- + +.. automodule:: bo4e.com.fremdkostenblock + :members: + :undoc-members: + :show-inheritance: + bo4e.com.fremdkostenposition module ----------------------------------- @@ -164,6 +188,22 @@ bo4e.com.katasteradresse module :undoc-members: :show-inheritance: +bo4e.com.kostenblock module +--------------------------- + +.. automodule:: bo4e.com.kostenblock + :members: + :undoc-members: + :show-inheritance: + +bo4e.com.kostenposition module +------------------------------ + +.. automodule:: bo4e.com.kostenposition + :members: + :undoc-members: + :show-inheritance: + bo4e.com.kriteriumwert module ----------------------------- @@ -220,6 +260,14 @@ bo4e.com.preisgarantie module :undoc-members: :show-inheritance: +bo4e.com.preisposition module +----------------------------- + +.. automodule:: bo4e.com.preisposition + :members: + :undoc-members: + :show-inheritance: + bo4e.com.preisstaffel module ---------------------------- @@ -228,6 +276,14 @@ bo4e.com.preisstaffel module :undoc-members: :show-inheritance: +bo4e.com.rechnungsposition module +--------------------------------- + +.. automodule:: bo4e.com.rechnungsposition + :members: + :undoc-members: + :show-inheritance: + bo4e.com.regionalegueltigkeit module ------------------------------------ @@ -236,6 +292,38 @@ bo4e.com.regionalegueltigkeit module :undoc-members: :show-inheritance: +bo4e.com.regionalepreisgarantie module +-------------------------------------- + +.. automodule:: bo4e.com.regionalepreisgarantie + :members: + :undoc-members: + :show-inheritance: + +bo4e.com.regionalepreisstaffel module +------------------------------------- + +.. automodule:: bo4e.com.regionalepreisstaffel + :members: + :undoc-members: + :show-inheritance: + +bo4e.com.regionaleraufabschlag module +------------------------------------- + +.. automodule:: bo4e.com.regionaleraufabschlag + :members: + :undoc-members: + :show-inheritance: + +bo4e.com.regionaletarifpreisposition module +------------------------------------------- + +.. automodule:: bo4e.com.regionaletarifpreisposition + :members: + :undoc-members: + :show-inheritance: + bo4e.com.regionskriterium module -------------------------------- @@ -276,6 +364,14 @@ bo4e.com.standorteigenschaftengas module :undoc-members: :show-inheritance: +bo4e.com.standorteigenschaftenstrom module +------------------------------------------ + +.. automodule:: bo4e.com.standorteigenschaftenstrom + :members: + :undoc-members: + :show-inheritance: + bo4e.com.steuerbetrag module ---------------------------- @@ -292,6 +388,14 @@ bo4e.com.tagesvektor module :undoc-members: :show-inheritance: +bo4e.com.tarifberechnungsparameter module +----------------------------------------- + +.. automodule:: bo4e.com.tarifberechnungsparameter + :members: + :undoc-members: + :show-inheritance: + bo4e.com.tarifeinschraenkung module ----------------------------------- @@ -308,6 +412,14 @@ bo4e.com.tarifpreis module :undoc-members: :show-inheritance: +bo4e.com.tarifpreisposition module +---------------------------------- + +.. automodule:: bo4e.com.tarifpreisposition + :members: + :undoc-members: + :show-inheritance: + bo4e.com.unterschrift module ---------------------------- diff --git a/docs/api/bo4e.enum.rst b/docs/api/bo4e.enum.rst index d90f64b89..2fe7e7c8f 100644 --- a/docs/api/bo4e.enum.rst +++ b/docs/api/bo4e.enum.rst @@ -28,6 +28,14 @@ bo4e.enum.arithmetische\_operation module :undoc-members: :show-inheritance: +bo4e.enum.artikelid module +-------------------------- + +.. automodule:: bo4e.enum.artikelid + :members: + :undoc-members: + :show-inheritance: + bo4e.enum.aufabschlagstyp module -------------------------------- From 7c4578626e951c974db225c5aac12ea96e136260 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sat, 22 Jan 2022 09:55:29 +0100 Subject: [PATCH 04/20] Implement COM TarifpreisstaffelProOrt --- src/bo4e/com/aufabschlagstaffelproort.py | 4 +- src/bo4e/com/tarifpreisstaffelproort.py | 51 ++++++++++++++++++++++++ tests/test_tarifpreisstaffelproort.py | 35 ++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/bo4e/com/tarifpreisstaffelproort.py create mode 100644 tests/test_tarifpreisstaffelproort.py diff --git a/src/bo4e/com/aufabschlagstaffelproort.py b/src/bo4e/com/aufabschlagstaffelproort.py index 7b862ddd7..5b8f59b04 100644 --- a/src/bo4e/com/aufabschlagstaffelproort.py +++ b/src/bo4e/com/aufabschlagstaffelproort.py @@ -15,7 +15,7 @@ @attr.s(auto_attribs=True, kw_only=True) class AufAbschlagstaffelProOrt(COM): """ - Gibt den Wert eines Auf- oder Abschlags und dessen Staffelgrenzen an. + Gibt den Wert eines Auf- oder Abschlags und dessen Staffelgrenzen an """ # required attributes @@ -29,7 +29,7 @@ class AufAbschlagstaffelProOrt(COM): class AufAbschlagstaffelProOrtSchema(COMSchema): """ - Schema for de-/serialization of AufAbschlagstaffelProOrt. + Schema for de-/serialization of AufAbschlagstaffelProOrt """ class_name = AufAbschlagstaffelProOrt diff --git a/src/bo4e/com/tarifpreisstaffelproort.py b/src/bo4e/com/tarifpreisstaffelproort.py new file mode 100644 index 000000000..8106c229d --- /dev/null +++ b/src/bo4e/com/tarifpreisstaffelproort.py @@ -0,0 +1,51 @@ +""" +Contains TarifpreisstaffelProOrt class +and corresponding marshmallow schema for de-/serialization +""" +from decimal import Decimal + +import attr +from marshmallow import fields +from marshmallow_enum import EnumField # type:ignore[import] + +from bo4e.com.com import COM, COMSchema + + +# pylint: disable=too-few-public-methods +@attr.s(auto_attribs=True, kw_only=True) +class TarifpreisstaffelProOrt(COM): + """ + Gibt die Staffelgrenzen der jeweiligen Preise an + """ + + # todo: decimal doesn't make sense here imo + # https://github.com/Hochfrequenz/BO4E-python/issues/344 + + # required attributes + #: Der Arbeitspreis in ct/kWh + arbeitspreis: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal)) + #: Der Arbeitspreis für Verbräuche in der Niedertarifzeit in ct/kWh + arbeitspreis_n_t: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal)) + #: Der Grundpreis in Euro/Jahr + grundpreis: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal)) + #: Unterer Wert, ab dem die Staffel gilt (inklusive) + staffelgrenze_von: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal)) + #: Oberer Wert, bis zu dem die Staffel gilt (exklusive) + staffelgrenze_bis: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal)) + + # there are no optional attributes + + +class TarifpreisstaffelProOrtSchema(COMSchema): + """ + Schema for (de)serialization of TarifpreisstaffelProOrt + """ + + class_name = TarifpreisstaffelProOrt + + # required attributes + arbeitspreis = fields.Decimal(as_string=True) + arbeitspreis_n_t = fields.Decimal(as_string=True, data_key="arbeitspreisNT") + grundpreis = fields.Decimal(as_string=True) + staffelgrenze_von = fields.Decimal(as_string=True) + staffelgrenze_bis = fields.Decimal(as_string=True) diff --git a/tests/test_tarifpreisstaffelproort.py b/tests/test_tarifpreisstaffelproort.py new file mode 100644 index 000000000..86de6c533 --- /dev/null +++ b/tests/test_tarifpreisstaffelproort.py @@ -0,0 +1,35 @@ +from decimal import Decimal + +import pytest # type:ignore[import] + +from bo4e.com.tarifpreisstaffelproort import TarifpreisstaffelProOrt, TarifpreisstaffelProOrtSchema +from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] + + +class TestTarifpreisstaffelProOrt: + @pytest.mark.parametrize( + "tarifpreisstaffel", + [ + pytest.param( + TarifpreisstaffelProOrt( + arbeitspreis=Decimal(10), + arbeitspreis_n_t=Decimal(11), + grundpreis=Decimal(12), + staffelgrenze_von=Decimal(13), + staffelgrenze_bis=Decimal(14), + ), + id="maximal (and minimal) attributes", + ), + ], + ) + def test_serialization_roundtrip(self, tarifpreisstaffel: TarifpreisstaffelProOrt): + """ + Test de-/serialisation + """ + assert_serialization_roundtrip(tarifpreisstaffel, TarifpreisstaffelProOrtSchema()) + + def test_missing_required_attribute(self): + with pytest.raises(TypeError) as excinfo: + _ = TarifpreisstaffelProOrt() + + assert "missing 5 required" in str(excinfo.value) From 072ce37d2cf9c667240daaf7913690dc30d3fe36 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sat, 22 Jan 2022 10:05:00 +0100 Subject: [PATCH 05/20] Imiplement COM TarifpreispositionProOrt --- src/bo4e/com/tarifpreisposition.py | 10 ++--- src/bo4e/com/tarifpreispositionproort.py | 53 ++++++++++++++++++++++++ tests/test_tarifpreispositionproort.py | 33 +++++++++++++++ tests/test_tarifpreisstaffelproort.py | 16 +++---- 4 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 src/bo4e/com/tarifpreispositionproort.py create mode 100644 tests/test_tarifpreispositionproort.py diff --git a/src/bo4e/com/tarifpreisposition.py b/src/bo4e/com/tarifpreisposition.py index 232baf8eb..fd21aea3b 100644 --- a/src/bo4e/com/tarifpreisposition.py +++ b/src/bo4e/com/tarifpreisposition.py @@ -25,13 +25,13 @@ class Tarifpreisposition(COM): """ # required attributes - # Angabe des Preistypes (z.B. Grundpreis) + #: Angabe des Preistypes (z.B. Grundpreis) preistyp: Preistyp = attr.ib(validator=attr.validators.instance_of(Preistyp)) - # Einheit des Preises (z.B. EURO) + #: Einheit des Preises (z.B. EURO) einheit: Waehrungseinheit = attr.ib(validator=attr.validators.instance_of(Waehrungseinheit)) - # Größe, auf die sich die Einheit bezieht, beispielsweise kWh, Jahr + #: Größe, auf die sich die Einheit bezieht, beispielsweise kWh, Jahr bezugseinheit: Mengeneinheit = attr.ib(validator=attr.validators.instance_of(Mengeneinheit)) - # Hier sind die Staffeln mit ihren Preisenangaben definiert + #: Hier sind die Staffeln mit ihren Preisenangaben definiert preisstaffeln: List[Preisstaffel] = attr.ib( validator=[ attr.validators.deep_iterable( @@ -43,7 +43,7 @@ class Tarifpreisposition(COM): ) # optional attributes - # Gibt an, nach welcher Menge die vorgenannte Einschränkung erfolgt (z.B. Jahresstromverbrauch in kWh) + #: Gibt an, nach welcher Menge die vorgenannte Einschränkung erfolgt (z.B. Jahresstromverbrauch in kWh) mengeneinheitstaffel: Optional[Mengeneinheit] = attr.ib( default=None, validator=attr.validators.optional(attr.validators.instance_of(Mengeneinheit)) ) diff --git a/src/bo4e/com/tarifpreispositionproort.py b/src/bo4e/com/tarifpreispositionproort.py new file mode 100644 index 000000000..8bf2fe509 --- /dev/null +++ b/src/bo4e/com/tarifpreispositionproort.py @@ -0,0 +1,53 @@ +""" +Contains TarifpreispositionProOrt class +and corresponding marshmallow schema for de-/serialization +""" + +from typing import List + +import attr +from marshmallow import fields +from marshmallow_enum import EnumField # type:ignore[import] + +from bo4e.com.com import COM, COMSchema +from bo4e.com.tarifpreisstaffelproort import TarifpreisstaffelProOrt, TarifpreisstaffelProOrtSchema +from bo4e.validators import check_list_length_at_least_one + + +# pylint: disable=too-few-public-methods +@attr.s(auto_attribs=True, kw_only=True) +class TarifpreispositionProOrt(COM): + """ + Mit dieser Komponente können Tarifpreise verschiedener Typen abgebildet werden + """ + + # required attributes + #:Postleitzahl des Ortes für den der Preis gilt + postleitzahl: str = attr.ib(validator=attr.validators.matches_re(r"^\d{5}$")) + #: Ort für den der Preis gilt + ort: str = attr.ib(validator=attr.validators.instance_of(str)) + #: ene't-Netznummer des Netzes in dem der Preis gilt + netznr: str = attr.ib(validator=attr.validators.instance_of(str)) + # Hier sind die Staffeln mit ihren Preisenangaben definiert + preisstaffeln: List[TarifpreisstaffelProOrt] = attr.ib( + validator=[ + attr.validators.deep_iterable( + member_validator=attr.validators.instance_of(TarifpreisstaffelProOrt), + iterable_validator=check_list_length_at_least_one, + ), + ] + ) + # there are no optional attributes + + +class TarifpreispositionProOrtSchema(COMSchema): + """ + Schema for de-/serialization of Tarifpreisposition. + """ + + class_name = TarifpreispositionProOrt + # required attributes + postleitzahl = fields.Str() + ort = fields.Str() + netznr = fields.Str() + preisstaffeln = fields.List(fields.Nested(TarifpreisstaffelProOrtSchema)) diff --git a/tests/test_tarifpreispositionproort.py b/tests/test_tarifpreispositionproort.py new file mode 100644 index 000000000..2362a23c3 --- /dev/null +++ b/tests/test_tarifpreispositionproort.py @@ -0,0 +1,33 @@ +import pytest # type:ignore[import] + +from bo4e.com.tarifpreispositionproort import TarifpreispositionProOrt, TarifpreispositionProOrtSchema +from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +from tests.test_tarifpreisstaffelproort import example_tarifpreisstaffelproort # type:ignore[import] + + +class TestTarifpreispositionProOrt: + @pytest.mark.parametrize( + "tarifpreisposition", + [ + pytest.param( + TarifpreispositionProOrt( + postleitzahl="82031", + ort="Grünwald", + netznr="0815", + preisstaffeln=[example_tarifpreisstaffelproort], + ), + id="minimal and maximal attributes", + ), + ], + ) + def test_serialization_roundtrip(self, tarifpreisposition: TarifpreispositionProOrt): + """ + Test de-/serialisation + """ + assert_serialization_roundtrip(tarifpreisposition, TarifpreispositionProOrtSchema()) + + def test_missing_required_attribute(self): + with pytest.raises(TypeError) as excinfo: + _ = TarifpreispositionProOrt() + + assert "missing 4 required" in str(excinfo.value) diff --git a/tests/test_tarifpreisstaffelproort.py b/tests/test_tarifpreisstaffelproort.py index 86de6c533..a58dcc368 100644 --- a/tests/test_tarifpreisstaffelproort.py +++ b/tests/test_tarifpreisstaffelproort.py @@ -5,19 +5,21 @@ from bo4e.com.tarifpreisstaffelproort import TarifpreisstaffelProOrt, TarifpreisstaffelProOrtSchema from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +example_tarifpreisstaffelproort = TarifpreisstaffelProOrt( + arbeitspreis=Decimal(10), + arbeitspreis_n_t=Decimal(11), + grundpreis=Decimal(12), + staffelgrenze_von=Decimal(13), + staffelgrenze_bis=Decimal(14), +) + class TestTarifpreisstaffelProOrt: @pytest.mark.parametrize( "tarifpreisstaffel", [ pytest.param( - TarifpreisstaffelProOrt( - arbeitspreis=Decimal(10), - arbeitspreis_n_t=Decimal(11), - grundpreis=Decimal(12), - staffelgrenze_von=Decimal(13), - staffelgrenze_bis=Decimal(14), - ), + example_tarifpreisstaffelproort, id="maximal (and minimal) attributes", ), ], From 32970e7afb7c47ece2106ac9fc0d491f825e1846 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sat, 22 Jan 2022 10:06:04 +0100 Subject: [PATCH 06/20] pylint --- src/bo4e/com/tarifpreispositionproort.py | 1 - src/bo4e/com/tarifpreisstaffelproort.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/bo4e/com/tarifpreispositionproort.py b/src/bo4e/com/tarifpreispositionproort.py index 8bf2fe509..f3d367b1c 100644 --- a/src/bo4e/com/tarifpreispositionproort.py +++ b/src/bo4e/com/tarifpreispositionproort.py @@ -7,7 +7,6 @@ import attr from marshmallow import fields -from marshmallow_enum import EnumField # type:ignore[import] from bo4e.com.com import COM, COMSchema from bo4e.com.tarifpreisstaffelproort import TarifpreisstaffelProOrt, TarifpreisstaffelProOrtSchema diff --git a/src/bo4e/com/tarifpreisstaffelproort.py b/src/bo4e/com/tarifpreisstaffelproort.py index 8106c229d..d84976dfb 100644 --- a/src/bo4e/com/tarifpreisstaffelproort.py +++ b/src/bo4e/com/tarifpreisstaffelproort.py @@ -6,7 +6,6 @@ import attr from marshmallow import fields -from marshmallow_enum import EnumField # type:ignore[import] from bo4e.com.com import COM, COMSchema From ab76f2f28aa7a66103c63a0b1ee3cecbf9b7beef Mon Sep 17 00:00:00 2001 From: konstantin Date: Sat, 22 Jan 2022 10:26:08 +0100 Subject: [PATCH 07/20] Implement BO Tarif --- src/bo4e/bo/tarif.py | 88 ++++++++++++++++++++++++++ src/bo4e/enum/botyp.py | 1 + tests/test_aufabschlagregional.py | 36 ++++++----- tests/test_tarif.py | 64 +++++++++++++++++++ tests/test_tarifpreispositionproort.py | 14 ++-- 5 files changed, 180 insertions(+), 23 deletions(-) create mode 100644 src/bo4e/bo/tarif.py create mode 100644 tests/test_tarif.py diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py new file mode 100644 index 000000000..053565082 --- /dev/null +++ b/src/bo4e/bo/tarif.py @@ -0,0 +1,88 @@ +""" +Contains Tarif class and corresponding marshmallow schema for de-/serialization +""" + +from datetime import datetime +from typing import List, Optional + +import attr +from marshmallow import fields + +from bo4e.bo.tarifinfo import Tarifinfo, TarifinfoSchema +from bo4e.com.aufabschlagregional import AufAbschlagRegional, AufAbschlagRegionalSchema +from bo4e.com.preisgarantie import Preisgarantie, PreisgarantieSchema +from bo4e.com.regionaletarifpreisposition import RegionaleTarifpreisposition +from bo4e.com.tarifberechnungsparameter import Tarifberechnungsparameter, TarifberechnungsparameterSchema +from bo4e.com.tarifeinschraenkung import Tarifeinschraenkung, TarifeinschraenkungSchema +from bo4e.com.tarifpreispositionproort import TarifpreispositionProOrt, TarifpreispositionProOrtSchema +from bo4e.enum.botyp import BoTyp +from bo4e.validators import check_list_length_at_least_one + + +# pylint: disable=too-few-public-methods +@attr.s(auto_attribs=True, kw_only=True) +class Tarif(Tarifinfo): + """ + Abbildung eines Tarifs mit regionaler Zuordnung von Preisen und Auf- und Abschlägen + """ + + bo_typ: BoTyp = attr.ib(default=BoTyp.TARIF) + # required attributes + #: Gibt an, wann der Preis zuletzt angepasst wurde + preisstand: datetime = attr.ib(validator=attr.validators.instance_of(datetime)) + #: Für die Berechnung der Kosten sind die hier abgebildeten Parameter heranzuziehen + berechnungsparameter: Tarifberechnungsparameter = attr.ib( + validator=attr.validators.instance_of(Tarifberechnungsparameter) + ) + #: Die festgelegten Preise, z.B. für Arbeitspreis, Grundpreis etc. + tarifpreise: List[RegionaleTarifpreisposition] = attr.ib( + validator=attr.validators.deep_iterable( + member_validator=attr.validators.instance_of(TarifpreispositionProOrt), + iterable_validator=check_list_length_at_least_one, + ) + ) + + # optional attributes + #: Auf- und Abschläge auf die Preise oder Kosten mit regionaler Eingrenzung + tarif_auf_abschlaege: Optional[List[AufAbschlagRegional]] = attr.ib( + default=None, + validator=attr.validators.optional( + attr.validators.deep_iterable( + member_validator=attr.validators.instance_of(AufAbschlagRegional), + iterable_validator=attr.validators.instance_of(list), + ) + ), + ) + # todo: fix inconsistency: RegionalerAufAbschlag vs. AufAbschlagRegional + # https://github.com/Hochfrequenz/BO4E-python/issues/345 + + #: Festlegung von Garantien für bestimmte Preisanteile + preisgarantie: Optional[Preisgarantie] = attr.ib( + default=None, + validator=attr.validators.optional( + attr.validators.instance_of(Preisgarantie), + ), + ) + # todo: fix inconsistency with regionaltarif https://github.com/Hochfrequenz/BO4E-python/issues/346 + #: Die Bedingungen und Einschränkungen unter denen ein Tarif angewendet werden kann + tarifeinschraenkung: Optional[Tarifeinschraenkung] = attr.ib( + default=None, validator=attr.validators.optional(attr.validators.instance_of(Tarifeinschraenkung)) + ) + + +class TarifSchema(TarifinfoSchema): + """ + Schema for de-/serialization of Regionaltarif + """ + + class_name = Tarif # type:ignore[assignment] + + # required attributes + preisstand = fields.DateTime() + berechnungsparameter = fields.Nested(TarifberechnungsparameterSchema) + tarifpreise = fields.List(fields.Nested(TarifpreispositionProOrtSchema)) + + # optional attributes + tarif_auf_abschlaege = fields.List(fields.Nested(AufAbschlagRegionalSchema), allow_none=True) + preisgarantie = fields.Nested(PreisgarantieSchema, allow_none=True) + tarifeinschraenkung = fields.Nested(TarifeinschraenkungSchema, allow_none=True) diff --git a/src/bo4e/enum/botyp.py b/src/bo4e/enum/botyp.py index 217e3c103..1d1b4ec16 100644 --- a/src/bo4e/enum/botyp.py +++ b/src/bo4e/enum/botyp.py @@ -34,6 +34,7 @@ class BoTyp(StrEnum): REGION = "REGION" REGIONALTARIF = "REGIONALTARIF" STANDORTEIGENSCHAFTEN = "STANDORTEIGENSCHAFTEN" + TARIF = "TARIF" TARIFINFO = "TARIFINFO" TARIFKOSTEN = "TARIFKOSTEN" TARIFPREISBLATT = "TARIFPREISBLATT" diff --git a/tests/test_aufabschlagregional.py b/tests/test_aufabschlagregional.py index 58974f3e1..51482ecdf 100644 --- a/tests/test_aufabschlagregional.py +++ b/tests/test_aufabschlagregional.py @@ -20,29 +20,31 @@ from bo4e.enum.waehrungseinheit import Waehrungseinheit from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +example_aufabschlagregional = AufAbschlagRegional( + bezeichnung="foo", + betraege=[ + AufAbschlagProOrt( + postleitzahl="01187", + ort="Dresden", + netznr="2", + staffeln=[ + AufAbschlagstaffelProOrt( + wert=Decimal(2.5), + staffelgrenze_von=Decimal(1), + staffelgrenze_bis=Decimal(5), + ) + ], + ), + ], +) + class TestAufAbschlagRegional: @pytest.mark.parametrize( "aufabschlagregional, expected_json_dict", [ pytest.param( - AufAbschlagRegional( - bezeichnung="foo", - betraege=[ - AufAbschlagProOrt( - postleitzahl="01187", - ort="Dresden", - netznr="2", - staffeln=[ - AufAbschlagstaffelProOrt( - wert=Decimal(2.5), - staffelgrenze_von=Decimal(1), - staffelgrenze_bis=Decimal(5), - ) - ], - ), - ], - ), + example_aufabschlagregional, { "bezeichnung": "foo", "betraege": [ diff --git a/tests/test_tarif.py b/tests/test_tarif.py new file mode 100644 index 000000000..0ef0688b5 --- /dev/null +++ b/tests/test_tarif.py @@ -0,0 +1,64 @@ +from datetime import datetime, timezone + +import pytest # type:ignore[import] + +from bo4e.bo.tarif import Tarif, TarifSchema +from bo4e.enum.kundentyp import Kundentyp +from bo4e.enum.sparte import Sparte +from bo4e.enum.tarifart import Tarifart +from bo4e.enum.tarifmerkmal import Tarifmerkmal +from bo4e.enum.tariftyp import Tariftyp +from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] +from tests.test_aufabschlagregional import example_aufabschlagregional # type:ignore[import] +from tests.test_energiemix import example_energiemix # type:ignore[import] +from tests.test_marktteilnehmer import example_marktteilnehmer # type:ignore[import] +from tests.test_preisgarantie import example_preisgarantie # type:ignore[import] +from tests.test_regionaletarifpreisposition import example_regionale_tarifpreisposition # type:ignore[import] +from tests.test_tarifberechnungsparameter import example_tarifberechnungsparameter # type:ignore[import] +from tests.test_tarifeinschraenkung import example_tarifeinschraenkung # type:ignore[import] +from tests.test_tarifpreispositionproort import example_tarifpreispositionproort # type:ignore[import] +from tests.test_vertragskonditionen import example_vertragskonditionen # type:ignore[import] +from tests.test_zeitraum import example_zeitraum # type:ignore[import] + + +class TestTarif: + @pytest.mark.parametrize( + "tarif", + [ + pytest.param( + Tarif( + preisstand=datetime(2022, 2, 1, 0, 0, 0, tzinfo=timezone.utc), + berechnungsparameter=example_tarifberechnungsparameter, + tarif_auf_abschlaege=[example_aufabschlagregional], + tarifpreise=[example_tarifpreispositionproort], + preisgarantie=example_preisgarantie, + tarifeinschraenkung=example_tarifeinschraenkung, + # below are the attributes of tarifinfo + bezeichnung="foo", + anbietername="der beste stromanbieter", + sparte=Sparte.STROM, + kundentypen=[Kundentyp.PRIVAT, Kundentyp.GEWERBE], + tarifart=Tarifart.MEHRTARIF, + tariftyp=Tariftyp.GRUND_ERSATZVERSORGUNG, + tarifmerkmale=[Tarifmerkmal.HEIZSTROM], + website="https://foo.inv", + bemerkung="super billig aber auch super dreckig", + vertragskonditionen=example_vertragskonditionen, + zeitliche_gueltigkeit=example_zeitraum, + energiemix=example_energiemix, + anbieter=example_marktteilnehmer, + ), + id="required and optional attributes", + ), + ], + ) + def test_serialization_roundtrip(self, tarif: Tarif): + """ + Test de-/serialisation + """ + assert_serialization_roundtrip(tarif, TarifSchema()) + + def test_missing_required_attribute(self): + with pytest.raises(TypeError) as excinfo: + _ = Tarif() + assert "missing 11 required" in str(excinfo.value) # 3 from Tarif + 8 from tarifinfo diff --git a/tests/test_tarifpreispositionproort.py b/tests/test_tarifpreispositionproort.py index 2362a23c3..4d76af960 100644 --- a/tests/test_tarifpreispositionproort.py +++ b/tests/test_tarifpreispositionproort.py @@ -4,18 +4,20 @@ from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] from tests.test_tarifpreisstaffelproort import example_tarifpreisstaffelproort # type:ignore[import] +example_tarifpreispositionproort = TarifpreispositionProOrt( + postleitzahl="82031", + ort="Grünwald", + netznr="0815", + preisstaffeln=[example_tarifpreisstaffelproort], +) + class TestTarifpreispositionProOrt: @pytest.mark.parametrize( "tarifpreisposition", [ pytest.param( - TarifpreispositionProOrt( - postleitzahl="82031", - ort="Grünwald", - netznr="0815", - preisstaffeln=[example_tarifpreisstaffelproort], - ), + example_tarifpreispositionproort, id="minimal and maximal attributes", ), ], From 4d443e4ffbb5ff10ba56324cb0f37632922b6e6e Mon Sep 17 00:00:00 2001 From: kevin Date: Sun, 23 Jan 2022 14:39:55 +0100 Subject: [PATCH 08/20] =?UTF-8?q?=E2=9C=85=20Add=20test=20with=20minimal?= =?UTF-8?q?=20attributes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_tarif.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_tarif.py b/tests/test_tarif.py index 0ef0688b5..d6368cf7b 100644 --- a/tests/test_tarif.py +++ b/tests/test_tarif.py @@ -50,6 +50,23 @@ class TestTarif: ), id="required and optional attributes", ), + pytest.param( + Tarif( + preisstand=datetime(2022, 2, 1, 0, 0, 0, tzinfo=timezone.utc), + berechnungsparameter=example_tarifberechnungsparameter, + tarifpreise=[example_tarifpreispositionproort], + # below are the attributes of tarifinfo + bezeichnung="foo", + anbietername="der beste stromanbieter", + sparte=Sparte.STROM, + kundentypen=[Kundentyp.PRIVAT, Kundentyp.GEWERBE], + tarifart=Tarifart.MEHRTARIF, + tariftyp=Tariftyp.GRUND_ERSATZVERSORGUNG, + tarifmerkmale=[Tarifmerkmal.HEIZSTROM], + anbieter=example_marktteilnehmer, + ), + id="only required attributes", + ), ], ) def test_serialization_roundtrip(self, tarif: Tarif): From 7d48342c21557590d5b338f2dc3254831ba5c1ff Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 17:27:09 +0100 Subject: [PATCH 09/20] Update src/bo4e/com/tarifpreispositionproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- src/bo4e/com/tarifpreispositionproort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bo4e/com/tarifpreispositionproort.py b/src/bo4e/com/tarifpreispositionproort.py index f3d367b1c..94e81c929 100644 --- a/src/bo4e/com/tarifpreispositionproort.py +++ b/src/bo4e/com/tarifpreispositionproort.py @@ -21,7 +21,7 @@ class TarifpreispositionProOrt(COM): """ # required attributes - #:Postleitzahl des Ortes für den der Preis gilt + #: Postleitzahl des Ortes für den der Preis gilt postleitzahl: str = attr.ib(validator=attr.validators.matches_re(r"^\d{5}$")) #: Ort für den der Preis gilt ort: str = attr.ib(validator=attr.validators.instance_of(str)) From a0043ac3f0174a00dad35ab9a4712a04d81831be Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 17:27:16 +0100 Subject: [PATCH 10/20] Update src/bo4e/com/tarifpreispositionproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- src/bo4e/com/tarifpreispositionproort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bo4e/com/tarifpreispositionproort.py b/src/bo4e/com/tarifpreispositionproort.py index 94e81c929..d253e13b9 100644 --- a/src/bo4e/com/tarifpreispositionproort.py +++ b/src/bo4e/com/tarifpreispositionproort.py @@ -41,7 +41,7 @@ class TarifpreispositionProOrt(COM): class TarifpreispositionProOrtSchema(COMSchema): """ - Schema for de-/serialization of Tarifpreisposition. + Schema for de-/serialization of TarifpreispositionProOrt. """ class_name = TarifpreispositionProOrt From 85223db5779ffaeb9b71a12a207084f5c0e7cedc Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 17:28:15 +0100 Subject: [PATCH 11/20] Update src/bo4e/bo/tarif.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- src/bo4e/bo/tarif.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py index 053565082..3d51ac37b 100644 --- a/src/bo4e/bo/tarif.py +++ b/src/bo4e/bo/tarif.py @@ -72,7 +72,7 @@ class Tarif(Tarifinfo): class TarifSchema(TarifinfoSchema): """ - Schema for de-/serialization of Regionaltarif + Schema for de-/serialization of Tarif """ class_name = Tarif # type:ignore[assignment] From 431d82dc0f439cabe67cbc68b5039e28fd37785d Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 17:28:42 +0100 Subject: [PATCH 12/20] Update src/bo4e/bo/tarif.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- src/bo4e/bo/tarif.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py index 3d51ac37b..5b9fa5fb8 100644 --- a/src/bo4e/bo/tarif.py +++ b/src/bo4e/bo/tarif.py @@ -11,7 +11,6 @@ from bo4e.bo.tarifinfo import Tarifinfo, TarifinfoSchema from bo4e.com.aufabschlagregional import AufAbschlagRegional, AufAbschlagRegionalSchema from bo4e.com.preisgarantie import Preisgarantie, PreisgarantieSchema -from bo4e.com.regionaletarifpreisposition import RegionaleTarifpreisposition from bo4e.com.tarifberechnungsparameter import Tarifberechnungsparameter, TarifberechnungsparameterSchema from bo4e.com.tarifeinschraenkung import Tarifeinschraenkung, TarifeinschraenkungSchema from bo4e.com.tarifpreispositionproort import TarifpreispositionProOrt, TarifpreispositionProOrtSchema From 6a5e7e0973f4a2689c2fbb27071d99569faa0e78 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 19:57:08 +0100 Subject: [PATCH 13/20] Update tests/test_tarifpreisstaffelproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- tests/test_tarifpreisstaffelproort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tarifpreisstaffelproort.py b/tests/test_tarifpreisstaffelproort.py index a58dcc368..2b8ea9cb3 100644 --- a/tests/test_tarifpreisstaffelproort.py +++ b/tests/test_tarifpreisstaffelproort.py @@ -16,7 +16,7 @@ class TestTarifpreisstaffelProOrt: @pytest.mark.parametrize( - "tarifpreisstaffel", + "tarifpreisstaffelproort", [ pytest.param( example_tarifpreisstaffelproort, From 6ed5e769c45837a0910206bd7a145c46b1df2b34 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 19:57:13 +0100 Subject: [PATCH 14/20] Update tests/test_tarifpreisstaffelproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- tests/test_tarifpreisstaffelproort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tarifpreisstaffelproort.py b/tests/test_tarifpreisstaffelproort.py index 2b8ea9cb3..27ad7ba10 100644 --- a/tests/test_tarifpreisstaffelproort.py +++ b/tests/test_tarifpreisstaffelproort.py @@ -24,7 +24,7 @@ class TestTarifpreisstaffelProOrt: ), ], ) - def test_serialization_roundtrip(self, tarifpreisstaffel: TarifpreisstaffelProOrt): + def test_serialization_roundtrip(self, tarifpreisstaffelproort: TarifpreisstaffelProOrt): """ Test de-/serialisation """ From fd72520ef9ee06c546fd8177e693005b1c7bf108 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 19:57:17 +0100 Subject: [PATCH 15/20] Update tests/test_tarifpreispositionproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- tests/test_tarifpreispositionproort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tarifpreispositionproort.py b/tests/test_tarifpreispositionproort.py index 4d76af960..3f80927a6 100644 --- a/tests/test_tarifpreispositionproort.py +++ b/tests/test_tarifpreispositionproort.py @@ -14,7 +14,7 @@ class TestTarifpreispositionProOrt: @pytest.mark.parametrize( - "tarifpreisposition", + "tarifpreispositionproort", [ pytest.param( example_tarifpreispositionproort, From 70d7215f37ae08a2a922f737da39a4b9bbc0745c Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 19:57:24 +0100 Subject: [PATCH 16/20] Update tests/test_tarifpreisstaffelproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- tests/test_tarifpreisstaffelproort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tarifpreisstaffelproort.py b/tests/test_tarifpreisstaffelproort.py index 27ad7ba10..f5fc787aa 100644 --- a/tests/test_tarifpreisstaffelproort.py +++ b/tests/test_tarifpreisstaffelproort.py @@ -28,7 +28,7 @@ def test_serialization_roundtrip(self, tarifpreisstaffelproort: Tarifpreisstaffe """ Test de-/serialisation """ - assert_serialization_roundtrip(tarifpreisstaffel, TarifpreisstaffelProOrtSchema()) + assert_serialization_roundtrip(tarifpreisstaffelproort, TarifpreisstaffelProOrtSchema()) def test_missing_required_attribute(self): with pytest.raises(TypeError) as excinfo: From 73dd6e9a5c95048520bdb5b42b2e994e849bd7c7 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 19:57:33 +0100 Subject: [PATCH 17/20] Update tests/test_tarifpreispositionproort.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- tests/test_tarifpreispositionproort.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_tarifpreispositionproort.py b/tests/test_tarifpreispositionproort.py index 3f80927a6..0ba93a18c 100644 --- a/tests/test_tarifpreispositionproort.py +++ b/tests/test_tarifpreispositionproort.py @@ -22,11 +22,11 @@ class TestTarifpreispositionProOrt: ), ], ) - def test_serialization_roundtrip(self, tarifpreisposition: TarifpreispositionProOrt): + def test_serialization_roundtrip(self, tarifpreispositionproort: TarifpreispositionProOrt): """ Test de-/serialisation """ - assert_serialization_roundtrip(tarifpreisposition, TarifpreispositionProOrtSchema()) + assert_serialization_roundtrip(tarifpreispositionproort, TarifpreispositionProOrtSchema()) def test_missing_required_attribute(self): with pytest.raises(TypeError) as excinfo: From e5ab4db4f14e0eca752b40179fce37ca1df20537 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 22:50:19 +0100 Subject: [PATCH 18/20] Update src/bo4e/bo/tarif.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- src/bo4e/bo/tarif.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py index 5b9fa5fb8..4c83e68c8 100644 --- a/src/bo4e/bo/tarif.py +++ b/src/bo4e/bo/tarif.py @@ -33,8 +33,8 @@ class Tarif(Tarifinfo): berechnungsparameter: Tarifberechnungsparameter = attr.ib( validator=attr.validators.instance_of(Tarifberechnungsparameter) ) - #: Die festgelegten Preise, z.B. für Arbeitspreis, Grundpreis etc. - tarifpreise: List[RegionaleTarifpreisposition] = attr.ib( + #: Die festgelegten Preise mit regionaler Eingrenzung z.B. für Arbeitspreis, Grundpreis etc. + tarifpreise: List[TarifpreispositionProOrt] = attr.ib( validator=attr.validators.deep_iterable( member_validator=attr.validators.instance_of(TarifpreispositionProOrt), iterable_validator=check_list_length_at_least_one, From cd81da2de9c8fcf9f5cc45fa6e10a1228a1424cc Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 22:50:29 +0100 Subject: [PATCH 19/20] Update src/bo4e/bo/tarif.py Co-authored-by: Franziska <73471037+hf-fvesely@users.noreply.github.com> --- src/bo4e/bo/tarif.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py index 4c83e68c8..3feb1e381 100644 --- a/src/bo4e/bo/tarif.py +++ b/src/bo4e/bo/tarif.py @@ -55,7 +55,7 @@ class Tarif(Tarifinfo): # todo: fix inconsistency: RegionalerAufAbschlag vs. AufAbschlagRegional # https://github.com/Hochfrequenz/BO4E-python/issues/345 - #: Festlegung von Garantien für bestimmte Preisanteile + #: Preisgarantie für diesen Tarif preisgarantie: Optional[Preisgarantie] = attr.ib( default=None, validator=attr.validators.optional( From c671ba2e6b68dcacf0c866428dd90f7bfc872f67 Mon Sep 17 00:00:00 2001 From: konstantin Date: Sun, 23 Jan 2022 22:55:53 +0100 Subject: [PATCH 20/20] use data_key --- src/bo4e/bo/tarif.py | 4 +++- src/bo4e/com/tarifpreisstaffelproort.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py index 3feb1e381..1bb523d4b 100644 --- a/src/bo4e/bo/tarif.py +++ b/src/bo4e/bo/tarif.py @@ -82,6 +82,8 @@ class TarifSchema(TarifinfoSchema): tarifpreise = fields.List(fields.Nested(TarifpreispositionProOrtSchema)) # optional attributes - tarif_auf_abschlaege = fields.List(fields.Nested(AufAbschlagRegionalSchema), allow_none=True) + tarif_auf_abschlaege = fields.List( + fields.Nested(AufAbschlagRegionalSchema), allow_none=True, data_key="tarifAufAbschlaege" + ) preisgarantie = fields.Nested(PreisgarantieSchema, allow_none=True) tarifeinschraenkung = fields.Nested(TarifeinschraenkungSchema, allow_none=True) diff --git a/src/bo4e/com/tarifpreisstaffelproort.py b/src/bo4e/com/tarifpreisstaffelproort.py index d84976dfb..2114b0159 100644 --- a/src/bo4e/com/tarifpreisstaffelproort.py +++ b/src/bo4e/com/tarifpreisstaffelproort.py @@ -46,5 +46,5 @@ class TarifpreisstaffelProOrtSchema(COMSchema): arbeitspreis = fields.Decimal(as_string=True) arbeitspreis_n_t = fields.Decimal(as_string=True, data_key="arbeitspreisNT") grundpreis = fields.Decimal(as_string=True) - staffelgrenze_von = fields.Decimal(as_string=True) - staffelgrenze_bis = fields.Decimal(as_string=True) + staffelgrenze_von = fields.Decimal(as_string=True, data_key="staffelgrenzeVon") + staffelgrenze_bis = fields.Decimal(as_string=True, data_key="staffelgrenzeBis")