Skip to content
Merged
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
26 changes: 17 additions & 9 deletions src/bo4e/bo/ansprechpartner.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,27 @@ class Ansprechpartner(Geschaeftsobjekt):

# required attributes
bo_typ: BoTyp = attr.ib(default=BoTyp.ANSPRECHPARTNER)
nachname: str
geschaeftspartner: Geschaeftspartner
nachname: str #: Nachname (Familienname) des Ansprechpartners
geschaeftspartner: Geschaeftspartner #: Der Geschäftspartner, für den dieser Ansprechpartner modelliert wird

# optional attributes
anrede: Anrede = attr.ib(default=None)
anrede: Anrede = attr.ib(default=None) #: Mögliche Anrede des Ansprechpartners
individuelle_anrede: str = attr.ib(default=None)
titel: Titel = attr.ib(default=None)
vorname: str = attr.ib(default=None)
e_mail_adresse: str = attr.ib(default=None)
kommentar: str = attr.ib(default=None)
"""
Im Falle einer nicht standardisierten Anrede kann hier eine frei definierbare Anrede vorgegeben werden.
Beispiel: "Sehr geehrte Frau MĂĽller, sehr geehrter Herr Dr. MĂĽller"
"""

titel: Titel = attr.ib(default=None) #: Möglicher Titel des Ansprechpartners
vorname: str = attr.ib(default=None) #: Vorname des Ansprechpartners
e_mail_adresse: str = attr.ib(default=None) #: E-Mail Adresse
kommentar: str = attr.ib(default=None) #: Weitere Informationen zum Ansprechpartner
#: Adresse des Ansprechpartners, falls diese von der Adresse des Geschäftspartners abweicht
adresse: Adresse = attr.ib(default=None)
rufnummer: Rufnummer = attr.ib(default=None)
zustaendigkeit: Zustaendigkeit = attr.ib(default=None)
#: Liste der Telefonnummern, unter denen der Ansprechpartner erreichbar ist
rufnummer: Rufnummer = attr.ib(default=None) # todo: make this a list and rename to rufnummern
#: Liste der Abteilungen und Zuständigkeiten des Ansprechpartners
zustaendigkeit: Zustaendigkeit = attr.ib(default=None) # todo: make this a list and rename to "zustaendigkeiten"


class AnsprechpartnerSchema(GeschaeftsobjektSchema):
Expand Down
12 changes: 7 additions & 5 deletions src/bo4e/bo/geschaeftsobjekt.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ def _create_empty_referenzen_list() -> List[ExterneReferenz]:


@attr.s(auto_attribs=True, kw_only=True)
class Geschaeftsobjekt:
class Geschaeftsobjekt: # Base class for all business objects
"""
Base class for all business objects
Das BO Geschäftsobjekt ist der Master für alle Geschäftsobjekte.
Alle Attribute, die hier in diesem BO enthalten sind, werden an alle BOs vererbt.
"""

# required attributes
versionstruktur: str = attr.ib(default="2")
bo_typ: BoTyp = attr.ib(default=BoTyp.GESCHAEFTSOBJEKT)
versionstruktur: str = attr.ib(default="2") #: Version der BO-Struktur aka "fachliche Versionierung"
bo_typ: BoTyp = attr.ib(default=BoTyp.GESCHAEFTSOBJEKT) #: Der Typ des Geschäftsobjektes
# bo_typ is used as discriminator f.e. for databases or deserialization

# optional attributes
externe_referenzen: Optional[List[ExterneReferenz]] = attr.ib(
default=_create_empty_referenzen_list(), validator=attr.validators.instance_of(List) # type:ignore[arg-type]
)
) #: Hier können IDs anderer Systeme hinterlegt werden (z.B. eine SAP-GP-Nummer oder eine GUID)


class GeschaeftsobjektSchema(CaseConverterSchema):
Expand Down
41 changes: 39 additions & 2 deletions src/bo4e/bo/geschaeftspartner.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,64 @@
@attr.s(auto_attribs=True, kw_only=True)
class Geschaeftspartner(Geschaeftsobjekt):
"""
Object containing information about a Geschaeftspartner
Mit diesem Objekt können Geschäftspartner übertragen werden.
Sowohl Unternehmen, als auch Privatpersonen können Geschäftspartner sein.
Hinweis: Marktteilnehmer haben ein eigenes BO, welches sich von diesem BO ableitet.
Hier sollte daher keine Zuordnung zu Marktrollen erfolgen.
"""

# required attributes
bo_typ: BoTyp = attr.ib(default=BoTyp.GESCHAEFTSPARTNER)
name1: str
"""
Erster Teil des Namens.
Hier kann der Firmenname oder bei Privatpersonen beispielsweise der Nachname dagestellt werden.
Beispiele: Yellow Strom GmbH oder Hagen
"""
# todo: replace name1/2/3 with something more readable. no one wants to deal with that. maybe serialize as name1/2/3
# but resolve to readable python fields under the hood

gewerbekennzeichnung: bool
"""
Kennzeichnung ob es sich um einen Gewerbe/Unternehmen (gewerbeKennzeichnung = true)
oder eine Privatperson handelt. (gewerbeKennzeichnung = false)
"""
#: Rollen, die die Geschäftspartner inne haben (z.B. Interessent, Kunde)
geschaeftspartnerrolle: List[Geschaeftspartnerrolle] = attr.ib(validator=attr.validators.instance_of(List))
# todo: rename to plural

# optional attributes
#: Die Anrede fĂĽr den GePa, Z.B. "Herr"
anrede: Anrede = attr.ib(default=None)
name2: Optional[str] = attr.ib(default=None)
"""
Zweiter Teil des Namens.
Hier kann der eine Erweiterung zum Firmennamen oder bei Privatpersonen beispielsweise der Vorname dagestellt werden.
Beispiele: Bereich SĂĽd oder Nina
"""

name3: Optional[str] = attr.ib(default=None)
"""
Dritter Teil des Namens.
Hier können weitere Ergänzungen zum Firmennamen oder bei Privatpersonen Zusätze zum Namen dagestellt werden.
Beispiele: und Afrika oder Sängerin
"""
#: Handelsregisternummer des Geschäftspartners
hrnummer: Optional[str] = attr.ib(default=None)
#: Amtsgericht bzw Handelsregistergericht, das die Handelsregisternummer herausgegeben hat
amtsgericht: Optional[str] = attr.ib(default=None)
#: Bevorzugte Kontaktwege des Geschäftspartners
kontaktweg: List[Kontaktart] = attr.ib(default=[])
#: Die Steuer-ID des Geschäftspartners; Beispiel: "DE 813281825"
umsatzsteuer_id: Optional[str] = attr.ib(default=None)
#: Die Gläubiger-ID welche im Zahlungsverkehr verwendet wird; Z.B. "DE 47116789"
glaeubiger_id: Optional[str] = attr.ib(default=None)
#: E-Mail-Adresse des Ansprechpartners. Z.B. "info@hochfrequenz.de"
e_mail_adresse: Optional[str] = attr.ib(default=None)
#: Internetseite des Marktpartners
website: Optional[str] = attr.ib(default=None)
partneradresse: Adresse = attr.ib(default=None)
#: Adressen der Geschäftspartner, an denen sich der Hauptsitz befindet
partneradresse: Adresse = attr.ib(default=None) # todo: is it plural or not? the docs are bad


class GeschaeftspartnerSchema(GeschaeftsobjektSchema):
Expand Down
54 changes: 52 additions & 2 deletions src/bo4e/bo/marktlokation.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,78 @@ def _validate_marktlokations_id(self, marktlokations_id_attribute, value):

# required attributes
bo_typ: BoTyp = attr.ib(default=BoTyp.MARKTLOKATION)
#: Identifikationsnummer einer Marktlokation, an der Energie entweder verbraucht, oder erzeugt wird.
marktlokations_id: str = attr.ib(validator=_validate_marktlokations_id)
#: Sparte der Marktlokation, z.B. Gas oder Strom
sparte: Sparte
#: Kennzeichnung, ob Energie eingespeist oder entnommen (ausgespeist) wird
energierichtung: Energierichtung
#: Die Bilanzierungsmethode, RLM oder SLP
bilanzierungsmethode: Bilanzierungsmethode
netzebene: Netzebene
"""
Netzebene, in der der Bezug der Energie erfolgt.
Bei Strom Spannungsebene der Lieferung, bei Gas Druckstufe.
Beispiel Strom: Niederspannung Beispiel Gas: Niederdruck.
"""

# optional attributes
#: Verbrauchsart der Marktlokation.
verbrauchsart: Verbrauchsart = attr.ib(default=None)
#: Gibt an, ob es sich um eine unterbrechbare Belieferung handelt
unterbrechbar: bool = attr.ib(default=None)
#: Codenummer des Netzbetreibers, an dessen Netz diese Marktlokation angeschlossen ist.
netzbetreibercodenr: str = attr.ib(default=None)
#: Typ des Netzgebietes, z.B. Verteilnetz
gebietstyp: Gebiettyp = attr.ib(default=None)
netzgebietsnr: str = attr.ib(default=None)
#: Die ID des Gebietes in der ene't-Datenbank
netzgebietsnr: str = attr.ib(default=None) # todo: rename to "id" (see 2021-12-15 update)
#: Bilanzierungsgebiet, dem das Netzgebiet zugeordnet ist - im Falle eines Strom Netzes
bilanzierungsgebiet: str = attr.ib(default=None)
#: Codenummer des Grundversorgers, der für diese Marktlokation zuständig ist
grundversorgercodenr: str = attr.ib(default=None)
#: Die Gasqualität in diesem Netzgebiet. H-Gas oder L-Gas. Im Falle eines Gas-Netzes
gasqualitaet: Gasqualitaet = attr.ib(default=None)
#: Geschäftspartner, dem diese Marktlokation gehört
endkunde: Geschaeftspartner = attr.ib(default=None)
zugehoerige_messlokation: Messlokationszuordnung = attr.ib(default=None)
zugehoerige_messlokation: Messlokationszuordnung = attr.ib(default=None) # todo: rename to plural
"""
Aufzählung der Messlokationen, die zu dieser Marktlokation gehören.
Es können 3 verschiedene Konstrukte auftreten:

Beziehung 1 : 0 : Hier handelt es sich um Pauschalanlagen ohne Messung. D.h. die Verbrauchsdaten sind direkt ĂĽber
die Marktlokation abgreifbar.
Beziehung 1 : 1 : Das ist die Standard-Beziehung für die meisten Fälle. In diesem Fall gibt es zu einer
Marktlokation genau eine Messlokation.
Beziehung 1 : N : Hier liegt beispielsweise eine Untermessung vor. Der Verbrauch einer Marklokation berechnet sich
hier aus mehreren Messungen.

Es gibt praktisch auch noch die Beziehung N : 1, beispielsweise bei einer Zweirichtungsmessung bei der durch eine
Messeinrichtung die Messung sowohl fĂĽr die Einspreiseseite als auch fĂĽr die Aussspeiseseite erfolgt.
Da Abrechnung und Bilanzierung jedoch fĂĽr beide Marktlokationen getrennt erfolgt, werden nie beide Marktlokationen
gemeinsam betrachtet. Daher lässt sich dieses Konstrukt auf zwei 1:1-Beziehung zurückführen,
wobei die Messlokation in beiden Fällen die gleiche ist.

In den Zuordnungen sind ist die arithmetische Operation mit der der Verbrauch einer Messlokation zum Verbrauch einer
Marktlokation beitrögt mit aufgeführt.
Der Standard ist hier die Addition.
"""

# only one of the following three optional attributes can be set
#: Die Adresse, an der die Energie-Lieferung oder -Einspeisung erfolgt
lokationsadresse: Adresse = attr.ib(default=None)
geoadresse: Geokoordinaten = attr.ib(default=None)
"""
Alternativ zu einer postalischen Adresse kann hier ein Ort mittels Geokoordinaten angegeben werden
(z.B. zur Identifikation von Sendemasten).
"""
katasterinformation: Katasteradresse = attr.ib(default=None)
"""
Alternativ zu einer postalischen Adresse und Geokoordinaten kann hier eine Ortsangabe mittels Gemarkung und
FlurstĂĽck erfolgen.
"""

# todo: add kundengruppe

@lokationsadresse.validator
@geoadresse.validator
Expand Down
4 changes: 4 additions & 0 deletions src/bo4e/bo/marktteilnehmer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ class Marktteilnehmer(Geschaeftspartner):

# required attributes
bo_typ: BoTyp = attr.ib(default=BoTyp.MARKTTEILNEHMER)
#: Gibt im Klartext die Bezeichnung der Marktrolle an
marktrolle: Marktrolle
#: Gibt die Codenummer der Marktrolle an
rollencodenummer: str = attr.ib(validator=matches_re(r"^\d{13}$"))
#: Gibt den Typ des Codes an
rollencodetyp: Rollencodetyp

# optional attributes
#: Die 1:1-Kommunikationsadresse des Marktteilnehmers; Diese wird in der Marktkommunikation verwendet.
makoadresse: str = attr.ib(default=None)


Expand Down
31 changes: 29 additions & 2 deletions src/bo4e/bo/messlokation.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,51 @@ def _validate_messlokations_id(self, messlokations_id_attribute, value):

# required attributes
bo_typ: BoTyp = attr.ib(default=BoTyp.MESSLOKATION)
#: Die Messlokations-Identifikation; Das ist die frühere Zählpunktbezeichnung
messlokations_id: str = attr.ib(validator=_validate_messlokations_id)
#: Sparte der Messlokation, z.B. Gas oder Strom
sparte: Sparte

# optional attributes
#: Spannungsebene der Messung
netzebene_messung: Optional[Netzebene] = attr.ib(default=None)
#: Die Nummer des Messgebietes in der ene't-Datenbank
messgebietnr: Optional[str] = attr.ib(default=None)
#: Liste der Hardware, die zu dieser Messstelle gehört
geraete: Optional[List[Hardware]] = attr.ib(default=None)
messdienstleistung: Optional[List[Dienstleistung]] = attr.ib(default=None)
#: Liste der Messdienstleistungen, die zu dieser Messstelle gehört
messdienstleistung: Optional[List[Dienstleistung]] = attr.ib(default=None) # todo: rename to plural
#: Zähler, die zu dieser Messlokation gehören
messlokationszaehler: Optional[List[Zaehler]] = attr.ib(default=None)

# only one of the following two optional codenr attributes can be set
grundzustaendiger_msb_codenr: Optional[str] = attr.ib(default=None)
"""
Codenummer des grundzuständigen Messstellenbetreibers, der für diese Messlokation zuständig ist.
(Dieser ist immer dann Messstellenbetreiber, wenn kein anderer MSB die Einrichtungen an der Messlokation betreibt.)
"""
grundzustaendiger_msbim_codenr: Optional[str] = attr.ib(default=None)

"""
Codenummer des grundzuständigen Messstellenbetreibers für intelligente Messsysteme, der für diese Messlokation
zuständig ist.
(Dieser ist immer dann Messstellenbetreiber, wenn kein anderer MSB die Einrichtungen an der Messlokation betreibt.)
"""
# only one of the following three optional address attributes can be set
messadresse: Optional[Adresse] = attr.ib(default=None)
"""
Die Adresse, an der die Messeinrichtungen zu finden sind.
(Nur angeben, wenn diese von der Adresse der Marktlokation abweicht.)
"""
geoadresse: Optional[Geokoordinaten] = attr.ib(default=None)
"""
Alternativ zu einer postalischen Adresse kann hier ein Ort mittels Geokoordinaten angegeben werden
(z.B. zur Identifikation von Sendemasten).
"""
katasterinformation: Optional[Katasteradresse] = attr.ib(default=None)
"""
Alternativ zu einer postalischen Adresse und Geokoordinaten kann hier eine Ortsangabe mittels Gemarkung und
FlurstĂĽck erfolgen.
"""

@messadresse.validator
@geoadresse.validator
Expand Down
26 changes: 25 additions & 1 deletion src/bo4e/bo/vertrag.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,45 @@ class Vertrag(Geschaeftsobjekt):

# required attributes
bo_typ: BoTyp = attr.ib(default=BoTyp.VERTRAG)
#: Eine im Verwendungskontext eindeutige Nummer fĂĽr den Vertrag
vertragsnummer: str = attr.ib(validator=attr.validators.instance_of(str))
#: Hier ist festgelegt, um welche Art von Vertrag es sich handelt.
vertragsart: Vertragsart = attr.ib(validator=attr.validators.instance_of(Vertragsart))
#: Gibt den Status des Vertrags an
vertragsstatus: Vertragsstatus = attr.ib(validator=attr.validators.instance_of(Vertragsstatus))
#: Unterscheidungsmöglichkeiten für die Sparte
sparte: Sparte = attr.ib(validator=attr.validators.instance_of(Sparte))
#: Gibt an, wann der Vertrag beginnt (inklusiv)
vertragsbeginn: datetime = attr.ib(validator=attr.validators.instance_of(datetime))
#: Gibt an, wann der Vertrag (voraussichtlich) endet oder beendet wurde (exklusiv)
vertragsende: datetime = attr.ib(validator=attr.validators.instance_of(datetime))

# todo: add von/bis validator
vertragspartner1: Geschaeftspartner = attr.ib(validator=attr.validators.instance_of(Geschaeftspartner))
"""
Der "erstgenannte" Vertragspartner.
In der Regel der Aussteller des Vertrags.
Beispiel: "Vertrag zwischen Vertragspartner 1 ..."
"""
vertragspartner2: Geschaeftspartner = attr.ib(validator=attr.validators.instance_of(Geschaeftspartner))
"""
Der "zweitgenannte" Vertragspartner.
In der Regel der Empfänger des Vertrags.
Beispiel "Vertrag zwischen Vertragspartner 1 und Vertragspartner 2".
"""
vertragsteile: List[Vertragsteil] = attr.ib(validator=at_least_one_vertragsteil)
"""
Der Vertragsteil wird dazu verwendet, eine vertragliche Leistung in Bezug zu einer Lokation
(Markt- oder Messlokation) festzulegen.
"""

# optional attributes
#: Beschreibung zum Vertrag
beschreibung: Optional[str] = attr.ib(default=None)
#: Festlegungen zu Laufzeiten und KĂĽndigungsfristen
vertragskonditionen: Optional[Vertragskonditionen] = attr.ib(default=None)
#: Unterzeichner des Vertragspartners 1
unterzeichnervp1: Optional[List[Unterschrift]] = attr.ib(default=None)
#: Unterzeichner des Vertragspartners 2
unterzeichnervp2: Optional[List[Unterschrift]] = attr.ib(default=None)


Expand Down
20 changes: 10 additions & 10 deletions src/bo4e/bo/zaehler.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ class Zaehler(Geschaeftsobjekt):
bo_typ: BoTyp = attr.ib(default=BoTyp.ZAEHLER)
zaehlernummer: str = attr.ib(
validator=attr.validators.instance_of(str)
) # Nummerierung des Zählers, vergeben durch den Messstellenbetreiber
sparte: Sparte
zaehlerauspraegung: Zaehlerauspraegung
zaehlertyp: Zaehlertyp
zaehlwerke: List[Zaehlwerk] = attr.ib(validator=at_least_one_zaehlwerk)
tarifart: Tarifart # Spezifikation bezĂĽglich unterstĂĽtzter Tarifarten
) #: Nummerierung des Zählers,vergeben durch den Messstellenbetreiber
sparte: Sparte #: Strom oder Gas
zaehlerauspraegung: Zaehlerauspraegung #: Spezifikation die Richtung des Zählers betreffend
zaehlertyp: Zaehlertyp #: Typisierung des Zählers
zaehlwerke: List[Zaehlwerk] = attr.ib(validator=at_least_one_zaehlwerk) #: Die Zählwerke des Zählers
tarifart: Tarifart #: Spezifikation bezĂĽglich unterstĂĽtzter Tarifarten

# optional attributes
zaehlerkonstante: Optional[Decimal] = attr.ib(default=None) # Zählerkonstante auf dem Zähler
eichung_bis: Optional[datetime] = attr.ib(default=None) # Bis zu diesem Datum ist der Zähler geeicht.
zaehlerkonstante: Optional[Decimal] = attr.ib(default=None) #: Zählerkonstante auf dem Zähler
eichung_bis: Optional[datetime] = attr.ib(default=None) #: Bis zu diesem Datum (exklusiv) ist der Zähler geeicht.
letzte_eichung: Optional[datetime] = attr.ib(
default=None
) # Zu diesem Datum fand die letzte Eichprüfung des Zählers statt.
zaehlerhersteller: Optional[Geschaeftspartner] = attr.ib(default=None) # Der Hersteller des Zählers.
) #: Zu diesem Datum fand die letzte Eichprüfung des Zählers statt.
zaehlerhersteller: Optional[Geschaeftspartner] = attr.ib(default=None) #: Der Hersteller des Zählers


class ZaehlerSchema(GeschaeftsobjektSchema):
Expand Down