From f39675fa598695f5723e6b164bb6e35f5ee7a5af Mon Sep 17 00:00:00 2001 From: hf-ddernbach Date: Wed, 23 Aug 2023 10:03:31 +0200 Subject: [PATCH 01/11] :construction: created BO Avis and required classes, started testing --- src/bo4e/bo/avis.py | 18 ++ src/bo4e/com/abweichung.py | 17 ++ src/bo4e/com/abweichungsposition.py | 16 ++ src/bo4e/com/avisposition.py | 27 +++ src/bo4e/com/rueckmeldungsposition.py | 24 ++ src/bo4e/enum/abweichungsgrund.py | 65 ++++++ src/bo4e/enum/avistyp.py | 9 + src/bo4e/enum/botyp.py | 1 + tests/test_abweichung.py | 55 +++++ tests/test_abweichungsposition.py | 53 +++++ tests/test_avis.py | 323 ++++++++++++++++++++++++++ tests/test_avisposition.py | 214 +++++++++++++++++ tests/test_rueckmeldungsposition.py | 100 ++++++++ 13 files changed, 922 insertions(+) create mode 100644 src/bo4e/bo/avis.py create mode 100644 src/bo4e/com/abweichung.py create mode 100644 src/bo4e/com/abweichungsposition.py create mode 100644 src/bo4e/com/avisposition.py create mode 100644 src/bo4e/com/rueckmeldungsposition.py create mode 100644 src/bo4e/enum/abweichungsgrund.py create mode 100644 src/bo4e/enum/avistyp.py create mode 100644 tests/test_abweichung.py create mode 100644 tests/test_abweichungsposition.py create mode 100644 tests/test_avis.py create mode 100644 tests/test_avisposition.py create mode 100644 tests/test_rueckmeldungsposition.py diff --git a/src/bo4e/bo/avis.py b/src/bo4e/bo/avis.py new file mode 100644 index 000000000..b92921401 --- /dev/null +++ b/src/bo4e/bo/avis.py @@ -0,0 +1,18 @@ +"""Contains class Avis""" +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 bo4e.enum.botyp import BoTyp + + +class Avis(Geschaeftsobjekt): + """Avis BO""" + + bo_typ: BoTyp = BoTyp.AVIS # added to botyp.py + + #: required attributes + 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 diff --git a/src/bo4e/com/abweichung.py b/src/bo4e/com/abweichung.py new file mode 100644 index 000000000..0cf70189a --- /dev/null +++ b/src/bo4e/com/abweichung.py @@ -0,0 +1,17 @@ +"""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).""" + + # optional attributes + 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) diff --git a/src/bo4e/com/abweichungsposition.py b/src/bo4e/com/abweichungsposition.py new file mode 100644 index 000000000..f74c3d207 --- /dev/null +++ b/src/bo4e/com/abweichungsposition.py @@ -0,0 +1,16 @@ +"""Contains class Abweichungsposition.""" +from typing import Optional + +from bo4e.com.com import COM + + +class Abweichungsposition(COM): + """Zur Angabe einer Abweichung einer einzelnen Position.""" + + # optional attributes + 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 + # todo: prüfen, ob zugehörige Rechnung angegeben ist, wenn Abw.Grund gegeben? + zugehoerige_rechnung: Optional[str] = None #: Zugehörige Rechnung + zugehoerige_bestellung: Optional[str] = None #: Zugehörige Bestellung diff --git a/src/bo4e/com/avisposition.py b/src/bo4e/com/avisposition.py new file mode 100644 index 000000000..5e28bc8a6 --- /dev/null +++ b/src/bo4e/com/avisposition.py @@ -0,0 +1,27 @@ +"""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""" + + # required attributes + 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 + + # optional attributes + 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 diff --git a/src/bo4e/com/rueckmeldungsposition.py b/src/bo4e/com/rueckmeldungsposition.py new file mode 100644 index 000000000..20c8e1766 --- /dev/null +++ b/src/bo4e/com/rueckmeldungsposition.py @@ -0,0 +1,24 @@ +"""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.""" + + # optional attributes + positionsnummer: Optional[str] = None #: Positionsnummer der Referenzierung + abweichungspositionen: Optional[list[Abweichungsposition]] = None #: Abweichungspositionen + + #: model validator for !XOR pos.nr. and abweichungspos. + @model_validator(mode="after") + def _field_combination_xor(self) -> "Rueckmeldungsposition": + if (self.positionsnummer and self.abweichungspositionen is None) or ( + self.abweichungspositionen and self.positionsnummer is None + ): + raise ValueError("Attributes missing") + return self diff --git a/src/bo4e/enum/abweichungsgrund.py b/src/bo4e/enum/abweichungsgrund.py new file mode 100644 index 000000000..9bbdbb0f7 --- /dev/null +++ b/src/bo4e/enum/abweichungsgrund.py @@ -0,0 +1,65 @@ +"""contains class 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, 5 + PREIS_RECHENREGEL_FALSCH = "PREIS_RECHENREGEL_FALSCH" + #: FALSCHER_ABRECHNUNGSZEITRAUM, 9 + FALSCHER_ABRECHNUNGSZEITRAUM = "FALSCHER_ABRECHNUNGSZEITRAUM" + #: UNBEKANNTE_MARKTLOKATION_MESSLOKATION, 14 + UNBEKANNTE_MARKTLOKATION_MESSLOKATION = "UNBEKANNTE_MARKTLOKATION_MESSLOKATION" + #: SONSTIGER_ABWEICHUNGSGRUND, 28 + SONSTIGER_ABWEICHUNGSGRUND = "SONSTIGER_ABWEICHUNGSGRUND" + #: DOPPELTE_RECHNUNG, 53 + DOPPELTE_RECHNUNG = "DOPPELTE_RECHNUNG" + #: ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN, Z01 + ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN = "ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN" + #: ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE, Z02 + ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE = "ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE" + #: BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH, Z03 + BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH = "BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH" + #: VORAUSBEZAHLTER_BETRAG_FALSCH, Z04 + VORAUSBEZAHLTER_BETRAG_FALSCH = "VORAUSBEZAHLTER_BETRAG_FALSCH" + #: ARTIKEL_NICHT_VEREINBART, Z06 + ARTIKEL_NICHT_VEREINBART = "ARTIKEL_NICHT_VEREINBART" + #: NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN, Z07 + NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN = "NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN" + #: RECHNUNGSNUMMER_BEREITS_ERHALTEN, Z08 + RECHNUNGSNUMMER_BEREITS_ERHALTEN = "RECHNUNGSNUMMER_BEREITS_ERHALTEN" + #: NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH, Z10 + NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH = "NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH" + #: ZEITLICHE_MENGENANGABE_FEHLERHAFT, Z33 + ZEITLICHE_MENGENANGABE_FEHLERHAFT = "ZEITLICHE_MENGENANGABE_FEHLERHAFT" + #: FALSCHER_BILANZIERUNGSBEGINN, Z35 + FALSCHER_BILANZIERUNGSBEGINN = "FALSCHER_BILANZIERUNGSBEGINN" + #: FALSCHES_NETZNUTZUNGSENDE, Z36 + FALSCHES_NETZNUTZUNGSENDE = "FALSCHES_NETZNUTZUNGSENDE" + #: BILANZIERTE_MENGE_FEHLT, Z37 + BILANZIERTE_MENGE_FEHLT = "BILANZIERTE_MENGE_FEHLT" + #: BILANZIERTE_MENGE_FALSCH, Z38 + BILANZIERTE_MENGE_FALSCH = "BILANZIERTE_MENGE_FALSCH" + #: NETZNUTZUNGSABRECHNUNG_FEHLT, Z39 + NETZNUTZUNGSABRECHNUNG_FEHLT = "NETZNUTZUNGSABRECHNUNG_FEHLT" + #: REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT, Z40 + REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT = "REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT" + #: ALLOKATIONSLISTE_FEHLT, Z41 + ALLOKATIONSLISTE_FEHLT = "ALLOKATIONSLISTE_FEHLT" + #: MEHR_MINDERMENGE_FALSCH, Z42 + MEHR_MINDERMENGE_FALSCH = "MEHR_MINDERMENGE_FALSCH" + #: UNGUELTIGES_RECHNUNGSDATUM, Z43 + UNGUELTIGES_RECHNUNGSDATUM = "UNGUELTIGES_RECHNUNGSDATUM" + #: ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT, Z44 + ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT = "ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT" + #: RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS, Z45 + RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS = ( + "RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS" + ) + #: ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN, Z52 + ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN = "ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN" + #: RECHNUNGSABWICKLUNG_NICHT_VEREINBART, Z53 + RECHNUNGSABWICKLUNG_NICHT_VEREINBART = "RECHNUNGSABWICKLUNG_NICHT_VEREINBART" + #: COMDIS_WIRD_ABGELEHNT, Z63 + COMDIS_WIRD_ABGELEHNT = "COMDIS_WIRD_ABGELEHNT" diff --git a/src/bo4e/enum/avistyp.py b/src/bo4e/enum/avistyp.py new file mode 100644 index 000000000..36453c474 --- /dev/null +++ b/src/bo4e/enum/avistyp.py @@ -0,0 +1,9 @@ +"""Contains class 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 diff --git a/src/bo4e/enum/botyp.py b/src/bo4e/enum/botyp.py index 4b83d4de8..53d2b7ffb 100644 --- a/src/bo4e/enum/botyp.py +++ b/src/bo4e/enum/botyp.py @@ -10,6 +10,7 @@ class BoTyp(StrEnum): ANGEBOT = "ANGEBOT" ANSPRECHPARTNER = "ANSPRECHPARTNER" AUSSCHREIBUNG = "AUSSCHREIUNG" + AVIS = "AVIS" BUENDELVERTRAG = "BUENDELVERTRAG" ENERGIEMENGE = "ENERGIEMENGE" FREMDKOSTEN = "FREMDKOSTEN" diff --git a/tests/test_abweichung.py b/tests/test_abweichung.py new file mode 100644 index 000000000..fd279478b --- /dev/null +++ b/tests/test_abweichung.py @@ -0,0 +1,55 @@ +# todo: cf. alias_generator=camelize in geschaeftsobjekte.py +from typing import Any, Dict + +import pytest + +from bo4e.com.abweichung import Abweichung +from bo4e.enum.abweichungsgrund import Abweichungsgrund +from tests.serialization_helper import assert_serialization_roundtrip + +#: create full example +example_abweichung = Abweichung( + abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="4580112", + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", +) + + +class Test_Abweichung: + @pytest.mark.parametrize( + "abweichung, expected_json_dict", + [ + pytest.param( + example_abweichung, + { + "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + "abweichungsgrundBemerkung": "sonst", + "zugehoerigeRechnung": "458011", + "abschlagsrechnung": "4580112", + "abweichungsgrundCode": "14", + "abweichungsgrundCodeliste": "G_0081", + }, + id="max param test", + ), + pytest.param( + Abweichung(), + { + "abweichungsgrund": None, + "abweichungsgrundBemerkung": None, + "zugehoerigeRechnung": None, + "abschlagsrechnung": None, + "abweichungsgrundCode": None, + "abweichungsgrundCodeliste": None, + }, + id="min param test", + ), + ], + ) + def test_serialization_roundtrip(self, abweichung: Abweichung, expected_json_dict: Dict[str, Any]) -> None: + """ + Test de-/serialisation of Abweichung with minimal attributes. + """ + assert_serialization_roundtrip(abweichung, expected_json_dict) diff --git a/tests/test_abweichungsposition.py b/tests/test_abweichungsposition.py new file mode 100644 index 000000000..4f050b97b --- /dev/null +++ b/tests/test_abweichungsposition.py @@ -0,0 +1,53 @@ +# todo: cf. alias_generator=camelize in geschaeftsobjekte.py +from typing import Any, Dict + +import pytest + +from bo4e.com.abweichungsposition import Abweichungsposition +from tests.serialization_helper import assert_serialization_roundtrip + +#: full example +example_abweichungsposition = Abweichungsposition( + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", + abweichungsgrund_bemerkung="Umsatzsteuersatz", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", +) + + +class TestAbweichungsposition: + @pytest.mark.parametrize( + "abweichungsposition, expected_json_dict", + [ + pytest.param( + example_abweichungsposition, + { + "abweichungsgrundCode": "14", + "abweichungsgrundCodeliste": "G_0081", + "abweichungsgrundBemerkung": "Umsatzsteuersatz", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo", + }, + id="max param test", + ), + pytest.param( + Abweichungsposition(), + { + "abweichungsgrundCode": None, + "abweichungsgrundCodeliste": None, + "abweichungsgrundBemerkung": None, + "zugehoerigeRechnung": None, + "zugehoerigeBestellung": None, + }, + id="min param test", + ), + ], + ) + def test_serialization_roundtrip( + self, abweichungsposition: Abweichungsposition, expected_json_dict: Dict[str, Any] + ) -> None: + """ + Test de-/serialisation of Abweichungsposition with minimal attributes. + """ + assert_serialization_roundtrip(abweichungsposition, expected_json_dict) diff --git a/tests/test_avis.py b/tests/test_avis.py new file mode 100644 index 000000000..13b8c30d8 --- /dev/null +++ b/tests/test_avis.py @@ -0,0 +1,323 @@ +from datetime import datetime +from typing import Any, Dict + +import pytest +from _decimal import Decimal + +from bo4e.bo.avis import Avis +from bo4e.com.abweichung import Abweichung +from bo4e.com.abweichungsposition import Abweichungsposition +from bo4e.com.avisposition import Avisposition +from bo4e.com.betrag import Betrag +from bo4e.com.rueckmeldungsposition import Rueckmeldungsposition +from bo4e.enum.abweichungsgrund import Abweichungsgrund +from bo4e.enum.avistyp import AvisTyp +from bo4e.enum.botyp import BoTyp +from bo4e.enum.waehrungscode import Waehrungscode +from tests.serialization_helper import assert_serialization_roundtrip + +#: full example +example_full_avis = Avis( + avis_nummer="2", + avis_typ=AvisTyp.ZAHLUNGSAVIS, + positionen=[ + Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ist_selbstausgestellt=True, + referenz="foo1", + abweichungen=[ + Abweichung( + abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="4580112", + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", + ), + Abweichung( + abweichungsgrund=Abweichungsgrund.VORAUSBEZAHLTER_BETRAG_FALSCH, + abweichungsgrund_bemerkung="foo6", + zugehoerige_rechnung="foo7", + abschlagsrechnung="foo8", + abweichungsgrund_code="foo9", + abweichungsgrund_codeliste="foo0", + ), + ], + positionen=[ + Rueckmeldungsposition( + positionsnummer="1", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="foo11", + abweichungsgrund_codeliste="foo12", + abweichungsgrund_bemerkung="foo13", + zugehoerige_rechnung="foo14", + zugehoerige_bestellung="foo15", + ), + Abweichungsposition( + abweichungsgrund_code="foo21", + abweichungsgrund_codeliste="foo22", + abweichungsgrund_bemerkung="foo23", + zugehoerige_rechnung="foo24", + zugehoerige_bestellung="foo25", + ), + ], + ), + Rueckmeldungsposition( + positionsnummer="2", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="foo111", + abweichungsgrund_codeliste="foo112", + abweichungsgrund_bemerkung="foo113", + zugehoerige_rechnung="foo114", + zugehoerige_bestellung="foo115", + ), + Abweichungsposition( + abweichungsgrund_code="foo221", + abweichungsgrund_codeliste="foo222", + abweichungsgrund_bemerkung="foo223", + zugehoerige_rechnung="foo224", + zugehoerige_bestellung="foo225", + ), + ], + ), + ], + ), + Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ), + ], + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), +) +#: min example +example_min_avis = Avis( + avis_nummer="2", + avis_typ=AvisTyp.ZAHLUNGSAVIS, + positionen=[ + Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ), + Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ), + ], + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), +) + + +class TestAvis: + @pytest.mark.parametrize( + "avis, expected_json_dict", + [ + pytest.param( + example_full_avis, + { + "versionstruktur": "2", + "boTyp": BoTyp.AVIS, + "externeReferenzen": [], + "avisNummer": "2", + "avisTyp": AvisTyp.ZAHLUNGSAVIS, + "positionen": [ + { + "rechnungsNummer": "12345", + "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), + "istStorno": True, + "gesamtbrutto": { + "wert": Decimal(100.5), + "waehrung": Waehrungscode.EUR, + }, + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + "istSelbstausgestellt": True, + "referenz": "foo1", + "abweichungen": [ + { + "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + "abweichungsgrundBemerkung": "sonst", + "zugehoerigeRechnung": "458011", + "abschlagsrechnung": "4580112", + "abweichungsgrundCode": "14", + "abweichungsgrundCodeliste": "G_0081", + }, + { + "abweichungsgrund": Abweichungsgrund.VORAUSBEZAHLTER_BETRAG_FALSCH, + "abweichungsgrundBemerkung": "foo6", + "zugehoerigeRechnung": "foo7", + "abschlagsrechnung": "foo8", + "abweichungsgrundCode": "foo9", + "abweichungsgrundCodeliste": "foo0", + }, + ], + "positionen": [ + { + "positionsnummer": "1", + "abweichungspositionen": [ + { + "abweichungsgrundCode": "foo11", + "abweichungsgrundCodeliste": "foo12", + "abweichungsgrundBemerkung": "foo13", + "zugehoerigeRechnung": "foo14", + "zugehoerigeBestellung": "foo15", + }, + { + "abweichungsgrundCode": "foo21", + "abweichungsgrundCodeliste": "foo22", + "abweichungsgrundBemerkung": "foo23", + "zugehoerigeRechnung": "foo24", + "zugehoerigeBestellung": "foo25", + }, + ], + }, + { + "positionsnummer": "2", + "abweichungspositionen": [ + { + "abweichungsgrundCode": "foo111", + "abweichungsgrundCodeliste": "foo112", + "abweichungsgrundBemerkung": "foo113", + "zugehoerigeRechnung": "foo114", + "zugehoerigeBestellung": "foo115", + }, + { + "abweichungsgrundCode": "foo221", + "abweichungsgrundCodeliste": "foo222", + "abweichungsgrundBemerkung": "foo223", + "zugehoerigeRechnung": "foo224", + "zugehoerigeBestellung": "foo225", + }, + ], + }, + ], + }, + { + "rechnungsNummer": "12345", + "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), + "istStorno": True, + "gesamtbrutto": { + "wert": Decimal(100.5), + "waehrung": Waehrungscode.EUR, + }, + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + "istSelbstausgestellt": None, + "referenz": None, + "abweichungen": None, + "positionen": None, + }, + ], + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + }, + id="full param test", + ), + pytest.param( + example_min_avis, + { + "versionstruktur": "2", + "boTyp": BoTyp.AVIS, + "externeReferenzen": [], + "avisNummer": "2", + "avisTyp": AvisTyp.ZAHLUNGSAVIS, + "positionen": [ + { + "rechnungsNummer": "12345", + "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), + "istStorno": True, + "gesamtbrutto": { + "wert": Decimal(100.5), + "waehrung": Waehrungscode.EUR, + }, + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + "istSelbstausgestellt": None, + "referenz": None, + "abweichungen": None, + "positionen": None, + }, + { + "rechnungsNummer": "12345", + "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), + "istStorno": True, + "gesamtbrutto": { + "wert": Decimal(100.5), + "waehrung": Waehrungscode.EUR, + }, + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + "istSelbstausgestellt": None, + "referenz": None, + "abweichungen": None, + "positionen": None, + }, + ], + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + }, + id="min param test", + ), + ], + ) + def test_serialization_roundtrip(self, avis: Avis, expected_json_dict: Dict[str, Any]) -> None: + """ + Test de-/serialisation of Avis with minimal attributes. + """ + assert_serialization_roundtrip(avis, expected_json_dict) diff --git a/tests/test_avisposition.py b/tests/test_avisposition.py new file mode 100644 index 000000000..4aa54c1bb --- /dev/null +++ b/tests/test_avisposition.py @@ -0,0 +1,214 @@ +from datetime import datetime +from typing import Any, Dict + +import pytest +from _decimal import Decimal + +from bo4e.com.abweichung import Abweichung +from bo4e.com.abweichungsposition import Abweichungsposition +from bo4e.com.avisposition import Avisposition +from bo4e.com.betrag import Betrag +from bo4e.com.rueckmeldungsposition import Rueckmeldungsposition +from bo4e.enum.abweichungsgrund import Abweichungsgrund +from bo4e.enum.waehrungscode import Waehrungscode +from tests.serialization_helper import assert_serialization_roundtrip + +#: full example +example_full_avisposition = Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ist_selbstausgestellt=True, + referenz="1234", + abweichungen=[ + Abweichung( + abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="4580112", + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", + ), + Abweichung( + abweichungsgrund=Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="foo8", + abweichungsgrund_code="foo9", + abweichungsgrund_codeliste="foo0", + ), + ], + positionen=[ + Rueckmeldungsposition( + positionsnummer="1", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="foo11", + abweichungsgrund_codeliste="foo12", + abweichungsgrund_bemerkung="foo13", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo15", + ), + Abweichungsposition( + abweichungsgrund_code="foo21", + abweichungsgrund_codeliste="foo22", + abweichungsgrund_bemerkung="foo23", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo25", + ), + ], + ), + Rueckmeldungsposition( + positionsnummer="2", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="foo111", + abweichungsgrund_codeliste="foo112", + abweichungsgrund_bemerkung="foo113", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo115", + ), + Abweichungsposition( + abweichungsgrund_code="foo221", + abweichungsgrund_codeliste="foo222", + abweichungsgrund_bemerkung="foo223", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo225", + ), + ], + ), + ], +) + +example_min_avisposition = Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), +) + + +class TestAvisposition: + @pytest.mark.parametrize( + "avisposition, expected_json_dict", + [ + pytest.param( + example_full_avisposition, + { + "rechnungsNummer": "12345", + "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), + "istStorno": True, + "gesamtbrutto": { + "wert": Decimal(100.5), + "waehrung": Waehrungscode.EUR, + }, + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + "istSelbstausgestellt": True, + "referenz": "1234", + "abweichungen": [ + { + "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + "abweichungsgrundBemerkung": "sonst", + "zugehoerigeRechnung": "458011", + "abschlagsrechnung": "4580112", + "abweichungsgrundCode": "14", + "abweichungsgrundCodeliste": "G_0081", + }, + { + "abweichungsgrund": Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, + "abweichungsgrundBemerkung": "sonst", + "zugehoerigeRechnung": "458011", + "abschlagsrechnung": "foo8", + "abweichungsgrundCode": "foo9", + "abweichungsgrundCodeliste": "foo0", + }, + ], + "positionen": [ + { + "positionsnummer": "1", + "abweichungspositionen": [ + { + "abweichungsgrundCode": "foo11", + "abweichungsgrundCodeliste": "foo12", + "abweichungsgrundBemerkung": "foo13", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo15", + }, + { + "abweichungsgrundCode": "foo21", + "abweichungsgrundCodeliste": "foo22", + "abweichungsgrundBemerkung": "foo23", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo25", + }, + ], + }, + { + "positionsnummer": "2", + "abweichungspositionen": [ + { + "abweichungsgrundCode": "foo111", + "abweichungsgrundCodeliste": "foo112", + "abweichungsgrundBemerkung": "foo113", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo115", + }, + { + "abweichungsgrundCode": "foo221", + "abweichungsgrundCodeliste": "foo222", + "abweichungsgrundBemerkung": "foo223", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo225", + }, + ], + }, + ], + }, + id="max param test", + ), + pytest.param( + example_min_avisposition, + { + "rechnungsNummer": "12345", + "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), + "istStorno": True, + "gesamtbrutto": { + "wert": Decimal(100.5), + "waehrung": Waehrungscode.EUR, + }, + "zuZahlen": { + "wert": Decimal(15.5), + "waehrung": Waehrungscode.EUR, + }, + "istSelbstausgestellt": None, + "referenz": None, + "abweichungen": None, + "positionen": None, + }, + id="min param test", + ), + ], + ) + def test_serialization_roundtrip(self, avisposition: Avisposition, expected_json_dict: Dict[str, Any]) -> None: + """ + Test de-/serialisation of Avisposition with minimal attributes. + """ + assert_serialization_roundtrip(avisposition, expected_json_dict) diff --git a/tests/test_rueckmeldungsposition.py b/tests/test_rueckmeldungsposition.py new file mode 100644 index 000000000..3682945a8 --- /dev/null +++ b/tests/test_rueckmeldungsposition.py @@ -0,0 +1,100 @@ +# todo: cf. alias_generator=camelize in geschaeftsobjekte.py +from typing import Any, Dict + +import pytest +from pydantic import ValidationError + +from bo4e.com.abweichungsposition import Abweichungsposition +from bo4e.com.rueckmeldungsposition import Rueckmeldungsposition +from tests.serialization_helper import assert_serialization_roundtrip + +#: full example +example_rueckmeldungsposition = Rueckmeldungsposition( + positionsnummer="1", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="A15", + abweichungsgrund_codeliste="E_0210", + abweichungsgrund_bemerkung="Umsatzsteuersatz", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ), + Abweichungsposition( + abweichungsgrund_code="A16", + abweichungsgrund_codeliste="E_0210", + abweichungsgrund_bemerkung="Preisschlüsselstamm", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ), + ], +) + + +class TestRueckmeldungsposition: + @pytest.mark.parametrize( + "rueckmeldungsposition, expected_json_dict", + [ + pytest.param( + example_rueckmeldungsposition, + { + "positionsnummer": "1", + "abweichungspositionen": [ + { + "abweichungsgrundCode": "A15", + "abweichungsgrundCodeliste": "E_0210", + "abweichungsgrundBemerkung": "Umsatzsteuersatz", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo", + }, + { + "abweichungsgrundCode": "A16", + "abweichungsgrundCodeliste": "E_0210", + "abweichungsgrundBemerkung": "Preisschlüsselstamm", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo", + }, + ], + }, + id="max param test", + ), + pytest.param( + Rueckmeldungsposition(), + { + "positionsnummer": None, + "abweichungspositionen": None, + }, + id="min param test", + ), + ], + ) + def test_serialization_roundtrip( + self, rueckmeldungsposition: Rueckmeldungsposition, expected_json_dict: Dict[str, Any] + ) -> None: + """ + Test de-/serialisation of Rueckmeldungsposition with minimal attributes. + """ + assert_serialization_roundtrip(rueckmeldungsposition, expected_json_dict) + + def test_required_field_combinations(self) -> None: + """ + Test different Rueckmeldungspositionen. + If one field is given the other is required as well. + """ + # todo: is this useful? + with pytest.raises(ValidationError) as excinfo: + _ = Rueckmeldungsposition(positionsnummer="1") + assert "1 validation error" in str(excinfo.value) + + with pytest.raises(ValidationError) as excinfo: + _ = Rueckmeldungsposition( + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="A15", + abweichungsgrund_codeliste="E_0210", + abweichungsgrund_bemerkung="Umsatzsteuersatz", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ) + ] + ) + assert "1 validation error" in str(excinfo.value) From b4c2a0fdc74daafd458083415e50012be190e2e6 Mon Sep 17 00:00:00 2001 From: hf-ddernbach Date: Wed, 23 Aug 2023 11:24:01 +0200 Subject: [PATCH 02/11] :construction: added further testing --- src/bo4e/enum/abweichungsgrund.py | 2 +- src/bo4e/enum/avistyp.py | 2 +- tests/test_avis.py | 151 ++++++++++++------------------ tests/test_avisposition.py | 83 ++++++++-------- 4 files changed, 99 insertions(+), 139 deletions(-) diff --git a/src/bo4e/enum/abweichungsgrund.py b/src/bo4e/enum/abweichungsgrund.py index 9bbdbb0f7..9a04077ba 100644 --- a/src/bo4e/enum/abweichungsgrund.py +++ b/src/bo4e/enum/abweichungsgrund.py @@ -1,4 +1,4 @@ -"""contains class Abweichungsgrund.""" +"""contains enum class Abweichungsgrund.""" from bo4e.enum.strenum import StrEnum diff --git a/src/bo4e/enum/avistyp.py b/src/bo4e/enum/avistyp.py index 36453c474..b6d1692b8 100644 --- a/src/bo4e/enum/avistyp.py +++ b/src/bo4e/enum/avistyp.py @@ -1,4 +1,4 @@ -"""Contains class Avisposition""" +"""Contains enum class Avisposition""" from bo4e.enum.strenum import StrEnum diff --git a/tests/test_avis.py b/tests/test_avis.py index 13b8c30d8..e789faf08 100644 --- a/tests/test_avis.py +++ b/tests/test_avis.py @@ -3,6 +3,7 @@ import pytest from _decimal import Decimal +from pydantic import ValidationError from bo4e.bo.avis import Avis from bo4e.com.abweichung import Abweichung @@ -18,7 +19,7 @@ #: full example example_full_avis = Avis( - avis_nummer="2", + avis_nummer="654321", avis_typ=AvisTyp.ZAHLUNGSAVIS, positionen=[ Avisposition( @@ -34,7 +35,7 @@ waehrung=Waehrungscode.EUR, ), ist_selbstausgestellt=True, - referenz="foo1", + referenz="1234", abweichungen=[ Abweichung( abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, @@ -45,12 +46,12 @@ abweichungsgrund_codeliste="G_0081", ), Abweichung( - abweichungsgrund=Abweichungsgrund.VORAUSBEZAHLTER_BETRAG_FALSCH, - abweichungsgrund_bemerkung="foo6", - zugehoerige_rechnung="foo7", - abschlagsrechnung="foo8", - abweichungsgrund_code="foo9", - abweichungsgrund_codeliste="foo0", + abweichungsgrund=Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="4580112", + abweichungsgrund_code="28", + abweichungsgrund_codeliste="G_0081", ), ], positionen=[ @@ -58,18 +59,18 @@ positionsnummer="1", abweichungspositionen=[ Abweichungsposition( - abweichungsgrund_code="foo11", - abweichungsgrund_codeliste="foo12", - abweichungsgrund_bemerkung="foo13", - zugehoerige_rechnung="foo14", - zugehoerige_bestellung="foo15", + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", ), Abweichungsposition( - abweichungsgrund_code="foo21", - abweichungsgrund_codeliste="foo22", - abweichungsgrund_bemerkung="foo23", - zugehoerige_rechnung="foo24", - zugehoerige_bestellung="foo25", + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", ), ], ), @@ -77,18 +78,11 @@ positionsnummer="2", abweichungspositionen=[ Abweichungsposition( - abweichungsgrund_code="foo111", - abweichungsgrund_codeliste="foo112", - abweichungsgrund_bemerkung="foo113", - zugehoerige_rechnung="foo114", - zugehoerige_bestellung="foo115", - ), - Abweichungsposition( - abweichungsgrund_code="foo221", - abweichungsgrund_codeliste="foo222", - abweichungsgrund_bemerkung="foo223", - zugehoerige_rechnung="foo224", - zugehoerige_bestellung="foo225", + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", ), ], ), @@ -115,7 +109,7 @@ ) #: min example example_min_avis = Avis( - avis_nummer="2", + avis_nummer="654321", avis_typ=AvisTyp.ZAHLUNGSAVIS, positionen=[ Avisposition( @@ -130,20 +124,7 @@ wert=Decimal(15.5), waehrung=Waehrungscode.EUR, ), - ), - Avisposition( - rechnungs_nummer="12345", - rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), - ist_storno=True, - gesamtbrutto=Betrag( - wert=Decimal(100.5), - waehrung=Waehrungscode.EUR, - ), - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), - ), + ) ], zu_zahlen=Betrag( wert=Decimal(15.5), @@ -162,7 +143,7 @@ class TestAvis: "versionstruktur": "2", "boTyp": BoTyp.AVIS, "externeReferenzen": [], - "avisNummer": "2", + "avisNummer": "654321", "avisTyp": AvisTyp.ZAHLUNGSAVIS, "positionen": [ { @@ -178,7 +159,7 @@ class TestAvis: "waehrung": Waehrungscode.EUR, }, "istSelbstausgestellt": True, - "referenz": "foo1", + "referenz": "1234", "abweichungen": [ { "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, @@ -189,12 +170,12 @@ class TestAvis: "abweichungsgrundCodeliste": "G_0081", }, { - "abweichungsgrund": Abweichungsgrund.VORAUSBEZAHLTER_BETRAG_FALSCH, - "abweichungsgrundBemerkung": "foo6", - "zugehoerigeRechnung": "foo7", - "abschlagsrechnung": "foo8", - "abweichungsgrundCode": "foo9", - "abweichungsgrundCodeliste": "foo0", + "abweichungsgrund": Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, + "abweichungsgrundBemerkung": "sonst", + "zugehoerigeRechnung": "458011", + "abschlagsrechnung": "4580112", + "abweichungsgrundCode": "28", + "abweichungsgrundCodeliste": "G_0081", }, ], "positionen": [ @@ -202,18 +183,18 @@ class TestAvis: "positionsnummer": "1", "abweichungspositionen": [ { - "abweichungsgrundCode": "foo11", - "abweichungsgrundCodeliste": "foo12", - "abweichungsgrundBemerkung": "foo13", - "zugehoerigeRechnung": "foo14", - "zugehoerigeBestellung": "foo15", + "abweichungsgrundCode": "foo", + "abweichungsgrundCodeliste": "foo", + "abweichungsgrundBemerkung": "foo", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo", }, { - "abweichungsgrundCode": "foo21", - "abweichungsgrundCodeliste": "foo22", - "abweichungsgrundBemerkung": "foo23", - "zugehoerigeRechnung": "foo24", - "zugehoerigeBestellung": "foo25", + "abweichungsgrundCode": "foo", + "abweichungsgrundCodeliste": "foo", + "abweichungsgrundBemerkung": "foo", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo", }, ], }, @@ -221,18 +202,11 @@ class TestAvis: "positionsnummer": "2", "abweichungspositionen": [ { - "abweichungsgrundCode": "foo111", - "abweichungsgrundCodeliste": "foo112", - "abweichungsgrundBemerkung": "foo113", - "zugehoerigeRechnung": "foo114", - "zugehoerigeBestellung": "foo115", - }, - { - "abweichungsgrundCode": "foo221", - "abweichungsgrundCodeliste": "foo222", - "abweichungsgrundBemerkung": "foo223", - "zugehoerigeRechnung": "foo224", - "zugehoerigeBestellung": "foo225", + "abweichungsgrundCode": "foo", + "abweichungsgrundCodeliste": "foo", + "abweichungsgrundBemerkung": "foo", + "zugehoerigeRechnung": "458011", + "zugehoerigeBestellung": "foo", }, ], }, @@ -269,7 +243,7 @@ class TestAvis: "versionstruktur": "2", "boTyp": BoTyp.AVIS, "externeReferenzen": [], - "avisNummer": "2", + "avisNummer": "654321", "avisTyp": AvisTyp.ZAHLUNGSAVIS, "positionen": [ { @@ -289,23 +263,6 @@ class TestAvis: "abweichungen": None, "positionen": None, }, - { - "rechnungsNummer": "12345", - "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), - "istStorno": True, - "gesamtbrutto": { - "wert": Decimal(100.5), - "waehrung": Waehrungscode.EUR, - }, - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - "istSelbstausgestellt": None, - "referenz": None, - "abweichungen": None, - "positionen": None, - }, ], "zuZahlen": { "wert": Decimal(15.5), @@ -321,3 +278,11 @@ def test_serialization_roundtrip(self, avis: Avis, expected_json_dict: Dict[str, Test de-/serialisation of Avis with minimal attributes. """ assert_serialization_roundtrip(avis, expected_json_dict) + + def test_missing_required_attribute(self) -> None: + """ + Check if missing required attributes are identified correctly + """ + with pytest.raises(ValidationError) as excinfo: + _ = Avis() # type: ignore[call-arg] + assert "4 validation errors" in str(excinfo.value) diff --git a/tests/test_avisposition.py b/tests/test_avisposition.py index 4aa54c1bb..8bf274e5c 100644 --- a/tests/test_avisposition.py +++ b/tests/test_avisposition.py @@ -3,6 +3,7 @@ import pytest from _decimal import Decimal +from pydantic import ValidationError from bo4e.com.abweichung import Abweichung from bo4e.com.abweichungsposition import Abweichungsposition @@ -41,9 +42,9 @@ abweichungsgrund=Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, abweichungsgrund_bemerkung="sonst", zugehoerige_rechnung="458011", - abschlagsrechnung="foo8", - abweichungsgrund_code="foo9", - abweichungsgrund_codeliste="foo0", + abschlagsrechnung="4580112", + abweichungsgrund_code="28", + abweichungsgrund_codeliste="G_0081", ), ], positionen=[ @@ -51,18 +52,18 @@ positionsnummer="1", abweichungspositionen=[ Abweichungsposition( - abweichungsgrund_code="foo11", - abweichungsgrund_codeliste="foo12", - abweichungsgrund_bemerkung="foo13", + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo15", + zugehoerige_bestellung="foo", ), Abweichungsposition( - abweichungsgrund_code="foo21", - abweichungsgrund_codeliste="foo22", - abweichungsgrund_bemerkung="foo23", + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo25", + zugehoerige_bestellung="foo", ), ], ), @@ -70,18 +71,11 @@ positionsnummer="2", abweichungspositionen=[ Abweichungsposition( - abweichungsgrund_code="foo111", - abweichungsgrund_codeliste="foo112", - abweichungsgrund_bemerkung="foo113", + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo115", - ), - Abweichungsposition( - abweichungsgrund_code="foo221", - abweichungsgrund_codeliste="foo222", - abweichungsgrund_bemerkung="foo223", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo225", + zugehoerige_bestellung="foo", ), ], ), @@ -136,9 +130,9 @@ class TestAvisposition: "abweichungsgrund": Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, "abweichungsgrundBemerkung": "sonst", "zugehoerigeRechnung": "458011", - "abschlagsrechnung": "foo8", - "abweichungsgrundCode": "foo9", - "abweichungsgrundCodeliste": "foo0", + "abschlagsrechnung": "4580112", + "abweichungsgrundCode": "28", + "abweichungsgrundCodeliste": "G_0081", }, ], "positionen": [ @@ -146,18 +140,18 @@ class TestAvisposition: "positionsnummer": "1", "abweichungspositionen": [ { - "abweichungsgrundCode": "foo11", - "abweichungsgrundCodeliste": "foo12", - "abweichungsgrundBemerkung": "foo13", + "abweichungsgrundCode": "foo", + "abweichungsgrundCodeliste": "foo", + "abweichungsgrundBemerkung": "foo", "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo15", + "zugehoerigeBestellung": "foo", }, { - "abweichungsgrundCode": "foo21", - "abweichungsgrundCodeliste": "foo22", - "abweichungsgrundBemerkung": "foo23", + "abweichungsgrundCode": "foo", + "abweichungsgrundCodeliste": "foo", + "abweichungsgrundBemerkung": "foo", "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo25", + "zugehoerigeBestellung": "foo", }, ], }, @@ -165,18 +159,11 @@ class TestAvisposition: "positionsnummer": "2", "abweichungspositionen": [ { - "abweichungsgrundCode": "foo111", - "abweichungsgrundCodeliste": "foo112", - "abweichungsgrundBemerkung": "foo113", + "abweichungsgrundCode": "foo", + "abweichungsgrundCodeliste": "foo", + "abweichungsgrundBemerkung": "foo", "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo115", - }, - { - "abweichungsgrundCode": "foo221", - "abweichungsgrundCodeliste": "foo222", - "abweichungsgrundBemerkung": "foo223", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo225", + "zugehoerigeBestellung": "foo", }, ], }, @@ -212,3 +199,11 @@ def test_serialization_roundtrip(self, avisposition: Avisposition, expected_json Test de-/serialisation of Avisposition with minimal attributes. """ assert_serialization_roundtrip(avisposition, expected_json_dict) + + def test_missing_required_attribute(self) -> None: + """ + Check if missing required attributes are identified correctly + """ + with pytest.raises(ValidationError) as excinfo: + _ = Avisposition() # type: ignore[call-arg] + assert "5 validation errors" in str(excinfo.value) From 03a1976c47cc28c42c8e892870035afb636d86cf Mon Sep 17 00:00:00 2001 From: hf-ddernbach Date: Wed, 23 Aug 2023 15:47:52 +0200 Subject: [PATCH 03/11] :bulb: Updated comments/documentation --- src/bo4e/enum/abweichungsgrund.py | 2 +- src/bo4e/enum/avistyp.py | 2 +- tests/test_abweichung.py | 2 +- tests/test_abweichungsposition.py | 2 +- tests/test_avis.py | 1 + tests/test_avisposition.py | 1 + tests/test_rueckmeldungsposition.py | 2 +- 7 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bo4e/enum/abweichungsgrund.py b/src/bo4e/enum/abweichungsgrund.py index 9a04077ba..7b2418a05 100644 --- a/src/bo4e/enum/abweichungsgrund.py +++ b/src/bo4e/enum/abweichungsgrund.py @@ -1,4 +1,4 @@ -"""contains enum class Abweichungsgrund.""" +"""Contains Enums for Abweichungsgrund.""" from bo4e.enum.strenum import StrEnum diff --git a/src/bo4e/enum/avistyp.py b/src/bo4e/enum/avistyp.py index b6d1692b8..f36b77f43 100644 --- a/src/bo4e/enum/avistyp.py +++ b/src/bo4e/enum/avistyp.py @@ -1,4 +1,4 @@ -"""Contains enum class Avisposition""" +"""Contains Enums for Avisposition""" from bo4e.enum.strenum import StrEnum diff --git a/tests/test_abweichung.py b/tests/test_abweichung.py index fd279478b..57b60ccc2 100644 --- a/tests/test_abweichung.py +++ b/tests/test_abweichung.py @@ -1,4 +1,4 @@ -# todo: cf. alias_generator=camelize in geschaeftsobjekte.py +# todo: check camelizing from typing import Any, Dict import pytest diff --git a/tests/test_abweichungsposition.py b/tests/test_abweichungsposition.py index 4f050b97b..7f900473a 100644 --- a/tests/test_abweichungsposition.py +++ b/tests/test_abweichungsposition.py @@ -1,4 +1,4 @@ -# todo: cf. alias_generator=camelize in geschaeftsobjekte.py +# todo: check camelizing from typing import Any, Dict import pytest diff --git a/tests/test_avis.py b/tests/test_avis.py index e789faf08..7e5964bc0 100644 --- a/tests/test_avis.py +++ b/tests/test_avis.py @@ -1,3 +1,4 @@ +# todo: check camelizing from datetime import datetime from typing import Any, Dict diff --git a/tests/test_avisposition.py b/tests/test_avisposition.py index 8bf274e5c..0deaee7be 100644 --- a/tests/test_avisposition.py +++ b/tests/test_avisposition.py @@ -1,3 +1,4 @@ +# todo: check camelizing from datetime import datetime from typing import Any, Dict diff --git a/tests/test_rueckmeldungsposition.py b/tests/test_rueckmeldungsposition.py index 3682945a8..ca400c5b9 100644 --- a/tests/test_rueckmeldungsposition.py +++ b/tests/test_rueckmeldungsposition.py @@ -1,4 +1,4 @@ -# todo: cf. alias_generator=camelize in geschaeftsobjekte.py +# todo: check camelizing from typing import Any, Dict import pytest From d902be80dfd5da82cefb92da38fe875321c98700 Mon Sep 17 00:00:00 2001 From: hf-ddernbach Date: Wed, 23 Aug 2023 15:57:18 +0200 Subject: [PATCH 04/11] Changed parameters for testing --- tests/test_avis.py | 84 ----------------------------- tests/test_avisposition.py | 54 ------------------- tests/test_rueckmeldungsposition.py | 14 ----- 3 files changed, 152 deletions(-) diff --git a/tests/test_avis.py b/tests/test_avis.py index 7e5964bc0..d87f55183 100644 --- a/tests/test_avis.py +++ b/tests/test_avis.py @@ -46,37 +46,10 @@ abweichungsgrund_code="14", abweichungsgrund_codeliste="G_0081", ), - Abweichung( - abweichungsgrund=Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, - abweichungsgrund_bemerkung="sonst", - zugehoerige_rechnung="458011", - abschlagsrechnung="4580112", - abweichungsgrund_code="28", - abweichungsgrund_codeliste="G_0081", - ), ], positionen=[ Rueckmeldungsposition( positionsnummer="1", - abweichungspositionen=[ - Abweichungsposition( - abweichungsgrund_code="foo", - abweichungsgrund_codeliste="foo", - abweichungsgrund_bemerkung="foo", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - Abweichungsposition( - abweichungsgrund_code="foo", - abweichungsgrund_codeliste="foo", - abweichungsgrund_bemerkung="foo", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - ], - ), - Rueckmeldungsposition( - positionsnummer="2", abweichungspositionen=[ Abweichungsposition( abweichungsgrund_code="foo", @@ -89,19 +62,6 @@ ), ], ), - Avisposition( - rechnungs_nummer="12345", - rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), - ist_storno=True, - gesamtbrutto=Betrag( - wert=Decimal(100.5), - waehrung=Waehrungscode.EUR, - ), - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), - ), ], zu_zahlen=Betrag( wert=Decimal(15.5), @@ -170,37 +130,10 @@ class TestAvis: "abweichungsgrundCode": "14", "abweichungsgrundCodeliste": "G_0081", }, - { - "abweichungsgrund": Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, - "abweichungsgrundBemerkung": "sonst", - "zugehoerigeRechnung": "458011", - "abschlagsrechnung": "4580112", - "abweichungsgrundCode": "28", - "abweichungsgrundCodeliste": "G_0081", - }, ], "positionen": [ { "positionsnummer": "1", - "abweichungspositionen": [ - { - "abweichungsgrundCode": "foo", - "abweichungsgrundCodeliste": "foo", - "abweichungsgrundBemerkung": "foo", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, - { - "abweichungsgrundCode": "foo", - "abweichungsgrundCodeliste": "foo", - "abweichungsgrundBemerkung": "foo", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, - ], - }, - { - "positionsnummer": "2", "abweichungspositionen": [ { "abweichungsgrundCode": "foo", @@ -213,23 +146,6 @@ class TestAvis: }, ], }, - { - "rechnungsNummer": "12345", - "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), - "istStorno": True, - "gesamtbrutto": { - "wert": Decimal(100.5), - "waehrung": Waehrungscode.EUR, - }, - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - "istSelbstausgestellt": None, - "referenz": None, - "abweichungen": None, - "positionen": None, - }, ], "zuZahlen": { "wert": Decimal(15.5), diff --git a/tests/test_avisposition.py b/tests/test_avisposition.py index 0deaee7be..eebd6525a 100644 --- a/tests/test_avisposition.py +++ b/tests/test_avisposition.py @@ -39,37 +39,10 @@ abweichungsgrund_code="14", abweichungsgrund_codeliste="G_0081", ), - Abweichung( - abweichungsgrund=Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, - abweichungsgrund_bemerkung="sonst", - zugehoerige_rechnung="458011", - abschlagsrechnung="4580112", - abweichungsgrund_code="28", - abweichungsgrund_codeliste="G_0081", - ), ], positionen=[ Rueckmeldungsposition( positionsnummer="1", - abweichungspositionen=[ - Abweichungsposition( - abweichungsgrund_code="foo", - abweichungsgrund_codeliste="foo", - abweichungsgrund_bemerkung="foo", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - Abweichungsposition( - abweichungsgrund_code="foo", - abweichungsgrund_codeliste="foo", - abweichungsgrund_bemerkung="foo", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - ], - ), - Rueckmeldungsposition( - positionsnummer="2", abweichungspositionen=[ Abweichungsposition( abweichungsgrund_code="foo", @@ -127,37 +100,10 @@ class TestAvisposition: "abweichungsgrundCode": "14", "abweichungsgrundCodeliste": "G_0081", }, - { - "abweichungsgrund": Abweichungsgrund.SONSTIGER_ABWEICHUNGSGRUND, - "abweichungsgrundBemerkung": "sonst", - "zugehoerigeRechnung": "458011", - "abschlagsrechnung": "4580112", - "abweichungsgrundCode": "28", - "abweichungsgrundCodeliste": "G_0081", - }, ], "positionen": [ { "positionsnummer": "1", - "abweichungspositionen": [ - { - "abweichungsgrundCode": "foo", - "abweichungsgrundCodeliste": "foo", - "abweichungsgrundBemerkung": "foo", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, - { - "abweichungsgrundCode": "foo", - "abweichungsgrundCodeliste": "foo", - "abweichungsgrundBemerkung": "foo", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, - ], - }, - { - "positionsnummer": "2", "abweichungspositionen": [ { "abweichungsgrundCode": "foo", diff --git a/tests/test_rueckmeldungsposition.py b/tests/test_rueckmeldungsposition.py index ca400c5b9..18e6a3806 100644 --- a/tests/test_rueckmeldungsposition.py +++ b/tests/test_rueckmeldungsposition.py @@ -19,13 +19,6 @@ zugehoerige_rechnung="458011", zugehoerige_bestellung="foo", ), - Abweichungsposition( - abweichungsgrund_code="A16", - abweichungsgrund_codeliste="E_0210", - abweichungsgrund_bemerkung="Preisschlüsselstamm", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), ], ) @@ -46,13 +39,6 @@ class TestRueckmeldungsposition: "zugehoerigeRechnung": "458011", "zugehoerigeBestellung": "foo", }, - { - "abweichungsgrundCode": "A16", - "abweichungsgrundCodeliste": "E_0210", - "abweichungsgrundBemerkung": "Preisschlüsselstamm", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, ], }, id="max param test", From d4849408be054ef35d9544062cc3b881c7faeeec Mon Sep 17 00:00:00 2001 From: hf-ddernbach Date: Mon, 28 Aug 2023 15:17:34 +0200 Subject: [PATCH 05/11] :memo: removed todos --- tests/test_abweichung.py | 3 +-- tests/test_abweichungsposition.py | 3 +-- tests/test_avis.py | 3 +-- tests/test_avisposition.py | 3 +-- tests/test_rueckmeldungsposition.py | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/test_abweichung.py b/tests/test_abweichung.py index 57b60ccc2..d33ef280d 100644 --- a/tests/test_abweichung.py +++ b/tests/test_abweichung.py @@ -1,4 +1,3 @@ -# todo: check camelizing from typing import Any, Dict import pytest @@ -50,6 +49,6 @@ class Test_Abweichung: ) def test_serialization_roundtrip(self, abweichung: Abweichung, expected_json_dict: Dict[str, Any]) -> None: """ - Test de-/serialisation of Abweichung with minimal attributes. + Test de-/serialisation of Abweichung with maximal/minimal attributes. """ assert_serialization_roundtrip(abweichung, expected_json_dict) diff --git a/tests/test_abweichungsposition.py b/tests/test_abweichungsposition.py index 7f900473a..f291e8592 100644 --- a/tests/test_abweichungsposition.py +++ b/tests/test_abweichungsposition.py @@ -1,4 +1,3 @@ -# todo: check camelizing from typing import Any, Dict import pytest @@ -48,6 +47,6 @@ def test_serialization_roundtrip( self, abweichungsposition: Abweichungsposition, expected_json_dict: Dict[str, Any] ) -> None: """ - Test de-/serialisation of Abweichungsposition with minimal attributes. + Test de-/serialisation of Abweichungsposition with maximal/minimal attributes. """ assert_serialization_roundtrip(abweichungsposition, expected_json_dict) diff --git a/tests/test_avis.py b/tests/test_avis.py index d87f55183..8efc24be0 100644 --- a/tests/test_avis.py +++ b/tests/test_avis.py @@ -1,4 +1,3 @@ -# todo: check camelizing from datetime import datetime from typing import Any, Dict @@ -192,7 +191,7 @@ class TestAvis: ) def test_serialization_roundtrip(self, avis: Avis, expected_json_dict: Dict[str, Any]) -> None: """ - Test de-/serialisation of Avis with minimal attributes. + Test de-/serialisation of Avis with maximal/minimal attributes. """ assert_serialization_roundtrip(avis, expected_json_dict) diff --git a/tests/test_avisposition.py b/tests/test_avisposition.py index eebd6525a..77a0fa543 100644 --- a/tests/test_avisposition.py +++ b/tests/test_avisposition.py @@ -1,4 +1,3 @@ -# todo: check camelizing from datetime import datetime from typing import Any, Dict @@ -143,7 +142,7 @@ class TestAvisposition: ) def test_serialization_roundtrip(self, avisposition: Avisposition, expected_json_dict: Dict[str, Any]) -> None: """ - Test de-/serialisation of Avisposition with minimal attributes. + Test de-/serialisation of Avisposition with maximal/minimal attributes. """ assert_serialization_roundtrip(avisposition, expected_json_dict) diff --git a/tests/test_rueckmeldungsposition.py b/tests/test_rueckmeldungsposition.py index 18e6a3806..26beaac42 100644 --- a/tests/test_rueckmeldungsposition.py +++ b/tests/test_rueckmeldungsposition.py @@ -1,4 +1,3 @@ -# todo: check camelizing from typing import Any, Dict import pytest @@ -57,7 +56,7 @@ def test_serialization_roundtrip( self, rueckmeldungsposition: Rueckmeldungsposition, expected_json_dict: Dict[str, Any] ) -> None: """ - Test de-/serialisation of Rueckmeldungsposition with minimal attributes. + Test de-/serialisation of Rueckmeldungsposition with minimal/maximal attributes. """ assert_serialization_roundtrip(rueckmeldungsposition, expected_json_dict) From e1a87bbddcbf24fb3ca4198cf86f553d565a58ef Mon Sep 17 00:00:00 2001 From: hf-ddernbach Date: Mon, 28 Aug 2023 15:29:05 +0200 Subject: [PATCH 06/11] :memo: updated documentation --- src/bo4e/com/abweichung.py | 1 - src/bo4e/com/abweichungsposition.py | 2 - src/bo4e/com/avisposition.py | 2 - src/bo4e/com/rueckmeldungsposition.py | 5 +- src/bo4e/enum/abweichungsgrund.py | 76 ++++++++++----------------- src/bo4e/enum/avistyp.py | 4 +- 6 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/bo4e/com/abweichung.py b/src/bo4e/com/abweichung.py index 0cf70189a..72db2d7ff 100644 --- a/src/bo4e/com/abweichung.py +++ b/src/bo4e/com/abweichung.py @@ -8,7 +8,6 @@ class Abweichung(COM): """Zur Angabe einer Abweichung bei Ablehnung einer COMDIS. (REMADV SG5 RFF und SG7 AJT/FTX).""" - # optional attributes abweichungsgrund: Optional[Abweichungsgrund] = None #: Angabe Abweichungsgrund abweichungsgrund_bemerkung: Optional[str] = None #: Nähere Erläuterung zum Abweichungsgrund zugehoerige_rechnung: Optional[str] = None #: Zugehoerige Rechnung diff --git a/src/bo4e/com/abweichungsposition.py b/src/bo4e/com/abweichungsposition.py index f74c3d207..67a57c4ba 100644 --- a/src/bo4e/com/abweichungsposition.py +++ b/src/bo4e/com/abweichungsposition.py @@ -7,10 +7,8 @@ class Abweichungsposition(COM): """Zur Angabe einer Abweichung einer einzelnen Position.""" - # optional attributes 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 - # todo: prüfen, ob zugehörige Rechnung angegeben ist, wenn Abw.Grund gegeben? zugehoerige_rechnung: Optional[str] = None #: Zugehörige Rechnung zugehoerige_bestellung: Optional[str] = None #: Zugehörige Bestellung diff --git a/src/bo4e/com/avisposition.py b/src/bo4e/com/avisposition.py index 5e28bc8a6..f4d7b72f2 100644 --- a/src/bo4e/com/avisposition.py +++ b/src/bo4e/com/avisposition.py @@ -11,7 +11,6 @@ class Avisposition(COM): """Die Position eines Avis""" - # required attributes 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 @@ -19,7 +18,6 @@ class Avisposition(COM): gesamtbrutto: Betrag #: Überweisungsbetrag zu_zahlen: Betrag #: Geforderter Rechnungsbetrag - # optional attributes 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 diff --git a/src/bo4e/com/rueckmeldungsposition.py b/src/bo4e/com/rueckmeldungsposition.py index 20c8e1766..2b0ea5fc7 100644 --- a/src/bo4e/com/rueckmeldungsposition.py +++ b/src/bo4e/com/rueckmeldungsposition.py @@ -10,13 +10,14 @@ class Rueckmeldungsposition(COM): """Zur Angabe einer Rückmeldung einer einzelnen Position.""" - # optional attributes positionsnummer: Optional[str] = None #: Positionsnummer der Referenzierung abweichungspositionen: Optional[list[Abweichungsposition]] = None #: Abweichungspositionen - #: model validator for !XOR pos.nr. and abweichungspos. @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 ): diff --git a/src/bo4e/enum/abweichungsgrund.py b/src/bo4e/enum/abweichungsgrund.py index 7b2418a05..fb0b058fa 100644 --- a/src/bo4e/enum/abweichungsgrund.py +++ b/src/bo4e/enum/abweichungsgrund.py @@ -5,61 +5,41 @@ class Abweichungsgrund(StrEnum): """Gibt einen Abweichungsgrund bei Ablehung einer COMDIS an. (REMADV SG7 AJT 4465)""" - #: PREIS_RECHENREGEL_FALSCH, 5 - PREIS_RECHENREGEL_FALSCH = "PREIS_RECHENREGEL_FALSCH" - #: FALSCHER_ABRECHNUNGSZEITRAUM, 9 - FALSCHER_ABRECHNUNGSZEITRAUM = "FALSCHER_ABRECHNUNGSZEITRAUM" - #: UNBEKANNTE_MARKTLOKATION_MESSLOKATION, 14 + PREIS_RECHENREGEL_FALSCH = "PREIS_RECHENREGEL_FALSCH" #: PREIS_RECHENREGEL_FALSCH, 5 + FALSCHER_ABRECHNUNGSZEITRAUM = "FALSCHER_ABRECHNUNGSZEITRAUM" #: FALSCHER_ABRECHNUNGSZEITRAUM, 9 UNBEKANNTE_MARKTLOKATION_MESSLOKATION = "UNBEKANNTE_MARKTLOKATION_MESSLOKATION" - #: SONSTIGER_ABWEICHUNGSGRUND, 28 - SONSTIGER_ABWEICHUNGSGRUND = "SONSTIGER_ABWEICHUNGSGRUND" - #: DOPPELTE_RECHNUNG, 53 - DOPPELTE_RECHNUNG = "DOPPELTE_RECHNUNG" - #: ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN, Z01 + """UNBEKANNTE_MARKTLOKATION_MESSLOKATION, 14.""" + SONSTIGER_ABWEICHUNGSGRUND = "SONSTIGER_ABWEICHUNGSGRUND" #: SONSTIGER_ABWEICHUNGSGRUND, 28 + DOPPELTE_RECHNUNG = "DOPPELTE_RECHNUNG" #: DOPPELTE_RECHNUNG, 53 ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN = "ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN" - #: ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE, Z02 + """ABRECHNUNGSBEGINN_UNGLEICH_VERTRAGSBEGINN, Z01.""" ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE = "ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE" - #: BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH, Z03 + """ABRECHNUNGSENDE_UNGLEICH_VERTRAGSENDE, Z02.""" BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH = "BETRAG_DER_ABSCHLAGSRECHNUNG_FALSCH" - #: VORAUSBEZAHLTER_BETRAG_FALSCH, Z04 - VORAUSBEZAHLTER_BETRAG_FALSCH = "VORAUSBEZAHLTER_BETRAG_FALSCH" - #: ARTIKEL_NICHT_VEREINBART, Z06 - ARTIKEL_NICHT_VEREINBART = "ARTIKEL_NICHT_VEREINBART" - #: NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN, Z07 + "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" - #: RECHNUNGSNUMMER_BEREITS_ERHALTEN, Z08 - RECHNUNGSNUMMER_BEREITS_ERHALTEN = "RECHNUNGSNUMMER_BEREITS_ERHALTEN" - #: NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH, Z10 + """NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FEHLEN, Z07.""" + RECHNUNGSNUMMER_BEREITS_ERHALTEN = "RECHNUNGSNUMMER_BEREITS_ERHALTEN" #: RECHNUNGSNUMMER_BEREITS_ERHALTEN, Z08 NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH = "NETZNUTZUNGSMESSWERTE_ENERGIEMENGEN_FALSCH" - #: ZEITLICHE_MENGENANGABE_FEHLERHAFT, Z33 - ZEITLICHE_MENGENANGABE_FEHLERHAFT = "ZEITLICHE_MENGENANGABE_FEHLERHAFT" - #: FALSCHER_BILANZIERUNGSBEGINN, Z35 - FALSCHER_BILANZIERUNGSBEGINN = "FALSCHER_BILANZIERUNGSBEGINN" - #: FALSCHES_NETZNUTZUNGSENDE, Z36 - FALSCHES_NETZNUTZUNGSENDE = "FALSCHES_NETZNUTZUNGSENDE" - #: BILANZIERTE_MENGE_FEHLT, Z37 - BILANZIERTE_MENGE_FEHLT = "BILANZIERTE_MENGE_FEHLT" - #: BILANZIERTE_MENGE_FALSCH, Z38 - BILANZIERTE_MENGE_FALSCH = "BILANZIERTE_MENGE_FALSCH" - #: NETZNUTZUNGSABRECHNUNG_FEHLT, Z39 - NETZNUTZUNGSABRECHNUNG_FEHLT = "NETZNUTZUNGSABRECHNUNG_FEHLT" - #: REVERSE_CHARGE_ANWENDUNG_FEHLT_ODER_FEHLERHAFT, Z40 + """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" - #: ALLOKATIONSLISTE_FEHLT, Z41 - ALLOKATIONSLISTE_FEHLT = "ALLOKATIONSLISTE_FEHLT" - #: MEHR_MINDERMENGE_FALSCH, Z42 - MEHR_MINDERMENGE_FALSCH = "MEHR_MINDERMENGE_FALSCH" - #: UNGUELTIGES_RECHNUNGSDATUM, Z43 - UNGUELTIGES_RECHNUNGSDATUM = "UNGUELTIGES_RECHNUNGSDATUM" - #: ZEITINTERVALL_DER_BILANZIERTEN_MENGE_INKONSISTENT, Z44 + """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" - #: RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS, Z45 - RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS = ( - "RECHNUNGSEMPFAENGER_WIDERSPRICHT_DER_STEUERRECHTLICHEN_EINSCHAETZUNG_DES_RECHNUNGSSTELLERS" - ) - #: ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN, Z52 + "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" - #: RECHNUNGSABWICKLUNG_NICHT_VEREINBART, Z53 + """ANGEGEBENE_QUOTES_AN_MARKTLOKATION_NICHT_VORHANDEN, Z52.""" RECHNUNGSABWICKLUNG_NICHT_VEREINBART = "RECHNUNGSABWICKLUNG_NICHT_VEREINBART" - #: COMDIS_WIRD_ABGELEHNT, Z63 - COMDIS_WIRD_ABGELEHNT = "COMDIS_WIRD_ABGELEHNT" + """RECHNUNGSABWICKLUNG_NICHT_VEREINBART, Z53.""" + COMDIS_WIRD_ABGELEHNT = "COMDIS_WIRD_ABGELEHNT" #: COMDIS_WIRD_ABGELEHNT, Z63 diff --git a/src/bo4e/enum/avistyp.py b/src/bo4e/enum/avistyp.py index f36b77f43..276273c5d 100644 --- a/src/bo4e/enum/avistyp.py +++ b/src/bo4e/enum/avistyp.py @@ -5,5 +5,5 @@ class AvisTyp(StrEnum): """Gibt den Typ des Avis an. (REMADV BGM 1001).""" - ABGELEHNTE_FORDERUNG = "ABGELEHNTE_FORDERUNG" #: ABGELEHNTE_FORDERUNG - ZAHLUNGSAVIS = "ZAHLUNGSAVIS" #: ZAHLUNGSAVIS + ABGELEHNTE_FORDERUNG = "ABGELEHNTE_FORDERUNG" #: Abgelehnte Forderung + ZAHLUNGSAVIS = "ZAHLUNGSAVIS" #: Zahlungsavis From fe590a536110a01739c30c2c1bb40c79d08b6acc Mon Sep 17 00:00:00 2001 From: Franziska Date: Fri, 24 Nov 2023 21:45:58 +0100 Subject: [PATCH 07/11] Add Avis and its peers to init.py --- src/bo4e/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/bo4e/__init__.py b/src/bo4e/__init__.py index 3d132ae4a..dd43ab6d1 100644 --- a/src/bo4e/__init__.py +++ b/src/bo4e/__init__.py @@ -11,6 +11,7 @@ "Angebot", "Ansprechpartner", "Ausschreibung", + "Avis", "Buendelvertrag", "Energiemenge", "Fremdkosten", @@ -39,6 +40,8 @@ "Vertrag", "Zaehler", "Zeitreihe", + "Abweichung", + "Abweichungsposition", "Adresse", "Angebotsposition", "Angebotsteil", @@ -49,6 +52,7 @@ "AufAbschlagstaffelProOrt", "Ausschreibungsdetail", "Ausschreibungslos", + "Avisposition", "Betrag", "COM", "Dienstleistung", @@ -78,6 +82,7 @@ "RegionalerAufAbschlag", "RegionaleTarifpreisposition", "Regionskriterium", + "Rueckmeldungsposition", "Rufnummer", "Sigmoidparameter", "StandorteigenschaftenGas", @@ -101,6 +106,7 @@ "Zeitspanne", "Zustaendigkeit", "AbgabeArt", + "Abweichungsgrund", "Angebotsstatus", "Anrede", "ArithmetischeOperation", @@ -110,6 +116,7 @@ "Ausschreibungsportal", "Ausschreibungsstatus", "Ausschreibungstyp", + "AvisTyp", "BDEWArtikelnummer", "Befestigungsart", "Bemessungsgroesse", @@ -189,6 +196,7 @@ from .bo.angebot import Angebot from .bo.ansprechpartner import Ansprechpartner 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 @@ -219,6 +227,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 @@ -229,6 +239,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 @@ -258,6 +269,7 @@ from .com.regionaleraufabschlag import RegionalerAufAbschlag from .com.regionaletarifpreisposition import RegionaleTarifpreisposition from .com.regionskriterium import Regionskriterium +from .com.rueckmeldungsposition import Rueckmeldungsposition from .com.rufnummer import Rufnummer from .com.sigmoidparameter import Sigmoidparameter from .com.standorteigenschaftengas import StandorteigenschaftenGas @@ -283,6 +295,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 @@ -292,6 +305,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 From 05ae7b85ffae02d3588fe81dc70cb209dcbbf3f4 Mon Sep 17 00:00:00 2001 From: Franziska Date: Fri, 24 Nov 2023 21:46:36 +0100 Subject: [PATCH 08/11] Change from BOTyp to Typ --- src/bo4e/bo/avis.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bo4e/bo/avis.py b/src/bo4e/bo/avis.py index b92921401..e12c14793 100644 --- a/src/bo4e/bo/avis.py +++ b/src/bo4e/bo/avis.py @@ -1,17 +1,21 @@ """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 bo4e.enum.botyp import BoTyp + +from ..enum.typ import Typ class Avis(Geschaeftsobjekt): """Avis BO""" - bo_typ: BoTyp = BoTyp.AVIS # added to botyp.py + typ: Annotated[Optional[Typ], Field(alias="_typ")] = Typ.AVIS - #: required attributes 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 From ca3297d2a629af020fa2c9069875a709c276e7b5 Mon Sep 17 00:00:00 2001 From: Franziska Date: Fri, 24 Nov 2023 21:46:50 +0100 Subject: [PATCH 09/11] Adapt all tests --- tests/test_abweichung.py | 50 ++----- tests/test_abweichungsposition.py | 48 ++---- tests/test_avis.py | 221 ++++++---------------------- tests/test_avisposition.py | 168 +++++---------------- tests/test_rueckmeldungsposition.py | 58 ++------ 5 files changed, 126 insertions(+), 419 deletions(-) diff --git a/tests/test_abweichung.py b/tests/test_abweichung.py index d33ef280d..e282e2cbc 100644 --- a/tests/test_abweichung.py +++ b/tests/test_abweichung.py @@ -1,54 +1,28 @@ -from typing import Any, Dict - import pytest from bo4e.com.abweichung import Abweichung from bo4e.enum.abweichungsgrund import Abweichungsgrund from tests.serialization_helper import assert_serialization_roundtrip -#: create full example -example_abweichung = Abweichung( - abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, - abweichungsgrund_bemerkung="sonst", - zugehoerige_rechnung="458011", - abschlagsrechnung="4580112", - abweichungsgrund_code="14", - abweichungsgrund_codeliste="G_0081", -) - class Test_Abweichung: @pytest.mark.parametrize( - "abweichung, expected_json_dict", + "abweichung", [ pytest.param( - example_abweichung, - { - "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, - "abweichungsgrundBemerkung": "sonst", - "zugehoerigeRechnung": "458011", - "abschlagsrechnung": "4580112", - "abweichungsgrundCode": "14", - "abweichungsgrundCodeliste": "G_0081", - }, - id="max param test", - ), - pytest.param( - Abweichung(), - { - "abweichungsgrund": None, - "abweichungsgrundBemerkung": None, - "zugehoerigeRechnung": None, - "abschlagsrechnung": None, - "abweichungsgrundCode": None, - "abweichungsgrundCodeliste": None, - }, - id="min param test", + 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, expected_json_dict: Dict[str, Any]) -> None: + def test_serialization_roundtrip(self, abweichung: Abweichung) -> None: """ - Test de-/serialisation of Abweichung with maximal/minimal attributes. + Test de-/serialisation of Abweichung. """ - assert_serialization_roundtrip(abweichung, expected_json_dict) + assert_serialization_roundtrip(abweichung) diff --git a/tests/test_abweichungsposition.py b/tests/test_abweichungsposition.py index f291e8592..904afeb51 100644 --- a/tests/test_abweichungsposition.py +++ b/tests/test_abweichungsposition.py @@ -1,52 +1,26 @@ -from typing import Any, Dict - import pytest from bo4e.com.abweichungsposition import Abweichungsposition from tests.serialization_helper import assert_serialization_roundtrip -#: full example -example_abweichungsposition = Abweichungsposition( - abweichungsgrund_code="14", - abweichungsgrund_codeliste="G_0081", - abweichungsgrund_bemerkung="Umsatzsteuersatz", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", -) - class TestAbweichungsposition: @pytest.mark.parametrize( - "abweichungsposition, expected_json_dict", + "abweichungsposition", [ pytest.param( - example_abweichungsposition, - { - "abweichungsgrundCode": "14", - "abweichungsgrundCodeliste": "G_0081", - "abweichungsgrundBemerkung": "Umsatzsteuersatz", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, - id="max param test", - ), - pytest.param( - Abweichungsposition(), - { - "abweichungsgrundCode": None, - "abweichungsgrundCodeliste": None, - "abweichungsgrundBemerkung": None, - "zugehoerigeRechnung": None, - "zugehoerigeBestellung": None, - }, - id="min param test", + Abweichungsposition( + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", + abweichungsgrund_bemerkung="Umsatzsteuersatz", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ) ), ], ) - def test_serialization_roundtrip( - self, abweichungsposition: Abweichungsposition, expected_json_dict: Dict[str, Any] - ) -> None: + def test_serialization_roundtrip(self, abweichungsposition: Abweichungsposition) -> None: """ - Test de-/serialisation of Abweichungsposition with maximal/minimal attributes. + Test de-/serialisation of Abweichungsposition. """ - assert_serialization_roundtrip(abweichungsposition, expected_json_dict) + assert_serialization_roundtrip(abweichungsposition) diff --git a/tests/test_avis.py b/tests/test_avis.py index 8efc24be0..94165e2cb 100644 --- a/tests/test_avis.py +++ b/tests/test_avis.py @@ -1,9 +1,7 @@ from datetime import datetime -from typing import Any, Dict import pytest from _decimal import Decimal -from pydantic import ValidationError from bo4e.bo.avis import Avis from bo4e.com.abweichung import Abweichung @@ -13,192 +11,69 @@ from bo4e.com.rueckmeldungsposition import Rueckmeldungsposition from bo4e.enum.abweichungsgrund import Abweichungsgrund from bo4e.enum.avistyp import AvisTyp -from bo4e.enum.botyp import BoTyp from bo4e.enum.waehrungscode import Waehrungscode from tests.serialization_helper import assert_serialization_roundtrip -#: full example -example_full_avis = Avis( - avis_nummer="654321", - avis_typ=AvisTyp.ZAHLUNGSAVIS, - positionen=[ - Avisposition( - rechnungs_nummer="12345", - rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), - ist_storno=True, - gesamtbrutto=Betrag( - wert=Decimal(100.5), - waehrung=Waehrungscode.EUR, - ), - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), - ist_selbstausgestellt=True, - referenz="1234", - abweichungen=[ - Abweichung( - abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, - abweichungsgrund_bemerkung="sonst", - zugehoerige_rechnung="458011", - abschlagsrechnung="4580112", - abweichungsgrund_code="14", - abweichungsgrund_codeliste="G_0081", - ), - ], - positionen=[ - Rueckmeldungsposition( - positionsnummer="1", - abweichungspositionen=[ - Abweichungsposition( - abweichungsgrund_code="foo", - abweichungsgrund_codeliste="foo", - abweichungsgrund_bemerkung="foo", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - ], - ), - ], - ), - ], - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), -) -#: min example -example_min_avis = Avis( - avis_nummer="654321", - avis_typ=AvisTyp.ZAHLUNGSAVIS, - positionen=[ - Avisposition( - rechnungs_nummer="12345", - rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), - ist_storno=True, - gesamtbrutto=Betrag( - wert=Decimal(100.5), - waehrung=Waehrungscode.EUR, - ), - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), - ) - ], - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), -) - class TestAvis: @pytest.mark.parametrize( "avis, expected_json_dict", [ pytest.param( - example_full_avis, - { - "versionstruktur": "2", - "boTyp": BoTyp.AVIS, - "externeReferenzen": [], - "avisNummer": "654321", - "avisTyp": AvisTyp.ZAHLUNGSAVIS, - "positionen": [ - { - "rechnungsNummer": "12345", - "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), - "istStorno": True, - "gesamtbrutto": { - "wert": Decimal(100.5), - "waehrung": Waehrungscode.EUR, - }, - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - "istSelbstausgestellt": True, - "referenz": "1234", - "abweichungen": [ - { - "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, - "abweichungsgrundBemerkung": "sonst", - "zugehoerigeRechnung": "458011", - "abschlagsrechnung": "4580112", - "abweichungsgrundCode": "14", - "abweichungsgrundCodeliste": "G_0081", - }, + Avis( + avis_nummer="654321", + avis_typ=AvisTyp.ZAHLUNGSAVIS, + positionen=[ + Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ist_selbstausgestellt=True, + referenz="1234", + abweichungen=[ + Abweichung( + abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="4580112", + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", + ), ], - "positionen": [ - { - "positionsnummer": "1", - "abweichungspositionen": [ - { - "abweichungsgrundCode": "foo", - "abweichungsgrundCodeliste": "foo", - "abweichungsgrundBemerkung": "foo", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, + positionen=[ + Rueckmeldungsposition( + positionsnummer="1", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ), ], - }, + ), ], - }, - ], - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - }, - id="full param test", - ), - pytest.param( - example_min_avis, - { - "versionstruktur": "2", - "boTyp": BoTyp.AVIS, - "externeReferenzen": [], - "avisNummer": "654321", - "avisTyp": AvisTyp.ZAHLUNGSAVIS, - "positionen": [ - { - "rechnungsNummer": "12345", - "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), - "istStorno": True, - "gesamtbrutto": { - "wert": Decimal(100.5), - "waehrung": Waehrungscode.EUR, - }, - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - "istSelbstausgestellt": None, - "referenz": None, - "abweichungen": None, - "positionen": None, - }, + ), ], - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - }, - id="min param test", + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ) ), ], ) - def test_serialization_roundtrip(self, avis: Avis, expected_json_dict: Dict[str, Any]) -> None: - """ - Test de-/serialisation of Avis with maximal/minimal attributes. - """ - assert_serialization_roundtrip(avis, expected_json_dict) - - def test_missing_required_attribute(self) -> None: + def test_serialization_roundtrip(self, avis: Avis) -> None: """ - Check if missing required attributes are identified correctly + Test de-/serialisation of Avis. """ - with pytest.raises(ValidationError) as excinfo: - _ = Avis() # type: ignore[call-arg] - assert "4 validation errors" in str(excinfo.value) + assert_serialization_roundtrip(avis) diff --git a/tests/test_avisposition.py b/tests/test_avisposition.py index 77a0fa543..ad643986a 100644 --- a/tests/test_avisposition.py +++ b/tests/test_avisposition.py @@ -1,9 +1,7 @@ from datetime import datetime -from typing import Any, Dict import pytest from _decimal import Decimal -from pydantic import ValidationError from bo4e.com.abweichung import Abweichung from bo4e.com.abweichungsposition import Abweichungsposition @@ -14,142 +12,56 @@ from bo4e.enum.waehrungscode import Waehrungscode from tests.serialization_helper import assert_serialization_roundtrip -#: full example -example_full_avisposition = Avisposition( - rechnungs_nummer="12345", - rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), - ist_storno=True, - gesamtbrutto=Betrag( - wert=Decimal(100.5), - waehrung=Waehrungscode.EUR, - ), - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), - ist_selbstausgestellt=True, - referenz="1234", - abweichungen=[ - Abweichung( - abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, - abweichungsgrund_bemerkung="sonst", - zugehoerige_rechnung="458011", - abschlagsrechnung="4580112", - abweichungsgrund_code="14", - abweichungsgrund_codeliste="G_0081", - ), - ], - positionen=[ - Rueckmeldungsposition( - positionsnummer="1", - abweichungspositionen=[ - Abweichungsposition( - abweichungsgrund_code="foo", - abweichungsgrund_codeliste="foo", - abweichungsgrund_bemerkung="foo", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - ], - ), - ], -) - -example_min_avisposition = Avisposition( - rechnungs_nummer="12345", - rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), - ist_storno=True, - gesamtbrutto=Betrag( - wert=Decimal(100.5), - waehrung=Waehrungscode.EUR, - ), - zu_zahlen=Betrag( - wert=Decimal(15.5), - waehrung=Waehrungscode.EUR, - ), -) - class TestAvisposition: @pytest.mark.parametrize( - "avisposition, expected_json_dict", + "avisposition", [ pytest.param( - example_full_avisposition, - { - "rechnungsNummer": "12345", - "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), - "istStorno": True, - "gesamtbrutto": { - "wert": Decimal(100.5), - "waehrung": Waehrungscode.EUR, - }, - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - "istSelbstausgestellt": True, - "referenz": "1234", - "abweichungen": [ - { - "abweichungsgrund": Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, - "abweichungsgrundBemerkung": "sonst", - "zugehoerigeRechnung": "458011", - "abschlagsrechnung": "4580112", - "abweichungsgrundCode": "14", - "abweichungsgrundCodeliste": "G_0081", - }, + Avisposition( + rechnungs_nummer="12345", + rechnungs_datum=datetime(2022, 1, 1, 0, 0, 0), + ist_storno=True, + gesamtbrutto=Betrag( + wert=Decimal(100.5), + waehrung=Waehrungscode.EUR, + ), + zu_zahlen=Betrag( + wert=Decimal(15.5), + waehrung=Waehrungscode.EUR, + ), + ist_selbstausgestellt=True, + referenz="1234", + abweichungen=[ + Abweichung( + abweichungsgrund=Abweichungsgrund.UNBEKANNTE_MARKTLOKATION_MESSLOKATION, + abweichungsgrund_bemerkung="sonst", + zugehoerige_rechnung="458011", + abschlagsrechnung="4580112", + abweichungsgrund_code="14", + abweichungsgrund_codeliste="G_0081", + ), ], - "positionen": [ - { - "positionsnummer": "1", - "abweichungspositionen": [ - { - "abweichungsgrundCode": "foo", - "abweichungsgrundCodeliste": "foo", - "abweichungsgrundBemerkung": "foo", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, + positionen=[ + Rueckmeldungsposition( + positionsnummer="1", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="foo", + abweichungsgrund_codeliste="foo", + abweichungsgrund_bemerkung="foo", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ), ], - }, + ), ], - }, - id="max param test", - ), - pytest.param( - example_min_avisposition, - { - "rechnungsNummer": "12345", - "rechnungsDatum": datetime(2022, 1, 1, 0, 0, 0), - "istStorno": True, - "gesamtbrutto": { - "wert": Decimal(100.5), - "waehrung": Waehrungscode.EUR, - }, - "zuZahlen": { - "wert": Decimal(15.5), - "waehrung": Waehrungscode.EUR, - }, - "istSelbstausgestellt": None, - "referenz": None, - "abweichungen": None, - "positionen": None, - }, - id="min param test", + ) ), ], ) - def test_serialization_roundtrip(self, avisposition: Avisposition, expected_json_dict: Dict[str, Any]) -> None: - """ - Test de-/serialisation of Avisposition with maximal/minimal attributes. - """ - assert_serialization_roundtrip(avisposition, expected_json_dict) - - def test_missing_required_attribute(self) -> None: + def test_serialization_roundtrip(self, avisposition: Avisposition) -> None: """ - Check if missing required attributes are identified correctly + Test de-/serialisation of Avisposition. """ - with pytest.raises(ValidationError) as excinfo: - _ = Avisposition() # type: ignore[call-arg] - assert "5 validation errors" in str(excinfo.value) + assert_serialization_roundtrip(avisposition) diff --git a/tests/test_rueckmeldungsposition.py b/tests/test_rueckmeldungsposition.py index 26beaac42..5b2d82af4 100644 --- a/tests/test_rueckmeldungsposition.py +++ b/tests/test_rueckmeldungsposition.py @@ -1,5 +1,3 @@ -from typing import Any, Dict - import pytest from pydantic import ValidationError @@ -7,58 +5,32 @@ from bo4e.com.rueckmeldungsposition import Rueckmeldungsposition from tests.serialization_helper import assert_serialization_roundtrip -#: full example -example_rueckmeldungsposition = Rueckmeldungsposition( - positionsnummer="1", - abweichungspositionen=[ - Abweichungsposition( - abweichungsgrund_code="A15", - abweichungsgrund_codeliste="E_0210", - abweichungsgrund_bemerkung="Umsatzsteuersatz", - zugehoerige_rechnung="458011", - zugehoerige_bestellung="foo", - ), - ], -) - class TestRueckmeldungsposition: @pytest.mark.parametrize( - "rueckmeldungsposition, expected_json_dict", + "rueckmeldungsposition", [ pytest.param( - example_rueckmeldungsposition, - { - "positionsnummer": "1", - "abweichungspositionen": [ - { - "abweichungsgrundCode": "A15", - "abweichungsgrundCodeliste": "E_0210", - "abweichungsgrundBemerkung": "Umsatzsteuersatz", - "zugehoerigeRechnung": "458011", - "zugehoerigeBestellung": "foo", - }, + Rueckmeldungsposition( + positionsnummer="1", + abweichungspositionen=[ + Abweichungsposition( + abweichungsgrund_code="A15", + abweichungsgrund_codeliste="E_0210", + abweichungsgrund_bemerkung="Umsatzsteuersatz", + zugehoerige_rechnung="458011", + zugehoerige_bestellung="foo", + ), ], - }, - id="max param test", - ), - pytest.param( - Rueckmeldungsposition(), - { - "positionsnummer": None, - "abweichungspositionen": None, - }, - id="min param test", + ) ), ], ) - def test_serialization_roundtrip( - self, rueckmeldungsposition: Rueckmeldungsposition, expected_json_dict: Dict[str, Any] - ) -> None: + def test_serialization_roundtrip(self, rueckmeldungsposition: Rueckmeldungsposition) -> None: """ - Test de-/serialisation of Rueckmeldungsposition with minimal/maximal attributes. + Test de-/serialisation of Rueckmeldungsposition. """ - assert_serialization_roundtrip(rueckmeldungsposition, expected_json_dict) + assert_serialization_roundtrip(rueckmeldungsposition) def test_required_field_combinations(self) -> None: """ From 19f30344e589519f2595d8c18c277af131f5adb4 Mon Sep 17 00:00:00 2001 From: Franziska Date: Fri, 24 Nov 2023 21:49:07 +0100 Subject: [PATCH 10/11] Fix Avis test --- tests/test_avis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_avis.py b/tests/test_avis.py index 94165e2cb..063e630e4 100644 --- a/tests/test_avis.py +++ b/tests/test_avis.py @@ -17,7 +17,7 @@ class TestAvis: @pytest.mark.parametrize( - "avis, expected_json_dict", + "avis", [ pytest.param( Avis( From ae74b7b14ebdf796c9e8dd815b631fc0908fb441 Mon Sep 17 00:00:00 2001 From: DeltaDaniel Date: Tue, 30 Apr 2024 15:18:19 +0200 Subject: [PATCH 11/11] removed unused import --- src/bo4e/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bo4e/__init__.py b/src/bo4e/__init__.py index 0fadda74d..0bbf83b1c 100644 --- a/src/bo4e/__init__.py +++ b/src/bo4e/__init__.py @@ -272,7 +272,6 @@ from .com.regionaletarifpreisposition import RegionaleTarifpreisposition from .com.regionskriterium import Regionskriterium from .com.rueckmeldungsposition import Rueckmeldungsposition -from .com.rufnummer import Rufnummer from .com.sigmoidparameter import Sigmoidparameter from .com.standorteigenschaftengas import StandorteigenschaftenGas from .com.standorteigenschaftenstrom import StandorteigenschaftenStrom