Repository: bo4e/BO4E-python (language: python)

Issue:
Implement BO Tarifkosten
https://www.bo4e.de/dokumentation/geschaeftsobjekte/bo-tarifkosten
- #207 
- #191 


Discussion / hints:

Fix patch:
diff --git a/src/bo4e/bo/tarifkosten.py b/src/bo4e/bo/tarifkosten.py
new file mode 100644
index 000000000..1ea65770d
--- /dev/null
+++ b/src/bo4e/bo/tarifkosten.py
@@ -0,0 +1,41 @@
+"""
+Contains Tarifkosten class
+and corresponding marshmallow schema for de-/serialization
+"""
+import attr
+from marshmallow import fields
+
+from bo4e.bo.kosten import Kosten, KostenSchema
+from bo4e.bo.tarifinfo import Tarifinfo, TarifinfoSchema
+from bo4e.enum.botyp import BoTyp
+
+
+# pylint: disable=too-few-public-methods
+@attr.s(auto_attribs=True, kw_only=True)
+class Tarifkosten(Tarifinfo):
+    """
+    Objekt zur Kommunikation von Kosten, die im Rahmen der Tarifanwendung entstehen
+    """
+
+    # required attributes
+    bo_typ: BoTyp = attr.ib(default=BoTyp.TARIFKOSTEN)
+    kosten: Kosten = attr.ib(validator=attr.validators.instance_of(Kosten))
+    """
+    Referenz (Link) zu einem Kostenobjekt, in dem die Kosten für die Anwendung
+    des Tarifs auf eine Abnahmesituation berechnet wurden
+    """
+
+    # there are no optional attributes
+
+
+class TarifkostenSchema(TarifinfoSchema):
+    """
+    Schema for de-/serialization of Tarifkosten.
+    """
+
+    # class_name is needed to use the correct schema for deserialization.
+    # see function `deserialize` in geschaeftsobjekt.py
+    class_name = Tarifkosten  # type:ignore[assignment]
+
+    # required attributes
+    kosten = fields.Nested(KostenSchema)


Test patch:
diff --git a/tests/test_kosten.py b/tests/test_kosten.py
index 766ede02c..be802fd09 100644
--- a/tests/test_kosten.py
+++ b/tests/test_kosten.py
@@ -7,22 +7,24 @@
 from tests.test_betrag import example_betrag  # type:ignore[import]
 from tests.test_zeitraum import example_zeitraum  # type:ignore[import]
 
+example_kosten = Kosten(
+    kostenklasse=Kostenklasse.FREMDKOSTEN,
+    gueltigkeit=example_zeitraum,
+    kostenbloecke=[
+        Kostenblock(
+            kostenblockbezeichnung="Mein Kostenblock",
+        )
+    ],
+    summe_kosten=[example_betrag],
+)
+
 
 class TestKosten:
     @pytest.mark.parametrize(
         "kosten",
         [
             pytest.param(
-                Kosten(
-                    kostenklasse=Kostenklasse.FREMDKOSTEN,
-                    gueltigkeit=example_zeitraum,
-                    kostenbloecke=[
-                        Kostenblock(
-                            kostenblockbezeichnung="Mein Kostenblock",
-                        )
-                    ],
-                    summe_kosten=[example_betrag],
-                ),
+                example_kosten,
                 id="maximal attributes",
             )
         ],
diff --git a/tests/test_tarifkosten.py b/tests/test_tarifkosten.py
new file mode 100644
index 000000000..ff259e92a
--- /dev/null
+++ b/tests/test_tarifkosten.py
@@ -0,0 +1,51 @@
+import pytest  # type:ignore[import]
+
+from bo4e.bo.tarifkosten import Tarifkosten, TarifkostenSchema
+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_kosten import example_kosten  # type:ignore[import]
+from tests.test_marktteilnehmer import example_marktteilnehmer  # type:ignore[import]
+from tests.test_vertragskonditionen import example_vertragskonditionen  # type:ignore[import]
+from tests.test_zeitraum import example_zeitraum  # type:ignore[import]
+
+
+class TestTarifkosten:
+    @pytest.mark.parametrize(
+        "tarifkosten",
+        [
+            pytest.param(
+                Tarifkosten(
+                    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,
+                    kosten=example_kosten,
+                )
+            ),
+        ],
+    )
+    def test_serialization_roundtrip(self, tarifkosten: Tarifkosten):
+        """
+        Test de-/serialisation
+        """
+        assert_serialization_roundtrip(tarifkosten, TarifkostenSchema())
+
+    def test_missing_required_attribute(self):
+        with pytest.raises(TypeError) as excinfo:
+            _ = Tarifkosten()
+
+        assert "missing 9 required" in str(excinfo.value)