Skip to content
Draft
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
6 changes: 5 additions & 1 deletion src/bo4e/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"PreisblattKonzessionsabgabe",
"PreisblattMessung",
"PreisblattNetznutzung",
"Produkt",
"Rechnung",
"Region",
"Standorteigenschaften",
Expand Down Expand Up @@ -160,6 +161,7 @@
"Preisreferenz",
"Preisstatus",
"Preistyp",
"Produkttyp",
"Profilart",
"Profiltyp",
"Profilverfahren",
Expand Down Expand Up @@ -233,11 +235,11 @@
from .bo.preisblattkonzessionsabgabe import PreisblattKonzessionsabgabe
from .bo.preisblattmessung import PreisblattMessung
from .bo.preisblattnetznutzung import PreisblattNetznutzung
from .bo.produkt import Produkt
from .bo.rechnung import Rechnung
from .bo.region import Region
from .bo.standorteigenschaften import Standorteigenschaften
from .bo.steuerbareressource import SteuerbareRessource
from .bo.tarif import Tarif
from .bo.tarifinfo import Tarifinfo
from .bo.tarifkosten import Tarifkosten
from .bo.tarifpreisblatt import Tarifpreisblatt
Expand Down Expand Up @@ -289,6 +291,7 @@
from .com.standorteigenschaftenstrom import StandorteigenschaftenStrom
from .com.steuerbetrag import Steuerbetrag
from .com.tagesparameter import Tagesparameter
from .com.tarif import Tarif
from .com.tarifberechnungsparameter import Tarifberechnungsparameter
from .com.tarifeinschraenkung import Tarifeinschraenkung
from .com.tarifpreis import Tarifpreis
Expand Down Expand Up @@ -367,6 +370,7 @@
from .enum.preisreferenz import Preisreferenz
from .enum.preisstatus import Preisstatus
from .enum.preistyp import Preistyp
from .enum.produkttyp import Produkttyp
from .enum.profilart import Profilart
from .enum.profiltyp import Profiltyp
from .enum.profilverfahren import Profilverfahren
Expand Down
70 changes: 70 additions & 0 deletions src/bo4e/bo/produkt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
Contains Produkt class
"""

from typing import TYPE_CHECKING, Annotated, Literal, Optional

from pydantic import Field

from ..enum.botyp import BoTyp
from ..utils import postprocess_docstring
from .geschaeftsobjekt import Geschaeftsobjekt

if TYPE_CHECKING:
from ..com.tarif import Tarif
from ..com.vertragskonditionen import Vertragskonditionen
from ..com.zeitraum import Zeitraum
from ..enum.kundentyp import Kundentyp
from ..enum.produkttyp import Produkttyp
from ..enum.sparte import Sparte
from .marktteilnehmer import Marktteilnehmer

# pylint: disable=too-few-public-methods
# pylint: disable=no-name-in-module
# pylint: disable=too-many-instance-attributes


@postprocess_docstring
class Produkt(Geschaeftsobjekt):
"""
Modell für die Abbildung eines Produkts, z.B. eines Tarifprodukts.
Ein Produkt bündelt die vermarktungsrelevanten Eigenschaften und referenziert
den zugrundeliegenden Tarif.

.. raw:: html

<object data="../_static/images/bo4e/bo/Produkt.svg" type="image/svg+xml"></object>

.. HINT::
`Produkt JSON Schema <https://json-schema.app/view/%23?url=https://raw.githubusercontent.com/BO4E/BO4E-Schemas/{__gh_version__}/src/bo4e_schemas/bo/Produkt.json>`_

"""

typ: Annotated[Literal[BoTyp.PRODUKT], Field(alias="_typ")] = BoTyp.PRODUKT

bezeichnung: Optional[str] = None
"""Eine (beliebige) Bezeichnung für das Produkt."""
beschreibung: Optional[str] = None
"""Eine (beliebige) Beschreibung für das Produkt."""
produkttyp: Optional["Produkttyp"] = None
"""Die Art des Produkts, z.B. Tarifprodukt."""
tarif: Optional["Tarif"] = None
"""Der dem Produkt zugrundeliegende Tarif."""
sparte: Optional["Sparte"] = None
"""Strom / Gas"""
anbieter: Optional["Marktteilnehmer"] = None
"""Der Marktteilnehmer, der dieses Produkt anbietet, angeboten hat oder anbieten wird."""
zeitraum_vermarktung: Optional["Zeitraum"] = None
"""Der Zeitraum, in dem das Produkt beim Anbieter vertraglich abschließbar ist."""
zeitraum_belieferbarkeit: Optional["Zeitraum"] = None
"""Der Zeitraum, in dem eine Belieferung (für dieses Produkt) möglich ist."""
vertragskonditionen: Optional["Vertragskonditionen"] = None
"""
Vertragskonditionen für dieses Produkt.
Die Redundanz zu den Vertragskonditionen am Vertrag ist gewollt: die Konditionen
des Produkts können bei der Vertragsausgestaltung überschrieben werden.
"""
website: Optional[str] = None
"""Internetseite, auf der das Produkt veröffentlicht ist."""
kundentypen: Optional[list["Kundentyp"]] = None
"""Eine Liste an Kundentypen, für die dieses Produkt vorgesehen ist."""
61 changes: 14 additions & 47 deletions src/bo4e/bo/tarif.py → src/bo4e/com/tarif.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,28 @@

from pydantic import Field

from ..enum.botyp import BoTyp
from ..enum.comtyp import ComTyp
from ..utils import postprocess_docstring
from .tarifinfo import Tarifinfo
from .com import COM

if TYPE_CHECKING:
from ..bo.marktteilnehmer import Marktteilnehmer
from ..com.energiemix import Energiemix
from ..com.preisgarantie import Preisgarantie
from ..com.regionspreis import Regionspreis
from ..com.tarifberechnungsparameter import Tarifberechnungsparameter
from ..com.tarifeinschraenkung import Tarifeinschraenkung
from ..com.vertragskonditionen import Vertragskonditionen
from ..com.zeitraum import Zeitraum
from ..enum.kundentyp import Kundentyp
from ..enum.registeranzahl import Registeranzahl
from ..enum.sparte import Sparte
from ..enum.tarifmerkmal import Tarifmerkmal
from ..enum.tariftyp import Tariftyp


# pylint: disable=too-few-public-methods
# pylint: disable=no-name-in-module


@postprocess_docstring
class Tarif(Tarifinfo):
class Tarif(COM):
"""
Abbildung eines Tarifs.
Abbildung eines Tarifs (Preisbestandteile eines Produkts).

Der Tarifpreis kann regionsaufgelöst und unter Angabe von Zeitscheiben angegeben werden. So kann bspw. derselbe
Tarif je nach Region andere Preise aufweisen. Es können auch Tarifpreise abgebildet werden, die sich ab einem
Expand All @@ -43,25 +37,18 @@ class Tarif(Tarifinfo):
`COM RelativePreisposition` prozentuale Auf- und Abschläge auf andere Preispositionen definiert werden.
Alle Preispositionen hängen unter `COM Tarifpreiszeitscheibe` mit einer Ausnahme.

Möchten Sie einen dynamischen Tarif modellieren, so gibt es das `COM DynamischePreisposition`. Da diese
Preisposition weder orts- noch zeitabhängig ist, hängt diese direkt unter dem `BO Tarif`. Eine zeitabhängige
Änderung einer dynamischen Tarifpreisposition ist unsinnig, da es sich (unserer Ansicht nach) dann um einen
völlig neuen Tarif handelt. Davon unabhängig können (und müssen) natürlich weiterhin zusätzlich alle anderen
Preispositionen orts- und zeitabhängig angegeben werden.

> Hinweis: Das Vorhandensein einer `COM DynamischePreisposition` dient gleichzeitig auch als "Flag" dafür, ob
> es sich bei diesem Tarif um einen dynamischen handelt.
Möchten Sie einen dynamischen Tarif modellieren, so gibt es das `COM DynamischePreisposition`.

.. raw:: html

<object data="../_static/images/bo4e/bo/Tarif.svg" type="image/svg+xml"></object>
<object data="../_static/images/bo4e/com/Tarif.svg" type="image/svg+xml"></object>

.. HINT::
`Tarif JSON Schema <https://json-schema.app/view/%23?url=https://raw.githubusercontent.com/BO4E/BO4E-Schemas/{__gh_version__}/src/bo4e_schemas/bo/Tarif.json>`_
`Tarif JSON Schema <https://json-schema.app/view/%23?url=https://raw.githubusercontent.com/BO4E/BO4E-Schemas/{__gh_version__}/src/bo4e_schemas/com/Tarif.json>`_

"""

typ: Annotated[Literal[BoTyp.TARIF], Field(alias="_typ")] = BoTyp.TARIF # type:ignore[assignment]
typ: Annotated[Literal[ComTyp.TARIF], Field(alias="_typ")] = ComTyp.TARIF

regionspreise: Optional[list["Regionspreis"]] = None
"""
Expand All @@ -74,40 +61,20 @@ class Tarif(Tarifinfo):
Gibt die Bezugsquelle (z.B. Börsenindex) für den dynamischen Tarif an.
Dieses Feld muss genau dann gesetzt werden, wenn es sich bei diesem Tarif um einen dynamischen Tarif handelt.
"""

bezeichnung: Optional[str] = None
"""Eine (beliebige) Bezeichnung für den Tarif."""
beschreibung: Optional[str] = None
"""Eine (beliebige) Beschreibung für den Tarif."""
anbieter: Optional["Marktteilnehmer"] = None
"""Der Marktteilnehmer, der diesen Tarif anbietet, angeboten hat oder anbieten wird."""

zeitraum_vermarktung: Optional["Zeitraum"] = None
"""Der Zeitraum, in dem der Tarif beim Anbieter vertraglich abschließbar ist."""
zeitraum_belieferbarkeit: Optional["Zeitraum"] = None
"""Der Zeitraum, in dem eine Belieferung (für diesen Tarif) möglich ist."""
vertragskonditionen: Optional["Vertragskonditionen"]
"""Vertragskonditionen für diesen Tarif."""
website: Optional[str]
"""Internetseite, auf der der Tarif veröffentlicht ist."""
energiemix: Optional[list["Energiemix"]] # type:ignore[assignment]
energiemix: Optional[list["Energiemix"]] = None
"""Der Energiemix mit einem Eintrag pro Gültigkeitsjahr (siehe `Energiemix.gueltigkeitsjahr`)."""
kundentypen: Optional[list["Kundentyp"]]
"""Eine Liste an Kundentypen, für die dieser Tarif vorgesehen ist."""
tariftyp: Optional["Tariftyp"]
tariftyp: Optional["Tariftyp"] = None
"""Der Tariftyp. Bsp.: Grundversorgung, Ersatzversorgung, etc."""
tarifmerkmale: Optional[list["Tarifmerkmal"]]
tarifmerkmale: Optional[list["Tarifmerkmal"]] = None
"""Eine Liste von Produktmerkmalen im Zusammenhang mit diesem Tarif."""
sparte: Optional["Sparte"]
"""Strom / Gas"""
registeranzahl: Optional["Registeranzahl"]
registeranzahl: Optional["Registeranzahl"] = None
"""
Hinweis zu den Registern bzw. Zählwerken.
Bspw. benötigt ein HT-/NT-Tarif auch eine entsprechende Registeranzahl.
"""
preisgarantie: Optional["Preisgarantie"]
preisgarantie: Optional["Preisgarantie"] = None
"""Preisgarantie für diesen Tarif"""
berechnungsparameter: Optional["Tarifberechnungsparameter"]
berechnungsparameter: Optional["Tarifberechnungsparameter"] = None
"""Für die Berechnung der Kosten sind die hier abgebildeten Parameter heranzuziehen"""
tarifeinschraenkung: Optional["Tarifeinschraenkung"] = None
"""Die Bedingungen und Einschränkungen unter denen ein Tarif angewendet werden kann"""
2 changes: 1 addition & 1 deletion src/bo4e/enum/botyp.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ class BoTyp(StrEnum):
PREISBLATTMESSUNG = "PREISBLATTMESSUNG"
PREISBLATTNETZNUTZUNG = "PREISBLATTNETZNUTZUNG"
PREISBLATTUMLAGEN = "PREISBLATTUMLAGEN"
PRODUKT = "PRODUKT"
RECHNUNG = "RECHNUNG"
REGION = "REGION"
STANDORTEIGENSCHAFTEN = "STANDORTEIGENSCHAFTEN"
TARIF = "TARIF"
TARIFINFO = "TARIFINFO"
TARIFKOSTEN = "TARIFKOSTEN"
TARIFPREISBLATT = "TARIFPREISBLATT"
Expand Down
1 change: 1 addition & 0 deletions src/bo4e/enum/comtyp.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class ComTyp(StrEnum):
STANDORTEIGENSCHAFTENSTROM = "STANDORTEIGENSCHAFTENSTROM"
STEUERBETRAG = "STEUERBETRAG"
TAGESPARAMETER = "TAGESPARAMETER"
TARIF = "TARIF"
TARIFBERECHNUNGSPARAMETER = "TARIFBERECHNUNGSPARAMETER"
TARIFEINSCHRAENKUNG = "TARIFEINSCHRAENKUNG"
TARIFPREIS = "TARIFPREIS"
Expand Down
2 changes: 2 additions & 0 deletions src/bo4e/enum/kundentyp.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ class Kundentyp(StrEnum):
"""Unterbrechbare Verbrauchseinrichtungen"""
WAERMEPUMPE = "WAERMEPUMPE"
"""Wärmepumpen"""
INDUSTRIE = "INDUSTRIE"
"""Großkunden / Kunden, die viel Energie verbrauchen"""
11 changes: 11 additions & 0 deletions src/bo4e/enum/produkttyp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# pylint:disable=missing-module-docstring
from bo4e.enum.strenum import StrEnum


class Produkttyp(StrEnum):
"""
Aufzählung der Produktarten.
"""

TARIFPRODUKT = "TARIFPRODUKT"
"""Ein Produkt, das auf einem Tarif basiert."""
28 changes: 28 additions & 0 deletions tests/test_produkt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

from bo4e import BoTyp, Produkt, Produkttyp, Tarif
from tests.serialization_helper import assert_serialization_roundtrip


class TestProdukt:
@pytest.mark.parametrize(
"produkt",
[
pytest.param(
Produkt(
bezeichnung="Ökostrom Basis",
beschreibung="100% Ökostrom",
produkttyp=Produkttyp.TARIFPRODUKT,
tarif=Tarif(),
website="https://foo.inv",
),
id="max attributes",
),
pytest.param(Produkt(), id="min attributes"),
],
)
def test_serialization_roundtrip(self, produkt: Produkt) -> None:
assert_serialization_roundtrip(produkt)

def test_produkt_typ(self) -> None:
assert Produkt().typ == BoTyp.PRODUKT
19 changes: 5 additions & 14 deletions tests/test_tarif.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
import pytest

from bo4e import (
ComTyp,
EinheitsPreisposition,
Energiemix,
Kundentyp,
Marktteilnehmer,
Mengeneinheit,
Operator,
Preis,
Expand All @@ -20,14 +19,12 @@
Regionszeitscheibe,
Registeranzahl,
RelativePreisposition,
Sparte,
Tarif,
Tarifberechnungsparameter,
Tarifeinschraenkung,
Tarifmerkmal,
Tarifpreiszeitscheibe,
Tariftyp,
Vertragskonditionen,
Waehrungseinheit,
Zeitraum,
)
Expand All @@ -43,20 +40,10 @@ class TestTarif:
berechnungsparameter=Tarifberechnungsparameter(),
preisgarantie=Preisgarantie(),
tarifeinschraenkung=Tarifeinschraenkung(),
# below are the attributes of tarifinfo
bezeichnung="foo",
anbietername="der beste stromanbieter",
sparte=Sparte.STROM,
kundentypen=[Kundentyp.PRIVAT, Kundentyp.GEWERBE],
registeranzahl=Registeranzahl.MEHRTARIF,
tariftyp=Tariftyp.GRUND_ERSATZVERSORGUNG,
tarifmerkmale=[Tarifmerkmal.HEIZSTROM],
website="https://foo.inv",
bemerkung="super billig aber auch super dreckig",
vertragskonditionen=Vertragskonditionen(),
zeitliche_gueltigkeit=Zeitraum(),
energiemix=[Energiemix()],
anbieter=Marktteilnehmer(),
regionspreise=[
Regionspreis(
regionszeitscheiben=[
Expand Down Expand Up @@ -111,3 +98,7 @@ def test_serialization_roundtrip(self, tarif: Tarif) -> None:
Test de-/serialisation
"""
assert_serialization_roundtrip(tarif)

def test_tarif_typ(self) -> None:
tarif = Tarif()
assert tarif.typ == ComTyp.TARIF
Loading