Skip to content
Open
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
14 changes: 14 additions & 0 deletions src/bo4e/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
__all__ = [
"Angebot",
"Ausschreibung",
"Avis",
"Buendelvertrag",
"Energiemenge",
"Fremdkosten",
Expand Down Expand Up @@ -40,6 +41,8 @@
"Vertrag",
"Zaehler",
"Zeitreihe",
"Abweichung",
"Abweichungsposition",
"Adresse",
"Angebotsposition",
"Angebotsteil",
Expand All @@ -50,6 +53,7 @@
"AufAbschlagstaffelProOrt",
"Ausschreibungsdetail",
"Ausschreibungslos",
"Avisposition",
"Betrag",
"COM",
"Dienstleistung",
Expand Down Expand Up @@ -79,6 +83,7 @@
"RegionalerAufAbschlag",
"RegionaleTarifpreisposition",
"Regionskriterium",
"Rueckmeldungsposition",
"Sigmoidparameter",
"StandorteigenschaftenGas",
"StandorteigenschaftenStrom",
Expand All @@ -101,6 +106,7 @@
"Zeitspanne",
"Zustaendigkeit",
"AbgabeArt",
"Abweichungsgrund",
"Angebotsstatus",
"Anrede",
"ArithmetischeOperation",
Expand All @@ -110,6 +116,7 @@
"Ausschreibungsportal",
"Ausschreibungsstatus",
"Ausschreibungstyp",
"AvisTyp",
"BDEWArtikelnummer",
"Befestigungsart",
"Bemessungsgroesse",
Expand Down Expand Up @@ -190,6 +197,7 @@
# Import BOs
from .bo.angebot import Angebot
from .bo.ausschreibung import Ausschreibung
from .bo.avis import Avis
from .bo.buendelvertrag import Buendelvertrag
from .bo.energiemenge import Energiemenge
from .bo.fremdkosten import Fremdkosten
Expand Down Expand Up @@ -221,6 +229,8 @@
from .bo.zeitreihe import Zeitreihe

# Import COMs
from .com.abweichung import Abweichung
from .com.abweichungsposition import Abweichungsposition
from .com.adresse import Adresse
from .com.angebotsposition import Angebotsposition
from .com.angebotsteil import Angebotsteil
Expand All @@ -231,6 +241,7 @@
from .com.aufabschlagstaffelproort import AufAbschlagstaffelProOrt
from .com.ausschreibungsdetail import Ausschreibungsdetail
from .com.ausschreibungslos import Ausschreibungslos
from .com.avisposition import Avisposition
from .com.betrag import Betrag
from .com.com import COM
from .com.dienstleistung import Dienstleistung
Expand Down Expand Up @@ -260,6 +271,7 @@
from .com.regionaleraufabschlag import RegionalerAufAbschlag
from .com.regionaletarifpreisposition import RegionaleTarifpreisposition
from .com.regionskriterium import Regionskriterium
from .com.rueckmeldungsposition import Rueckmeldungsposition
from .com.sigmoidparameter import Sigmoidparameter
from .com.standorteigenschaftengas import StandorteigenschaftenGas
from .com.standorteigenschaftenstrom import StandorteigenschaftenStrom
Expand All @@ -284,6 +296,7 @@

# Import Enums
from .enum.abgabeart import AbgabeArt
from .enum.abweichungsgrund import Abweichungsgrund
from .enum.angebotsstatus import Angebotsstatus
from .enum.anrede import Anrede
from .enum.arithmetische_operation import ArithmetischeOperation
Expand All @@ -293,6 +306,7 @@
from .enum.ausschreibungsportal import Ausschreibungsportal
from .enum.ausschreibungsstatus import Ausschreibungsstatus
from .enum.ausschreibungstyp import Ausschreibungstyp
from .enum.avistyp import AvisTyp
from .enum.bdewartikelnummer import BDEWArtikelnummer
from .enum.befestigungsart import Befestigungsart
from .enum.bemessungsgroesse import Bemessungsgroesse
Expand Down
22 changes: 22 additions & 0 deletions src/bo4e/bo/avis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Contains class Avis"""
from typing import Annotated, Optional

from pydantic import Field

from bo4e.bo.geschaeftsobjekt import Geschaeftsobjekt
from bo4e.com.avisposition import Avisposition
from bo4e.com.betrag import Betrag
from bo4e.enum.avistyp import AvisTyp

from ..enum.typ import Typ


class Avis(Geschaeftsobjekt):
"""Avis BO"""

typ: Annotated[Optional[Typ], Field(alias="_typ")] = Typ.AVIS

avis_nummer: str #: Eine im Verwendungskontext eindeutige Nummer für das Avis.
avis_typ: AvisTyp #: Gibt den Typ des Avis an.
positionen: list[Avisposition] #: Avispositionen
zu_zahlen: Betrag #: Summenbetrag
16 changes: 16 additions & 0 deletions src/bo4e/com/abweichung.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Contains Class: Abweichung."""
from typing import Optional

from bo4e.com.com import COM
from bo4e.enum.abweichungsgrund import Abweichungsgrund


class Abweichung(COM):
"""Zur Angabe einer Abweichung bei Ablehnung einer COMDIS. (REMADV SG5 RFF und SG7 AJT/FTX)."""

abweichungsgrund: Optional[Abweichungsgrund] = None #: Angabe Abweichungsgrund
abweichungsgrund_bemerkung: Optional[str] = None #: Nähere Erläuterung zum Abweichungsgrund
zugehoerige_rechnung: Optional[str] = None #: Zugehoerige Rechnung
abschlagsrechnung: Optional[str] = None #: Abschlagsrechnung
abweichungsgrund_code: Optional[str] = None #: Angabe Abweichungsgrund(Code)
abweichungsgrund_codeliste: Optional[str] = None #: Angabe Abweichungsgrund(Codeliste)
14 changes: 14 additions & 0 deletions src/bo4e/com/abweichungsposition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Contains class Abweichungsposition."""
from typing import Optional

from bo4e.com.com import COM


class Abweichungsposition(COM):
"""Zur Angabe einer Abweichung einer einzelnen Position."""

abweichungsgrund_code: Optional[str] = None #: Angabe Abweichungsgrund(Code)
abweichungsgrund_codeliste: Optional[str] = None #:Angabe Abweichungsgrund(Codeliste)
abweichungsgrund_bemerkung: Optional[str] = None #: Nähere Erläuterung zum Abweichungsgrund
zugehoerige_rechnung: Optional[str] = None #: Zugehörige Rechnung
zugehoerige_bestellung: Optional[str] = None #: Zugehörige Bestellung
25 changes: 25 additions & 0 deletions src/bo4e/com/avisposition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Contains class Avisposition"""
from datetime import datetime
from typing import Optional

from bo4e.com.abweichung import Abweichung
from bo4e.com.betrag import Betrag
from bo4e.com.com import COM
from bo4e.com.rueckmeldungsposition import Rueckmeldungsposition


class Avisposition(COM):
"""Die Position eines Avis"""

rechnungs_nummer: str #: Die Rechnungsnummer der Rechnung, auf welche sich das Avis bezieht.
rechnungs_datum: datetime #: Das Rechnungsdatum der Rechnung, auf die sich das Avis bezieht.
ist_storno: bool
#: Kennzeichnung, ob es sich bei der Rechnung auf die sich das Avis bezieht, um eine Stornorechnung handelt.
gesamtbrutto: Betrag #: Überweisungsbetrag
zu_zahlen: Betrag #: Geforderter Rechnungsbetrag

ist_selbstausgestellt: Optional[bool] = None
#: Kennzeichnung, ob es sich bei der Rechnung auf die sich das Avis bezieht, um eine Stornorechnung handelt.
referenz: Optional[str] = None #: Referenzierung auf eine vorherige COMDIS-Nachricht
abweichungen: Optional[list[Abweichung]] = None #: Abweichungen bei Ablehnung einer COMDIS
positionen: Optional[list[Rueckmeldungsposition]] = None #: Rückmeldungspositionen
25 changes: 25 additions & 0 deletions src/bo4e/com/rueckmeldungsposition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Contains class Rueckmeldeposition"""
from typing import Optional

from pydantic import model_validator

from bo4e.com.abweichungsposition import Abweichungsposition
from bo4e.com.com import COM


class Rueckmeldungsposition(COM):
"""Zur Angabe einer Rückmeldung einer einzelnen Position."""

positionsnummer: Optional[str] = None #: Positionsnummer der Referenzierung
abweichungspositionen: Optional[list[Abweichungsposition]] = None #: Abweichungspositionen

@model_validator(mode="after")
def _field_combination_xor(self) -> "Rueckmeldungsposition":
"""Model validator.
Ensures that either both or no attributes are set
"""
if (self.positionsnummer and self.abweichungspositionen is None) or (
self.abweichungspositionen and self.positionsnummer is None
):
raise ValueError("Attributes missing")
return self
45 changes: 45 additions & 0 deletions src/bo4e/enum/abweichungsgrund.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Contains Enums for Abweichungsgrund."""
from bo4e.enum.strenum import StrEnum


class Abweichungsgrund(StrEnum):
"""Gibt einen Abweichungsgrund bei Ablehung einer COMDIS an. (REMADV SG7 AJT 4465)"""

PREIS_RECHENREGEL_FALSCH = "PREIS_RECHENREGEL_FALSCH" #: PREIS_RECHENREGEL_FALSCH, 5
FALSCHER_ABRECHNUNGSZEITRAUM = "FALSCHER_ABRECHNUNGSZEITRAUM" #: FALSCHER_ABRECHNUNGSZEITRAUM, 9
UNBEKANNTE_MARKTLOKATION_MESSLOKATION = "UNBEKANNTE_MARKTLOKATION_MESSLOKATION"
"""UNBEKANNTE_MARKTLOKATION_MESSLOKATION, 14."""
SONSTIGER_ABWEICHUNGSGRUND = "SONSTIGER_ABWEICHUNGSGRUND" #: SONSTIGER_ABWEICHUNGSGRUND, 28
DOPPELTE_RECHNUNG = "DOPPELTE_RECHNUNG" #: DOPPELTE_RECHNUNG, 53
ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN = "ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN"
"""ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN, Z01."""
ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE = "ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE"
"""ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE, Z02."""
BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH = "BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH"
"BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH, Z03."
VORAUSBEZAHLTER_BETRAG_FALSCH = "VORAUSBEZAHLTER_BETRAG_FALSCH" #: VORAUSBEZAHLTER_BETRAG_FALSCH, Z04
ARTIKEL_NICHT_VEREINBART = "ARTIKEL_NICHT_VEREINBART" #: ARTIKEL_NICHT_VEREINBART, Z06
NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN = "NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN"
"""NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN, Z07."""
RECHNUNGSNUMMER_BEREITS_ERHALTEN = "RECHNUNGSNUMMER_BEREITS_ERHALTEN" #: RECHNUNGSNUMMER_BEREITS_ERHALTEN, Z08
NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH = "NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH"
"""NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH, Z10."""
ZEITLICHE_MENGENANGABE_FEHLERHAFT = "ZEITLICHE_MENGENANGABE_FEHLERHAFT" #: ZEITLICHE_MENGENANGABE_FEHLERHAFT, Z33
FALSCHER_BILANZIERUNGSBEGINN = "FALSCHER_BILANZIERUNGSBEGINN" #: FALSCHER_BILANZIERUNGSBEGINN, Z35
FALSCHES_NETZNUTZUNGSENDE = "FALSCHES_NETZNUTZUNGSENDE" #: FALSCHES_NETZNUTZUNGSENDE, Z36
BILANZIERTE_MENGE_FEHLT = "BILANZIERTE_MENGE_FEHLT" #: BILANZIERTE_MENGE_FEHLT, Z37
BILANZIERTE_MENGE_FALSCH = "BILANZIERTE_MENGE_FALSCH" #: BILANZIERTE_MENGE_FALSCH, Z38
NETZNUTZUNGSABRECHNUNG_FEHLT = "NETZNUTZUNGSABRECHNUNG_FEHLT" #: NETZNUTZUNGSABRECHNUNG_FEHLT, Z39
REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT = "REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT"
"""REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT, Z40."""
ALLOKATIONSLISTE_FEHLT = "ALLOKATIONSLISTE_FEHLT" #: ALLOKATIONSLISTE_FEHLT, Z41
MEHR_MINDERMENGE_FALSCH = "MEHR_MINDERMENGE_FALSCH" #: MEHR_MINDERMENGE_FALSCH, Z42
UNGUELTIGES_RECHNUNGSDATUM = "UNGUELTIGES_RECHNUNGSDATUM" #: UNGUELTIGES_RECHNUNGSDATUM, Z43
ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT = "ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT"
"ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT, Z44."
RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS = "RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS" #: RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS, Z45
ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN = "ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN"
"""ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN, Z52."""
RECHNUNGSABWICKLUNG_NICHT_VEREINBART = "RECHNUNGSABWICKLUNG_NICHT_VEREINBART"
"""RECHNUNGSABWICKLUNG_NICHT_VEREINBART, Z53."""
COMDIS_WIRD_ABGELEHNT = "COMDIS_WIRD_ABGELEHNT" #: COMDIS_WIRD_ABGELEHNT, Z63
9 changes: 9 additions & 0 deletions src/bo4e/enum/avistyp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Contains Enums for Avisposition"""
from bo4e.enum.strenum import StrEnum


class AvisTyp(StrEnum):
"""Gibt den Typ des Avis an. (REMADV BGM 1001)."""

ABGELEHNTE_FORDERUNG = "ABGELEHNTE_FORDERUNG" #: Abgelehnte Forderung
ZAHLUNGSAVIS = "ZAHLUNGSAVIS" #: Zahlungsavis
1 change: 1 addition & 0 deletions src/bo4e/enum/typ.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Typ(StrEnum):

ANGEBOT = "ANGEBOT"
AUSSCHREIBUNG = "AUSSCHREIBUNG"
AVIS = "AVIS"
BUENDELVERTRAG = "BUENDELVERTRAG"
ENERGIEMENGE = "ENERGIEMENGE"
FREMDKOSTEN = "FREMDKOSTEN"
Expand Down
28 changes: 28 additions & 0 deletions tests/test_abweichung.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

from bo4e.com.abweichung import Abweichung
from bo4e.enum.abweichungsgrund import Abweichungsgrund
from tests.serialization_helper import assert_serialization_roundtrip


class Test_Abweichung:
@pytest.mark.parametrize(
"abweichung",
[
pytest.param(
Abweichung(
abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION,
abweichungsgrund_bemerkung="sonst",
zugehoerige_rechnung="458011",
abschlagsrechnung="4580112",
abweichungsgrund_code="14",
abweichungsgrund_codeliste="G_0081",
)
),
],
)
def test_serialization_roundtrip(self, abweichung: Abweichung) -> None:
"""
Test de-/serialisation of Abweichung.
"""
assert_serialization_roundtrip(abweichung)
26 changes: 26 additions & 0 deletions tests/test_abweichungsposition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pytest

from bo4e.com.abweichungsposition import Abweichungsposition
from tests.serialization_helper import assert_serialization_roundtrip


class TestAbweichungsposition:
@pytest.mark.parametrize(
"abweichungsposition",
[
pytest.param(
Abweichungsposition(
abweichungsgrund_code="14",
abweichungsgrund_codeliste="G_0081",
abweichungsgrund_bemerkung="Umsatzsteuersatz",
zugehoerige_rechnung="458011",
zugehoerige_bestellung="foo",
)
),
],
)
def test_serialization_roundtrip(self, abweichungsposition: Abweichungsposition) -> None:
"""
Test de-/serialisation of Abweichungsposition.
"""
assert_serialization_roundtrip(abweichungsposition)
Loading