from __future__ import annotations
from dateutil.parser import parse
from markupsafe import Markup
from onegov.gazette.models import Issue
from typing import overload
from typing import Any
from typing import Literal
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Callable
from datetime import datetime
from lxml.etree import _Element
from sqlalchemy.orm import Session
from typing import TypeVar
[docs]
def html_converter(text: str) -> Markup:
return Markup('<br>').join(line.strip() for line in text.split('\n'))
[docs]
def line_converter(text: str) -> str:
assert '\n' not in text, 'Encountered line break in single line field'
return text.strip()
[docs]
class SogcConverter:
""" The base class for all converters. """
def __init__(self, root: _Element) -> None:
# FIXME: This returning Literal[""] regardless of the conversion
# seems a little bit esoteric, we should probably return
# None unless we force the result to be a string
@overload
[docs]
def get(
self,
path: str,
converter: Callable[[str], Markup] | None = html_converter,
root: _Element | None = None
) -> Markup | Literal['']: ...
@overload
def get(
self,
path: str,
converter: Callable[[str], _T],
root: _Element | None = None
) -> _T | Literal['']: ...
def get(
self,
path: str,
converter: Callable[[str], Any] | None = html_converter,
root: _Element | None = None
) -> Any:
root = root if root is not None else self.root
node = root.find(path)
result = node.text.strip() if node is not None and node.text else ''
if converter and result != '':
result = converter(result)
return result
[docs]
def get_line(self, path: str, root: _Element | None = None) -> str:
return self.get(path, converter=line_converter, root=root)
@property
[docs]
def title(self) -> str:
return self.get_line('meta/title/de')
@property
[docs]
def source(self) -> str:
return self.get_line('meta/publicationNumber')
@property
[docs]
def publication_date(self) -> datetime | Literal['']:
return self.get('meta/publicationDate', converter=parse)
@property
[docs]
def expiration_date(self) -> datetime | Literal['']:
return self.get('meta/expirationDate', converter=parse)
[docs]
def issues(self, session: Session) -> list[str]:
query = session.query(Issue.name)
query = query.filter(Issue.date >= self.publication_date)
query = query.order_by(Issue.date)
row = query.first()
return list(row) if row else []
[docs]
def p(
self,
value: object,
title: str = '',
title_break: bool = True,
subtitle: str = '',
subtitle_break: bool = False,
fmt: str | None = None
) -> Markup:
""" Adds a paragraph.
Example::
<p>
<strong>title</strong><br>
subtitle:<br>
value
</p>
"""
if not value:
return Markup('')
if fmt == 'date':
value = f'{value:%d.%m.%Y}'
elif fmt == 'days':
value = f'{value} Tage'
elif fmt == 'currency':
value = f'{value:.02f} CHF'
if subtitle:
if subtitle_break:
template = Markup('{}:<br>{}')
else:
template = Markup('{}: {}')
value = template.format(subtitle, value)
if title:
if title_break:
template = Markup('<strong>{}</strong><br>{}')
else:
template = Markup('<strong>{}</strong>{}')
value = template.format(title, value)
return Markup('<p>{}</p>').format(value)
[docs]
class KK(SogcConverter):
@property
[docs]
def addition(self) -> Markup:
value = self.get('content/addition')
if value == 'legacy':
return self.p('Erbschaft', 'Zusatz')
elif value == 'refusedLegacy':
return self.p('ausgeschlagene Erbschaft', 'Zusatz')
elif value == 'custom':
value = self.get('content/additionCustom')
return self.p(value, 'Zusatz')
else:
return Markup('')
@property
@property
[docs]
def days_after_publication(self) -> Markup:
return self.p(
self.get('content/daysAfterPublication', int),
'Frist',
fmt='days'
)
@property
[docs]
def debtor(self) -> Markup:
debtor_type = self.get('content/debtor/selectType')
if debtor_type == 'company':
companies = self.root.findall('content/debtor/companies/company')
result = Markup('')
for company in companies:
result += self.p(
self.get('name', root=company),
'Schuldner'
)
result += self.p(self.get('uid', root=company), subtitle='UID')
result += self.p(
Markup('<br>').join((
Markup('{} {}').format(
self.get('address/street', root=company),
self.get('address/houseNumber', root=company)
).strip(),
Markup('{} {}').format(
self.get('address/swissZipCode', root=company),
self.get('address/town', root=company)
).strip()
)),
)
result += self.p(self.get('customAddress', root=company))
result += self.p(self.get('country/name/de', root=company))
return result
elif debtor_type == 'person':
result = self.p(
Markup('{} {}').format(
self.get('content/debtor/person/prename'),
self.get('content/debtor/person/name')
).strip(),
'Schuldner'
)
result += self.p(
self.get('content/debtor/person/countryOfOrigin/name/de'),
subtitle='Staatsbürger'
)
result += self.p(
self.get('content/debtor/person/placeOfOrigin'),
subtitle='Heimatort'
)
result += self.p(
self.get('content/debtor/person/dateOfBirth', parse),
subtitle='Geburtsdatum',
fmt='date'
)
result += self.p(
self.get('content/debtor/person/dateOfDeath', parse),
subtitle='Todesdatum',
fmt='date'
)
residence_type = self.get(
'content/debtor/person/residence/selectType'
)
if residence_type == 'switzerland':
path = 'content/debtor/person/addressSwitzerland'
result += self.p(
Markup('<br>').join((
Markup('{} {}').format(
self.get(f'{path}/street'),
self.get(f'{path}/houseNumber')
).strip(),
Markup('{} {}').format(
self.get(f'{path}/swissZipCode'),
self.get(f'{path}/town')
).strip()
)),
subtitle='Wohnsitz',
subtitle_break=True
)
elif residence_type == 'foreign':
path = 'content/debtor/person/addressForeign'
result += self.p(
Markup('<br>').join((
self.get(f'{path}/addressCustomText'),
self.get(f'{path}/country/name/de')
)),
subtitle='Wohnsitz',
subtitle_break=True
)
elif residence_type == 'unknown':
result += self.p('unbekannt', 'Wohnsitz')
result += self.p(
self.get('content/debtor/person/personInformation'),
subtitle='Weitere Informationen zur Person',
subtitle_break=True
)
return result
return Markup('')
@property
[docs]
def entry_deadline(self) -> Markup:
result = self.p(
self.get('content/entryDeadline', parse),
'Ablauf der Frist',
fmt='date'
)
result += self.p(
self.get('content/commentEntryDeadline'),
'Kommentar zur Frist'
)
return result
@property
@property
[docs]
def legal(self) -> Markup:
result = self.p(
self.get('meta/legalRemedy'),
'Rechtliche Hinweise und Fristen'
)
if self.get('content/or731b') == 'Yes':
result += self.p('Aufgelöste Gesellschaft gemäss Art. 731b OR')
result += self.p(
self.get('content/additionalLegalRemedy'),
'Ergänzende rechtliche Hinweise'
)
result += self.p(
self.get('content/additionalLegalRemedyStatic'),
'Ergänzende rechtliche Hinweise'
)
return result
@property
@property
[docs]
def registration_office(self) -> Markup:
return self.p(
self.get('content/registrationOffice'),
'Anmeldestelle'
)
@property
[docs]
def resolution_date(self) -> Markup:
return self.p(
self.get('content/resolutionDate', parse),
'Datum der Konkurseröffnung',
fmt='date'
)
[docs]
class KK01(KK):
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.resolution_date,
self.addition,
self.legal,
self.remarks,
))
[docs]
class KK02(KK):
@property
[docs]
def proceeding(self) -> Markup:
value = self.get('content/proceeding/selectType')
if value == 'summary':
return self.p('summarisch', 'Art des Konkursverfahrens')
elif value == 'ordinary':
return self.p('ordentlich', 'Art des Konkursverfahrens')
elif value == 'other':
value = self.get('content/otherProceeding')
return self.p(value, 'Art des Konkursverfahrens')
else:
return Markup('')
@property
[docs]
def creditor_meeting(self) -> Markup:
value_date = self.get('content/creditorMeeting/dateFrom', parse)
value_time = self.get('content/creditorMeeting/time', parse)
value_location = self.get('content/creditorMeeting/location')
if not value_date:
return Markup('')
value = f'{value_date:%d.%m.%Y}'
if value_time:
value = f'{value_date:%d.%m.%Y} um {value_time:%H:%M}'
if value_location:
value = Markup('{}<br>{}').format(value, value_location)
return self.p(value, 'Gläubigerversammlung')
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.proceeding,
self.resolution_date,
self.creditor_meeting,
self.days_after_publication,
self.entry_deadline,
self.registration_office,
self.addition,
self.legal,
self.remarks,
))
[docs]
class KK03(KK):
@property
[docs]
def cessation_date(self) -> Markup:
return self.p(
self.get('content/cessationDate', parse),
'Datum der Einstellung',
fmt='date'
)
@property
[docs]
def advance_amount(self) -> Markup:
return self.p(
self.get('content/advanceAmount', float),
'Betrag des Kostenvorschusses',
fmt='currency'
)
@property
[docs]
def text(self) -> str:
return Markup('').join((
self.debtor,
self.resolution_date,
self.cessation_date,
self.advance_amount,
self.days_after_publication,
self.entry_deadline,
self.registration_office,
self.addition,
self.legal,
self.remarks,
))
[docs]
class KK04(KK):
@property
[docs]
def claim_of_creditors(self) -> Markup:
result = self.p(
self.get('content/claimOfCreditors/daysAfterPublication', int),
'Auflagefrist Kollokationsplan nach Publikation',
fmt='days'
)
result += self.p(
self.get('content/claimOfCreditors/entryDeadline', parse),
'Ablauf der Auflagefrist Kollokationsplan',
fmt='date'
)
result += self.p(
self.get('content/claimOfCreditors/commentEntryDeadline'),
'Kommentar zur Auflagefrist Kollokationsplan'
)
return result
@property
[docs]
def inventory(self) -> Markup:
result = self.p(
self.get('content/inventory/daysAfterPublication', int),
'Auflagefrist Inventar nach Publikation',
fmt='days'
)
result += self.p(
self.get('content/inventory/entryDeadline', parse),
'Ablauf der Auflagefrist Inventar',
fmt='date'
)
result += self.p(
self.get('content/inventory/commentEntryDeadline'),
'Kommentar zur Auflagefrist Inventar'
)
return result
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.claim_of_creditors,
self.inventory,
self.registration_office,
self.addition,
self.legal,
self.remarks,
))
[docs]
class KK05(KK):
@property
[docs]
def location_circulation_authority(self) -> Markup:
return self.p(
self.get('content/locationCirculationAuthority'),
'Angaben zur Auflage'
)
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.location_circulation_authority,
self.days_after_publication,
self.entry_deadline,
self.registration_office,
self.legal,
self.remarks,
))
[docs]
class KK06(KK):
@property
[docs]
def proceeding_end_date(self) -> Markup:
return self.p(
self.get('content/proceedingEndDate', parse),
'Datum des Schlusses',
fmt='date'
)
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.proceeding_end_date,
self.addition,
self.legal,
self.remarks,
))
[docs]
class KK07(KK):
@property
[docs]
def proceeding_revocation_date(self) -> Markup:
return self.p(
self.get('content/proceedingRevocationDate', parse),
'Datum des Widerrufs',
fmt='date'
)
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.proceeding_revocation_date,
self.legal,
self.remarks,
))
[docs]
class KK08(KK):
@property
[docs]
def auction(self) -> Markup:
value_date = self.get('content/auction/date', parse)
value_time = self.get('content/auction/time', parse)
value_location = self.get('content/auction/location')
if not value_date:
return Markup('')
value = f'{value_date:%d.%m.%Y}'
if value_time:
value = f'{value_date:%d.%m.%Y} um {value_time:%H:%M}'
if value_location:
value = Markup('{}<br>{}').format(value, value_location)
return self.p(value, 'Steigerung')
@property
[docs]
def auction_objects(self) -> Markup:
return self.p(
self.get('content/auctionObjects'),
'Steigerungsobjekte'
)
@property
[docs]
def entry_start(self) -> Markup:
return self.p(
self.get('content/entryStart', parse),
'Beginn der Frist',
fmt='date'
)
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.auction,
self.auction_objects,
self.information_about_edition,
self.entry_start,
self.entry_deadline,
self.registration_office,
self.addition,
self.legal,
self.remarks,
))
[docs]
class KK09(KK):
@property
[docs]
def affected_land(self) -> Markup:
return self.p(
self.get('content/affectedLand'),
'Betroffenes Grundstück'
)
@property
[docs]
def appeal(self) -> Markup:
result = self.p(
self.get('content/appeal/daysAfterPublication', int),
'Klage- und Beschwerdefrist',
fmt='days'
)
result += self.p(
self.get('content/appeal/entryDeadline', parse),
'Ablauf der Klage- und Beschwerdefrist',
fmt='date'
)
result += self.p(
self.get('content/appeal/commentEntryDeadline'),
'Kommentar zur Klage- und Beschwerdefrist'
)
return result
@property
[docs]
def location_circulation_authority(self) -> Markup:
return self.p(
self.get('content/locationCirculationAuthority'),
'Weitere Angaben'
)
@property
[docs]
def registration_office(self) -> Markup:
result = self.p(
self.get('content/registrationOfficeComplain'),
'Anmeldestelle für Klagen'
)
result += self.p(
self.get('content/registrationOfficeAppeal'),
'Anmeldestelle für Beschwerden'
)
return result
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.debtor,
self.affected_land,
self.location_circulation_authority,
self.information_about_edition,
self.days_after_publication,
self.entry_deadline,
self.appeal,
self.registration_office,
self.legal,
self.remarks,
))
[docs]
class KK10(KK):
@property
[docs]
def title(self) -> str:
return self.get_line('content/title') or self.get_line('meta/title/de')
@property
[docs]
def publication(self) -> Markup:
return self.p(self.get('content/publication'))
@property
[docs]
def text(self) -> Markup:
return Markup('').join((
self.publication,
self.legal,
self.remarks,
))