From d77edcd67c4d5b3d37b386f32a06ec748e5699ea Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Tue, 10 Jun 2025 07:09:41 +0200 Subject: [PATCH 01/17] RIS light initial commit --- src/onegov/ris/__init__.py | 13 + src/onegov/ris/collections/__init__.py | 0 src/onegov/ris/forms/__init__.py | 0 src/onegov/ris/i18n.py | 5 + src/onegov/ris/layouts/__init__.py | 0 src/onegov/ris/models/__init__.py | 26 ++ src/onegov/ris/models/commission.py | 116 +++++++ src/onegov/ris/models/meeting.py | 74 ++++ src/onegov/ris/models/membership.py | 112 +++++++ src/onegov/ris/models/parliamentarian.py | 315 ++++++++++++++++++ src/onegov/ris/models/parliamentarian_role.py | 211 ++++++++++++ src/onegov/ris/models/parliamentary_group.py | 91 +++++ src/onegov/ris/models/party.py | 79 +++++ src/onegov/ris/models/political_business.py | 200 +++++++++++ src/onegov/ris/templates/__init__.py | 0 src/onegov/ris/views/__init__.py | 0 16 files changed, 1242 insertions(+) create mode 100644 src/onegov/ris/__init__.py create mode 100644 src/onegov/ris/collections/__init__.py create mode 100644 src/onegov/ris/forms/__init__.py create mode 100644 src/onegov/ris/i18n.py create mode 100644 src/onegov/ris/layouts/__init__.py create mode 100644 src/onegov/ris/models/__init__.py create mode 100644 src/onegov/ris/models/commission.py create mode 100644 src/onegov/ris/models/meeting.py create mode 100644 src/onegov/ris/models/membership.py create mode 100644 src/onegov/ris/models/parliamentarian.py create mode 100644 src/onegov/ris/models/parliamentarian_role.py create mode 100644 src/onegov/ris/models/parliamentary_group.py create mode 100644 src/onegov/ris/models/party.py create mode 100644 src/onegov/ris/models/political_business.py create mode 100644 src/onegov/ris/templates/__init__.py create mode 100644 src/onegov/ris/views/__init__.py diff --git a/src/onegov/ris/__init__.py b/src/onegov/ris/__init__.py new file mode 100644 index 0000000000..7534bc6086 --- /dev/null +++ b/src/onegov/ris/__init__.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +import logging + +log = logging.getLogger('onegov.ris') +log.addHandler(logging.NullHandler()) + +from onegov.ris.i18n import _ + +__all__ = ( + '_', + 'log' +) diff --git a/src/onegov/ris/collections/__init__.py b/src/onegov/ris/collections/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/onegov/ris/forms/__init__.py b/src/onegov/ris/forms/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/onegov/ris/i18n.py b/src/onegov/ris/i18n.py new file mode 100644 index 0000000000..40c901770e --- /dev/null +++ b/src/onegov/ris/i18n.py @@ -0,0 +1,5 @@ +from __future__ import annotations + +from onegov.core.i18n.translation_string import TranslationStringFactory + +_ = TranslationStringFactory('onegov.ris') diff --git a/src/onegov/ris/layouts/__init__.py b/src/onegov/ris/layouts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/onegov/ris/models/__init__.py b/src/onegov/ris/models/__init__.py new file mode 100644 index 0000000000..1f3f3f883c --- /dev/null +++ b/src/onegov/ris/models/__init__.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from onegov.ris.models.commission import RISCommission +from onegov.ris.models.membership import RISCommissionMembership +from onegov.ris.models.parliamentarian import RISParliamentarian +from onegov.ris.models.parliamentarian_role import RISParliamentarianRole +from onegov.ris.models.parliamentary_group import RISParliamentaryGroup +from onegov.ris.models.party import RISParty +from onegov.ris.models.political_business import ( + RISPoliticalBusiness, + RISPoliticalBusinessParticipation +) +from onegov.ris.models.meeting import RISMeeting + + +__all__ = ( + 'RISCommission', + 'RISMeeting', + 'RISCommissionMembership', + 'RISParliamentarian', + 'RISParliamentarianRole', + 'RISParliamentaryGroup', + 'RISParty', + 'RISPoliticalBusiness', + 'RISPoliticalBusinessParticipation', +) diff --git a/src/onegov/ris/models/commission.py b/src/onegov/ris/models/commission.py new file mode 100644 index 0000000000..e990e83728 --- /dev/null +++ b/src/onegov/ris/models/commission.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +from sqlalchemy import Column, Date, Enum, Text +from sqlalchemy.orm import relationship +from uuid import uuid4 + +from onegov.core.orm import Base, observes +from onegov.core.orm.mixins import dict_markup_property +from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.types import UUID +from onegov.ris import _ +from onegov.search import ORMSearchable + + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import uuid + from datetime import date + from typing import Literal + from typing import TypeAlias + + from onegov.ris.models.membership import RISCommissionMembership + + CommissionType: TypeAlias = Literal[ + 'normal', + 'intercantonal', + 'official', + ] + +TYPES: dict[CommissionType, str] = { + 'normal': _('normal'), + 'intercantonal': _('intercantonal'), + 'official': _('official mission'), +} + + +class RISCommission(Base, TimestampMixin, ORMSearchable): + + __tablename__ = 'ris_commissions' + + es_public = True + es_properties = { + 'title': {'type': 'text'}, + 'description': {'type': 'localized_html'} + } + + @property + def es_suggestion(self) -> str: + return self.name + + @property + def title(self) -> str: + return self.name + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4 + ) + + #: the name + name: Column[str] = Column( + Text, + nullable=False + ) + + #: The start date + start: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The end date + end: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The type value + type: Column[CommissionType] = Column( + Enum( + *TYPES.keys(), # type:ignore[arg-type] + name='ris_commission_type' + ), + nullable=False, + default='normal' + ) + + #: The type as translated text + @property + def type_label(self) -> str: + return TYPES.get(self.type, '') + + #: The description + description = dict_markup_property('content') + + #: A commission may have n parliamentarians + memberships: relationship[list[RISCommissionMembership]] + memberships = relationship( + 'RISCommissionMembership', + cascade='all, delete-orphan', + back_populates='commission', + order_by='Commission.name' + ) + + @observes('end') + def end_observer(self, end: date | None) -> None: + if end: + for membership in self.memberships: + if not membership.end: + membership.end = end + + def __repr__(self) -> str: + return f'' diff --git a/src/onegov/ris/models/meeting.py b/src/onegov/ris/models/meeting.py new file mode 100644 index 0000000000..4df96e6174 --- /dev/null +++ b/src/onegov/ris/models/meeting.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +import uuid + +from sqlalchemy import Column, Text, ForeignKey +from sqlalchemy.orm import RelationshipProperty, relationship + +from onegov.core.orm import Base +from onegov.core.orm.types import UUID, MarkupText, UTCDateTime +from onegov.search import ORMSearchable + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import uuid + + from markupsafe import Markup + from datetime import datetime + + from onegov.ris.models.political_business import RISPoliticalBusiness + + +class RISMeeting(Base, ORMSearchable): + __tablename__ = 'ris_meetings' + + es_public = True + es_properties = {'title_text': {'type': 'text'}} + + @property + def es_suggestion(self) -> str: + return self.title + + @property + def title_text(self) -> str: + return f'{self.title} ({self.start_datetime})' + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid.uuid4, + ) + + #: The title of the meeting + title: Column[str] = Column(Text, nullable=False) + + #: date and time of the meeting + start_datetime: Column[datetime | None] + start_datetime = Column(UTCDateTime, nullable=True) + + #: location address of meeting + address: Column[str] = Column(Text, nullable=False) + + description: Column[Markup | None] = Column(MarkupText, nullable=True) + + #: political business id + political_business_id: Column[uuid.UUID | None] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_political_businesses.id'), + ) + + #: list of political businesses, "Traktanden" + political_businesses: RelationshipProperty[RISPoliticalBusiness] = ( + relationship( + 'RISPoliticalBusiness', + back_populates='meetings', + order_by='RISPoliticalBusiness.number', + primaryjoin='RISMeeting.political_business_id == ' + 'RISPoliticalBusiness.id', + ) + ) + + def __repr__(self) -> str: + return f'' diff --git a/src/onegov/ris/models/membership.py b/src/onegov/ris/models/membership.py new file mode 100644 index 0000000000..be33f67a96 --- /dev/null +++ b/src/onegov/ris/models/membership.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +from sqlalchemy import Column +from sqlalchemy import Date +from sqlalchemy import Enum +from sqlalchemy import ForeignKey +from sqlalchemy.orm import relationship +from uuid import uuid4 + +from onegov.core.orm import Base +from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.types import UUID +from onegov.ris import _ + + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import uuid + from datetime import date + from typing import Literal + from typing import TypeAlias + + from onegov.ris.models.commission import RISCommission + from onegov.ris.models.parliamentarian import RISParliamentarian + + MembershipRole: TypeAlias = Literal[ + 'guest', + 'member', + 'extended_member', + 'president', + ] + +ROLES: dict[MembershipRole, str] = { + 'guest': _('Guest'), + 'member': _('Member'), + 'extended_member': _('Extended Member'), + 'president': _('President') +} + + +class RISCommissionMembership(Base, TimestampMixin): + + __tablename__ = 'ris_parliamentary_memberships' + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4 + ) + + #: The start date + start: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The end date + end: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The role value + role: Column[MembershipRole] = Column( + Enum( + *ROLES.keys(), # type:ignore[arg-type] + name='ris_parliamentary_membership_role' + ), + nullable=False, + default='member' + ) + + #: The role as translated text + @property + def role_label(self) -> str: + return ROLES.get(self.role, '') + + #: the id of the commission + commission_id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_commissions.id'), + nullable=False + ) + + #: the related commission (which may have any number of memberships) + commission: relationship[RISCommission] = relationship( + 'RISCommission', + back_populates='memberships' + ) + + #: the id of the parliamentarian + # NEEDED??? + parliamentarian_id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parliamentarians.id'), + nullable=False + ) + + #: the related parliamentarian (which may have any number of memberships) + parliamentarian: relationship[RISParliamentarian] = relationship( + 'RISParliamentarian', + back_populates='commission_memberships' + ) + + def __repr__(self) -> str: + return ( + f' tuple[str, ...]: + return ( + f'{self.first_name} {self.last_name}', + f'{self.last_name} {self.first_name}' + ) + + @property + def title(self) -> str: + return f'{self.first_name} {self.last_name}' + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4 + ) + + #: The first name + first_name: Column[str] = Column( + Text, + nullable=False + ) + + #: The last name + last_name: Column[str] = Column( + Text, + nullable=False + ) + + #: The personnel number + personnel_number: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The gender value + gender: Column[Gender] = Column( + Enum( + *GENDERS.keys(), # type:ignore[arg-type] + name='ris_gender' + ), + nullable=False, + default='male' + ) + + #: The gender as translated text + @property + def gender_label(self) -> str: + return GENDERS.get(self.gender, '') + + @property + def formal_greeting(self) -> str: + # fixme: Use salutation + """Returns the formal German greeting based on gender.""" + if self.gender == 'female': + return 'Frau ' + self.first_name + ' ' + self.last_name + return 'Herr ' + self.first_name + ' ' + self.last_name + + #: The private address + private_address: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The private address addition + private_address_addition: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The private address zip code + private_address_zip_code: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The private address city + private_address_city: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The date of birth + date_of_birth: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The date of death + date_of_death: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The place of origin + place_of_origin: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The occupation + occupation: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The academic title + academic_title: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The salutation + salutation: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The private phone number + phone_private: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The mobile phone number + phone_mobile: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The business phone number + phone_business: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The primary email address + email_primary: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The secondary email address + email_secondary: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The website + website: Column[str | None] = Column( + Text, + nullable=True + ) + + #: The remarks + remarks: Column[str | None] = Column( + Text, + nullable=True + ) + + #: A picture + picture = NamedFile() + + #: A parliamentarian may have n roles + roles: relationship[list[RISParliamentarianRole]] + roles = relationship( + 'RISParliamentarianRole', + cascade='all, delete-orphan', + back_populates='parliamentarian', + order_by='desc(ParliamentarianRole.start)' + ) + + #: political businesses participations [0..n] + political_businesses: relationship[list[RISPoliticalBusinessParticipation]] + political_businesses = relationship( + 'RISPoliticalBusinessParticipation', + back_populates='parliamentarian', + lazy='joined' + ) + + def get_party_during_period( + self, start_date: date, end_date: date, session: Session + ) -> RISParty | None: + """Get the party this parliamentarian belonged to during a specific + period.""" + + role = ( + session.query(RISParliamentarianRole) + .filter( + RISParliamentarianRole.parliamentarian_id == self.id, + RISParliamentarianRole.party_id.isnot( + None + ), + or_( + RISParliamentarianRole.end.is_(None), + RISParliamentarianRole.end >= start_date, + ), + RISParliamentarianRole.start + <= end_date, + ) + .order_by(RISParliamentarianRole.start.desc()) + .first() + ) + + return role.party if role else None + + @property + def active(self) -> bool: + if not self.roles: + return True + for role in self.roles: + if role.end is None or role.end >= date.today(): + return True + return False + + def active_during(self, start: date, end: date) -> bool: + if not self.roles: + return True + for role in self.roles: + role_start = role.start if role.start is not None else date.min + role_end = role.end if role.end is not None else date.max + if role_end >= start and role_start <= end: + return True + return False + + @property + def display_name(self) -> str: + return f'{self.first_name} {self.last_name}' + + #: A parliamentarian may be a member of n commissions + commission_memberships: relationship[list[RISCommissionMembership]] + commission_memberships = relationship( + 'RISCommissionMembership', + cascade='all, delete-orphan', + back_populates='parliamentarian' + ) + + political_groups: relationship[list[RISParliamentaryGroup]] + political_groups = relationship( + 'RISParliamentaryGroup', + back_populates='members', + primaryjoin='RISParliamentarian.id == ' + 'RISParliamentaryGroup.parliamentarian_id', + ) + + def __repr__(self) -> str: + info = [ + f'id={self.id}', + f"last_name='{self.last_name}'", + f"first_name='{self.first_name}'", + ] + if self.academic_title: + info.append(f"title='{self.academic_title}'") + if self.salutation: + info.append(f"salutation='{self.salutation}'") + if self.email_primary: + info.append( + f"email='{self.email_primary}'") + + return f"" diff --git a/src/onegov/ris/models/parliamentarian_role.py b/src/onegov/ris/models/parliamentarian_role.py new file mode 100644 index 0000000000..76ebc670bc --- /dev/null +++ b/src/onegov/ris/models/parliamentarian_role.py @@ -0,0 +1,211 @@ +from __future__ import annotations + +from sqlalchemy import Column +from sqlalchemy import Date +from sqlalchemy import Enum +from sqlalchemy import ForeignKey +from sqlalchemy import Text +from sqlalchemy.orm import relationship +from uuid import uuid4 + +from onegov.core.orm import Base +from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.types import UUID +from onegov.ris import _ + + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import uuid + from datetime import date + from typing import Literal + from typing import TypeAlias + + from onegov.ris.models.parliamentarian import RISParliamentarian + from onegov.ris.models.parliamentary_group import RISParliamentaryGroup + from onegov.ris.models.party import RISParty + + Role: TypeAlias = Literal[ + 'none', + 'member', + 'vote_counter', + 'vice_president', + 'president', + ] + + PartyRole: TypeAlias = Literal[ + 'none', + 'member', + 'media_manager', + 'vote_counter', + 'vice_president', + 'president', + ] + + ParliamentaryGroupRole: TypeAlias = Literal[ + 'none', + 'non_permanent_member', + 'member', + 'substitute_member', + 'vote_counter', + 'secretary', + 'vice_president', + 'president', + ] + +PARLIAMENTARIAN_ROLES: dict[Role, str] = { + 'none': _('none'), + 'member': _('Member'), + 'vote_counter': _('Vote Counter'), + 'vice_president': _('Vice President'), + 'president': _('President'), +} + +PARTY_ROLES: dict[PartyRole, str] = { + 'none': _('none'), + 'member': _('Member'), + 'media_manager': _('Media Manager'), + 'vote_counter': _('Vote Counter'), + 'vice_president': _('Vice President'), + 'president': _('President'), +} + +PARLIAMENTARY_GROUP_ROLES: dict[ParliamentaryGroupRole, str] = { + 'none': _('none'), + 'non_permanent_member': _('Non-permanent Member'), + 'member': _('Member'), + 'substitute_member': _('Substitute Member'), + 'secretary': _('Secretary'), + 'vote_counter': _('Vote Counter'), + 'vice_president': _('Vice President'), + 'president': _('President'), +} + + +class RISParliamentarianRole(Base, TimestampMixin): + + __tablename__ = 'ris_parliamentarian_roles' + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4 + ) + + #: The start date + start: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The end date + end: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The id of the parliamentarian + parliamentarian_id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parliamentarians.id'), + nullable=False + ) + + #: The parliamentarian + parliamentarian: relationship[RISParliamentarian] = relationship( + 'RISParliamentarian', + back_populates='roles' + ) + + #: The parliament role name + role: Column[Role] = Column( + Enum( + *PARLIAMENTARIAN_ROLES.keys(), # type:ignore[arg-type] + name='ris_parliamentarian_role' + ), + nullable=False, + default='member' + ) + + #: The role as translated text + @property + def role_label(self) -> str: + return PARLIAMENTARIAN_ROLES.get(self.role, '') + + #: Party ID as a foreign key + party_id: Column[uuid.UUID | None] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parties.id'), + nullable=True + ) + + #: The party + party: relationship[RISParty | None] = relationship( + 'RISParty', + back_populates='roles', + primaryjoin='RISParliamentarianRole.party_id == RISParty.id' + ) + + #: The party role value + party_role: Column[PartyRole] = Column( + Enum( + *PARTY_ROLES.keys(), # type:ignore[arg-type] + name='ris_party_role' + ), + nullable=False, + default='member' + ) + + #: The party role as translated text + @property + def party_role_label(self) -> str: + return PARTY_ROLES.get(self.party_role, '') + + #: The id of the parliamentary group + parliamentary_group_id: Column[uuid.UUID | None] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parliamentary_groups.id'), + nullable=True + ) + + #: The parliamentary group + parliamentary_group: relationship[RISParliamentaryGroup | None] + parliamentary_group = relationship( + 'RISParliamentaryGroup', + back_populates='roles' + ) + + #: The parliamentary group role value + parliamentary_group_role: Column[ParliamentaryGroupRole] = Column( + Enum( + *PARLIAMENTARY_GROUP_ROLES.keys(), # type:ignore[arg-type] + name='ris_parliamentary_group_role' + ), + nullable=False, + default='member' + ) + + #: The parliamentary group role as translated text + @property + def parliamentary_group_role_label(self) -> str: + return PARLIAMENTARY_GROUP_ROLES.get(self.parliamentary_group_role, '') + + #: The district + district: Column[str | None] = Column( + Text, + nullable=True + ) + + #: Additional information + additional_information: Column[str | None] = Column( + Text, + nullable=True + ) + + def __repr__(self) -> str: + return ( + f' str: + return self.name + + @property + def title(self) -> str: + return self.name + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4 + ) + + #: the name + name: Column[str] = Column( + Text, + nullable=False + ) + + #: The start date + start: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The end date + end: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The description + description = dict_markup_property('content') + + #: A parliamentary group may have n role + roles: relationship[list[RISParliamentarianRole]] + roles = relationship( + 'RISParliamentarianRole', + back_populates='parliamentary_group', + ) + + # #: the id of the parliamentarian + parliamentarian_id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parliamentarians.id'), + nullable=False + ) + + members: relationship[list[RISParliamentarian]] = relationship( + 'RISParliamentarian', + back_populates='political_groups', + ) + + def __repr__(self) -> str: + return f'' diff --git a/src/onegov/ris/models/party.py b/src/onegov/ris/models/party.py new file mode 100644 index 0000000000..09de15da19 --- /dev/null +++ b/src/onegov/ris/models/party.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from sqlalchemy import Column +from sqlalchemy import Date +from sqlalchemy import Text +from sqlalchemy.orm import relationship +from uuid import uuid4 + +from onegov.core.orm import Base +from onegov.core.orm.mixins import dict_markup_property +from onegov.core.orm.mixins import ContentMixin +from onegov.core.orm.types import UUID +from onegov.search import ORMSearchable + + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import uuid + from datetime import date + from onegov.ris.models.parliamentarian_role import RISParliamentarianRole + + +class RISParty(Base, ContentMixin, ORMSearchable): + + __tablename__ = 'ris_parties' + + es_public = False + es_properties = {'name': {'type': 'text'}} + + @property + def es_suggestion(self) -> str: + return self.name + + @property + def title(self) -> str: + return self.name + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4 + ) + + #: the name + name: Column[str] = Column( + Text, + nullable=False + ) + + #: The start date + start: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The end date + end: Column[date | None] = Column( + Date, + nullable=True + ) + + #: The portrait + portrait = dict_markup_property('content') + + #: The description + description = dict_markup_property('content') + + #: A party may have n roles + roles: relationship[list[RISParliamentarianRole]] + roles = relationship( + 'RISParliamentarianRole', + cascade='all, delete-orphan', + back_populates='party' + ) + + def __repr__(self) -> str: + return f'' diff --git a/src/onegov/ris/models/political_business.py b/src/onegov/ris/models/political_business.py new file mode 100644 index 0000000000..c8cea8c64c --- /dev/null +++ b/src/onegov/ris/models/political_business.py @@ -0,0 +1,200 @@ +from __future__ import annotations + +from sqlalchemy import Column, Date, Enum, ForeignKey, Text +from sqlalchemy.orm import RelationshipProperty, relationship +from uuid import uuid4 + +from onegov.core.orm import Base +from onegov.core.orm.types import UUID +from onegov.file import MultiAssociatedFiles +from onegov.ris import _ +from onegov.ris.models.meeting import RISMeeting +from onegov.search import ORMSearchable + + +from typing import TYPE_CHECKING, TypeAlias, Literal + +if TYPE_CHECKING: + import uuid + + from datetime import date + + from onegov.ris.models import RISParliamentarian + + PoliticalBusinessType: TypeAlias = Literal[ + 'inquiry', # Anfrage + 'proposal', # Antrag + 'mandate', # Auftrag + 'report', # Bericht + 'report and proposal', # Bericht und Antrag + 'decision', # Beschluss + 'message', # Botschaft + 'urgent interpellation', # Dringliche Interpellation + 'invitation', # Einladung + 'interpelleation', # Interpellation + 'commission report', # Kommissionsbericht + 'communication', # Mitteilung + 'motion', # Motion + 'postulate', # Postulat + 'resolution', # Resolution + 'regulation', # Verordnung + 'miscellaneous', # Verschiedenes + 'elections' # Wahlen + ] + + PoliticalBusinessStatus: TypeAlias = Literal[ + 'pending legislative', + 'pending executive', + 'substantial', + 'converted', + ] + +POLITICAL_BUSINESS_TYPE: dict[PoliticalBusinessType, str] = { + 'inquiry': _('Inquiry'), + 'proposal': _('Proposal'), + 'mandate': _('Mandate'), + 'report': _('Report'), + 'report and proposal': _('Report and Proposal'), + 'decision': _('Decision'), + 'message': _('Message'), + 'urgent interpellation': _('Urgent Interpellation'), + 'invitation': _('Invitation'), + 'interpelleation': _('Interpellation'), + 'commission report': _('Commission Report'), + 'communication': _('Communication'), + 'motion': _('Motion'), + 'postulate': _('Postulate'), + 'resolution': _('Resolution'), + 'regulation': _('Regulation'), + 'miscellaneous': _('Miscellaneous'), + 'elections': _('Elections'), +} + +POLITICAL_BUSINESS_STATUS: dict[PoliticalBusinessStatus, str] = { + 'pending legislative': _('Pending legislative'), + 'pending executive': _('Pending executive'), + 'substantial': _('Substantial'), + 'converted': _('Converted'), +} + + +class RISPoliticalBusiness(Base, MultiAssociatedFiles, ORMSearchable): + # Politisches Geschäft + + __tablename__ = 'ris_political_businesses' + + es_public = True + es_properties = { + 'title': {'type': 'text'}, + 'number': {'type': 'text'} + } + + @property + def es_suggestion(self) -> str: + return f'{self.title} {self.number}' + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4, + ) + + #: The title of the agenda item + title: Column[str] = Column(Text, nullable=False) + + #: number of the agenda item + number: Column[str | None] = Column(Text, nullable=True) + + #: business type of the agenda item + political_business_type: Column[PoliticalBusinessType] = Column( + Enum( + *POLITICAL_BUSINESS_TYPE.keys(), # type:ignore[arg-type] + name='ris_political_business_type', + ), + nullable=False, + ) + + #: status of the political business + status: Column[PoliticalBusinessStatus | None] = Column( + Enum( + *POLITICAL_BUSINESS_STATUS.keys(), # type:ignore[arg-type] + name='ris_political_business_status', + ), + nullable=True, + ) + + #: entry date of political business + entry_date: Column[date | None] = Column(Date, nullable=True) + + #: may have participants (Verfasser/Beteiligte) depending on the type + participants = relationship( + 'RISPoliticalBusinessParticipation', + back_populates='political_business', + lazy='joined', + ) + + #: parliamentary group (Fraktion) + parliamentary_group_id: Column[uuid.UUID | None] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parliamentary_groups.id'), + nullable=True, + ) + + #: The meetings this agenda item was discussed in + meetings: RelationshipProperty[RISMeeting] = relationship( + 'RISMeeting', + back_populates='political_businesses', + order_by=RISMeeting.start_datetime, + lazy='joined', + ) + + def __repr__(self) -> str: + return (f'') + + +class RISPoliticalBusinessParticipation(Base): + """ A participant of a political business, e.g. a parliamentarian. """ + + __tablename__ = 'ris_political_business_participants' + + #: Internal ID + id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + primary_key=True, + default=uuid4, + ) + + #: The id of the political business + political_business_id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_political_businesses.id'), + nullable=False, + ) + + #: The id of the parliamentarian + parliamentarian_id: Column[uuid.UUID] = Column( + UUID, # type:ignore[arg-type] + ForeignKey('ris_parliamentarians.id'), + nullable=False, + ) + + #: + participant_type: Column[str] = Column( + Enum('author', 'participant', name='ris_participant_type'), + nullable=False, + ) + + #: the related political business + political_business: RelationshipProperty[RISPoliticalBusiness] + political_business = relationship( + 'RISPoliticalBusiness', + back_populates='participants', + ) + + #: the related parliamentarian + parliamentarian: RelationshipProperty[RISParliamentarian] = relationship( + 'RISParliamentarian', + back_populates='political_businesses', + ) diff --git a/src/onegov/ris/templates/__init__.py b/src/onegov/ris/templates/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/onegov/ris/views/__init__.py b/src/onegov/ris/views/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 77b4c4dc985d5f617c3802fb35de5097ceaabb36 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Tue, 10 Jun 2025 08:59:10 +0200 Subject: [PATCH 02/17] Add to most models --- src/onegov/ris/models/commission.py | 4 ++-- src/onegov/ris/models/meeting.py | 3 ++- src/onegov/ris/models/membership.py | 4 ++-- src/onegov/ris/models/parliamentarian.py | 3 ++- src/onegov/ris/models/parliamentarian_role.py | 4 ++-- src/onegov/ris/models/political_business.py | 6 ++++-- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/onegov/ris/models/commission.py b/src/onegov/ris/models/commission.py index e990e83728..2c7626312d 100644 --- a/src/onegov/ris/models/commission.py +++ b/src/onegov/ris/models/commission.py @@ -5,7 +5,7 @@ from uuid import uuid4 from onegov.core.orm import Base, observes -from onegov.core.orm.mixins import dict_markup_property +from onegov.core.orm.mixins import dict_markup_property, ContentMixin from onegov.core.orm.mixins import TimestampMixin from onegov.core.orm.types import UUID from onegov.ris import _ @@ -35,7 +35,7 @@ } -class RISCommission(Base, TimestampMixin, ORMSearchable): +class RISCommission(Base, TimestampMixin, ContentMixin, ORMSearchable): __tablename__ = 'ris_commissions' diff --git a/src/onegov/ris/models/meeting.py b/src/onegov/ris/models/meeting.py index 4df96e6174..e5937d73e2 100644 --- a/src/onegov/ris/models/meeting.py +++ b/src/onegov/ris/models/meeting.py @@ -6,6 +6,7 @@ from sqlalchemy.orm import RelationshipProperty, relationship from onegov.core.orm import Base +from onegov.core.orm.mixins import ContentMixin from onegov.core.orm.types import UUID, MarkupText, UTCDateTime from onegov.search import ORMSearchable @@ -20,7 +21,7 @@ from onegov.ris.models.political_business import RISPoliticalBusiness -class RISMeeting(Base, ORMSearchable): +class RISMeeting(Base, ContentMixin, ORMSearchable): __tablename__ = 'ris_meetings' es_public = True diff --git a/src/onegov/ris/models/membership.py b/src/onegov/ris/models/membership.py index be33f67a96..403c0ca7dc 100644 --- a/src/onegov/ris/models/membership.py +++ b/src/onegov/ris/models/membership.py @@ -8,7 +8,7 @@ from uuid import uuid4 from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.mixins import TimestampMixin, ContentMixin from onegov.core.orm.types import UUID from onegov.ris import _ @@ -39,7 +39,7 @@ } -class RISCommissionMembership(Base, TimestampMixin): +class RISCommissionMembership(Base, ContentMixin, TimestampMixin): __tablename__ = 'ris_parliamentary_memberships' diff --git a/src/onegov/ris/models/parliamentarian.py b/src/onegov/ris/models/parliamentarian.py index b14469d089..5a23d6f197 100644 --- a/src/onegov/ris/models/parliamentarian.py +++ b/src/onegov/ris/models/parliamentarian.py @@ -9,6 +9,7 @@ from uuid import uuid4 from onegov.core.orm import Base +from onegov.core.orm.mixins import ContentMixin from onegov.core.orm.types import UUID from onegov.file import AssociatedFiles from onegov.file import NamedFile @@ -43,7 +44,7 @@ } -class RISParliamentarian(Base, AssociatedFiles, ORMSearchable): +class RISParliamentarian(Base, AssociatedFiles, ContentMixin, ORMSearchable): __tablename__ = 'ris_parliamentarians' es_public = False diff --git a/src/onegov/ris/models/parliamentarian_role.py b/src/onegov/ris/models/parliamentarian_role.py index 76ebc670bc..d8eaf5a4f3 100644 --- a/src/onegov/ris/models/parliamentarian_role.py +++ b/src/onegov/ris/models/parliamentarian_role.py @@ -9,7 +9,7 @@ from uuid import uuid4 from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.mixins import TimestampMixin, ContentMixin from onegov.core.orm.types import UUID from onegov.ris import _ @@ -83,7 +83,7 @@ } -class RISParliamentarianRole(Base, TimestampMixin): +class RISParliamentarianRole(Base, ContentMixin, TimestampMixin): __tablename__ = 'ris_parliamentarian_roles' diff --git a/src/onegov/ris/models/political_business.py b/src/onegov/ris/models/political_business.py index c8cea8c64c..c4e12b7841 100644 --- a/src/onegov/ris/models/political_business.py +++ b/src/onegov/ris/models/political_business.py @@ -5,6 +5,7 @@ from uuid import uuid4 from onegov.core.orm import Base +from onegov.core.orm.mixins import ContentMixin from onegov.core.orm.types import UUID from onegov.file import MultiAssociatedFiles from onegov.ris import _ @@ -78,7 +79,8 @@ } -class RISPoliticalBusiness(Base, MultiAssociatedFiles, ORMSearchable): +class RISPoliticalBusiness(Base, MultiAssociatedFiles, ContentMixin, + ORMSearchable): # Politisches Geschäft __tablename__ = 'ris_political_businesses' @@ -154,7 +156,7 @@ def __repr__(self) -> str: f'{self.title}, {self.political_business_type}>') -class RISPoliticalBusinessParticipation(Base): +class RISPoliticalBusinessParticipation(Base, ContentMixin, ORMSearchable): """ A participant of a political business, e.g. a parliamentarian. """ __tablename__ = 'ris_political_business_participants' From fcf66f9242133a1229f83bf48f8cc95382648c5e Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Tue, 10 Jun 2025 09:17:12 +0200 Subject: [PATCH 03/17] Undo searchable for PoliticalBusinessParticipation --- src/onegov/ris/models/political_business.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onegov/ris/models/political_business.py b/src/onegov/ris/models/political_business.py index c4e12b7841..e86d52982d 100644 --- a/src/onegov/ris/models/political_business.py +++ b/src/onegov/ris/models/political_business.py @@ -156,7 +156,7 @@ def __repr__(self) -> str: f'{self.title}, {self.political_business_type}>') -class RISPoliticalBusinessParticipation(Base, ContentMixin, ORMSearchable): +class RISPoliticalBusinessParticipation(Base, ContentMixin): """ A participant of a political business, e.g. a parliamentarian. """ __tablename__ = 'ris_political_business_participants' From d032c35fd7702432a19bf32e9f1cc1775bdc9083 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Thu, 12 Jun 2025 08:04:42 +0200 Subject: [PATCH 04/17] Move lowest common donominator from ris and pas to parliament namespace --- src/onegov/{ris => parliament}/__init__.py | 4 +- src/onegov/{ris => parliament}/i18n.py | 2 +- src/onegov/parliament/models/__init__.py | 49 +++ .../{pas => parliament}/models/attendence.py | 38 ++- .../{pas => parliament}/models/change.py | 21 +- .../{pas => parliament}/models/commission.py | 22 +- .../models/commission_membership.py | 36 +- .../{pas => parliament}/models/import_log.py | 2 +- .../models/legislative_period.py | 2 +- .../{ris => parliament}/models/meeting.py | 21 +- .../models/parliamentarian.py | 65 +++- .../models/parliamentarian_role.py | 40 ++- .../models/parliamentary_group.py | 6 +- .../{pas => parliament}/models/party.py | 6 +- .../models/political_business.py | 42 +-- .../{pas => parliament}/models/rate_set.py | 2 +- .../models/settlement_run.py | 2 +- src/onegov/pas/calculate_pay.py | 2 +- src/onegov/pas/collections/attendence.py | 3 +- src/onegov/pas/collections/change.py | 2 +- src/onegov/pas/collections/commission.py | 2 +- .../pas/collections/commission_membership.py | 2 +- src/onegov/pas/collections/import_log.py | 2 +- .../pas/collections/legislative_period.py | 2 +- src/onegov/pas/collections/parliamentarian.py | 2 +- .../pas/collections/parliamentarian_role.py | 2 +- .../pas/collections/parliamentary_group.py | 2 +- src/onegov/pas/collections/party.py | 2 +- src/onegov/pas/collections/rate_set.py | 2 +- src/onegov/pas/collections/settlement_run.py | 2 +- src/onegov/pas/custom.py | 2 +- src/onegov/pas/data_import.py | 4 +- src/onegov/pas/excel_import_cli.py | 2 +- .../pas/export_single_parliamentarian.py | 6 +- src/onegov/pas/forms/attendence.py | 6 +- src/onegov/pas/forms/commission.py | 2 +- src/onegov/pas/forms/commission_membership.py | 2 +- src/onegov/pas/forms/data_import.py | 2 +- src/onegov/pas/forms/legislative_period.py | 2 +- src/onegov/pas/forms/parliamentarian.py | 6 +- src/onegov/pas/forms/parliamentarian_role.py | 14 +- src/onegov/pas/forms/rate_set.py | 2 +- src/onegov/pas/forms/settlement_run.py | 2 +- src/onegov/pas/importer/json_import.py | 10 +- src/onegov/pas/models/__init__.py | 29 -- src/onegov/pas/path.py | 24 +- src/onegov/pas/utils.py | 10 +- src/onegov/pas/views/attendence.py | 4 +- src/onegov/pas/views/change.py | 2 +- src/onegov/pas/views/commission.py | 6 +- src/onegov/pas/views/commission_membership.py | 2 +- src/onegov/pas/views/import_log.py | 2 +- src/onegov/pas/views/legislative_period.py | 2 +- src/onegov/pas/views/parliamentarian.py | 4 +- src/onegov/pas/views/parliamentarian_role.py | 2 +- src/onegov/pas/views/parliamentary_group.py | 2 +- src/onegov/pas/views/party.py | 2 +- src/onegov/pas/views/rate_set.py | 2 +- src/onegov/pas/views/settlement_run.py | 8 +- src/onegov/ris/collections/__init__.py | 0 src/onegov/ris/forms/__init__.py | 0 src/onegov/ris/layouts/__init__.py | 0 src/onegov/ris/models/__init__.py | 26 -- src/onegov/ris/models/commission.py | 116 ------- src/onegov/ris/models/membership.py | 112 ------- src/onegov/ris/models/parliamentarian.py | 316 ------------------ src/onegov/ris/models/parliamentarian_role.py | 211 ------------ src/onegov/ris/models/parliamentary_group.py | 91 ----- src/onegov/ris/models/party.py | 79 ----- src/onegov/ris/templates/__init__.py | 0 src/onegov/ris/views/__init__.py | 0 src/onegov/search/indexer.py | 3 +- 72 files changed, 343 insertions(+), 1161 deletions(-) rename src/onegov/{ris => parliament}/__init__.py (60%) rename src/onegov/{ris => parliament}/i18n.py (68%) create mode 100644 src/onegov/parliament/models/__init__.py rename src/onegov/{pas => parliament}/models/attendence.py (88%) rename src/onegov/{pas => parliament}/models/change.py (91%) rename src/onegov/{pas => parliament}/models/commission.py (87%) rename src/onegov/{pas => parliament}/models/commission_membership.py (81%) rename src/onegov/{pas => parliament}/models/import_log.py (97%) rename src/onegov/{pas => parliament}/models/legislative_period.py (96%) rename src/onegov/{ris => parliament}/models/meeting.py (77%) rename src/onegov/{pas => parliament}/models/parliamentarian.py (86%) rename src/onegov/{pas => parliament}/models/parliamentarian_role.py (85%) rename src/onegov/{pas => parliament}/models/parliamentary_group.py (92%) rename src/onegov/{pas => parliament}/models/party.py (93%) rename src/onegov/{ris => parliament}/models/political_business.py (82%) rename src/onegov/{pas => parliament}/models/rate_set.py (98%) rename src/onegov/{pas => parliament}/models/settlement_run.py (98%) delete mode 100644 src/onegov/pas/models/__init__.py delete mode 100644 src/onegov/ris/collections/__init__.py delete mode 100644 src/onegov/ris/forms/__init__.py delete mode 100644 src/onegov/ris/layouts/__init__.py delete mode 100644 src/onegov/ris/models/__init__.py delete mode 100644 src/onegov/ris/models/commission.py delete mode 100644 src/onegov/ris/models/membership.py delete mode 100644 src/onegov/ris/models/parliamentarian.py delete mode 100644 src/onegov/ris/models/parliamentarian_role.py delete mode 100644 src/onegov/ris/models/parliamentary_group.py delete mode 100644 src/onegov/ris/models/party.py delete mode 100644 src/onegov/ris/templates/__init__.py delete mode 100644 src/onegov/ris/views/__init__.py diff --git a/src/onegov/ris/__init__.py b/src/onegov/parliament/__init__.py similarity index 60% rename from src/onegov/ris/__init__.py rename to src/onegov/parliament/__init__.py index 7534bc6086..7a4beeef64 100644 --- a/src/onegov/ris/__init__.py +++ b/src/onegov/parliament/__init__.py @@ -2,10 +2,10 @@ import logging -log = logging.getLogger('onegov.ris') +log = logging.getLogger('onegov.parliament') log.addHandler(logging.NullHandler()) -from onegov.ris.i18n import _ +from onegov.parliament.i18n import _ __all__ = ( '_', diff --git a/src/onegov/ris/i18n.py b/src/onegov/parliament/i18n.py similarity index 68% rename from src/onegov/ris/i18n.py rename to src/onegov/parliament/i18n.py index 40c901770e..11586f5a65 100644 --- a/src/onegov/ris/i18n.py +++ b/src/onegov/parliament/i18n.py @@ -2,4 +2,4 @@ from onegov.core.i18n.translation_string import TranslationStringFactory -_ = TranslationStringFactory('onegov.ris') +_ = TranslationStringFactory('onegov.parliament') diff --git a/src/onegov/parliament/models/__init__.py b/src/onegov/parliament/models/__init__.py new file mode 100644 index 0000000000..a3c9520ba0 --- /dev/null +++ b/src/onegov/parliament/models/__init__.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import logging + +log = logging.getLogger('onegov.parliament') +log.addHandler(logging.NullHandler()) + +from onegov.parliament.i18n import _ +from onegov.parliament.models.attendence import Attendence +from onegov.parliament.models.change import Change +from onegov.parliament.models.commission import Commission +from onegov.parliament.models.commission_membership import CommissionMembership +from onegov.parliament.models.import_log import ImportLog +from onegov.parliament.models.legislative_period import LegislativePeriod +from onegov.parliament.models.meeting import Meeting +from onegov.parliament.models.parliamentarian import ( + Parliamentarian, + RISParliamentarian +) +from onegov.parliament.models.parliamentarian_role import ParliamentarianRole +from onegov.parliament.models.parliamentary_group import ParliamentaryGroup +from onegov.parliament.models.party import Party +from onegov.parliament.models.political_business import ( + PoliticalBusiness, + PoliticalBusinessParticipation, +) +from onegov.parliament.models.rate_set import RateSet +from onegov.parliament.models.settlement_run import SettlementRun + + +__all__ = ( + '_', + 'log', + 'Attendence', + 'Change', + 'Commission', + 'CommissionMembership', + 'ImportLog', + 'LegislativePeriod', + 'Parliamentarian', + 'RISParliamentarian', + 'ParliamentarianRole', + 'ParliamentaryGroup', + 'Party', + 'PoliticalBusiness', + 'PoliticalBusinessParticipation', + 'RateSet', + 'SettlementRun', 'Attendence', 'Meeting' +) diff --git a/src/onegov/pas/models/attendence.py b/src/onegov/parliament/models/attendence.py similarity index 88% rename from src/onegov/pas/models/attendence.py rename to src/onegov/parliament/models/attendence.py index 0656481742..9beefb2608 100644 --- a/src/onegov/pas/models/attendence.py +++ b/src/onegov/parliament/models/attendence.py @@ -2,27 +2,30 @@ from decimal import ROUND_HALF_UP, Decimal -from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin -from onegov.core.orm.types import UUID -from onegov.pas import _ -from onegov.pas.models.commission import Commission -from onegov.pas.models.parliamentarian import Parliamentarian from sqlalchemy import Column from sqlalchemy import Date from sqlalchemy import Enum from sqlalchemy import ForeignKey from sqlalchemy import Integer +from sqlalchemy import Text from sqlalchemy.orm import relationship from uuid import uuid4 +from onegov.core.orm import Base +from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.types import UUID +from onegov.parliament import _ + from typing import TYPE_CHECKING + if TYPE_CHECKING: import uuid import datetime from typing import Literal from typing import TypeAlias + from onegov.parliament.models import Parliamentarian, Commission + AttendenceType: TypeAlias = Literal[ 'plenary', 'commission', @@ -40,7 +43,18 @@ class Attendence(Base, TimestampMixin): - __tablename__ = 'pas_attendence' + __tablename__ = 'par_attendence' + + attendence_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': attendence_type, + 'polymorphic_identity': 'generic', + } #: Internal ID id: Column[uuid.UUID] = Column( @@ -65,7 +79,7 @@ class Attendence(Base, TimestampMixin): type: Column[AttendenceType] = Column( Enum( *TYPES.keys(), # type:ignore[arg-type] - name='pas_attendence_type' + name='par_attendence_type' ), nullable=False, default='plenary' @@ -79,26 +93,26 @@ def type_label(self) -> str: #: The id of the parliamentarian parliamentarian_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_parliamentarians.id'), + ForeignKey('par_parliamentarians.id'), nullable=False ) #: The parliamentarian parliamentarian: relationship[Parliamentarian] = relationship( - Parliamentarian, + 'Parliamentarian', back_populates='attendences' ) #: the id of the commission commission_id: Column[uuid.UUID | None] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_commissions.id'), + ForeignKey('par_commissions.id'), nullable=True ) #: the related commission (which may have any number of memberships) commission: relationship[Commission | None] = relationship( - Commission, + 'Commission', back_populates='attendences' ) diff --git a/src/onegov/pas/models/change.py b/src/onegov/parliament/models/change.py similarity index 91% rename from src/onegov/pas/models/change.py rename to src/onegov/parliament/models/change.py index 2899972758..9b62dac00c 100644 --- a/src/onegov/pas/models/change.py +++ b/src/onegov/parliament/models/change.py @@ -6,20 +6,21 @@ from onegov.core.orm.mixins import ContentMixin from onegov.core.orm.mixins import TimestampMixin from onegov.core.orm.types import UUID -from onegov.pas import _ from sqlalchemy import Column from sqlalchemy import Enum from sqlalchemy import String from sqlalchemy.orm import object_session from uuid import uuid4 +from onegov.parliament import _ + from typing import TYPE_CHECKING if TYPE_CHECKING: import uuid from onegov.core.orm.mixins import dict_property - from onegov.pas.models import Attendence - from onegov.pas.models import Commission - from onegov.pas.models import Parliamentarian + from onegov.parliament.models import Attendence + from onegov.parliament.models import Commission + from onegov.parliament.models import Parliamentarian from onegov.town6.request import TownRequest from typing import Literal from typing import TypeAlias @@ -39,7 +40,7 @@ class Change(Base, ContentMixin, TimestampMixin): - __tablename__ = 'pas_changes' + __tablename__ = 'par_changes' #: Internal ID id: Column[uuid.UUID] = Column( @@ -54,7 +55,7 @@ class Change(Base, ContentMixin, TimestampMixin): nullable=True ) - #: The user name responsible for the change + #: The username responsible for the change user_name: Column[str | None] = Column( String, nullable=True @@ -74,7 +75,7 @@ def user(self) -> str | None: action: Column[Action] = Column( Enum( *ACTIONS, # type:ignore[arg-type] - name='pas_actions' + name='par_actions' ), nullable=False ) @@ -97,7 +98,7 @@ def action_label(self) -> str: @property def attendence(self) -> Attendence | None: - from onegov.pas.models import Attendence + from onegov.parliament.models import Attendence attendence_id = (self.changes or {}).get('id') if self.model == 'attendence' and attendence_id: session = object_session(self) @@ -119,7 +120,7 @@ def date(self) -> date | None: @property def parliamentarian(self) -> Parliamentarian | None: - from onegov.pas.models import Parliamentarian + from onegov.parliament.models import Parliamentarian parliamentarian_id = (self.changes or {}).get('parliamentarian_id') if self.model == 'attendence' and parliamentarian_id: session = object_session(self) @@ -131,7 +132,7 @@ def parliamentarian(self) -> Parliamentarian | None: @property def commission(self) -> Commission | None: - from onegov.pas.models import Commission + from onegov.parliament.models import Commission commission_id = (self.changes or {}).get('commission_id') if self.model == 'attendence' and commission_id: session = object_session(self) diff --git a/src/onegov/pas/models/commission.py b/src/onegov/parliament/models/commission.py similarity index 87% rename from src/onegov/pas/models/commission.py rename to src/onegov/parliament/models/commission.py index 8645236b40..656197469f 100644 --- a/src/onegov/pas/models/commission.py +++ b/src/onegov/parliament/models/commission.py @@ -5,7 +5,7 @@ from onegov.core.orm.mixins import ContentMixin from onegov.core.orm.mixins import TimestampMixin from onegov.core.orm.types import UUID -from onegov.pas import _ +from onegov.parliament import _ from onegov.search import ORMSearchable from sqlalchemy import Column from sqlalchemy import Date @@ -17,14 +17,15 @@ from typing import TYPE_CHECKING + if TYPE_CHECKING: import uuid from datetime import date - from onegov.pas.models.attendence import Attendence - from onegov.pas.models.commission_membership import CommissionMembership from typing import Literal from typing import TypeAlias + from onegov.parliament.models import CommissionMembership, Attendence + CommissionType: TypeAlias = Literal[ 'normal', 'intercantonal', @@ -41,7 +42,18 @@ class Commission(Base, ContentMixin, TimestampMixin, ORMSearchable): - __tablename__ = 'pas_commissions' + __tablename__ = 'par_commissions' + + commission_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': commission_type, + 'polymorphic_identity': 'generic', + } es_public = False es_properties = {'name': {'type': 'text'}} @@ -91,7 +103,7 @@ def title(self) -> str: type: Column[CommissionType] = Column( Enum( *TYPES.keys(), # type:ignore[arg-type] - name='pas_commission_type' + name='commission_type' ), nullable=False, default='normal' diff --git a/src/onegov/pas/models/commission_membership.py b/src/onegov/parliament/models/commission_membership.py similarity index 81% rename from src/onegov/pas/models/commission_membership.py rename to src/onegov/parliament/models/commission_membership.py index 61ba12f548..56a6286941 100644 --- a/src/onegov/pas/models/commission_membership.py +++ b/src/onegov/parliament/models/commission_membership.py @@ -1,25 +1,28 @@ from __future__ import annotations -from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin -from onegov.core.orm.types import UUID -from onegov.pas import _ -from onegov.pas.models.commission import Commission -from onegov.pas.models.parliamentarian import Parliamentarian from sqlalchemy import Column from sqlalchemy import Date from sqlalchemy import Enum from sqlalchemy import ForeignKey +from sqlalchemy import Text from sqlalchemy.orm import relationship from uuid import uuid4 +from onegov.core.orm import Base +from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.types import UUID +from onegov.parliament import _ + from typing import TYPE_CHECKING + if TYPE_CHECKING: import uuid from datetime import date from typing import Literal from typing import TypeAlias + from onegov.parliament.models import Commission, Parliamentarian + MembershipRole: TypeAlias = Literal[ 'guest', 'member', @@ -37,7 +40,18 @@ class CommissionMembership(Base, TimestampMixin): - __tablename__ = 'pas_commission_memberships' + __tablename__ = 'par_commission_memberships' + + membership_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': membership_type, + 'polymorphic_identity': 'generic', + } #: Internal ID id: Column[uuid.UUID] = Column( @@ -76,26 +90,26 @@ def role_label(self) -> str: #: the id of the commission commission_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_commissions.id'), + ForeignKey('par_commissions.id'), nullable=False ) #: the related commission (which may have any number of memberships) commission: relationship[Commission] = relationship( - Commission, + 'Commission', back_populates='memberships' ) #: the id of the parliamentarian parliamentarian_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_parliamentarians.id'), + ForeignKey('par_parliamentarians.id'), nullable=False ) #: the related parliamentarian (which may have any number of memberships) parliamentarian: relationship[Parliamentarian] = relationship( - Parliamentarian, + 'Parliamentarian', back_populates='commission_memberships' ) diff --git a/src/onegov/pas/models/import_log.py b/src/onegov/parliament/models/import_log.py similarity index 97% rename from src/onegov/pas/models/import_log.py rename to src/onegov/parliament/models/import_log.py index 040c5f9799..65748ccab9 100644 --- a/src/onegov/pas/models/import_log.py +++ b/src/onegov/parliament/models/import_log.py @@ -18,7 +18,7 @@ class ImportLog(Base, TimestampMixin): """ Logs the summary of a KUB data import attempt. """ - __tablename__ = 'pas_import_logs' + __tablename__ = 'par_import_logs' id: Column[uuid.UUID] = Column( UUID, # type: ignore[arg-type] diff --git a/src/onegov/pas/models/legislative_period.py b/src/onegov/parliament/models/legislative_period.py similarity index 96% rename from src/onegov/pas/models/legislative_period.py rename to src/onegov/parliament/models/legislative_period.py index 7bbea71c6c..19821c3301 100644 --- a/src/onegov/pas/models/legislative_period.py +++ b/src/onegov/parliament/models/legislative_period.py @@ -17,7 +17,7 @@ class LegislativePeriod(Base, TimestampMixin, ORMSearchable): - __tablename__ = 'pas_legislative_periods' + __tablename__ = 'par_legislative_periods' es_public = False es_properties = {'name': {'type': 'text'}} diff --git a/src/onegov/ris/models/meeting.py b/src/onegov/parliament/models/meeting.py similarity index 77% rename from src/onegov/ris/models/meeting.py rename to src/onegov/parliament/models/meeting.py index e5937d73e2..df52153598 100644 --- a/src/onegov/ris/models/meeting.py +++ b/src/onegov/parliament/models/meeting.py @@ -18,11 +18,14 @@ from markupsafe import Markup from datetime import datetime - from onegov.ris.models.political_business import RISPoliticalBusiness + from onegov.parliament.models.political_business import ( + PoliticalBusiness, + ) + +class Meeting(Base, ContentMixin, ORMSearchable): -class RISMeeting(Base, ContentMixin, ORMSearchable): - __tablename__ = 'ris_meetings' + __tablename__ = 'par_meetings' es_public = True es_properties = {'title_text': {'type': 'text'}} @@ -57,17 +60,17 @@ def title_text(self) -> str: #: political business id political_business_id: Column[uuid.UUID | None] = Column( UUID, # type:ignore[arg-type] - ForeignKey('ris_political_businesses.id'), + ForeignKey('par_political_businesses.id'), ) #: list of political businesses, "Traktanden" - political_businesses: RelationshipProperty[RISPoliticalBusiness] = ( + political_businesses: RelationshipProperty[PoliticalBusiness] = ( relationship( - 'RISPoliticalBusiness', + 'PoliticalBusiness', back_populates='meetings', - order_by='RISPoliticalBusiness.number', - primaryjoin='RISMeeting.political_business_id == ' - 'RISPoliticalBusiness.id', + order_by='PoliticalBusiness.number', + primaryjoin='Meeting.political_business_id == ' + 'PoliticalBusiness.id', ) ) diff --git a/src/onegov/pas/models/parliamentarian.py b/src/onegov/parliament/models/parliamentarian.py similarity index 86% rename from src/onegov/pas/models/parliamentarian.py rename to src/onegov/parliament/models/parliamentarian.py index bd95552404..542f1a6ed4 100644 --- a/src/onegov/pas/models/parliamentarian.py +++ b/src/onegov/parliament/models/parliamentarian.py @@ -7,6 +7,7 @@ from onegov.core.orm.types import UUID from onegov.file import AssociatedFiles from onegov.file import NamedFile +from onegov.parliament.models import ParliamentarianRole from onegov.pas import _ from onegov.search import ORMSearchable from sqlalchemy import Column, or_ @@ -18,16 +19,23 @@ from typing import TYPE_CHECKING + if TYPE_CHECKING: - import uuid - from onegov.pas.models.attendence import Attendence - from onegov.pas.models import ParliamentarianRole - from sqlalchemy.orm import Session - from onegov.pas.models.commission_membership import CommissionMembership - from onegov.pas.models.party import Party from typing import Literal from typing import TypeAlias + from sqlalchemy.orm import Session + import uuid + + from onegov.parliament.models.attendence import Attendence + from onegov.parliament.models.commission_membership import ( + CommissionMembership + ) + from onegov.parliament.models.political_business import ( + PoliticalBusinessParticipation + ) + from onegov.parliament.models.party import Party + Gender: TypeAlias = Literal[ 'male', 'female', @@ -56,11 +64,21 @@ } -class Parliamentarian( - Base, ContentMixin, TimestampMixin, AssociatedFiles, ORMSearchable -): +class Parliamentarian(Base, ContentMixin, TimestampMixin, AssociatedFiles, + ORMSearchable): + + __tablename__ = 'par_parliamentarians' + + parliamentarian_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) - __tablename__ = 'pas_parliamentarians' + __mapper_args__ = { + 'polymorphic_on': parliamentarian_type, + 'polymorphic_identity': 'generic', + } es_public = False es_properties = { @@ -79,6 +97,12 @@ def es_suggestion(self) -> tuple[str, ...]: def title(self) -> str: return f'{self.first_name} {self.last_name}' + type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + #: Internal ID id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] @@ -322,7 +346,9 @@ def get_party_during_period( """Get the party this parliamentarian belonged to during a specific period.""" - from onegov.pas.models.parliamentarian_role import ParliamentarianRole + from onegov.parliament.models.parliamentarian_role import ( + ParliamentarianRole + ) role = ( session.query(ParliamentarianRole) .filter( @@ -396,3 +422,20 @@ def __repr__(self) -> str: f"email='{self.email_primary}'") return f"" + + +class RISParliamentarian(Parliamentarian): + + __mapper_args__ = { + 'polymorphic_identity': 'ris_parliamentarian', + } + + es_type_name = 'ris_parliamentarian' + + #: political businesses participations [0..n] + political_businesses: relationship[list[PoliticalBusinessParticipation]] + political_businesses = relationship( + 'PoliticalBusinessParticipation', + back_populates='parliamentarian', + lazy='joined' + ) diff --git a/src/onegov/pas/models/parliamentarian_role.py b/src/onegov/parliament/models/parliamentarian_role.py similarity index 85% rename from src/onegov/pas/models/parliamentarian_role.py rename to src/onegov/parliament/models/parliamentarian_role.py index e743ab802f..bf693505c6 100644 --- a/src/onegov/pas/models/parliamentarian_role.py +++ b/src/onegov/parliament/models/parliamentarian_role.py @@ -1,12 +1,5 @@ from __future__ import annotations -from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin -from onegov.core.orm.types import UUID -from onegov.pas import _ -from onegov.pas.models.parliamentarian import Parliamentarian -from onegov.pas.models.parliamentary_group import ParliamentaryGroup -from onegov.pas.models.party import Party from sqlalchemy import Column from sqlalchemy import Date from sqlalchemy import Enum @@ -15,6 +8,14 @@ from sqlalchemy.orm import relationship from uuid import uuid4 +from onegov.core.orm import Base +from onegov.core.orm.mixins import TimestampMixin +from onegov.core.orm.types import UUID +from onegov.parliament import _ +from onegov.parliament.models.parliamentarian import Parliamentarian +from onegov.parliament.models.parliamentary_group import ParliamentaryGroup +from onegov.parliament.models.party import Party + from typing import TYPE_CHECKING if TYPE_CHECKING: import uuid @@ -74,7 +75,18 @@ class ParliamentarianRole(Base, TimestampMixin): - __tablename__ = 'pas_parliamentarian_roles' + __tablename__ = 'par_parliamentarian_roles' + + parliamentarian_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': parliamentarian_type, + 'polymorphic_identity': 'generic', + } #: Internal ID id: Column[uuid.UUID] = Column( @@ -98,7 +110,7 @@ class ParliamentarianRole(Base, TimestampMixin): #: The id of the parliamentarian parliamentarian_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_parliamentarians.id'), + ForeignKey('par_parliamentarians.id'), nullable=False ) @@ -112,7 +124,7 @@ class ParliamentarianRole(Base, TimestampMixin): role: Column[Role] = Column( Enum( *PARLIAMENTARIAN_ROLES.keys(), # type:ignore[arg-type] - name='pas_pariliamentarian_role' + name='par_parliamentarian_role' ), nullable=False, default='member' @@ -126,7 +138,7 @@ def role_label(self) -> str: #: The id of the party party_id: Column[uuid.UUID | None] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_parties.id'), + ForeignKey('par_parties.id'), nullable=True ) @@ -140,7 +152,7 @@ def role_label(self) -> str: party_role: Column[PartyRole] = Column( Enum( *PARTY_ROLES.keys(), # type:ignore[arg-type] - name='pas_party_role' + name='par_party_role' ), nullable=False, default='member' @@ -154,7 +166,7 @@ def party_role_label(self) -> str: #: The id of the parliamentary group parliamentary_group_id: Column[uuid.UUID | None] = Column( UUID, # type:ignore[arg-type] - ForeignKey('pas_parliamentary_groups.id'), + ForeignKey('par_parliamentary_groups.id'), nullable=True ) @@ -169,7 +181,7 @@ def party_role_label(self) -> str: parliamentary_group_role: Column[ParliamentaryGroupRole] = Column( Enum( *PARLIAMENTARY_GROUP_ROLES.keys(), # type:ignore[arg-type] - name='pas_parliamentary_group_role' + name='par_parliamentary_group_role' ), nullable=False, default='member' diff --git a/src/onegov/pas/models/parliamentary_group.py b/src/onegov/parliament/models/parliamentary_group.py similarity index 92% rename from src/onegov/pas/models/parliamentary_group.py rename to src/onegov/parliament/models/parliamentary_group.py index f879138d53..7a0e90fc01 100644 --- a/src/onegov/pas/models/parliamentary_group.py +++ b/src/onegov/parliament/models/parliamentary_group.py @@ -16,13 +16,15 @@ if TYPE_CHECKING: import uuid from datetime import date - from onegov.pas.models.parliamentarian_role import ParliamentarianRole + from onegov.parliament.models.parliamentarian_role import ( + ParliamentarianRole + ) class ParliamentaryGroup(Base, ContentMixin, TimestampMixin, ORMSearchable): """ Fraktion """ - __tablename__ = 'pas_parliamentary_groups' + __tablename__ = 'par_parliamentary_groups' es_public = False es_properties = {'name': {'type': 'text'}} diff --git a/src/onegov/pas/models/party.py b/src/onegov/parliament/models/party.py similarity index 93% rename from src/onegov/pas/models/party.py rename to src/onegov/parliament/models/party.py index 5fa82bbaa6..ea5811a668 100644 --- a/src/onegov/pas/models/party.py +++ b/src/onegov/parliament/models/party.py @@ -16,12 +16,14 @@ if TYPE_CHECKING: import uuid from datetime import date - from onegov.pas.models.parliamentarian_role import ParliamentarianRole + from onegov.parliament.models.parliamentarian_role import ( + ParliamentarianRole + ) class Party(Base, ContentMixin, TimestampMixin, ORMSearchable): - __tablename__ = 'pas_parties' + __tablename__ = 'par_parties' es_public = False es_properties = {'name': {'type': 'text'}} diff --git a/src/onegov/ris/models/political_business.py b/src/onegov/parliament/models/political_business.py similarity index 82% rename from src/onegov/ris/models/political_business.py rename to src/onegov/parliament/models/political_business.py index e86d52982d..86e92ec9aa 100644 --- a/src/onegov/ris/models/political_business.py +++ b/src/onegov/parliament/models/political_business.py @@ -8,8 +8,8 @@ from onegov.core.orm.mixins import ContentMixin from onegov.core.orm.types import UUID from onegov.file import MultiAssociatedFiles -from onegov.ris import _ -from onegov.ris.models.meeting import RISMeeting +from onegov.parliament import _ +from onegov.parliament.models.meeting import Meeting from onegov.search import ORMSearchable @@ -20,7 +20,7 @@ from datetime import date - from onegov.ris.models import RISParliamentarian + from onegov.parliament.models import Parliamentarian PoliticalBusinessType: TypeAlias = Literal[ 'inquiry', # Anfrage @@ -79,11 +79,11 @@ } -class RISPoliticalBusiness(Base, MultiAssociatedFiles, ContentMixin, +class PoliticalBusiness(Base, MultiAssociatedFiles, ContentMixin, ORMSearchable): # Politisches Geschäft - __tablename__ = 'ris_political_businesses' + __tablename__ = 'par_political_businesses' es_public = True es_properties = { @@ -112,7 +112,7 @@ def es_suggestion(self) -> str: political_business_type: Column[PoliticalBusinessType] = Column( Enum( *POLITICAL_BUSINESS_TYPE.keys(), # type:ignore[arg-type] - name='ris_political_business_type', + name='par_political_business_type', ), nullable=False, ) @@ -121,7 +121,7 @@ def es_suggestion(self) -> str: status: Column[PoliticalBusinessStatus | None] = Column( Enum( *POLITICAL_BUSINESS_STATUS.keys(), # type:ignore[arg-type] - name='ris_political_business_status', + name='par_political_business_status', ), nullable=True, ) @@ -131,7 +131,7 @@ def es_suggestion(self) -> str: #: may have participants (Verfasser/Beteiligte) depending on the type participants = relationship( - 'RISPoliticalBusinessParticipation', + 'PoliticalBusinessParticipation', back_populates='political_business', lazy='joined', ) @@ -139,15 +139,15 @@ def es_suggestion(self) -> str: #: parliamentary group (Fraktion) parliamentary_group_id: Column[uuid.UUID | None] = Column( UUID, # type:ignore[arg-type] - ForeignKey('ris_parliamentary_groups.id'), + ForeignKey('par_parliamentary_groups.id'), nullable=True, ) #: The meetings this agenda item was discussed in - meetings: RelationshipProperty[RISMeeting] = relationship( - 'RISMeeting', + meetings: RelationshipProperty[Meeting] = relationship( + 'Meeting', back_populates='political_businesses', - order_by=RISMeeting.start_datetime, + order_by=Meeting.start_datetime, lazy='joined', ) @@ -156,10 +156,10 @@ def __repr__(self) -> str: f'{self.title}, {self.political_business_type}>') -class RISPoliticalBusinessParticipation(Base, ContentMixin): +class PoliticalBusinessParticipation(Base, ContentMixin): """ A participant of a political business, e.g. a parliamentarian. """ - __tablename__ = 'ris_political_business_participants' + __tablename__ = 'par_political_business_participants' #: Internal ID id: Column[uuid.UUID] = Column( @@ -171,32 +171,32 @@ class RISPoliticalBusinessParticipation(Base, ContentMixin): #: The id of the political business political_business_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] - ForeignKey('ris_political_businesses.id'), + ForeignKey('par_political_businesses.id'), nullable=False, ) #: The id of the parliamentarian parliamentarian_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] - ForeignKey('ris_parliamentarians.id'), + ForeignKey('par_parliamentarians.id'), nullable=False, ) #: participant_type: Column[str] = Column( - Enum('author', 'participant', name='ris_participant_type'), + Enum('author', 'participant', name='par_participant_type'), nullable=False, ) #: the related political business - political_business: RelationshipProperty[RISPoliticalBusiness] + political_business: RelationshipProperty[PoliticalBusiness] political_business = relationship( - 'RISPoliticalBusiness', + 'PoliticalBusiness', back_populates='participants', ) #: the related parliamentarian - parliamentarian: RelationshipProperty[RISParliamentarian] = relationship( - 'RISParliamentarian', + parliamentarian: RelationshipProperty[Parliamentarian] = relationship( + 'Parliamentarian', back_populates='political_businesses', ) diff --git a/src/onegov/pas/models/rate_set.py b/src/onegov/parliament/models/rate_set.py similarity index 98% rename from src/onegov/pas/models/rate_set.py rename to src/onegov/parliament/models/rate_set.py index fe28dff291..b98e673ad2 100644 --- a/src/onegov/pas/models/rate_set.py +++ b/src/onegov/parliament/models/rate_set.py @@ -18,7 +18,7 @@ class RateSet(Base, ContentMixin, TimestampMixin): """ Sätze """ - __tablename__ = 'pas_rate_sets' + __tablename__ = 'par_rate_sets' #: Internal ID id: Column[uuid.UUID] = Column( diff --git a/src/onegov/pas/models/settlement_run.py b/src/onegov/parliament/models/settlement_run.py similarity index 98% rename from src/onegov/pas/models/settlement_run.py rename to src/onegov/parliament/models/settlement_run.py index c1171c452a..9d8bc136ba 100644 --- a/src/onegov/pas/models/settlement_run.py +++ b/src/onegov/parliament/models/settlement_run.py @@ -20,7 +20,7 @@ class SettlementRun(Base, ContentMixin, TimestampMixin, ORMSearchable): """ Abrechnungslauf """ - __tablename__ = 'pas_settlements' + __tablename__ = 'par_settlements' es_public = False es_properties = {'name': {'type': 'text'}} diff --git a/src/onegov/pas/calculate_pay.py b/src/onegov/pas/calculate_pay.py index 12b23c5b16..b6006412a6 100644 --- a/src/onegov/pas/calculate_pay.py +++ b/src/onegov/pas/calculate_pay.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from onegov.pas.models.rate_set import RateSet + from onegov.parliament.models.rate_set import RateSet def calculate_rate( diff --git a/src/onegov/pas/collections/attendence.py b/src/onegov/pas/collections/attendence.py index b2474c1888..3afcebf6a1 100644 --- a/src/onegov/pas/collections/attendence.py +++ b/src/onegov/pas/collections/attendence.py @@ -1,12 +1,13 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models import ( +from onegov.parliament.models import ( Attendence, SettlementRun, Parliamentarian, ParliamentarianRole, ) + from sqlalchemy import desc, or_ diff --git a/src/onegov/pas/collections/change.py b/src/onegov/pas/collections/change.py index 608d109492..261b191cba 100644 --- a/src/onegov/pas/collections/change.py +++ b/src/onegov/pas/collections/change.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models import Change +from onegov.parliament.models import Change from sqlalchemy import desc from typing import TYPE_CHECKING diff --git a/src/onegov/pas/collections/commission.py b/src/onegov/pas/collections/commission.py index 64f2e7e6a6..8f8b2786e1 100644 --- a/src/onegov/pas/collections/commission.py +++ b/src/onegov/pas/collections/commission.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.pas.models import Commission +from onegov.parliament.models import Commission from sqlalchemy import or_ from typing import TYPE_CHECKING diff --git a/src/onegov/pas/collections/commission_membership.py b/src/onegov/pas/collections/commission_membership.py index 2d962f506e..6b74b9de08 100644 --- a/src/onegov/pas/collections/commission_membership.py +++ b/src/onegov/pas/collections/commission_membership.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models import CommissionMembership +from onegov.parliament.models import CommissionMembership class CommissionMembershipCollection(GenericCollection[CommissionMembership]): diff --git a/src/onegov/pas/collections/import_log.py b/src/onegov/pas/collections/import_log.py index 5098de9162..ec0003101f 100644 --- a/src/onegov/pas/collections/import_log.py +++ b/src/onegov/pas/collections/import_log.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models.import_log import ImportLog +from onegov.parliament.models.import_log import ImportLog from typing import Self, TYPE_CHECKING diff --git a/src/onegov/pas/collections/legislative_period.py b/src/onegov/pas/collections/legislative_period.py index fa2cd7d89a..3ff2c5de3c 100644 --- a/src/onegov/pas/collections/legislative_period.py +++ b/src/onegov/pas/collections/legislative_period.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.pas.models import LegislativePeriod +from onegov.parliament.models import LegislativePeriod from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/collections/parliamentarian.py b/src/onegov/pas/collections/parliamentarian.py index 41e7fcb06a..fe8d62244b 100644 --- a/src/onegov/pas/collections/parliamentarian.py +++ b/src/onegov/pas/collections/parliamentarian.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models import Parliamentarian +from onegov.parliament.models import Parliamentarian from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/collections/parliamentarian_role.py b/src/onegov/pas/collections/parliamentarian_role.py index 95caedf942..4df04c8159 100644 --- a/src/onegov/pas/collections/parliamentarian_role.py +++ b/src/onegov/pas/collections/parliamentarian_role.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models import ParliamentarianRole +from onegov.parliament.models import ParliamentarianRole class ParliamentarianRoleCollection(GenericCollection[ParliamentarianRole]): diff --git a/src/onegov/pas/collections/parliamentary_group.py b/src/onegov/pas/collections/parliamentary_group.py index bac3c6385e..c340211bfe 100644 --- a/src/onegov/pas/collections/parliamentary_group.py +++ b/src/onegov/pas/collections/parliamentary_group.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.pas.models import ParliamentaryGroup +from onegov.parliament.models import ParliamentaryGroup from sqlalchemy import or_ from typing import TYPE_CHECKING diff --git a/src/onegov/pas/collections/party.py b/src/onegov/pas/collections/party.py index 41046b4dd6..7f0e7df088 100644 --- a/src/onegov/pas/collections/party.py +++ b/src/onegov/pas/collections/party.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.pas.models import Party +from onegov.parliament.models import Party from sqlalchemy import or_ from typing import TYPE_CHECKING diff --git a/src/onegov/pas/collections/rate_set.py b/src/onegov/pas/collections/rate_set.py index bf47dcae15..783f7d6fd2 100644 --- a/src/onegov/pas/collections/rate_set.py +++ b/src/onegov/pas/collections/rate_set.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.pas.models import RateSet +from onegov.parliament.models import RateSet from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/collections/settlement_run.py b/src/onegov/pas/collections/settlement_run.py index 186fa24d30..c0d6c52aaa 100644 --- a/src/onegov/pas/collections/settlement_run.py +++ b/src/onegov/pas/collections/settlement_run.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.pas.models import SettlementRun +from onegov.parliament.models import SettlementRun from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/custom.py b/src/onegov/pas/custom.py index c10a5b5c82..0b3e56afc8 100644 --- a/src/onegov/pas/custom.py +++ b/src/onegov/pas/custom.py @@ -7,7 +7,7 @@ from onegov.pas.collections import AttendenceCollection from onegov.pas.collections import ChangeCollection from onegov.user import Auth -from onegov.pas.models import SettlementRun, RateSet +from onegov.parliament.models import SettlementRun, RateSet from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/data_import.py b/src/onegov/pas/data_import.py index d92f0d57fc..ffa43893fc 100644 --- a/src/onegov/pas/data_import.py +++ b/src/onegov/pas/data_import.py @@ -16,7 +16,7 @@ import openpyxl from onegov.core.csv import CSVFile, convert_excel_to_csv, detect_encoding -from onegov.pas.models import ( +from onegov.parliament.models import ( CommissionMembership, ParliamentarianRole, Parliamentarian, @@ -32,7 +32,7 @@ from typing import Any as Incomplete from typing import TYPE_CHECKING if TYPE_CHECKING: - from onegov.pas.models.commission_membership import MembershipRole + from onegov.parliament.models.commission_membership import MembershipRole from collections.abc import Callable from sqlalchemy.orm import Session from types import TracebackType diff --git a/src/onegov/pas/excel_import_cli.py b/src/onegov/pas/excel_import_cli.py index 934d729d40..9e65c6ecae 100644 --- a/src/onegov/pas/excel_import_cli.py +++ b/src/onegov/pas/excel_import_cli.py @@ -15,7 +15,7 @@ import openpyxl from onegov.core.csv import CSVFile, convert_excel_to_csv, detect_encoding -from onegov.pas.models import ( +from onegov.parliament.models import ( CommissionMembership, ParliamentarianRole, Parliamentarian, diff --git a/src/onegov/pas/export_single_parliamentarian.py b/src/onegov/pas/export_single_parliamentarian.py index 0d0af93545..81c2c0c859 100644 --- a/src/onegov/pas/export_single_parliamentarian.py +++ b/src/onegov/pas/export_single_parliamentarian.py @@ -11,15 +11,15 @@ from weasyprint.text.fonts import ( # type: ignore[import-untyped] FontConfiguration, ) -from onegov.pas.models.attendence import TYPES, Attendence +from onegov.parliament.models.attendence import TYPES, Attendence from datetime import date # noqa: TC003 from onegov.pas.utils import format_swiss_number from typing import TYPE_CHECKING, Literal, TypedDict if TYPE_CHECKING: - from onegov.pas.models import Parliamentarian, RateSet - from onegov.pas.models.settlement_run import SettlementRun + from onegov.parliament.models import Parliamentarian, RateSet + from onegov.parliament.models.settlement_run import SettlementRun @dataclass diff --git a/src/onegov/pas/forms/attendence.py b/src/onegov/pas/forms/attendence.py index 427735ff21..5d805c2f0c 100644 --- a/src/onegov/pas/forms/attendence.py +++ b/src/onegov/pas/forms/attendence.py @@ -8,8 +8,8 @@ from onegov.pas import _ from onegov.pas.collections import CommissionCollection from onegov.pas.collections import ParliamentarianCollection -from onegov.pas.models import SettlementRun -from onegov.pas.models.attendence import TYPES +from onegov.parliament.models import SettlementRun +from onegov.parliament.models.attendence import TYPES from wtforms.fields import DateField from wtforms.fields import FloatField from wtforms.fields import RadioField @@ -19,7 +19,7 @@ if TYPE_CHECKING: from collections.abc import Collection from onegov.core.request import CoreRequest - from onegov.pas.models import Attendence + from onegov.parliament.models import Attendence from typing import Any diff --git a/src/onegov/pas/forms/commission.py b/src/onegov/pas/forms/commission.py index a000ef64b4..038350df9b 100644 --- a/src/onegov/pas/forms/commission.py +++ b/src/onegov/pas/forms/commission.py @@ -4,7 +4,7 @@ from onegov.form.fields import TranslatedSelectField from onegov.org.forms.fields import HtmlField from onegov.pas import _ -from onegov.pas.models.commission import TYPES +from onegov.parliament.models.commission import TYPES from wtforms.fields import DateField from wtforms.fields import StringField from wtforms.validators import InputRequired diff --git a/src/onegov/pas/forms/commission_membership.py b/src/onegov/pas/forms/commission_membership.py index 56f0b23c2b..03bbe7151b 100644 --- a/src/onegov/pas/forms/commission_membership.py +++ b/src/onegov/pas/forms/commission_membership.py @@ -7,7 +7,7 @@ from onegov.pas import _ from onegov.pas.collections import CommissionCollection from onegov.pas.collections import ParliamentarianCollection -from onegov.pas.models.commission_membership import ROLES +from onegov.parliament.models.commission_membership import ROLES from wtforms.fields import DateField from wtforms.validators import InputRequired from wtforms.validators import Optional diff --git a/src/onegov/pas/forms/data_import.py b/src/onegov/pas/forms/data_import.py index b91fa2aa71..31f21c2bf0 100644 --- a/src/onegov/pas/forms/data_import.py +++ b/src/onegov/pas/forms/data_import.py @@ -5,7 +5,7 @@ from onegov.form import Form from onegov.form.fields import UploadMultipleField from wtforms.fields import BooleanField -from onegov.pas import _ +from onegov.parliament import _ from onegov.pas.importer.json_import import ( MembershipData, OrganizationData, diff --git a/src/onegov/pas/forms/legislative_period.py b/src/onegov/pas/forms/legislative_period.py index 7ac5e92ac3..fa4ffd5aab 100644 --- a/src/onegov/pas/forms/legislative_period.py +++ b/src/onegov/pas/forms/legislative_period.py @@ -2,7 +2,7 @@ from datetime import date from onegov.form import Form -from onegov.pas import _ +from onegov.parliament import _ from wtforms.fields import StringField from wtforms.fields import DateField from wtforms.validators import InputRequired diff --git a/src/onegov/pas/forms/parliamentarian.py b/src/onegov/pas/forms/parliamentarian.py index fe34dfd6f8..ec197a2ef6 100644 --- a/src/onegov/pas/forms/parliamentarian.py +++ b/src/onegov/pas/forms/parliamentarian.py @@ -5,9 +5,9 @@ from onegov.form.fields import UploadField from onegov.form.forms import NamedFileForm from onegov.form.validators import ValidPhoneNumber -from onegov.pas import _ -from onegov.pas.models.parliamentarian import GENDERS -from onegov.pas.models.parliamentarian import SHIPPING_METHODS +from onegov.parliament import _ +from onegov.parliament.models.parliamentarian import GENDERS +from onegov.parliament.models.parliamentarian import SHIPPING_METHODS from wtforms.fields import DateField from wtforms.fields import EmailField from wtforms.fields import StringField diff --git a/src/onegov/pas/forms/parliamentarian_role.py b/src/onegov/pas/forms/parliamentarian_role.py index 4bc7c9d421..38d5fd1083 100644 --- a/src/onegov/pas/forms/parliamentarian_role.py +++ b/src/onegov/pas/forms/parliamentarian_role.py @@ -8,9 +8,15 @@ from onegov.pas.collections import ParliamentarianCollection from onegov.pas.collections import ParliamentaryGroupCollection from onegov.pas.collections import PartyCollection -from onegov.pas.models.parliamentarian_role import PARLIAMENTARIAN_ROLES -from onegov.pas.models.parliamentarian_role import PARLIAMENTARY_GROUP_ROLES -from onegov.pas.models.parliamentarian_role import PARTY_ROLES +from onegov.parliament.models.parliamentarian_role import ( + PARLIAMENTARIAN_ROLES +) +from onegov.parliament.models.parliamentarian_role import ( + PARLIAMENTARY_GROUP_ROLES +) +from onegov.parliament.models.parliamentarian_role import ( + PARTY_ROLES +) from wtforms.fields import DateField from wtforms.validators import InputRequired from wtforms.validators import Optional @@ -18,7 +24,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Collection - from onegov.pas.models import ParliamentarianRole + from onegov.parliament.models import ParliamentarianRole from typing import Any diff --git a/src/onegov/pas/forms/rate_set.py b/src/onegov/pas/forms/rate_set.py index 2e66296102..d4df0745a3 100644 --- a/src/onegov/pas/forms/rate_set.py +++ b/src/onegov/pas/forms/rate_set.py @@ -3,7 +3,7 @@ from datetime import date from onegov.form import Form from onegov.pas import _ -from onegov.pas.models import RateSet +from onegov.parliament.models import RateSet from wtforms.fields import DecimalField from wtforms.fields import IntegerField from wtforms.validators import InputRequired diff --git a/src/onegov/pas/forms/settlement_run.py b/src/onegov/pas/forms/settlement_run.py index ae6e12c627..296a4cf958 100644 --- a/src/onegov/pas/forms/settlement_run.py +++ b/src/onegov/pas/forms/settlement_run.py @@ -5,7 +5,7 @@ from onegov.org.forms.fields import HtmlField from onegov.pas import _ from onegov.pas.layouts import DefaultLayout -from onegov.pas.models import SettlementRun +from onegov.parliament.models import SettlementRun from wtforms.fields import BooleanField from wtforms.fields import DateField from wtforms.fields import StringField diff --git a/src/onegov/pas/importer/json_import.py b/src/onegov/pas/importer/json_import.py index c0290e2dab..06d3b7f31f 100644 --- a/src/onegov/pas/importer/json_import.py +++ b/src/onegov/pas/importer/json_import.py @@ -4,7 +4,7 @@ from uuid import UUID from onegov.pas import log -from onegov.pas.models import ( +from onegov.parliament.models import ( CommissionMembership, Parliamentarian, Commission, @@ -172,9 +172,11 @@ class MembershipData(TypedDict): from typing import TYPE_CHECKING, TypedDict if TYPE_CHECKING: - from onegov.pas.models.parliamentarian_role import ParliamentaryGroupRole - from onegov.pas.models.parliamentarian_role import PartyRole - from onegov.pas.models.parliamentarian_role import Role + from onegov.parliament.models.parliamentarian_role import ( + ParliamentaryGroupRole + ) + from onegov.parliament.models.parliamentarian_role import PartyRole + from onegov.parliament.models.parliamentarian_role import Role from collections.abc import Sequence from sqlalchemy.orm import Session diff --git a/src/onegov/pas/models/__init__.py b/src/onegov/pas/models/__init__.py deleted file mode 100644 index 7a968b48e3..0000000000 --- a/src/onegov/pas/models/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from onegov.pas.models.attendence import Attendence -from onegov.pas.models.change import Change -from onegov.pas.models.commission import Commission -from onegov.pas.models.commission_membership import CommissionMembership -from onegov.pas.models.import_log import ImportLog -from onegov.pas.models.legislative_period import LegislativePeriod -from onegov.pas.models.parliamentarian import Parliamentarian -from onegov.pas.models.parliamentarian_role import ParliamentarianRole -from onegov.pas.models.parliamentary_group import ParliamentaryGroup -from onegov.pas.models.party import Party -from onegov.pas.models.rate_set import RateSet -from onegov.pas.models.settlement_run import SettlementRun - -__all__ = ( - 'Attendence', - 'Change', - 'Commission', - 'CommissionMembership', - 'ImportLog', - 'LegislativePeriod', - 'Parliamentarian', - 'ParliamentarianRole', - 'ParliamentaryGroup', - 'Party', - 'RateSet', - 'SettlementRun' -) diff --git a/src/onegov/pas/path.py b/src/onegov/pas/path.py index 8a4de0c133..e5d6ea0fc0 100644 --- a/src/onegov/pas/path.py +++ b/src/onegov/pas/path.py @@ -13,18 +13,18 @@ from onegov.pas.collections import RateSetCollection from onegov.pas.collections import SettlementRunCollection from onegov.pas.collections import ImportLogCollection -from onegov.pas.models import Attendence -from onegov.pas.models import Change -from onegov.pas.models import Commission -from onegov.pas.models import CommissionMembership -from onegov.pas.models import ImportLog -from onegov.pas.models import LegislativePeriod -from onegov.pas.models import Parliamentarian -from onegov.pas.models import ParliamentarianRole -from onegov.pas.models import ParliamentaryGroup -from onegov.pas.models import Party -from onegov.pas.models import RateSet -from onegov.pas.models import SettlementRun +from onegov.parliament.models import Attendence +from onegov.parliament.models import Change +from onegov.parliament.models import Commission +from onegov.parliament.models import CommissionMembership +from onegov.parliament.models import ImportLog +from onegov.parliament.models import LegislativePeriod +from onegov.parliament.models import Parliamentarian +from onegov.parliament.models import ParliamentarianRole +from onegov.parliament.models import ParliamentaryGroup +from onegov.parliament.models import Party +from onegov.parliament.models import RateSet +from onegov.parliament.models import SettlementRun from uuid import UUID from datetime import date diff --git a/src/onegov/pas/utils.py b/src/onegov/pas/utils.py index 61af1c67a2..57d27d6c0d 100644 --- a/src/onegov/pas/utils.py +++ b/src/onegov/pas/utils.py @@ -2,17 +2,17 @@ from onegov.pas import log from onegov.pas.collections import AttendenceCollection -from onegov.pas.models.party import Party -from onegov.pas.models.parliamentarian import Parliamentarian -from onegov.pas.models.parliamentarian_role import ParliamentarianRole -from onegov.pas.models.attendence import Attendence +from onegov.parliament.models.party import Party +from onegov.parliament.models.parliamentarian import Parliamentarian +from onegov.parliament.models.parliamentarian_role import ParliamentarianRole +from onegov.parliament.models.attendence import Attendence from decimal import Decimal from babel.numbers import format_decimal from typing import TYPE_CHECKING if TYPE_CHECKING: - from onegov.pas.models import SettlementRun + from onegov.parliament.models import SettlementRun from onegov.town6.request import TownRequest from datetime import date from sqlalchemy.orm import Session diff --git a/src/onegov/pas/views/attendence.py b/src/onegov/pas/views/attendence.py index 2575d15b6c..4c12cc5e64 100644 --- a/src/onegov/pas/views/attendence.py +++ b/src/onegov/pas/views/attendence.py @@ -10,8 +10,8 @@ from onegov.pas.forms import AttendenceForm from onegov.pas.layouts import AttendenceCollectionLayout from onegov.pas.layouts import AttendenceLayout -from onegov.pas.models import Attendence -from onegov.pas.models import Change +from onegov.parliament.models import Attendence +from onegov.parliament.models import Change from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/change.py b/src/onegov/pas/views/change.py index 4eee1491bc..4d0c896cb6 100644 --- a/src/onegov/pas/views/change.py +++ b/src/onegov/pas/views/change.py @@ -5,7 +5,7 @@ from onegov.pas.collections import ChangeCollection from onegov.pas.layouts import ChangeCollectionLayout from onegov.pas.layouts import ChangeLayout -from onegov.pas.models import Change +from onegov.parliament.models import Change from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/commission.py b/src/onegov/pas/views/commission.py index 661d1de9d6..7cc6a744a0 100644 --- a/src/onegov/pas/views/commission.py +++ b/src/onegov/pas/views/commission.py @@ -11,9 +11,9 @@ from onegov.pas.forms import CommissionForm from onegov.pas.layouts import CommissionCollectionLayout from onegov.pas.layouts import CommissionLayout -from onegov.pas.models import Change -from onegov.pas.models import Commission -from onegov.pas.models import CommissionMembership +from onegov.parliament.models import Change +from onegov.parliament.models import Commission +from onegov.parliament.models import CommissionMembership from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/commission_membership.py b/src/onegov/pas/views/commission_membership.py index 35f25fc579..63fb46f4eb 100644 --- a/src/onegov/pas/views/commission_membership.py +++ b/src/onegov/pas/views/commission_membership.py @@ -7,7 +7,7 @@ from onegov.pas.collections import CommissionMembershipCollection from onegov.pas.forms import CommissionMembershipForm from onegov.pas.layouts import CommissionMembershipLayout -from onegov.pas.models import CommissionMembership +from onegov.parliament.models import CommissionMembership from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/import_log.py b/src/onegov/pas/views/import_log.py index 9bbbe63acb..9dad536bb3 100644 --- a/src/onegov/pas/views/import_log.py +++ b/src/onegov/pas/views/import_log.py @@ -5,7 +5,7 @@ from onegov.pas import PasApp, _ from onegov.pas.collections import ImportLogCollection from onegov.pas.layouts.default import DefaultLayout -from onegov.pas.models import ImportLog +from onegov.parliament.models import ImportLog from typing import TYPE_CHECKING diff --git a/src/onegov/pas/views/legislative_period.py b/src/onegov/pas/views/legislative_period.py index 81dd0da2ec..73fbf5f3db 100644 --- a/src/onegov/pas/views/legislative_period.py +++ b/src/onegov/pas/views/legislative_period.py @@ -8,7 +8,7 @@ from onegov.pas.forms import LegislativePeriodForm from onegov.pas.layouts import LegislativePeriodCollectionLayout from onegov.pas.layouts import LegislativePeriodLayout -from onegov.pas.models import LegislativePeriod +from onegov.parliament.models import LegislativePeriod from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/parliamentarian.py b/src/onegov/pas/views/parliamentarian.py index 10a65641ff..f187f1c295 100644 --- a/src/onegov/pas/views/parliamentarian.py +++ b/src/onegov/pas/views/parliamentarian.py @@ -9,8 +9,8 @@ from onegov.pas.forms import ParliamentarianRoleForm from onegov.pas.layouts import ParliamentarianCollectionLayout from onegov.pas.layouts import ParliamentarianLayout -from onegov.pas.models import Parliamentarian -from onegov.pas.models import ParliamentarianRole +from onegov.parliament.models import Parliamentarian +from onegov.parliament.models import ParliamentarianRole from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/parliamentarian_role.py b/src/onegov/pas/views/parliamentarian_role.py index 8500395639..225f02b61d 100644 --- a/src/onegov/pas/views/parliamentarian_role.py +++ b/src/onegov/pas/views/parliamentarian_role.py @@ -7,7 +7,7 @@ from onegov.pas.collections import ParliamentarianRoleCollection from onegov.pas.forms import ParliamentarianRoleForm from onegov.pas.layouts import ParliamentarianRoleLayout -from onegov.pas.models import ParliamentarianRole +from onegov.parliament.models import ParliamentarianRole from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/parliamentary_group.py b/src/onegov/pas/views/parliamentary_group.py index 879d5406a5..9642e7444c 100644 --- a/src/onegov/pas/views/parliamentary_group.py +++ b/src/onegov/pas/views/parliamentary_group.py @@ -8,7 +8,7 @@ from onegov.pas.forms import ParliamentaryGroupForm from onegov.pas.layouts import ParliamentaryGroupCollectionLayout from onegov.pas.layouts import ParliamentaryGroupLayout -from onegov.pas.models import ParliamentaryGroup +from onegov.parliament.models import ParliamentaryGroup from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/party.py b/src/onegov/pas/views/party.py index 93201938e7..b7b009574e 100644 --- a/src/onegov/pas/views/party.py +++ b/src/onegov/pas/views/party.py @@ -8,7 +8,7 @@ from onegov.pas.forms import PartyForm from onegov.pas.layouts import PartyCollectionLayout from onegov.pas.layouts import PartyLayout -from onegov.pas.models import Party +from onegov.parliament.models import Party from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/rate_set.py b/src/onegov/pas/views/rate_set.py index e2fc11327a..666c2ef583 100644 --- a/src/onegov/pas/views/rate_set.py +++ b/src/onegov/pas/views/rate_set.py @@ -8,7 +8,7 @@ from onegov.pas.forms import RateSetForm from onegov.pas.layouts import RateSetCollectionLayout from onegov.pas.layouts import RateSetLayout -from onegov.pas.models import RateSet +from onegov.parliament.models import RateSet from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/settlement_run.py b/src/onegov/pas/views/settlement_run.py index ec51e9b81f..3bf3bbf844 100644 --- a/src/onegov/pas/views/settlement_run.py +++ b/src/onegov/pas/views/settlement_run.py @@ -13,7 +13,7 @@ from onegov.pas.forms import SettlementRunForm from onegov.pas.layouts import SettlementRunCollectionLayout from onegov.pas.layouts import SettlementRunLayout -from onegov.pas.models import ( +from onegov.parliament.models import ( SettlementRun, Party, Commission, @@ -23,9 +23,9 @@ from weasyprint import HTML, CSS # type: ignore[import-untyped] from weasyprint.text.fonts import ( # type: ignore[import-untyped] FontConfiguration) -from onegov.pas.models.attendence import TYPES, Attendence +from onegov.parliament.models.attendence import TYPES, Attendence from onegov.pas.path import SettlementRunExport, SettlementRunAllExport -from onegov.pas.models import Parliamentarian +from onegov.parliament.models import Parliamentarian from onegov.pas.utils import ( format_swiss_number, get_parliamentarians_with_settlements, @@ -1030,7 +1030,7 @@ def view_settlement_run_export( elif self.category == 'parliamentarian': assert isinstance(self.entity, Parliamentarian) - # Parliamentarian specific export has it's own rendering function + # PASParliamentarian specific export has it's own rendering function pdf_bytes = generate_parliamentarian_settlement_pdf( self.settlement_run, request, self.entity ) diff --git a/src/onegov/ris/collections/__init__.py b/src/onegov/ris/collections/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/onegov/ris/forms/__init__.py b/src/onegov/ris/forms/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/onegov/ris/layouts/__init__.py b/src/onegov/ris/layouts/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/onegov/ris/models/__init__.py b/src/onegov/ris/models/__init__.py deleted file mode 100644 index 1f3f3f883c..0000000000 --- a/src/onegov/ris/models/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import annotations - -from onegov.ris.models.commission import RISCommission -from onegov.ris.models.membership import RISCommissionMembership -from onegov.ris.models.parliamentarian import RISParliamentarian -from onegov.ris.models.parliamentarian_role import RISParliamentarianRole -from onegov.ris.models.parliamentary_group import RISParliamentaryGroup -from onegov.ris.models.party import RISParty -from onegov.ris.models.political_business import ( - RISPoliticalBusiness, - RISPoliticalBusinessParticipation -) -from onegov.ris.models.meeting import RISMeeting - - -__all__ = ( - 'RISCommission', - 'RISMeeting', - 'RISCommissionMembership', - 'RISParliamentarian', - 'RISParliamentarianRole', - 'RISParliamentaryGroup', - 'RISParty', - 'RISPoliticalBusiness', - 'RISPoliticalBusinessParticipation', -) diff --git a/src/onegov/ris/models/commission.py b/src/onegov/ris/models/commission.py deleted file mode 100644 index 2c7626312d..0000000000 --- a/src/onegov/ris/models/commission.py +++ /dev/null @@ -1,116 +0,0 @@ -from __future__ import annotations - -from sqlalchemy import Column, Date, Enum, Text -from sqlalchemy.orm import relationship -from uuid import uuid4 - -from onegov.core.orm import Base, observes -from onegov.core.orm.mixins import dict_markup_property, ContentMixin -from onegov.core.orm.mixins import TimestampMixin -from onegov.core.orm.types import UUID -from onegov.ris import _ -from onegov.search import ORMSearchable - - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - import uuid - from datetime import date - from typing import Literal - from typing import TypeAlias - - from onegov.ris.models.membership import RISCommissionMembership - - CommissionType: TypeAlias = Literal[ - 'normal', - 'intercantonal', - 'official', - ] - -TYPES: dict[CommissionType, str] = { - 'normal': _('normal'), - 'intercantonal': _('intercantonal'), - 'official': _('official mission'), -} - - -class RISCommission(Base, TimestampMixin, ContentMixin, ORMSearchable): - - __tablename__ = 'ris_commissions' - - es_public = True - es_properties = { - 'title': {'type': 'text'}, - 'description': {'type': 'localized_html'} - } - - @property - def es_suggestion(self) -> str: - return self.name - - @property - def title(self) -> str: - return self.name - - #: Internal ID - id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - primary_key=True, - default=uuid4 - ) - - #: the name - name: Column[str] = Column( - Text, - nullable=False - ) - - #: The start date - start: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The end date - end: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The type value - type: Column[CommissionType] = Column( - Enum( - *TYPES.keys(), # type:ignore[arg-type] - name='ris_commission_type' - ), - nullable=False, - default='normal' - ) - - #: The type as translated text - @property - def type_label(self) -> str: - return TYPES.get(self.type, '') - - #: The description - description = dict_markup_property('content') - - #: A commission may have n parliamentarians - memberships: relationship[list[RISCommissionMembership]] - memberships = relationship( - 'RISCommissionMembership', - cascade='all, delete-orphan', - back_populates='commission', - order_by='Commission.name' - ) - - @observes('end') - def end_observer(self, end: date | None) -> None: - if end: - for membership in self.memberships: - if not membership.end: - membership.end = end - - def __repr__(self) -> str: - return f'' diff --git a/src/onegov/ris/models/membership.py b/src/onegov/ris/models/membership.py deleted file mode 100644 index 403c0ca7dc..0000000000 --- a/src/onegov/ris/models/membership.py +++ /dev/null @@ -1,112 +0,0 @@ -from __future__ import annotations - -from sqlalchemy import Column -from sqlalchemy import Date -from sqlalchemy import Enum -from sqlalchemy import ForeignKey -from sqlalchemy.orm import relationship -from uuid import uuid4 - -from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin, ContentMixin -from onegov.core.orm.types import UUID -from onegov.ris import _ - - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - import uuid - from datetime import date - from typing import Literal - from typing import TypeAlias - - from onegov.ris.models.commission import RISCommission - from onegov.ris.models.parliamentarian import RISParliamentarian - - MembershipRole: TypeAlias = Literal[ - 'guest', - 'member', - 'extended_member', - 'president', - ] - -ROLES: dict[MembershipRole, str] = { - 'guest': _('Guest'), - 'member': _('Member'), - 'extended_member': _('Extended Member'), - 'president': _('President') -} - - -class RISCommissionMembership(Base, ContentMixin, TimestampMixin): - - __tablename__ = 'ris_parliamentary_memberships' - - #: Internal ID - id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - primary_key=True, - default=uuid4 - ) - - #: The start date - start: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The end date - end: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The role value - role: Column[MembershipRole] = Column( - Enum( - *ROLES.keys(), # type:ignore[arg-type] - name='ris_parliamentary_membership_role' - ), - nullable=False, - default='member' - ) - - #: The role as translated text - @property - def role_label(self) -> str: - return ROLES.get(self.role, '') - - #: the id of the commission - commission_id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - ForeignKey('ris_commissions.id'), - nullable=False - ) - - #: the related commission (which may have any number of memberships) - commission: relationship[RISCommission] = relationship( - 'RISCommission', - back_populates='memberships' - ) - - #: the id of the parliamentarian - # NEEDED??? - parliamentarian_id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - ForeignKey('ris_parliamentarians.id'), - nullable=False - ) - - #: the related parliamentarian (which may have any number of memberships) - parliamentarian: relationship[RISParliamentarian] = relationship( - 'RISParliamentarian', - back_populates='commission_memberships' - ) - - def __repr__(self) -> str: - return ( - f' tuple[str, ...]: - return ( - f'{self.first_name} {self.last_name}', - f'{self.last_name} {self.first_name}' - ) - - @property - def title(self) -> str: - return f'{self.first_name} {self.last_name}' - - #: Internal ID - id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - primary_key=True, - default=uuid4 - ) - - #: The first name - first_name: Column[str] = Column( - Text, - nullable=False - ) - - #: The last name - last_name: Column[str] = Column( - Text, - nullable=False - ) - - #: The personnel number - personnel_number: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The gender value - gender: Column[Gender] = Column( - Enum( - *GENDERS.keys(), # type:ignore[arg-type] - name='ris_gender' - ), - nullable=False, - default='male' - ) - - #: The gender as translated text - @property - def gender_label(self) -> str: - return GENDERS.get(self.gender, '') - - @property - def formal_greeting(self) -> str: - # fixme: Use salutation - """Returns the formal German greeting based on gender.""" - if self.gender == 'female': - return 'Frau ' + self.first_name + ' ' + self.last_name - return 'Herr ' + self.first_name + ' ' + self.last_name - - #: The private address - private_address: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The private address addition - private_address_addition: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The private address zip code - private_address_zip_code: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The private address city - private_address_city: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The date of birth - date_of_birth: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The date of death - date_of_death: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The place of origin - place_of_origin: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The occupation - occupation: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The academic title - academic_title: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The salutation - salutation: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The private phone number - phone_private: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The mobile phone number - phone_mobile: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The business phone number - phone_business: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The primary email address - email_primary: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The secondary email address - email_secondary: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The website - website: Column[str | None] = Column( - Text, - nullable=True - ) - - #: The remarks - remarks: Column[str | None] = Column( - Text, - nullable=True - ) - - #: A picture - picture = NamedFile() - - #: A parliamentarian may have n roles - roles: relationship[list[RISParliamentarianRole]] - roles = relationship( - 'RISParliamentarianRole', - cascade='all, delete-orphan', - back_populates='parliamentarian', - order_by='desc(ParliamentarianRole.start)' - ) - - #: political businesses participations [0..n] - political_businesses: relationship[list[RISPoliticalBusinessParticipation]] - political_businesses = relationship( - 'RISPoliticalBusinessParticipation', - back_populates='parliamentarian', - lazy='joined' - ) - - def get_party_during_period( - self, start_date: date, end_date: date, session: Session - ) -> RISParty | None: - """Get the party this parliamentarian belonged to during a specific - period.""" - - role = ( - session.query(RISParliamentarianRole) - .filter( - RISParliamentarianRole.parliamentarian_id == self.id, - RISParliamentarianRole.party_id.isnot( - None - ), - or_( - RISParliamentarianRole.end.is_(None), - RISParliamentarianRole.end >= start_date, - ), - RISParliamentarianRole.start - <= end_date, - ) - .order_by(RISParliamentarianRole.start.desc()) - .first() - ) - - return role.party if role else None - - @property - def active(self) -> bool: - if not self.roles: - return True - for role in self.roles: - if role.end is None or role.end >= date.today(): - return True - return False - - def active_during(self, start: date, end: date) -> bool: - if not self.roles: - return True - for role in self.roles: - role_start = role.start if role.start is not None else date.min - role_end = role.end if role.end is not None else date.max - if role_end >= start and role_start <= end: - return True - return False - - @property - def display_name(self) -> str: - return f'{self.first_name} {self.last_name}' - - #: A parliamentarian may be a member of n commissions - commission_memberships: relationship[list[RISCommissionMembership]] - commission_memberships = relationship( - 'RISCommissionMembership', - cascade='all, delete-orphan', - back_populates='parliamentarian' - ) - - political_groups: relationship[list[RISParliamentaryGroup]] - political_groups = relationship( - 'RISParliamentaryGroup', - back_populates='members', - primaryjoin='RISParliamentarian.id == ' - 'RISParliamentaryGroup.parliamentarian_id', - ) - - def __repr__(self) -> str: - info = [ - f'id={self.id}', - f"last_name='{self.last_name}'", - f"first_name='{self.first_name}'", - ] - if self.academic_title: - info.append(f"title='{self.academic_title}'") - if self.salutation: - info.append(f"salutation='{self.salutation}'") - if self.email_primary: - info.append( - f"email='{self.email_primary}'") - - return f"" diff --git a/src/onegov/ris/models/parliamentarian_role.py b/src/onegov/ris/models/parliamentarian_role.py deleted file mode 100644 index d8eaf5a4f3..0000000000 --- a/src/onegov/ris/models/parliamentarian_role.py +++ /dev/null @@ -1,211 +0,0 @@ -from __future__ import annotations - -from sqlalchemy import Column -from sqlalchemy import Date -from sqlalchemy import Enum -from sqlalchemy import ForeignKey -from sqlalchemy import Text -from sqlalchemy.orm import relationship -from uuid import uuid4 - -from onegov.core.orm import Base -from onegov.core.orm.mixins import TimestampMixin, ContentMixin -from onegov.core.orm.types import UUID -from onegov.ris import _ - - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - import uuid - from datetime import date - from typing import Literal - from typing import TypeAlias - - from onegov.ris.models.parliamentarian import RISParliamentarian - from onegov.ris.models.parliamentary_group import RISParliamentaryGroup - from onegov.ris.models.party import RISParty - - Role: TypeAlias = Literal[ - 'none', - 'member', - 'vote_counter', - 'vice_president', - 'president', - ] - - PartyRole: TypeAlias = Literal[ - 'none', - 'member', - 'media_manager', - 'vote_counter', - 'vice_president', - 'president', - ] - - ParliamentaryGroupRole: TypeAlias = Literal[ - 'none', - 'non_permanent_member', - 'member', - 'substitute_member', - 'vote_counter', - 'secretary', - 'vice_president', - 'president', - ] - -PARLIAMENTARIAN_ROLES: dict[Role, str] = { - 'none': _('none'), - 'member': _('Member'), - 'vote_counter': _('Vote Counter'), - 'vice_president': _('Vice President'), - 'president': _('President'), -} - -PARTY_ROLES: dict[PartyRole, str] = { - 'none': _('none'), - 'member': _('Member'), - 'media_manager': _('Media Manager'), - 'vote_counter': _('Vote Counter'), - 'vice_president': _('Vice President'), - 'president': _('President'), -} - -PARLIAMENTARY_GROUP_ROLES: dict[ParliamentaryGroupRole, str] = { - 'none': _('none'), - 'non_permanent_member': _('Non-permanent Member'), - 'member': _('Member'), - 'substitute_member': _('Substitute Member'), - 'secretary': _('Secretary'), - 'vote_counter': _('Vote Counter'), - 'vice_president': _('Vice President'), - 'president': _('President'), -} - - -class RISParliamentarianRole(Base, ContentMixin, TimestampMixin): - - __tablename__ = 'ris_parliamentarian_roles' - - #: Internal ID - id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - primary_key=True, - default=uuid4 - ) - - #: The start date - start: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The end date - end: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The id of the parliamentarian - parliamentarian_id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - ForeignKey('ris_parliamentarians.id'), - nullable=False - ) - - #: The parliamentarian - parliamentarian: relationship[RISParliamentarian] = relationship( - 'RISParliamentarian', - back_populates='roles' - ) - - #: The parliament role name - role: Column[Role] = Column( - Enum( - *PARLIAMENTARIAN_ROLES.keys(), # type:ignore[arg-type] - name='ris_parliamentarian_role' - ), - nullable=False, - default='member' - ) - - #: The role as translated text - @property - def role_label(self) -> str: - return PARLIAMENTARIAN_ROLES.get(self.role, '') - - #: Party ID as a foreign key - party_id: Column[uuid.UUID | None] = Column( - UUID, # type:ignore[arg-type] - ForeignKey('ris_parties.id'), - nullable=True - ) - - #: The party - party: relationship[RISParty | None] = relationship( - 'RISParty', - back_populates='roles', - primaryjoin='RISParliamentarianRole.party_id == RISParty.id' - ) - - #: The party role value - party_role: Column[PartyRole] = Column( - Enum( - *PARTY_ROLES.keys(), # type:ignore[arg-type] - name='ris_party_role' - ), - nullable=False, - default='member' - ) - - #: The party role as translated text - @property - def party_role_label(self) -> str: - return PARTY_ROLES.get(self.party_role, '') - - #: The id of the parliamentary group - parliamentary_group_id: Column[uuid.UUID | None] = Column( - UUID, # type:ignore[arg-type] - ForeignKey('ris_parliamentary_groups.id'), - nullable=True - ) - - #: The parliamentary group - parliamentary_group: relationship[RISParliamentaryGroup | None] - parliamentary_group = relationship( - 'RISParliamentaryGroup', - back_populates='roles' - ) - - #: The parliamentary group role value - parliamentary_group_role: Column[ParliamentaryGroupRole] = Column( - Enum( - *PARLIAMENTARY_GROUP_ROLES.keys(), # type:ignore[arg-type] - name='ris_parliamentary_group_role' - ), - nullable=False, - default='member' - ) - - #: The parliamentary group role as translated text - @property - def parliamentary_group_role_label(self) -> str: - return PARLIAMENTARY_GROUP_ROLES.get(self.parliamentary_group_role, '') - - #: The district - district: Column[str | None] = Column( - Text, - nullable=True - ) - - #: Additional information - additional_information: Column[str | None] = Column( - Text, - nullable=True - ) - - def __repr__(self) -> str: - return ( - f' str: - return self.name - - @property - def title(self) -> str: - return self.name - - #: Internal ID - id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - primary_key=True, - default=uuid4 - ) - - #: the name - name: Column[str] = Column( - Text, - nullable=False - ) - - #: The start date - start: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The end date - end: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The description - description = dict_markup_property('content') - - #: A parliamentary group may have n role - roles: relationship[list[RISParliamentarianRole]] - roles = relationship( - 'RISParliamentarianRole', - back_populates='parliamentary_group', - ) - - # #: the id of the parliamentarian - parliamentarian_id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - ForeignKey('ris_parliamentarians.id'), - nullable=False - ) - - members: relationship[list[RISParliamentarian]] = relationship( - 'RISParliamentarian', - back_populates='political_groups', - ) - - def __repr__(self) -> str: - return f'' diff --git a/src/onegov/ris/models/party.py b/src/onegov/ris/models/party.py deleted file mode 100644 index 09de15da19..0000000000 --- a/src/onegov/ris/models/party.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from sqlalchemy import Column -from sqlalchemy import Date -from sqlalchemy import Text -from sqlalchemy.orm import relationship -from uuid import uuid4 - -from onegov.core.orm import Base -from onegov.core.orm.mixins import dict_markup_property -from onegov.core.orm.mixins import ContentMixin -from onegov.core.orm.types import UUID -from onegov.search import ORMSearchable - - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - import uuid - from datetime import date - from onegov.ris.models.parliamentarian_role import RISParliamentarianRole - - -class RISParty(Base, ContentMixin, ORMSearchable): - - __tablename__ = 'ris_parties' - - es_public = False - es_properties = {'name': {'type': 'text'}} - - @property - def es_suggestion(self) -> str: - return self.name - - @property - def title(self) -> str: - return self.name - - #: Internal ID - id: Column[uuid.UUID] = Column( - UUID, # type:ignore[arg-type] - primary_key=True, - default=uuid4 - ) - - #: the name - name: Column[str] = Column( - Text, - nullable=False - ) - - #: The start date - start: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The end date - end: Column[date | None] = Column( - Date, - nullable=True - ) - - #: The portrait - portrait = dict_markup_property('content') - - #: The description - description = dict_markup_property('content') - - #: A party may have n roles - roles: relationship[list[RISParliamentarianRole]] - roles = relationship( - 'RISParliamentarianRole', - cascade='all, delete-orphan', - back_populates='party' - ) - - def __repr__(self) -> str: - return f'' diff --git a/src/onegov/ris/templates/__init__.py b/src/onegov/ris/templates/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/onegov/ris/views/__init__.py b/src/onegov/ris/views/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/onegov/search/indexer.py b/src/onegov/search/indexer.py index e6afd4c02b..d3fa838903 100644 --- a/src/onegov/search/indexer.py +++ b/src/onegov/search/indexer.py @@ -603,7 +603,8 @@ def register_type( As a consequence, a change in the mapping requires a reindex. """ - assert type_name not in self.mappings + assert type_name not in self.mappings, \ + f"Type '{type_name}' already registered" self.mappings[type_name] = TypeMapping(type_name, mapping, model) @property From f7bea9f0ef44cb5b8bdac73a0eeca2cd94b74173 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Thu, 12 Jun 2025 08:34:40 +0200 Subject: [PATCH 05/17] Multiple small fixes --- src/onegov/parliament/models/__init__.py | 11 ++--------- src/onegov/parliament/models/parliamentarian.py | 4 ++-- src/onegov/parliament/models/political_business.py | 6 +++--- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/onegov/parliament/models/__init__.py b/src/onegov/parliament/models/__init__.py index a3c9520ba0..d16b5ddb21 100644 --- a/src/onegov/parliament/models/__init__.py +++ b/src/onegov/parliament/models/__init__.py @@ -1,11 +1,5 @@ from __future__ import annotations -import logging - -log = logging.getLogger('onegov.parliament') -log.addHandler(logging.NullHandler()) - -from onegov.parliament.i18n import _ from onegov.parliament.models.attendence import Attendence from onegov.parliament.models.change import Change from onegov.parliament.models.commission import Commission @@ -29,14 +23,13 @@ __all__ = ( - '_', - 'log', 'Attendence', 'Change', 'Commission', 'CommissionMembership', 'ImportLog', 'LegislativePeriod', + 'Meeting', 'Parliamentarian', 'RISParliamentarian', 'ParliamentarianRole', @@ -45,5 +38,5 @@ 'PoliticalBusiness', 'PoliticalBusinessParticipation', 'RateSet', - 'SettlementRun', 'Attendence', 'Meeting' + 'SettlementRun' ) diff --git a/src/onegov/parliament/models/parliamentarian.py b/src/onegov/parliament/models/parliamentarian.py index 542f1a6ed4..97553e99a8 100644 --- a/src/onegov/parliament/models/parliamentarian.py +++ b/src/onegov/parliament/models/parliamentarian.py @@ -7,8 +7,7 @@ from onegov.core.orm.types import UUID from onegov.file import AssociatedFiles from onegov.file import NamedFile -from onegov.parliament.models import ParliamentarianRole -from onegov.pas import _ +from onegov.parliament import _ from onegov.search import ORMSearchable from sqlalchemy import Column, or_ from sqlalchemy import Date @@ -35,6 +34,7 @@ PoliticalBusinessParticipation ) from onegov.parliament.models.party import Party + from onegov.parliament.models import ParliamentarianRole Gender: TypeAlias = Literal[ 'male', diff --git a/src/onegov/parliament/models/political_business.py b/src/onegov/parliament/models/political_business.py index 86e92ec9aa..c1ee3a293e 100644 --- a/src/onegov/parliament/models/political_business.py +++ b/src/onegov/parliament/models/political_business.py @@ -20,7 +20,7 @@ from datetime import date - from onegov.parliament.models import Parliamentarian + from onegov.parliament.models import RISParliamentarian PoliticalBusinessType: TypeAlias = Literal[ 'inquiry', # Anfrage @@ -196,7 +196,7 @@ class PoliticalBusinessParticipation(Base, ContentMixin): ) #: the related parliamentarian - parliamentarian: RelationshipProperty[Parliamentarian] = relationship( - 'Parliamentarian', + parliamentarian: RelationshipProperty[RISParliamentarian] = relationship( + 'RISParliamentarian', back_populates='political_businesses', ) From 47bb63d30833bdba88a63a8588007aa5be08102e Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Thu, 12 Jun 2025 11:28:51 +0200 Subject: [PATCH 06/17] Puts subclasses for PAS namespace --- src/onegov/parliament/models/__init__.py | 6 - src/onegov/parliament/models/change.py | 6 +- .../parliament/models/parliamentarian.py | 16 +- src/onegov/pas/calculate_pay.py | 2 +- src/onegov/pas/collections/attendence.py | 46 ++--- src/onegov/pas/collections/change.py | 12 +- src/onegov/pas/collections/commission.py | 18 +- .../pas/collections/commission_membership.py | 10 +- src/onegov/pas/collections/import_log.py | 2 +- .../pas/collections/legislative_period.py | 16 +- src/onegov/pas/collections/parliamentarian.py | 20 +-- src/onegov/pas/collections/rate_set.py | 2 +- src/onegov/pas/collections/settlement_run.py | 2 +- src/onegov/pas/custom.py | 2 +- src/onegov/pas/data_import.py | 38 ++--- src/onegov/pas/excel_import_cli.py | 38 ++--- .../pas/export_single_parliamentarian.py | 13 +- src/onegov/pas/forms/attendence.py | 8 +- src/onegov/pas/forms/rate_set.py | 2 +- src/onegov/pas/forms/settlement_run.py | 2 +- src/onegov/pas/importer/json_import.py | 158 +++++++++--------- src/onegov/pas/models/__init__.py | 30 ++++ src/onegov/pas/models/attendence.py | 12 ++ src/onegov/pas/models/change.py | 12 ++ src/onegov/pas/models/commission.py | 12 ++ .../pas/models/commission_membership.py | 12 ++ .../{parliament => pas}/models/import_log.py | 0 src/onegov/pas/models/legislative_period.py | 12 ++ src/onegov/pas/models/parliamentarian.py | 12 ++ src/onegov/pas/models/parliamentarian_role.py | 12 ++ src/onegov/pas/models/parliamentary_group.py | 12 ++ src/onegov/pas/models/party.py | 11 ++ .../{parliament => pas}/models/rate_set.py | 2 +- .../models/settlement_run.py | 2 +- src/onegov/pas/path.py | 68 ++++---- src/onegov/pas/utils.py | 90 +++++----- src/onegov/pas/views/attendence.py | 24 +-- src/onegov/pas/views/change.py | 6 +- src/onegov/pas/views/commission.py | 30 ++-- src/onegov/pas/views/commission_membership.py | 14 +- src/onegov/pas/views/data_import.py | 19 +-- src/onegov/pas/views/import_log.py | 2 +- src/onegov/pas/views/legislative_period.py | 14 +- src/onegov/pas/views/parliamentarian.py | 22 +-- src/onegov/pas/views/rate_set.py | 2 +- src/onegov/pas/views/settlement_run.py | 62 ++++--- 46 files changed, 536 insertions(+), 377 deletions(-) create mode 100644 src/onegov/pas/models/__init__.py create mode 100644 src/onegov/pas/models/attendence.py create mode 100644 src/onegov/pas/models/change.py create mode 100644 src/onegov/pas/models/commission.py create mode 100644 src/onegov/pas/models/commission_membership.py rename src/onegov/{parliament => pas}/models/import_log.py (100%) create mode 100644 src/onegov/pas/models/legislative_period.py create mode 100644 src/onegov/pas/models/parliamentarian.py create mode 100644 src/onegov/pas/models/parliamentarian_role.py create mode 100644 src/onegov/pas/models/parliamentary_group.py create mode 100644 src/onegov/pas/models/party.py rename src/onegov/{parliament => pas}/models/rate_set.py (98%) rename src/onegov/{parliament => pas}/models/settlement_run.py (98%) diff --git a/src/onegov/parliament/models/__init__.py b/src/onegov/parliament/models/__init__.py index d16b5ddb21..a36a955eda 100644 --- a/src/onegov/parliament/models/__init__.py +++ b/src/onegov/parliament/models/__init__.py @@ -4,7 +4,6 @@ from onegov.parliament.models.change import Change from onegov.parliament.models.commission import Commission from onegov.parliament.models.commission_membership import CommissionMembership -from onegov.parliament.models.import_log import ImportLog from onegov.parliament.models.legislative_period import LegislativePeriod from onegov.parliament.models.meeting import Meeting from onegov.parliament.models.parliamentarian import ( @@ -18,8 +17,6 @@ PoliticalBusiness, PoliticalBusinessParticipation, ) -from onegov.parliament.models.rate_set import RateSet -from onegov.parliament.models.settlement_run import SettlementRun __all__ = ( @@ -27,7 +24,6 @@ 'Change', 'Commission', 'CommissionMembership', - 'ImportLog', 'LegislativePeriod', 'Meeting', 'Parliamentarian', @@ -37,6 +33,4 @@ 'Party', 'PoliticalBusiness', 'PoliticalBusinessParticipation', - 'RateSet', - 'SettlementRun' ) diff --git a/src/onegov/parliament/models/change.py b/src/onegov/parliament/models/change.py index 9b62dac00c..64f8e0cb2e 100644 --- a/src/onegov/parliament/models/change.py +++ b/src/onegov/parliament/models/change.py @@ -15,15 +15,17 @@ from onegov.parliament import _ from typing import TYPE_CHECKING + if TYPE_CHECKING: + from typing import Literal + from typing import TypeAlias import uuid + from onegov.core.orm.mixins import dict_property from onegov.parliament.models import Attendence from onegov.parliament.models import Commission from onegov.parliament.models import Parliamentarian from onegov.town6.request import TownRequest - from typing import Literal - from typing import TypeAlias Action: TypeAlias = Literal[ 'add', diff --git a/src/onegov/parliament/models/parliamentarian.py b/src/onegov/parliament/models/parliamentarian.py index 97553e99a8..43f178884d 100644 --- a/src/onegov/parliament/models/parliamentarian.py +++ b/src/onegov/parliament/models/parliamentarian.py @@ -26,15 +26,13 @@ from sqlalchemy.orm import Session import uuid - from onegov.parliament.models.attendence import Attendence - from onegov.parliament.models.commission_membership import ( - CommissionMembership + from onegov.parliament.models import ( + Attendence, + CommissionMembership, + PoliticalBusinessParticipation, + Party, + ParliamentarianRole, ) - from onegov.parliament.models.political_business import ( - PoliticalBusinessParticipation - ) - from onegov.parliament.models.party import Party - from onegov.parliament.models import ParliamentarianRole Gender: TypeAlias = Literal[ 'male', @@ -65,7 +63,7 @@ class Parliamentarian(Base, ContentMixin, TimestampMixin, AssociatedFiles, - ORMSearchable): + ORMSearchable): __tablename__ = 'par_parliamentarians' diff --git a/src/onegov/pas/calculate_pay.py b/src/onegov/pas/calculate_pay.py index b6006412a6..12b23c5b16 100644 --- a/src/onegov/pas/calculate_pay.py +++ b/src/onegov/pas/calculate_pay.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from onegov.parliament.models.rate_set import RateSet + from onegov.pas.models.rate_set import RateSet def calculate_rate( diff --git a/src/onegov/pas/collections/attendence.py b/src/onegov/pas/collections/attendence.py index 3afcebf6a1..0a5b19c120 100644 --- a/src/onegov/pas/collections/attendence.py +++ b/src/onegov/pas/collections/attendence.py @@ -1,23 +1,25 @@ from __future__ import annotations +from sqlalchemy import desc, or_ + from onegov.core.collection import GenericCollection from onegov.parliament.models import ( - Attendence, - SettlementRun, - Parliamentarian, ParliamentarianRole, ) - -from sqlalchemy import desc, or_ - +from onegov.pas.models import ( + PASAttendence, + PASParliamentarian, + SettlementRun, +) from typing import TYPE_CHECKING, Self + if TYPE_CHECKING: from datetime import date from sqlalchemy.orm import Query, Session -class AttendenceCollection(GenericCollection[Attendence]): +class AttendenceCollection(GenericCollection[PASAttendence]): def __init__( self, session: Session, @@ -39,10 +41,10 @@ def __init__( self.party_id = party_id @property - def model_class(self) -> type[Attendence]: - return Attendence + def model_class(self) -> type[PASAttendence]: + return PASAttendence - def query(self) -> Query[Attendence]: + def query(self) -> Query[PASAttendence]: query = super().query() if self.settlement_run_id: @@ -51,44 +53,44 @@ def query(self) -> Query[Attendence]: ) if settlement_run: query = query.filter( - Attendence.date >= settlement_run.start, - Attendence.date <= settlement_run.end, + PASAttendence.date >= settlement_run.start, + PASAttendence.date <= settlement_run.end, ) if self.date_from: - query = query.filter(Attendence.date >= self.date_from) + query = query.filter(PASAttendence.date >= self.date_from) if self.date_to: - query = query.filter(Attendence.date <= self.date_to) + query = query.filter(PASAttendence.date <= self.date_to) if self.type: - query = query.filter(Attendence.type == self.type) + query = query.filter(PASAttendence.type == self.type) if self.parliamentarian_id: query = query.filter( - Attendence.parliamentarian_id == self.parliamentarian_id + PASAttendence.parliamentarian_id == self.parliamentarian_id ) if self.commission_id: query = query.filter( - Attendence.commission_id == self.commission_id + PASAttendence.commission_id == self.commission_id ) # Check for any overlap in party membership period if self.party_id: query = ( - query.join(Attendence.parliamentarian) - .join(Parliamentarian.roles) + query.join(PASAttendence.parliamentarian) + .join(PASParliamentarian.roles) .filter( ParliamentarianRole.party_id == self.party_id, or_( ParliamentarianRole.start.is_(None), - ParliamentarianRole.start <= Attendence.date + ParliamentarianRole.start <= PASAttendence.date ), or_( ParliamentarianRole.end.is_(None), - ParliamentarianRole.end >= Attendence.date + ParliamentarianRole.end >= PASAttendence.date ) ) ) - return query.order_by(desc(Attendence.date)) + return query.order_by(desc(PASAttendence.date)) def for_filter( self, diff --git a/src/onegov/pas/collections/change.py b/src/onegov/pas/collections/change.py index 261b191cba..2048c0ea6c 100644 --- a/src/onegov/pas/collections/change.py +++ b/src/onegov/pas/collections/change.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.parliament.models import Change +from onegov.pas.models import PASChange from sqlalchemy import desc from typing import TYPE_CHECKING @@ -9,11 +9,11 @@ from sqlalchemy.orm import Query -class ChangeCollection(GenericCollection[Change]): +class ChangeCollection(GenericCollection[PASChange]): @property - def model_class(self) -> type[Change]: - return Change + def model_class(self) -> type[PASChange]: + return PASChange - def query(self) -> Query[Change]: - return super().query().order_by(desc(Change.last_change)) + def query(self) -> Query[PASChange]: + return super().query().order_by(desc(PASChange.last_change)) diff --git a/src/onegov/pas/collections/commission.py b/src/onegov/pas/collections/commission.py index 8f8b2786e1..416400169f 100644 --- a/src/onegov/pas/collections/commission.py +++ b/src/onegov/pas/collections/commission.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.parliament.models import Commission +from onegov.pas.models import PASCommission from sqlalchemy import or_ from typing import TYPE_CHECKING @@ -12,7 +12,7 @@ from typing import Self -class CommissionCollection(GenericCollection[Commission]): +class CommissionCollection(GenericCollection[PASCommission]): def __init__( self, @@ -23,24 +23,24 @@ def __init__( self.active = active @property - def model_class(self) -> type[Commission]: - return Commission + def model_class(self) -> type[PASCommission]: + return PASCommission - def query(self) -> Query[Commission]: + def query(self) -> Query[PASCommission]: query = super().query() if self.active is not None: if self.active: query = query.filter( or_( - Commission.end.is_(None), - Commission.end >= date.today() + PASCommission.end.is_(None), + PASCommission.end >= date.today() ) ) else: - query = query.filter(Commission.end < date.today()) + query = query.filter(PASCommission.end < date.today()) - return query.order_by(Commission.name) + return query.order_by(PASCommission.name) def for_filter( self, diff --git a/src/onegov/pas/collections/commission_membership.py b/src/onegov/pas/collections/commission_membership.py index 6b74b9de08..8acb89a055 100644 --- a/src/onegov/pas/collections/commission_membership.py +++ b/src/onegov/pas/collections/commission_membership.py @@ -1,11 +1,13 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.parliament.models import CommissionMembership +from onegov.pas.models import PASCommissionMembership -class CommissionMembershipCollection(GenericCollection[CommissionMembership]): +class CommissionMembershipCollection( + GenericCollection[PASCommissionMembership] +): @property - def model_class(self) -> type[CommissionMembership]: - return CommissionMembership + def model_class(self) -> type[PASCommissionMembership]: + return PASCommissionMembership diff --git a/src/onegov/pas/collections/import_log.py b/src/onegov/pas/collections/import_log.py index ec0003101f..5098de9162 100644 --- a/src/onegov/pas/collections/import_log.py +++ b/src/onegov/pas/collections/import_log.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.parliament.models.import_log import ImportLog +from onegov.pas.models.import_log import ImportLog from typing import Self, TYPE_CHECKING diff --git a/src/onegov/pas/collections/legislative_period.py b/src/onegov/pas/collections/legislative_period.py index 3ff2c5de3c..cfd5638c6c 100644 --- a/src/onegov/pas/collections/legislative_period.py +++ b/src/onegov/pas/collections/legislative_period.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.parliament.models import LegislativePeriod +from onegov.pas.models import PASLegislativePeriod from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -11,7 +11,7 @@ from typing import Self -class LegislativePeriodCollection(GenericCollection[LegislativePeriod]): +class LegislativePeriodCollection(GenericCollection[PASLegislativePeriod]): def __init__( self, @@ -22,19 +22,19 @@ def __init__( self.active = active @property - def model_class(self) -> type[LegislativePeriod]: - return LegislativePeriod + def model_class(self) -> type[PASLegislativePeriod]: + return PASLegislativePeriod - def query(self) -> Query[LegislativePeriod]: + def query(self) -> Query[PASLegislativePeriod]: query = super().query() if self.active is not None: if self.active: - query = query.filter(LegislativePeriod.end >= date.today()) + query = query.filter(PASLegislativePeriod.end >= date.today()) else: - query = query.filter(LegislativePeriod.end < date.today()) + query = query.filter(PASLegislativePeriod.end < date.today()) - return query.order_by(LegislativePeriod.name) + return query.order_by(PASLegislativePeriod.name) def for_filter( self, diff --git a/src/onegov/pas/collections/parliamentarian.py b/src/onegov/pas/collections/parliamentarian.py index fe8d62244b..ee7d4420c5 100644 --- a/src/onegov/pas/collections/parliamentarian.py +++ b/src/onegov/pas/collections/parliamentarian.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.parliament.models import Parliamentarian +from onegov.pas.models import PASParliamentarian from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -10,7 +10,7 @@ from typing import Self -class ParliamentarianCollection(GenericCollection[Parliamentarian]): +class ParliamentarianCollection(GenericCollection[PASParliamentarian]): def __init__( self, @@ -21,25 +21,25 @@ def __init__( self.active = active @property - def model_class(self) -> type[Parliamentarian]: - return Parliamentarian + def model_class(self) -> type[PASParliamentarian]: + return PASParliamentarian - def query(self) -> Query[Parliamentarian]: + def query(self) -> Query[PASParliamentarian]: query = super().query() if self.active is not None: - id_query = self.session.query(Parliamentarian) + id_query = self.session.query(PASParliamentarian) if self.active: ids = [p.id for p in id_query if p.active] - query = query.filter(Parliamentarian.id.in_(ids)) + query = query.filter(PASParliamentarian.id.in_(ids)) else: ids = [p.id for p in id_query if not p.active] - query = query.filter(Parliamentarian.id.in_(ids)) + query = query.filter(PASParliamentarian.id.in_(ids)) return query.order_by( - Parliamentarian.last_name, - Parliamentarian.first_name + PASParliamentarian.last_name, + PASParliamentarian.first_name ).distinct() def for_filter( diff --git a/src/onegov/pas/collections/rate_set.py b/src/onegov/pas/collections/rate_set.py index 783f7d6fd2..bf47dcae15 100644 --- a/src/onegov/pas/collections/rate_set.py +++ b/src/onegov/pas/collections/rate_set.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.parliament.models import RateSet +from onegov.pas.models import RateSet from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/collections/settlement_run.py b/src/onegov/pas/collections/settlement_run.py index c0d6c52aaa..186fa24d30 100644 --- a/src/onegov/pas/collections/settlement_run.py +++ b/src/onegov/pas/collections/settlement_run.py @@ -1,7 +1,7 @@ from __future__ import annotations from onegov.core.collection import GenericCollection -from onegov.parliament.models import SettlementRun +from onegov.pas.models import SettlementRun from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/custom.py b/src/onegov/pas/custom.py index 0b3e56afc8..c10a5b5c82 100644 --- a/src/onegov/pas/custom.py +++ b/src/onegov/pas/custom.py @@ -7,7 +7,7 @@ from onegov.pas.collections import AttendenceCollection from onegov.pas.collections import ChangeCollection from onegov.user import Auth -from onegov.parliament.models import SettlementRun, RateSet +from onegov.pas.models import SettlementRun, RateSet from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/data_import.py b/src/onegov/pas/data_import.py index ffa43893fc..fa8e59184e 100644 --- a/src/onegov/pas/data_import.py +++ b/src/onegov/pas/data_import.py @@ -16,13 +16,13 @@ import openpyxl from onegov.core.csv import CSVFile, convert_excel_to_csv, detect_encoding -from onegov.parliament.models import ( - CommissionMembership, - ParliamentarianRole, - Parliamentarian, - ParliamentaryGroup, - Party, - Commission, +from onegov.pas.models import ( + PASCommission, + PASCommissionMembership, + PASParliamentarian, + PASParliamentarianRole, + PASParliamentaryGroup, + PASParty, ) T = TypeVar('T') @@ -375,12 +375,12 @@ def parse_date(date_str: str | None) -> date | None: commission_name = commission_name.replace('_', ' ') # Get or create commission - commission = session.query(Commission).filter_by( + commission = session.query(PASCommission).filter_by( name=commission_name ).first() if not commission: - commission = Commission( + commission = PASCommission( name=commission_name, type='normal' ) @@ -389,17 +389,17 @@ def parse_date(date_str: str | None) -> date | None: # First pass - create parties and parliamentary groups for row in import_file.rows: # Create party if needed - party = session.query(Party).filter_by(name=row.partei).first() + party = session.query(PASParty).filter_by(name=row.partei).first() if not party: - party = Party(name=row.partei) + party = PASParty(name=row.partei) session.add(party) # Create parliamentary group if needed - group = session.query(ParliamentaryGroup).filter_by( + group = session.query(PASParliamentaryGroup).filter_by( name=row.fraktion ).first() if not group: - group = ParliamentaryGroup(name=row.fraktion) + group = PASParliamentaryGroup(name=row.fraktion) session.add(group) session.flush() @@ -407,18 +407,18 @@ def parse_date(date_str: str | None) -> date | None: # Second pass - create parliamentarians and memberships for row in import_file.rows: # Get party and group - party = session.query(Party).filter_by(name=row.partei).one() - group = session.query(ParliamentaryGroup).filter_by( + party = session.query(PASParty).filter_by(name=row.partei).one() + group = session.query(PASParliamentaryGroup).filter_by( name=row.fraktion ).one() # Create parliamentarian if needed - parliamentarian = session.query(Parliamentarian).filter_by( + parliamentarian = session.query(PASParliamentarian).filter_by( personnel_number=row.personalnummer ).first() if not parliamentarian: - parliamentarian = Parliamentarian( + parliamentarian = PASParliamentarian( personnel_number=row.personalnummer, contract_number=row.vertragsnummer, first_name=row.vorname, @@ -452,7 +452,7 @@ def parse_date(date_str: str | None) -> date | None: session.add(parliamentarian) # Create roles linking to party and group - parliamentarian.roles.append(ParliamentarianRole( + parliamentarian.roles.append(PASParliamentarianRole( party=party, party_role='member', parliamentary_group=group, @@ -468,7 +468,7 @@ def parse_date(date_str: str | None) -> date | None: 'member', ) # Create commission membership - membership = CommissionMembership( + membership = PASCommissionMembership( commission=commission, parliamentarian=parliamentarian, role=cast('MembershipRole', role), diff --git a/src/onegov/pas/excel_import_cli.py b/src/onegov/pas/excel_import_cli.py index 9e65c6ecae..ba0e4ec5bc 100644 --- a/src/onegov/pas/excel_import_cli.py +++ b/src/onegov/pas/excel_import_cli.py @@ -15,13 +15,13 @@ import openpyxl from onegov.core.csv import CSVFile, convert_excel_to_csv, detect_encoding -from onegov.parliament.models import ( - CommissionMembership, - ParliamentarianRole, - Parliamentarian, - ParliamentaryGroup, - Party, - Commission, +from onegov.pas.models import ( + PASCommissionMembership, + PASParliamentarianRole, + PASParliamentarian, + PASParliamentaryGroup, + PASParty, + PASCommission, ) T = TypeVar('T') @@ -367,12 +367,12 @@ def parse_date(date_str: str | None) -> date | None: commission_name = commission_name.replace('_', ' ') # Get or create commission - commission = session.query(Commission).filter_by( + commission = session.query(PASCommission).filter_by( name=commission_name ).first() if not commission: - commission = Commission( + commission = PASCommission( name=commission_name, type='normal' ) @@ -381,17 +381,17 @@ def parse_date(date_str: str | None) -> date | None: # First pass - create parties and parliamentary groups for row in import_file.rows: # Create party if needed - party = session.query(Party).filter_by(name=row.partei).first() + party = session.query(PASParty).filter_by(name=row.partei).first() if not party: - party = Party(name=row.partei) + party = PASParty(name=row.partei) session.add(party) # Create parliamentary group if needed - group = session.query(ParliamentaryGroup).filter_by( + group = session.query(PASParliamentaryGroup).filter_by( name=row.fraktion ).first() if not group: - group = ParliamentaryGroup(name=row.fraktion) + group = PASParliamentaryGroup(name=row.fraktion) session.add(group) session.flush() @@ -399,18 +399,18 @@ def parse_date(date_str: str | None) -> date | None: # Second pass - create parliamentarians and memberships for row in import_file.rows: # Get party and group - party = session.query(Party).filter_by(name=row.partei).one() - group = session.query(ParliamentaryGroup).filter_by( + party = session.query(PASParty).filter_by(name=row.partei).one() + group = session.query(PASParliamentaryGroup).filter_by( name=row.fraktion ).one() # Create parliamentarian if needed - parliamentarian = session.query(Parliamentarian).filter_by( + parliamentarian = session.query(PASParliamentarian).filter_by( personnel_number=row.personalnummer ).first() if not parliamentarian: - parliamentarian = Parliamentarian( + parliamentarian = PASParliamentarian( personnel_number=row.personalnummer, contract_number=row.vertragsnummer, first_name=row.vorname, @@ -444,7 +444,7 @@ def parse_date(date_str: str | None) -> date | None: session.add(parliamentarian) # Create roles linking to party and group - parliamentarian.roles.append(ParliamentarianRole( + parliamentarian.roles.append(PASParliamentarianRole( party=party, party_role='member', parliamentary_group=group, @@ -460,7 +460,7 @@ def parse_date(date_str: str | None) -> date | None: 'member', ) # Create commission membership - membership = CommissionMembership( + membership = PASCommissionMembership( commission=commission, parliamentarian=parliamentarian, role=role, # type:ignore[misc] diff --git a/src/onegov/pas/export_single_parliamentarian.py b/src/onegov/pas/export_single_parliamentarian.py index 81c2c0c859..5125558fe5 100644 --- a/src/onegov/pas/export_single_parliamentarian.py +++ b/src/onegov/pas/export_single_parliamentarian.py @@ -11,15 +11,16 @@ from weasyprint.text.fonts import ( # type: ignore[import-untyped] FontConfiguration, ) -from onegov.parliament.models.attendence import TYPES, Attendence +from onegov.parliament.models.attendence import TYPES +from onegov.pas.models.attendence import PASAttendence from datetime import date # noqa: TC003 from onegov.pas.utils import format_swiss_number from typing import TYPE_CHECKING, Literal, TypedDict if TYPE_CHECKING: - from onegov.parliament.models import Parliamentarian, RateSet - from onegov.parliament.models.settlement_run import SettlementRun + from onegov.pas.models import PASParliamentarian, RateSet + from onegov.pas.models.settlement_run import SettlementRun @dataclass @@ -51,7 +52,7 @@ class TypeTotal(TypedDict): def generate_parliamentarian_settlement_pdf( settlement_run: SettlementRun, request: TownRequest, - parliamentarian: Parliamentarian, + parliamentarian: PASParliamentarian, ) -> bytes: """Generate PDF for parliamentarian settlement data.""" font_config = FontConfiguration() @@ -281,7 +282,7 @@ def generate_parliamentarian_settlement_pdf( def _get_parliamentarian_settlement_data( settlement_run: SettlementRun, request: TownRequest, - parliamentarian: Parliamentarian, + parliamentarian: PASParliamentarian, rate_set: RateSet, ) -> dict[str, list[ParliamentarianEntry]]: """Get settlement data for a specific parliamentarian.""" @@ -294,7 +295,7 @@ def _get_parliamentarian_settlement_data( date_to=settlement_run.end, ) .query() - .filter(Attendence.parliamentarian_id == parliamentarian.id) + .filter(PASAttendence.parliamentarian_id == parliamentarian.id) ) result = [] diff --git a/src/onegov/pas/forms/attendence.py b/src/onegov/pas/forms/attendence.py index 5d805c2f0c..afee1ae3ab 100644 --- a/src/onegov/pas/forms/attendence.py +++ b/src/onegov/pas/forms/attendence.py @@ -8,7 +8,7 @@ from onegov.pas import _ from onegov.pas.collections import CommissionCollection from onegov.pas.collections import ParliamentarianCollection -from onegov.parliament.models import SettlementRun +from onegov.pas.models import SettlementRun from onegov.parliament.models.attendence import TYPES from wtforms.fields import DateField from wtforms.fields import FloatField @@ -19,7 +19,7 @@ if TYPE_CHECKING: from collections.abc import Collection from onegov.core.request import CoreRequest - from onegov.parliament.models import Attendence + from onegov.pas.models import PASAttendence from typing import Any @@ -102,13 +102,13 @@ def ensure_commission(self) -> bool: return True - def process_obj(self, obj: Attendence) -> None: # type:ignore + def process_obj(self, obj: PASAttendence) -> None: # type:ignore super().process_obj(obj) self.duration.data = obj.duration / 60 def populate_obj( # type: ignore[override] self, - obj: Attendence, # type: ignore[override] + obj: PASAttendence, # type: ignore[override] exclude: Collection[str] | None = None, include: Collection[str] | None = None ) -> None: diff --git a/src/onegov/pas/forms/rate_set.py b/src/onegov/pas/forms/rate_set.py index d4df0745a3..2e66296102 100644 --- a/src/onegov/pas/forms/rate_set.py +++ b/src/onegov/pas/forms/rate_set.py @@ -3,7 +3,7 @@ from datetime import date from onegov.form import Form from onegov.pas import _ -from onegov.parliament.models import RateSet +from onegov.pas.models import RateSet from wtforms.fields import DecimalField from wtforms.fields import IntegerField from wtforms.validators import InputRequired diff --git a/src/onegov/pas/forms/settlement_run.py b/src/onegov/pas/forms/settlement_run.py index 296a4cf958..ae6e12c627 100644 --- a/src/onegov/pas/forms/settlement_run.py +++ b/src/onegov/pas/forms/settlement_run.py @@ -5,7 +5,7 @@ from onegov.org.forms.fields import HtmlField from onegov.pas import _ from onegov.pas.layouts import DefaultLayout -from onegov.parliament.models import SettlementRun +from onegov.pas.models import SettlementRun from wtforms.fields import BooleanField from wtforms.fields import DateField from wtforms.fields import StringField diff --git a/src/onegov/pas/importer/json_import.py b/src/onegov/pas/importer/json_import.py index 06d3b7f31f..f6a971acc6 100644 --- a/src/onegov/pas/importer/json_import.py +++ b/src/onegov/pas/importer/json_import.py @@ -4,13 +4,13 @@ from uuid import UUID from onegov.pas import log -from onegov.parliament.models import ( - CommissionMembership, - Parliamentarian, - Commission, - ParliamentaryGroup, - Party, - ParliamentarianRole, +from onegov.pas.models import ( + PASCommissionMembership, + PASParliamentarian, + PASCommission, + PASParliamentaryGroup, + PASParty, + PASParliamentarianRole, ImportLog, ) from sqlalchemy.orm import selectinload @@ -173,8 +173,8 @@ class MembershipData(TypedDict): from typing import TYPE_CHECKING, TypedDict if TYPE_CHECKING: from onegov.parliament.models.parliamentarian_role import ( - ParliamentaryGroupRole - ) + ParliamentaryGroupRole, ParliamentarianRole +) from onegov.parliament.models.parliamentarian_role import PartyRole from onegov.parliament.models.parliamentarian_role import Role from collections.abc import Sequence @@ -255,8 +255,8 @@ class PeopleImporter(DataImporter): } def bulk_import(self, people_data: Sequence[PersonData]) -> tuple[ - dict[str, Parliamentarian], - dict[str, list[Parliamentarian]], + dict[str, PASParliamentarian], + dict[str, list[PASParliamentarian]], int, # Add processed count ]: """ @@ -268,16 +268,16 @@ def bulk_import(self, people_data: Sequence[PersonData]) -> tuple[ - A dictionary with lists of created and updated parliamentarians. - The total number of people records processed from the input. """ - new_parliamentarians: list[Parliamentarian] = [] - updated_parliamentarians: list[Parliamentarian] = [] + new_parliamentarians: list[PASParliamentarian] = [] + updated_parliamentarians: list[PASParliamentarian] = [] processed_count = 0 - result_map: dict[str, Parliamentarian] = {} + result_map: dict[str, PASParliamentarian] = {} # Fetch existing parliamentarians by external_kub_id existing_ids = [p['id'] for p in people_data if p.get('id')] existing_parliamentarians = ( - self.session.query(Parliamentarian) - .filter(Parliamentarian.external_kub_id.in_(existing_ids)) + self.session.query(PASParliamentarian) + .filter(PASParliamentarian.external_kub_id.in_(existing_ids)) .all() ) existing_map = { @@ -360,7 +360,7 @@ def bulk_import(self, people_data: Sequence[PersonData]) -> tuple[ return result_map, details, processed_count def _update_parliamentarian_attributes( - self, parliamentarian: Parliamentarian, person_data: PersonData + self, parliamentarian: PASParliamentarian, person_data: PersonData ) -> bool: """Updates attributes of an existing Parliamentarian object. Returns True if any attributes were changed, False otherwise.""" @@ -386,7 +386,7 @@ def _update_parliamentarian_attributes( def _create_parliamentarian( self, person_data: PersonData - ) -> Parliamentarian | None: + ) -> PASParliamentarian | None: """Creates a single new Parliamentarian object from person data.""" person_id = person_data.get('id') @@ -410,7 +410,7 @@ def _create_parliamentarian( 'email' ] - parliamentarian = Parliamentarian(**parliamentarian_kwargs) + parliamentarian = PASParliamentarian(**parliamentarian_kwargs) return parliamentarian @@ -420,12 +420,12 @@ class OrganizationImporter(DataImporter): def bulk_import( self, organizations_data: Sequence[OrganizationData] ) -> tuple[ - dict[str, Commission], - dict[str, ParliamentaryGroup], # Currently unused, but kept for + dict[str, PASCommission], + dict[str, PASParliamentaryGroup], # Currently unused, but kept for # structure - dict[str, Party], + dict[str, PASParty], dict[str, Any], # Other orgs - dict[str, dict[str, list[Commission | Party]]], # Details + dict[str, dict[str, list[PASCommission | PASParty]]], # Details dict[str, int], # Processed counts per type ]: """ @@ -440,13 +440,13 @@ def bulk_import( - Other organizations - Dictionary containing lists of created/updated objects per type. """ - commissions_to_create: list[Commission] = [] - commissions_to_update: list[Commission] = [] - parties_to_create: list[Party] = [] - parties_to_update: list[Party] = [] + commissions_to_create: list[PASCommission] = [] + commissions_to_update: list[PASCommission] = [] + parties_to_create: list[PASParty] = [] + parties_to_update: list[PASParty] = [] # Details structure to return - details: dict[str, dict[str, list[Commission | Party]]] = { + details: dict[str, dict[str, list[PASCommission | PASParty]]] = { 'commissions': {'created': [], 'updated': []}, 'parliamentary_groups': {'created': [], 'updated': []}, 'parties': {'created': [], 'updated': []}, @@ -460,22 +460,22 @@ def bulk_import( } # Maps to return (will contain both existing and new objects) - commission_map: dict[str, Commission] = {} - parliamentary_group_map: dict[str, ParliamentaryGroup] = {} - party_map: dict[str, Party] = {} + commission_map: dict[str, PASCommission] = {} + parliamentary_group_map: dict[str, PASParliamentaryGroup] = {} + party_map: dict[str, PASParty] = {} # Not ORM objects, no update needed other_organizations: dict[str, Any] = {} # Fetch existing organizations by external_kub_id existing_ids = [o['id'] for o in organizations_data if o.get('id')] existing_commissions = ( - self.session.query(Commission) - .filter(Commission.external_kub_id.in_(existing_ids)) + self.session.query(PASCommission) + .filter(PASCommission.external_kub_id.in_(existing_ids)) .all() ) existing_parties = ( - self.session.query(Party) - .filter(Party.external_kub_id.in_(existing_ids)) + self.session.query(PASParty) + .filter(PASParty.external_kub_id.in_(existing_ids)) .all() ) @@ -524,7 +524,7 @@ def bulk_import( ) # No need to add to save list, session tracks changes else: - commission = Commission( + commission = PASCommission( external_kub_id=org_uuid, name=org_name, type='normal', @@ -566,7 +566,8 @@ def bulk_import( # No need to add to save list, session tracks changes else: # Create new party (since not found in initial map) - party = Party(external_kub_id=org_uuid, name=org_name) + party = ( + PASParty(external_kub_id=org_uuid, name=org_name)) log.debug( f'Creating party (from Fraktion): {org_id}' ) @@ -675,20 +676,20 @@ class MembershipImporter(DataImporter): def __init__(self, session: Session) -> None: self.session = session - self.parliamentarian_map: dict[str, Parliamentarian] = {} - self.commission_map: dict[str, Commission] = {} - self.parliamentary_group_map: dict[str, ParliamentaryGroup] = {} + self.parliamentarian_map: dict[str, PASParliamentarian] = {} + self.commission_map: dict[str, PASCommission] = {} + self.parliamentary_group_map: dict[str, PASParliamentaryGroup] = {} # party_map now keyed by external_kub_id for consistency - self.party_map: dict[str, Party] = {} + self.party_map: dict[str, PASParty] = {} self.other_organization_map: dict[str, Any] = {} def init( self, session: Session, - parliamentarian_map: dict[str, Parliamentarian], - commission_map: dict[str, Commission], - parliamentary_group_map: dict[str, ParliamentaryGroup], - party_map: dict[str, Party], + parliamentarian_map: dict[str, PASParliamentarian], + commission_map: dict[str, PASCommission], + parliamentary_group_map: dict[str, PASParliamentaryGroup], + party_map: dict[str, PASParty], other_organization_map: dict[str, Any], ) -> None: """Initialize the importer with maps of objects by their external KUB @@ -702,7 +703,7 @@ def init( def _extract_and_update_or_create_missing_parliamentarians( self, memberships_data: Sequence[MembershipData] - ) -> dict[str, list[Parliamentarian]]: + ) -> dict[str, list[PASParliamentarian]]: """ Extracts/updates/creates parliamentarians found only in membership data. @@ -715,9 +716,9 @@ def _extract_and_update_or_create_missing_parliamentarians( missing info (address, email) from membership data. If no, create a new parliamentarian. Updates self.parliamentarian_map accordingly. """ - parliamentarians_to_create: list[Parliamentarian] = [] + parliamentarians_to_create: list[PASParliamentarian] = [] # Use a set for updates to automatically handle duplicates - parliamentarians_to_update: set[Parliamentarian] = set() + parliamentarians_to_update: set[PASParliamentarian] = set() # 1. Identify potential missing parliamentarian IDs missing_person_ids = { @@ -735,8 +736,8 @@ def _extract_and_update_or_create_missing_parliamentarians( return {'created': [], 'updated': []} existing_db_parliamentarians = ( - self.session.query(Parliamentarian) - .filter(Parliamentarian.external_kub_id.in_(missing_person_ids)) + self.session.query(PASParliamentarian) + .filter(PASParliamentarian.external_kub_id.in_(missing_person_ids)) .all() ) existing_db_map = { @@ -858,7 +859,7 @@ def _extract_and_update_or_create_missing_parliamentarians( def _update_parliamentarian_from_membership( self, - parliamentarian: Parliamentarian, + parliamentarian: PASParliamentarian, person_data: PersonData, membership_data: MembershipData, ) -> bool: @@ -918,7 +919,7 @@ def _update_parliamentarian_from_membership( def _create_parliamentarian_from_membership( self, person_data: PersonData, membership_data: MembershipData - ) -> Parliamentarian | None: + ) -> PASParliamentarian | None: """ Creates a new Parliamentarian object using data primarily from a membership record. @@ -933,7 +934,7 @@ def _create_parliamentarian_from_membership( try: uuid_value = UUID(person_id) - parliamentarian = Parliamentarian( + parliamentarian = PASParliamentarian( external_kub_id=uuid_value, first_name=person_data.get('firstName', ''), last_name=person_data.get('officialName', ''), @@ -983,8 +984,8 @@ def bulk_import( processed counts per category. - A dictionary containing the count of processed items per type. """ - commission_memberships_to_create: list[CommissionMembership] = [] - commission_memberships_to_update: list[CommissionMembership] = [] + commission_memberships_to_create: list[PASCommissionMembership] = [] + commission_memberships_to_update: list[PASCommissionMembership] = [] parliamentarian_roles_to_create: list[ParliamentarianRole] = [] parliamentarian_roles_to_update: list[ParliamentarianRole] = [] @@ -1034,16 +1035,16 @@ def bulk_import( [g.id for g in self.parliamentary_group_map.values() if g.id] existing_commission_memberships_map: dict[ - tuple[UUID | None, UUID | None], CommissionMembership + tuple[UUID | None, UUID | None], PASCommissionMembership ] = {} if parliamentarian_ids and commission_ids: existing_cms = ( - self.session.query(CommissionMembership) + self.session.query(PASCommissionMembership) .filter( - CommissionMembership.parliamentarian_id.in_( + PASCommissionMembership.parliamentarian_id.in_( parliamentarian_ids ), - CommissionMembership.commission_id.in_(commission_ids), + PASCommissionMembership.commission_id.in_(commission_ids), ) .all() ) @@ -1058,22 +1059,22 @@ def bulk_import( # Define the precise structure for the role key tuple role_key_type = tuple[UUID, UUID | None, UUID | None, str, str | None] - existing_roles_map: dict[role_key_type, ParliamentarianRole] = {} + existing_roles_map: dict[role_key_type, PASParliamentarianRole] = {} if parliamentarian_ids: # Fetch all roles for the relevant parliamentarians # We'll filter/map them client-side existing_roles = ( - self.session.query(ParliamentarianRole) + self.session.query(PASParliamentarianRole) .filter( - ParliamentarianRole.parliamentarian_id.in_( + PASParliamentarianRole.parliamentarian_id.in_( parliamentarian_ids ) ) .options( # Eager load related objects to prevent N+1 queries # during updates. - selectinload(ParliamentarianRole.party), - selectinload(ParliamentarianRole.parliamentary_group), + selectinload(PASParliamentarianRole.party), + selectinload(PASParliamentarianRole.parliamentary_group), ) .all() ) @@ -1531,10 +1532,10 @@ def bulk_import( def _create_commission_membership( self, - parliamentarian: Parliamentarian, - commission: Commission, + parliamentarian: PASParliamentarian, + commission: PASCommission, membership_data: MembershipData, - ) -> CommissionMembership | None: + ) -> PASCommissionMembership | None: """Create a CommissionMembership object.""" try: if not parliamentarian.id or not commission.id: @@ -1559,7 +1560,7 @@ def _create_commission_membership( assert parliamentarian.id is not None assert commission.id is not None - return CommissionMembership( + return PASCommissionMembership( parliamentarian=parliamentarian, parliamentarian_id=parliamentarian.id, commission=commission, @@ -1575,7 +1576,9 @@ def _create_commission_membership( return None def _update_commission_membership( - self, membership: CommissionMembership, membership_data: MembershipData + self, + membership: PASCommissionMembership, + membership_data: MembershipData ) -> bool: """ Updates an existing CommissionMembership object. @@ -1610,28 +1613,29 @@ def _update_commission_membership( def _create_parliamentarian_role( self, - parliamentarian: Parliamentarian, + parliamentarian: PASParliamentarian, role: Role, - parliamentary_group: ParliamentaryGroup | None = None, + parliamentary_group: PASParliamentaryGroup | None = None, parliamentary_group_role: ParliamentaryGroupRole | None = None, - party: Party | None = None, + party: PASParty | None = None, party_role: PartyRole | None = None, additional_information: str | None = None, start_date: str | None = None, end_date: str | None = None, - ) -> ParliamentarianRole | None: + ) -> PASParliamentarianRole | None: try: # Ensure parliamentarian has an ID if not parliamentarian.id: log.warning( - 'Skipping parliamentarian role: Parliamentarian missing ' + 'Skipping parliamentarian role: ' + 'PASParliamentarian missing ' f'ID: {parliamentarian.first_name} ' f'{parliamentarian.last_name}' ) return None assert parliamentarian.id is not None - return ParliamentarianRole( + return PASParliamentarianRole( parliamentarian=parliamentarian, parliamentarian_id=parliamentarian.id, role=role, @@ -1653,9 +1657,9 @@ def _update_parliamentarian_role( self, role_obj: ParliamentarianRole, role: Role, - parliamentary_group: ParliamentaryGroup | None = None, + parliamentary_group: PASParliamentaryGroup | None = None, parliamentary_group_role: ParliamentaryGroupRole | None = None, - party: Party | None = None, + party: PASParty | None = None, party_role: PartyRole | None = None, additional_information: str | None = None, start_date: str | None = None, diff --git a/src/onegov/pas/models/__init__.py b/src/onegov/pas/models/__init__.py new file mode 100644 index 0000000000..0e3db0cab2 --- /dev/null +++ b/src/onegov/pas/models/__init__.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from onegov.pas.models.attendence import PASAttendence +from onegov.pas.models.change import PASChange +from onegov.pas.models.commission import PASCommission +from onegov.pas.models.commission_membership import PASCommissionMembership +from onegov.pas.models.import_log import ImportLog +from onegov.pas.models.legislative_period import PASLegislativePeriod +from onegov.pas.models.parliamentarian import PASParliamentarian +from onegov.pas.models.parliamentarian_role import PASParliamentarianRole +from onegov.pas.models.parliamentary_group import PASParliamentaryGroup +from onegov.pas.models.party import PASParty +from onegov.pas.models.rate_set import RateSet +from onegov.pas.models.settlement_run import SettlementRun + + +__all__ = ( + 'ImportLog', + 'PASAttendence', + 'PASChange', + 'PASCommission', + 'PASCommissionMembership', + 'PASLegislativePeriod', + 'PASParliamentarian', + 'PASParliamentarianRole', + 'PASParliamentaryGroup', + 'PASParty', + 'RateSet', + 'SettlementRun', +) diff --git a/src/onegov/pas/models/attendence.py b/src/onegov/pas/models/attendence.py new file mode 100644 index 0000000000..d11576d4d0 --- /dev/null +++ b/src/onegov/pas/models/attendence.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import Attendence + + +class PASAttendence(Attendence): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_attendence', + } + + es_type_name = 'pas_attendence' diff --git a/src/onegov/pas/models/change.py b/src/onegov/pas/models/change.py new file mode 100644 index 0000000000..9bba6774ee --- /dev/null +++ b/src/onegov/pas/models/change.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import Change + + +class PASChange(Change): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_change', + } + + es_type_name = 'pas_change' diff --git a/src/onegov/pas/models/commission.py b/src/onegov/pas/models/commission.py new file mode 100644 index 0000000000..6f59925aa3 --- /dev/null +++ b/src/onegov/pas/models/commission.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import Commission + + +class PASCommission(Commission): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_commission', + } + + es_type_name = 'pas_commission' diff --git a/src/onegov/pas/models/commission_membership.py b/src/onegov/pas/models/commission_membership.py new file mode 100644 index 0000000000..f9c193a66b --- /dev/null +++ b/src/onegov/pas/models/commission_membership.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import CommissionMembership + + +class PASCommissionMembership(CommissionMembership): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_commission_membership', + } + + es_type_name = 'pas_commission_membership' diff --git a/src/onegov/parliament/models/import_log.py b/src/onegov/pas/models/import_log.py similarity index 100% rename from src/onegov/parliament/models/import_log.py rename to src/onegov/pas/models/import_log.py diff --git a/src/onegov/pas/models/legislative_period.py b/src/onegov/pas/models/legislative_period.py new file mode 100644 index 0000000000..0fc5f22687 --- /dev/null +++ b/src/onegov/pas/models/legislative_period.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import LegislativePeriod + + +class PASLegislativePeriod(LegislativePeriod): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_legislative_period', + } + + es_type_name = 'pas_legislative_period' diff --git a/src/onegov/pas/models/parliamentarian.py b/src/onegov/pas/models/parliamentarian.py new file mode 100644 index 0000000000..ed497409b7 --- /dev/null +++ b/src/onegov/pas/models/parliamentarian.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import Parliamentarian + + +class PASParliamentarian(Parliamentarian): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_parliamentarian', + } + + es_type_name = 'pas_parliamentarian' diff --git a/src/onegov/pas/models/parliamentarian_role.py b/src/onegov/pas/models/parliamentarian_role.py new file mode 100644 index 0000000000..35156545b4 --- /dev/null +++ b/src/onegov/pas/models/parliamentarian_role.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import ParliamentarianRole + + +class PASParliamentarianRole(ParliamentarianRole): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_parliamentarian_role', + } + + es_type_name = 'pas_parliamentarian_role' diff --git a/src/onegov/pas/models/parliamentary_group.py b/src/onegov/pas/models/parliamentary_group.py new file mode 100644 index 0000000000..1f83abc5fd --- /dev/null +++ b/src/onegov/pas/models/parliamentary_group.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +from onegov.parliament.models import ParliamentaryGroup + + +class PASParliamentaryGroup(ParliamentaryGroup): + + __mapper_args__ = { + 'polymorphic_identity': 'pas_parliamentary_group', + } + + es_type_name = 'pas_parliamentary_group' diff --git a/src/onegov/pas/models/party.py b/src/onegov/pas/models/party.py new file mode 100644 index 0000000000..97f1d9e0c4 --- /dev/null +++ b/src/onegov/pas/models/party.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +from onegov.parliament.models import Party + + +class PASParty(Party): + __mapper_args__ = { + 'polymorphic_identity': 'pas_party', + } + + es_type_name = 'pas_party' diff --git a/src/onegov/parliament/models/rate_set.py b/src/onegov/pas/models/rate_set.py similarity index 98% rename from src/onegov/parliament/models/rate_set.py rename to src/onegov/pas/models/rate_set.py index b98e673ad2..fe28dff291 100644 --- a/src/onegov/parliament/models/rate_set.py +++ b/src/onegov/pas/models/rate_set.py @@ -18,7 +18,7 @@ class RateSet(Base, ContentMixin, TimestampMixin): """ Sätze """ - __tablename__ = 'par_rate_sets' + __tablename__ = 'pas_rate_sets' #: Internal ID id: Column[uuid.UUID] = Column( diff --git a/src/onegov/parliament/models/settlement_run.py b/src/onegov/pas/models/settlement_run.py similarity index 98% rename from src/onegov/parliament/models/settlement_run.py rename to src/onegov/pas/models/settlement_run.py index 9d8bc136ba..c1171c452a 100644 --- a/src/onegov/parliament/models/settlement_run.py +++ b/src/onegov/pas/models/settlement_run.py @@ -20,7 +20,7 @@ class SettlementRun(Base, ContentMixin, TimestampMixin, ORMSearchable): """ Abrechnungslauf """ - __tablename__ = 'par_settlements' + __tablename__ = 'pas_settlements' es_public = False es_properties = {'name': {'type': 'text'}} diff --git a/src/onegov/pas/path.py b/src/onegov/pas/path.py index e5d6ea0fc0..0ef931b0fc 100644 --- a/src/onegov/pas/path.py +++ b/src/onegov/pas/path.py @@ -13,18 +13,18 @@ from onegov.pas.collections import RateSetCollection from onegov.pas.collections import SettlementRunCollection from onegov.pas.collections import ImportLogCollection -from onegov.parliament.models import Attendence -from onegov.parliament.models import Change -from onegov.parliament.models import Commission -from onegov.parliament.models import CommissionMembership -from onegov.parliament.models import ImportLog -from onegov.parliament.models import LegislativePeriod -from onegov.parliament.models import Parliamentarian -from onegov.parliament.models import ParliamentarianRole -from onegov.parliament.models import ParliamentaryGroup -from onegov.parliament.models import Party -from onegov.parliament.models import RateSet -from onegov.parliament.models import SettlementRun +from onegov.pas.models import PASAttendence +from onegov.pas.models import PASChange +from onegov.pas.models import PASCommission +from onegov.pas.models import PASCommissionMembership +from onegov.pas.models import ImportLog +from onegov.pas.models import PASLegislativePeriod +from onegov.pas.models import PASParliamentarian +from onegov.pas.models import PASParliamentarianRole +from onegov.pas.models import PASParliamentaryGroup +from onegov.pas.models import PASParty +from onegov.pas.models import RateSet +from onegov.pas.models import SettlementRun from uuid import UUID from datetime import date @@ -33,6 +33,12 @@ if TYPE_CHECKING: from onegov.town6.request import TownRequest + from onegov.parliament.models import ( + ParliamentarianRole, + Party, + ParliamentaryGroup + ) + @PasApp.path( model=AttendenceCollection, @@ -68,14 +74,14 @@ def get_attendences( @PasApp.path( - model=Attendence, + model=PASAttendence, path='/attendence/{id}', converters={'id': UUID} ) def get_attendence( app: PasApp, id: UUID -) -> Attendence | None: +) -> PASAttendence | None: return AttendenceCollection(app.session()).by_id(id) @@ -90,14 +96,14 @@ def get_changes( @PasApp.path( - model=Change, + model=PASChange, path='/change/{id}', converters={'id': UUID} ) def get_change( app: PasApp, id: UUID -) -> Change | None: +) -> PASChange | None: return ChangeCollection(app.session()).by_id(id) @@ -114,14 +120,14 @@ def get_commissions( @PasApp.path( - model=Commission, + model=PASCommission, path='/commission/{id}', converters={'id': UUID} ) def get_commission( app: PasApp, id: UUID, -) -> Commission | None: +) -> PASCommission | None: return CommissionCollection(app.session()).by_id(id) @@ -136,14 +142,14 @@ def get_commission_memberships( @PasApp.path( - model=CommissionMembership, + model=PASCommissionMembership, path='/commission-membership/{id}', converters={'id': UUID} ) def get_commission_membership( app: PasApp, id: UUID -) -> CommissionMembership | None: +) -> PASCommissionMembership | None: return CommissionMembershipCollection(app.session()).by_id(id) @@ -160,14 +166,14 @@ def get_legislative_periods( @PasApp.path( - model=LegislativePeriod, + model=PASLegislativePeriod, path='/legislative-period/{id}', converters={'id': UUID} ) def get_legislative_period( app: PasApp, id: UUID -) -> LegislativePeriod | None: +) -> PASLegislativePeriod | None: return LegislativePeriodCollection(app.session()).by_id(id) @@ -184,14 +190,14 @@ def get_parliamentarians( @PasApp.path( - model=Parliamentarian, + model=PASParliamentarian, path='/parliamenarian/{id}', converters={'id': UUID} ) def get_parliamentarian( app: PasApp, id: UUID -) -> Parliamentarian | None: +) -> PASParliamentarian | None: return ParliamentarianCollection(app.session()).by_id(id) @@ -206,7 +212,7 @@ def get_parliamentarian_roles( @PasApp.path( - model=ParliamentarianRole, + model=PASParliamentarianRole, path='/parliamenarian-role/{id}', converters={'id': UUID} ) @@ -230,7 +236,7 @@ def get_parliamentary_groups( @PasApp.path( - model=ParliamentaryGroup, + model=PASParliamentaryGroup, path='/parliamenary-group/{id}', converters={'id': UUID} ) @@ -254,7 +260,7 @@ def get_parties( @PasApp.path( - model=Party, + model=PASParty, path='/party/{id}', converters={'id': UUID} ) @@ -322,7 +328,7 @@ class SettlementRunExport: def __init__( self, settlement_run: SettlementRun, - entity: Party | Commission | Parliamentarian, + entity: PASParty | PASCommission | PASParliamentarian, category: str | None = None ): self.settlement_run = settlement_run @@ -363,9 +369,9 @@ def get_settlement_run_export( return None model_map: dict[str, type] = { - 'Party': Party, - 'Commission': Commission, - 'Parliamentarian': Parliamentarian, + 'Party': PASParty, + 'Commission': PASCommission, + 'Parliamentarian': PASParliamentarian, } entity = ( session.query(model_map.get(literal_type)) diff --git a/src/onegov/pas/utils.py b/src/onegov/pas/utils.py index 57d27d6c0d..9b9261c512 100644 --- a/src/onegov/pas/utils.py +++ b/src/onegov/pas/utils.py @@ -2,17 +2,17 @@ from onegov.pas import log from onegov.pas.collections import AttendenceCollection -from onegov.parliament.models.party import Party -from onegov.parliament.models.parliamentarian import Parliamentarian -from onegov.parliament.models.parliamentarian_role import ParliamentarianRole -from onegov.parliament.models.attendence import Attendence +from onegov.pas.models.party import PASParty +from onegov.pas.models.parliamentarian import PASParliamentarian +from onegov.pas.models.parliamentarian_role import PASParliamentarianRole +from onegov.pas.models.attendence import PASAttendence from decimal import Decimal from babel.numbers import format_decimal from typing import TYPE_CHECKING if TYPE_CHECKING: - from onegov.parliament.models import SettlementRun + from onegov.pas.models import SettlementRun from onegov.town6.request import TownRequest from datetime import date from sqlalchemy.orm import Session @@ -32,22 +32,25 @@ def get_parliamentarians_with_settlements( session: Session, start_date: date, end_date: date -) -> list[Parliamentarian]: +) -> list[PASParliamentarian]: """ Get all parliamentarians who were active and had settlements during the specified period. """ - active_parliamentarians = session.query(Parliamentarian).filter( - Parliamentarian.id.in_( - session.query(ParliamentarianRole.parliamentarian_id).filter( - (ParliamentarianRole.start.is_(None) | ( - ParliamentarianRole.start <= end_date)), - (ParliamentarianRole.end.is_(None) | ( - ParliamentarianRole.end >= start_date)) + active_parliamentarians = session.query(PASParliamentarian).filter( + PASParliamentarian.id.in_( + session.query(PASParliamentarianRole.parliamentarian_id).filter( + (PASParliamentarianRole.start.is_(None) | ( + PASParliamentarianRole.start <= end_date)), + (PASParliamentarianRole.end.is_(None) | ( + PASParliamentarianRole.end >= start_date)) ) ) - ).order_by(Parliamentarian.last_name, Parliamentarian.first_name).all() + ).order_by( + PASParliamentarian.last_name, + PASParliamentarian.first_name + ).all() roles_pretty_print = [ f'{p.last_name} {p.first_name}: {p.roles}' @@ -57,9 +60,10 @@ def get_parliamentarians_with_settlements( # Get all parliamentarians with attendances in one query parliamentarians_with_attendances = { - pid[0] for pid in session.query(Attendence.parliamentarian_id).filter( - Attendence.date >= start_date, - Attendence.date <= end_date + pid[0] for pid in + session.query(PASAttendence.parliamentarian_id).filter( + PASAttendence.date >= start_date, + PASAttendence.date <= end_date ).distinct() } log.info(f'Parli with attendances: {parliamentarians_with_attendances}') @@ -75,7 +79,7 @@ def get_parties_with_settlements( session: Session, start_date: date, end_date: date -) -> list[Party]: +) -> list[PASParty]: """ Get all parties that had active members with attendances during the specified period. @@ -88,32 +92,32 @@ def get_parties_with_settlements( """ return ( - session.query(Party) + session.query(PASParty) .filter( - Party.id.in_( - session.query(ParliamentarianRole.party_id) - .join(Parliamentarian) + PASParty.id.in_( + session.query(PASParliamentarianRole.party_id) + .join(PASParliamentarian) .join( - Attendence, - Parliamentarian.id == Attendence.parliamentarian_id, + PASAttendence, + PASParliamentarian.id == PASAttendence.parliamentarian_id, ) .filter( - Attendence.date >= start_date, - Attendence.date <= end_date, - ParliamentarianRole.party_id.isnot(None), + PASAttendence.date >= start_date, + PASAttendence.date <= end_date, + PASParliamentarianRole.party_id.isnot(None), ( - ParliamentarianRole.start.is_(None) - | (ParliamentarianRole.start <= Attendence.date) + PASParliamentarianRole.start.is_(None) + | (PASParliamentarianRole.start <= PASAttendence.date) ), ( - ParliamentarianRole.end.is_(None) - | (ParliamentarianRole.end >= Attendence.date) + PASParliamentarianRole.end.is_(None) + | (PASParliamentarianRole.end >= PASAttendence.date) ), ) .distinct() ) ) - .order_by(Party.name) + .order_by(PASParty.name) .all() ) @@ -123,7 +127,7 @@ def get_parties_with_settlements( def debug_party_export( settlement_run: SettlementRun, request: TownRequest, - party: Party + party: PASParty ) -> None: """Debug function to trace party export data retrieval""" session = request.session @@ -139,8 +143,8 @@ def debug_party_export( AttendenceCollection(session) .query() .filter( - Attendence.date >= settlement_run.start, - Attendence.date <= settlement_run.end + PASAttendence.date >= settlement_run.start, + PASAttendence.date <= settlement_run.end ) .all() ) @@ -152,9 +156,9 @@ def debug_party_export( print(f'\nParliamentarian: {parl.first_name} {parl.last_name}') # noqa: T201 print(f'Attendance date: {attendance.date}') # noqa: T201 - roles = session.query(ParliamentarianRole).filter( - ParliamentarianRole.parliamentarian_id == parl.id, - ParliamentarianRole.party_id == party.id, + roles = session.query(PASParliamentarianRole).filter( + PASParliamentarianRole.parliamentarian_id == parl.id, + PASParliamentarianRole.party_id == party.id, ).all() print('Roles:') # noqa: T201 @@ -185,21 +189,21 @@ def debug_party_export( def debug_party_export2( request: TownRequest, - party: Party + party: PASParty ) -> None: session = request.session - print(f'Party ID: {party.id}') # noqa: T201 + print(f'PASParty ID: {party.id}') # noqa: T201 # Check roles directly - all_roles = session.query(ParliamentarianRole).filter( - ParliamentarianRole.party_id == party.id + all_roles = session.query(PASParliamentarianRole).filter( + PASParliamentarianRole.party_id == party.id ).all() print(f'\nTotal roles for party: {len(all_roles)}') # noqa: T201 for role in all_roles: print(f'Role: {role.party_id} -> {role.parliamentarian_id}') # noqa: T201 # Check all parties - all_parties = session.query(Party).all() + all_parties = session.query(PASParty).all() print('\nAll parties:') # noqa: T201 for p in all_parties: print(f'ID: {p.id}, Name: {p.name}') # noqa: T201 diff --git a/src/onegov/pas/views/attendence.py b/src/onegov/pas/views/attendence.py index 4c12cc5e64..890d58013d 100644 --- a/src/onegov/pas/views/attendence.py +++ b/src/onegov/pas/views/attendence.py @@ -10,8 +10,8 @@ from onegov.pas.forms import AttendenceForm from onegov.pas.layouts import AttendenceCollectionLayout from onegov.pas.layouts import AttendenceLayout -from onegov.parliament.models import Attendence -from onegov.parliament.models import Change +from onegov.pas.models import PASAttendence +from onegov.pas.models import PASChange from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -55,7 +55,7 @@ def add_attendence( if form.submitted(request): attendence = self.add(**form.get_useful_data()) - Change.add(request, 'add', attendence) + PASChange.add(request, 'add', attendence) request.success(_('Added a new attendence')) return request.redirect(request.link(attendence)) @@ -91,7 +91,7 @@ def add_plenary_attendence( attendence = self.add( parliamentarian_id=parliamentarian_id, **data ) - Change.add(request, 'add', attendence) + PASChange.add(request, 'add', attendence) request.success(_('Added plenary session')) return request.redirect(request.link(self)) @@ -108,12 +108,12 @@ def add_plenary_attendence( @PasApp.html( - model=Attendence, + model=PASAttendence, template='attendence.pt', permission=Private ) def view_attendence( - self: Attendence, + self: PASAttendence, request: TownRequest ) -> RenderData: @@ -127,21 +127,21 @@ def view_attendence( @PasApp.form( - model=Attendence, + model=PASAttendence, name='edit', template='form.pt', permission=Private, form=AttendenceForm ) def edit_attendence( - self: Attendence, + self: PASAttendence, request: TownRequest, form: AttendenceForm ) -> RenderData | Response: if form.submitted(request): form.populate_obj(self) - Change.add(request, 'edit', self) + PASChange.add(request, 'edit', self) request.success(_('Your changes were saved')) return request.redirect(request.link(self)) @@ -160,17 +160,17 @@ def edit_attendence( @PasApp.view( - model=Attendence, + model=PASAttendence, request_method='DELETE', permission=Private ) def delete_attendence( - self: Attendence, + self: PASAttendence, request: TownRequest ) -> None: request.assert_valid_csrf_token() - Change.add(request, 'delete', self) + PASChange.add(request, 'delete', self) collection = AttendenceCollection(request.session) collection.delete(self) diff --git a/src/onegov/pas/views/change.py b/src/onegov/pas/views/change.py index 4d0c896cb6..f041100ecf 100644 --- a/src/onegov/pas/views/change.py +++ b/src/onegov/pas/views/change.py @@ -5,7 +5,7 @@ from onegov.pas.collections import ChangeCollection from onegov.pas.layouts import ChangeCollectionLayout from onegov.pas.layouts import ChangeLayout -from onegov.parliament.models import Change +from onegov.pas.models import PASChange from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -33,12 +33,12 @@ def view_changes( @PasApp.html( - model=Change, + model=PASChange, template='change.pt', permission=Private ) def view_change( - self: Change, + self: PASChange, request: TownRequest ) -> RenderData: diff --git a/src/onegov/pas/views/commission.py b/src/onegov/pas/views/commission.py index 7cc6a744a0..2dc77c2d31 100644 --- a/src/onegov/pas/views/commission.py +++ b/src/onegov/pas/views/commission.py @@ -11,9 +11,9 @@ from onegov.pas.forms import CommissionForm from onegov.pas.layouts import CommissionCollectionLayout from onegov.pas.layouts import CommissionLayout -from onegov.parliament.models import Change -from onegov.parliament.models import Commission -from onegov.parliament.models import CommissionMembership +from onegov.pas.models import PASChange +from onegov.pas.models import PASCommission +from onegov.pas.models import PASCommissionMembership from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -87,12 +87,12 @@ def add_commission( @PasApp.html( - model=Commission, + model=PASCommission, template='commission.pt', permission=Private ) def view_commission( - self: Commission, + self: PASCommission, request: TownRequest ) -> RenderData: @@ -106,14 +106,14 @@ def view_commission( @PasApp.form( - model=Commission, + model=PASCommission, name='edit', template='form.pt', permission=Private, form=CommissionForm ) def edit_commission( - self: Commission, + self: PASCommission, request: TownRequest, form: CommissionForm ) -> RenderData | Response: @@ -139,12 +139,12 @@ def edit_commission( @PasApp.view( - model=Commission, + model=PASCommission, request_method='DELETE', permission=Private ) def delete_commission( - self: Commission, + self: PASCommission, request: TownRequest ) -> None: @@ -155,21 +155,21 @@ def delete_commission( @PasApp.form( - model=Commission, + model=PASCommission, name='new-membership', template='form.pt', permission=Private, form=CommissionMembershipAddForm ) def add_commission_membership( - self: Commission, + self: PASCommission, request: TownRequest, form: CommissionMembershipAddForm ) -> RenderData | Response: if form.submitted(request): self.memberships.append( - CommissionMembership(**form.get_useful_data()) + PASCommissionMembership(**form.get_useful_data()) ) request.success(_('Added a new parliamentarian')) return request.redirect(request.link(self)) @@ -187,14 +187,14 @@ def add_commission_membership( @PasApp.form( - model=Commission, + model=PASCommission, name='add-attendence', template='form.pt', permission=Private, form=AttendenceAddCommissionForm ) def add_plenary_attendence( - self: Commission, + self: PASCommission, request: TownRequest, form: AttendenceAddCommissionForm ) -> RenderData | Response: @@ -208,7 +208,7 @@ def add_plenary_attendence( parliamentarian_id=parliamentarian_id, **data ) - Change.add(request, 'add', attendence) + PASChange.add(request, 'add', attendence) request.success(_('Added commission meeting')) return request.redirect(request.link(self)) diff --git a/src/onegov/pas/views/commission_membership.py b/src/onegov/pas/views/commission_membership.py index 63fb46f4eb..75b2dd3c16 100644 --- a/src/onegov/pas/views/commission_membership.py +++ b/src/onegov/pas/views/commission_membership.py @@ -7,7 +7,7 @@ from onegov.pas.collections import CommissionMembershipCollection from onegov.pas.forms import CommissionMembershipForm from onegov.pas.layouts import CommissionMembershipLayout -from onegov.parliament.models import CommissionMembership +from onegov.pas.models import PASCommissionMembership from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -17,12 +17,12 @@ @PasApp.html( - model=CommissionMembership, + model=PASCommissionMembership, template='commission_membership.pt', permission=Private ) def view_commission_membership( - self: CommissionMembership, + self: PASCommissionMembership, request: TownRequest ) -> RenderData: @@ -36,14 +36,14 @@ def view_commission_membership( @PasApp.form( - model=CommissionMembership, + model=PASCommissionMembership, name='edit', template='form.pt', permission=Private, form=CommissionMembershipForm ) def edit_commission_membership( - self: CommissionMembership, + self: PASCommissionMembership, request: TownRequest, form: CommissionMembershipForm ) -> RenderData | Response: @@ -68,12 +68,12 @@ def edit_commission_membership( @PasApp.view( - model=CommissionMembership, + model=PASCommissionMembership, request_method='DELETE', permission=Private ) def delete_commission_membership( - self: CommissionMembership, + self: PASCommissionMembership, request: TownRequest ) -> None: diff --git a/src/onegov/pas/views/data_import.py b/src/onegov/pas/views/data_import.py index cfae4195eb..3b4d2dee52 100644 --- a/src/onegov/pas/views/data_import.py +++ b/src/onegov/pas/views/data_import.py @@ -3,7 +3,6 @@ import json import logging - from onegov.core.elements import Link from onegov.core.security import Private from onegov.core.utils import dictionary_to_binary @@ -12,16 +11,16 @@ from onegov.pas.forms.data_import import DataImportForm from onegov.pas.importer.json_import import ( import_zug_kub_data, - Commission, - CommissionMembership, - Parliamentarian, - ParliamentarianRole, - Party, + PASParliamentarian, + PASParliamentarianRole, + PASParty, ) from onegov.pas.layouts import ImportLayout +from onegov.pas.models import PASCommission, PASCommissionMembership from typing import Any, TYPE_CHECKING, TypedDict + if TYPE_CHECKING: from onegov.core.types import LaxFileDict, RenderData from collections.abc import Sequence @@ -108,18 +107,18 @@ def handle_data_import( # Helper function to get display title for various imported objects def get_item_display_title(item: Any) -> str: - if isinstance(item, Parliamentarian): + if isinstance(item, PASParliamentarian): return item.title # Already includes first/last name etc. - elif isinstance(item, (Commission, Party)): + elif isinstance(item, (PASCommission, PASParty)): return item.name - elif isinstance(item, CommissionMembership): + elif isinstance(item, PASCommissionMembership): # Ensure related objects are loaded or handle potential errors parl_title = (item.parliamentarian.title if item.parliamentarian else 'Unknown Parl.') comm_name = (item.commission.name if item.commission else 'Unknown Comm.') return f'{parl_title} in {comm_name} ({item.role})' - elif isinstance(item, ParliamentarianRole): + elif isinstance(item, PASParliamentarianRole): parl_title = (item.parliamentarian.title if item.parliamentarian else 'Unknown Parl.') role_details: list[str] = [str(item.role)] diff --git a/src/onegov/pas/views/import_log.py b/src/onegov/pas/views/import_log.py index 9dad536bb3..9bbbe63acb 100644 --- a/src/onegov/pas/views/import_log.py +++ b/src/onegov/pas/views/import_log.py @@ -5,7 +5,7 @@ from onegov.pas import PasApp, _ from onegov.pas.collections import ImportLogCollection from onegov.pas.layouts.default import DefaultLayout -from onegov.parliament.models import ImportLog +from onegov.pas.models import ImportLog from typing import TYPE_CHECKING diff --git a/src/onegov/pas/views/legislative_period.py b/src/onegov/pas/views/legislative_period.py index 73fbf5f3db..db93271d51 100644 --- a/src/onegov/pas/views/legislative_period.py +++ b/src/onegov/pas/views/legislative_period.py @@ -8,7 +8,7 @@ from onegov.pas.forms import LegislativePeriodForm from onegov.pas.layouts import LegislativePeriodCollectionLayout from onegov.pas.layouts import LegislativePeriodLayout -from onegov.parliament.models import LegislativePeriod +from onegov.pas.models import PASLegislativePeriod from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -81,12 +81,12 @@ def add_legislative_period( @PasApp.html( - model=LegislativePeriod, + model=PASLegislativePeriod, template='legislative_period.pt', permission=Private ) def view_legislative_period( - self: LegislativePeriod, + self: PASLegislativePeriod, request: TownRequest ) -> RenderData: @@ -100,14 +100,14 @@ def view_legislative_period( @PasApp.form( - model=LegislativePeriod, + model=PASLegislativePeriod, name='edit', template='form.pt', permission=Private, form=LegislativePeriodForm ) def edit_legislative_period( - self: LegislativePeriod, + self: PASLegislativePeriod, request: TownRequest, form: LegislativePeriodForm ) -> RenderData | Response: @@ -132,12 +132,12 @@ def edit_legislative_period( @PasApp.view( - model=LegislativePeriod, + model=PASLegislativePeriod, request_method='DELETE', permission=Private ) def delete_legislative_period( - self: LegislativePeriod, + self: PASLegislativePeriod, request: TownRequest ) -> None: diff --git a/src/onegov/pas/views/parliamentarian.py b/src/onegov/pas/views/parliamentarian.py index f187f1c295..a95f5d100b 100644 --- a/src/onegov/pas/views/parliamentarian.py +++ b/src/onegov/pas/views/parliamentarian.py @@ -9,8 +9,8 @@ from onegov.pas.forms import ParliamentarianRoleForm from onegov.pas.layouts import ParliamentarianCollectionLayout from onegov.pas.layouts import ParliamentarianLayout -from onegov.parliament.models import Parliamentarian -from onegov.parliament.models import ParliamentarianRole +from onegov.pas.models import PASParliamentarian +from onegov.pas.models import PASParliamentarianRole from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -83,12 +83,12 @@ def add_parliamentarian( @PasApp.html( - model=Parliamentarian, + model=PASParliamentarian, template='parliamentarian.pt', permission=Private ) def view_parliamentarian( - self: Parliamentarian, + self: PASParliamentarian, request: TownRequest ) -> RenderData: @@ -102,14 +102,14 @@ def view_parliamentarian( @PasApp.form( - model=Parliamentarian, + model=PASParliamentarian, name='edit', template='form.pt', permission=Private, form=ParliamentarianForm ) def edit_parliamentarian( - self: Parliamentarian, + self: PASParliamentarian, request: TownRequest, form: ParliamentarianForm ) -> RenderData | Response: @@ -134,12 +134,12 @@ def edit_parliamentarian( @PasApp.view( - model=Parliamentarian, + model=PASParliamentarian, request_method='DELETE', permission=Private ) def delete_parliamentarian( - self: Parliamentarian, + self: PASParliamentarian, request: TownRequest ) -> None: @@ -150,14 +150,14 @@ def delete_parliamentarian( @PasApp.form( - model=Parliamentarian, + model=PASParliamentarian, name='new-role', template='form.pt', permission=Private, form=ParliamentarianRoleForm ) def add_commission_membership( - self: Parliamentarian, + self: PASParliamentarian, request: TownRequest, form: ParliamentarianRoleForm ) -> RenderData | Response: @@ -166,7 +166,7 @@ def add_commission_membership( if form.submitted(request): self.roles.append( - ParliamentarianRole(**form.get_useful_data()) + PASParliamentarianRole(**form.get_useful_data()) ) request.success(_('Added a new role')) return request.redirect(request.link(self)) diff --git a/src/onegov/pas/views/rate_set.py b/src/onegov/pas/views/rate_set.py index 666c2ef583..e2fc11327a 100644 --- a/src/onegov/pas/views/rate_set.py +++ b/src/onegov/pas/views/rate_set.py @@ -8,7 +8,7 @@ from onegov.pas.forms import RateSetForm from onegov.pas.layouts import RateSetCollectionLayout from onegov.pas.layouts import RateSetLayout -from onegov.parliament.models import RateSet +from onegov.pas.models import RateSet from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/src/onegov/pas/views/settlement_run.py b/src/onegov/pas/views/settlement_run.py index 3bf3bbf844..69080e8892 100644 --- a/src/onegov/pas/views/settlement_run.py +++ b/src/onegov/pas/views/settlement_run.py @@ -1,43 +1,53 @@ from __future__ import annotations +from webob import Response +from decimal import Decimal +from operator import itemgetter +from weasyprint import HTML, CSS # type: ignore[import-untyped] +from weasyprint.text.fonts import ( # type: ignore[import-untyped] + FontConfiguration) + from onegov.core.elements import Link from onegov.core.security import Private +from onegov.parliament.models.attendence import TYPES from onegov.pas import _ from onegov.pas import PasApp from onegov.pas.calculate_pay import calculate_rate -from onegov.pas.collections import SettlementRunCollection,\ - AttendenceCollection, CommissionCollection +from onegov.pas.collections import ( + SettlementRunCollection, + AttendenceCollection, + CommissionCollection +) from onegov.pas.custom import get_current_rate_set -from onegov.pas.export_single_parliamentarian import\ +from onegov.pas.export_single_parliamentarian import ( generate_parliamentarian_settlement_pdf +) from onegov.pas.forms import SettlementRunForm from onegov.pas.layouts import SettlementRunCollectionLayout from onegov.pas.layouts import SettlementRunLayout -from onegov.parliament.models import ( +from onegov.pas.models import ( + PASAttendence, + PASParliamentarian, + PASParty, + PASCommission, SettlementRun, - Party, - Commission, ) -from webob import Response -from decimal import Decimal -from weasyprint import HTML, CSS # type: ignore[import-untyped] -from weasyprint.text.fonts import ( # type: ignore[import-untyped] - FontConfiguration) -from onegov.parliament.models.attendence import TYPES, Attendence from onegov.pas.path import SettlementRunExport, SettlementRunAllExport -from onegov.parliament.models import Parliamentarian from onegov.pas.utils import ( format_swiss_number, get_parliamentarians_with_settlements, get_parties_with_settlements, ) -from operator import itemgetter from typing import TYPE_CHECKING, Literal + if TYPE_CHECKING: + from datetime import date from onegov.core.types import RenderData from onegov.town6.request import TownRequest - from datetime import date + + from onegov.parliament.models import Commission, Parliamentarian + SettlementDataRow = tuple[ 'date', Parliamentarian, str, Decimal, Decimal, Decimal ] @@ -241,7 +251,7 @@ def view_settlement_run( # Get commissions active during settlement run period commissions = CommissionCollection(session).query().order_by( - Commission.name + PASCommission.name ) # Get parliamentarians active during settlement run period with settlements @@ -329,7 +339,7 @@ def view_settlement_run( def _get_commission_totals( settlement_run: SettlementRun, request: TownRequest, - commission: Commission + commission: PASCommission ) -> list[TotalRow]: """Get totals for a specific commission grouped by party.""" session = request.session @@ -535,19 +545,19 @@ def generate_settlement_pdf( settlement_run: SettlementRun, request: TownRequest, entity_type: Literal['all', 'commission', 'party', 'parliamentarian'], - entity: Commission | Party | Parliamentarian | None = None, + entity: PASCommission | PASParty | PASParliamentarian | None = None, ) -> bytes: """ Entry point for almost all settlement PDF generations. """ font_config = FontConfiguration() css = CSS(string=PDF_CSS) - if entity_type == 'commission' and isinstance(entity, Commission): + if entity_type == 'commission' and isinstance(entity, PASCommission): settlement_data = _get_commission_settlement_data( settlement_run, request, entity ) totals = _get_commission_totals(settlement_run, request, entity) - elif entity_type == 'party' and isinstance(entity, Party): + elif entity_type == 'party' and isinstance(entity, PASParty): settlement_data = _get_party_settlement_data( settlement_run, request, entity ) @@ -588,7 +598,7 @@ def _get_commission_settlement_data( date_from=settlement_run.start, date_to=settlement_run.end ).query().filter( - Attendence.commission_id == commission.id + PASAttendence.commission_id == commission.id ) cola_multiplier = Decimal( str(1 + (rate_set.cost_of_living_adjustment / 100)) @@ -798,7 +808,7 @@ def _get_data_export_all( def get_party_specific_totals( - settlement_run: SettlementRun, request: TownRequest, party: Party + settlement_run: SettlementRun, request: TownRequest, party: PASParty ) -> list[TotalRow]: """Get totals for a specific party.""" session = request.session @@ -899,7 +909,7 @@ def get_party_specific_totals( def _get_party_settlement_data( settlement_run: SettlementRun, request: TownRequest, - party: Party + party: PASParty ) -> list[SettlementDataRow]: """Get settlement data for a specific party.""" @@ -1007,7 +1017,7 @@ def view_settlement_run_export( parliamentarian) in a settlement run.""" if self.category == 'party': - assert isinstance(self.entity, Party) + assert isinstance(self.entity, PASParty) pdf_bytes = generate_settlement_pdf( settlement_run=self.settlement_run, @@ -1018,7 +1028,7 @@ def view_settlement_run_export( filename = f'Partei_{self.entity.name}' elif self.category == 'commission': - assert isinstance(self.entity, Commission) + assert isinstance(self.entity, PASCommission) pdf_bytes = generate_settlement_pdf( settlement_run=self.settlement_run, @@ -1029,7 +1039,7 @@ def view_settlement_run_export( filename = f'commission_{self.entity.name}' elif self.category == 'parliamentarian': - assert isinstance(self.entity, Parliamentarian) + assert isinstance(self.entity, PASParliamentarian) # PASParliamentarian specific export has it's own rendering function pdf_bytes = generate_parliamentarian_settlement_pdf( self.settlement_run, request, self.entity From 8b8174ba8b4a56d96e04f7bc0e947efe8c1d20ab Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Thu, 12 Jun 2025 11:45:23 +0200 Subject: [PATCH 07/17] Fix table name --- src/onegov/pas/models/import_log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onegov/pas/models/import_log.py b/src/onegov/pas/models/import_log.py index 65748ccab9..040c5f9799 100644 --- a/src/onegov/pas/models/import_log.py +++ b/src/onegov/pas/models/import_log.py @@ -18,7 +18,7 @@ class ImportLog(Base, TimestampMixin): """ Logs the summary of a KUB data import attempt. """ - __tablename__ = 'par_import_logs' + __tablename__ = 'pas_import_logs' id: Column[uuid.UUID] = Column( UUID, # type: ignore[arg-type] From eecb5f7166385e47f7216c39c8845d81fc3da0ce Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Thu, 12 Jun 2025 11:51:46 +0200 Subject: [PATCH 08/17] Initialize tests/parliament --- tests/onegov/parliament/__init__.py | 0 tests/onegov/parliament/conftest.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/onegov/parliament/__init__.py create mode 100644 tests/onegov/parliament/conftest.py diff --git a/tests/onegov/parliament/__init__.py b/tests/onegov/parliament/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/onegov/parliament/conftest.py b/tests/onegov/parliament/conftest.py new file mode 100644 index 0000000000..e69de29bb2 From 48e1a75f5eb0e5c013f26cf37a1129b70e372b99 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Thu, 12 Jun 2025 13:39:19 +0200 Subject: [PATCH 09/17] Register module parliament and add upgrade step --- .pre-commit-config.yaml | 4 ++-- setup.cfg | 4 +++- src/onegov/parliament/upgrade.py | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/onegov/parliament/upgrade.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce0121d45a..19b245f9c7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: exclude: .pre-commit-config.yaml - id: pt_structure - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.12 + rev: v0.11.13 hooks: - id: ruff args: [ "--fix" ] @@ -70,6 +70,6 @@ repos: files: '^stubs/.*\.pyi$' pass_filenames: false - repo: https://github.com/gitleaks/gitleaks - rev: v8.27.0 + rev: v8.27.2 hooks: - id: gitleaks \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index e8aa42d21c..8f4f0e26c7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,7 @@ packages = onegov.onboarding onegov.org onegov.page + onegov.parliament onegov.pas onegov.pay onegov.pdf @@ -296,7 +297,7 @@ console_scripts = onegov-gazette = onegov.gazette.cli:cli onegov-landsgemeinde = onegov.org.cli:cli onegov-org = onegov.org.cli:cli - onegov-people = onegov.people.cli:cli + onegov-parliament = onegov.parliament.cli:cli onegov-pas = onegov.pas.cli:cli onegov-search = onegov.search.cli:cli onegov-server = onegov.server.cli:run @@ -328,6 +329,7 @@ onegov_upgrades = onegov.onboarding = onegov.onboarding.upgrade onegov.org = onegov.org.upgrade onegov.page = onegov.page.upgrade + onegov.parliament = onegov.parliament.upgrade onegov.pas = onegov.pas.upgrade onegov.pay = onegov.pay.upgrade onegov.pdf = onegov.pdf.upgrade diff --git a/src/onegov/parliament/upgrade.py b/src/onegov/parliament/upgrade.py new file mode 100644 index 0000000000..c042e0c8b6 --- /dev/null +++ b/src/onegov/parliament/upgrade.py @@ -0,0 +1,35 @@ +"""Contains upgrade tasks that are executed when the application is being +upgraded on the server. See :class:`onegov.core.upgrade.upgrade_task`. + +""" + +from __future__ import annotations + +from onegov.core.upgrade import upgrade_task, UpgradeContext + + +@upgrade_task('Introduce parliament module: rename pas tables') +def introduce_parliament_module_rename_pas_tables( + context: UpgradeContext +) -> None: + for current_name, target_name in ( + ('pas_attendence', 'par_attendence'), + ('pas_changes', 'par_changes'), + ('pas_commission_memberships', 'par_commission_memberships'), + ('pas_commissions', 'par_commissions'), + ('pas_legislative_periods', 'par_legislative_periods'), + ('pas_parliamentarian_roles', 'par_parliamentarian_roles'), + ('pas_parliamentarians', 'par_parliamentarians'), + ('pas_parliamentary_groups', 'par_parliamentary_groups'), + ('pas_parties', 'par_parties'), + ): + + if context.has_table(current_name): + if context.has_table(target_name): + # target may was created by defining the table in the model + context.operations.execute( + f'DROP TABLE IF EXISTS {target_name} CASCADE' + ) + + context.operations.rename_table( + current_name, target_name) From d09ec75431ea82fc401a34655e870c513e961c2c Mon Sep 17 00:00:00 2001 From: Reto Tschuppert <124258444+Tschuppi81@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:34:12 +0200 Subject: [PATCH 10/17] re-add onegov-people cli Co-authored-by: David Salvisberg --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 8f4f0e26c7..47bc040ced 100644 --- a/setup.cfg +++ b/setup.cfg @@ -297,7 +297,7 @@ console_scripts = onegov-gazette = onegov.gazette.cli:cli onegov-landsgemeinde = onegov.org.cli:cli onegov-org = onegov.org.cli:cli - onegov-parliament = onegov.parliament.cli:cli + onegov-people = onegov.people.cli:cli onegov-pas = onegov.pas.cli:cli onegov-search = onegov.search.cli:cli onegov-server = onegov.server.cli:run From 2c5d0dd10768bf9a0b5b14153ad3c7c599238892 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 08:49:58 +0200 Subject: [PATCH 11/17] Adds column for polymorphic type --- src/onegov/parliament/models/commission.py | 2 +- .../parliament/models/legislative_period.py | 13 +++++++++- .../parliament/models/parliamentarian.py | 8 +----- .../parliament/models/parliamentarian_role.py | 4 +-- .../parliament/models/parliamentary_group.py | 13 +++++++++- src/onegov/parliament/models/party.py | 14 ++++++++++- src/onegov/parliament/upgrade.py | 25 +++++++++++++++++++ src/onegov/pas/models/attendence.py | 1 + src/onegov/pas/models/commission.py | 2 ++ src/onegov/pas/models/legislative_period.py | 1 + src/onegov/pas/models/parliamentary_group.py | 1 + src/onegov/pas/models/party.py | 2 ++ tests/onegov/pas/test_cli.py | 10 ++++---- 13 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/onegov/parliament/models/commission.py b/src/onegov/parliament/models/commission.py index 656197469f..fd2de5598a 100644 --- a/src/onegov/parliament/models/commission.py +++ b/src/onegov/parliament/models/commission.py @@ -55,7 +55,7 @@ class Commission(Base, ContentMixin, TimestampMixin, ORMSearchable): 'polymorphic_identity': 'generic', } - es_public = False + es_public = True es_properties = {'name': {'type': 'text'}} @property diff --git a/src/onegov/parliament/models/legislative_period.py b/src/onegov/parliament/models/legislative_period.py index 19821c3301..e6216c7867 100644 --- a/src/onegov/parliament/models/legislative_period.py +++ b/src/onegov/parliament/models/legislative_period.py @@ -19,7 +19,18 @@ class LegislativePeriod(Base, TimestampMixin, ORMSearchable): __tablename__ = 'par_legislative_periods' - es_public = False + legislative_period_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': legislative_period_type, + 'polymorphic_identity': 'generic', + } + + es_public = True es_properties = {'name': {'type': 'text'}} @property diff --git a/src/onegov/parliament/models/parliamentarian.py b/src/onegov/parliament/models/parliamentarian.py index 43f178884d..071d315ab1 100644 --- a/src/onegov/parliament/models/parliamentarian.py +++ b/src/onegov/parliament/models/parliamentarian.py @@ -63,7 +63,7 @@ class Parliamentarian(Base, ContentMixin, TimestampMixin, AssociatedFiles, - ORMSearchable): + ORMSearchable): __tablename__ = 'par_parliamentarians' @@ -95,12 +95,6 @@ def es_suggestion(self) -> tuple[str, ...]: def title(self) -> str: return f'{self.first_name} {self.last_name}' - type: Column[str] = Column( - Text, - nullable=False, - default=lambda: 'generic' - ) - #: Internal ID id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] diff --git a/src/onegov/parliament/models/parliamentarian_role.py b/src/onegov/parliament/models/parliamentarian_role.py index bf693505c6..688a18de1b 100644 --- a/src/onegov/parliament/models/parliamentarian_role.py +++ b/src/onegov/parliament/models/parliamentarian_role.py @@ -77,14 +77,14 @@ class ParliamentarianRole(Base, TimestampMixin): __tablename__ = 'par_parliamentarian_roles' - parliamentarian_type: Column[str] = Column( + role_type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': parliamentarian_type, + 'polymorphic_on': role_type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/parliamentary_group.py b/src/onegov/parliament/models/parliamentary_group.py index 7a0e90fc01..6e2e1c5474 100644 --- a/src/onegov/parliament/models/parliamentary_group.py +++ b/src/onegov/parliament/models/parliamentary_group.py @@ -26,7 +26,18 @@ class ParliamentaryGroup(Base, ContentMixin, TimestampMixin, ORMSearchable): __tablename__ = 'par_parliamentary_groups' - es_public = False + group_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': group_type, + 'polymorphic_identity': 'generic', + } + + es_public = True es_properties = {'name': {'type': 'text'}} @property diff --git a/src/onegov/parliament/models/party.py b/src/onegov/parliament/models/party.py index ea5811a668..364ba2eb51 100644 --- a/src/onegov/parliament/models/party.py +++ b/src/onegov/parliament/models/party.py @@ -25,7 +25,19 @@ class Party(Base, ContentMixin, TimestampMixin, ORMSearchable): __tablename__ = 'par_parties' - es_public = False + #: The type of the party + party_type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': party_type, + 'polymorphic_identity': 'generic', + } + + es_public = True es_properties = {'name': {'type': 'text'}} @property diff --git a/src/onegov/parliament/upgrade.py b/src/onegov/parliament/upgrade.py index c042e0c8b6..49341af303 100644 --- a/src/onegov/parliament/upgrade.py +++ b/src/onegov/parliament/upgrade.py @@ -5,6 +5,9 @@ from __future__ import annotations +from sqlalchemy import Column +from sqlalchemy import Text + from onegov.core.upgrade import upgrade_task, UpgradeContext @@ -33,3 +36,25 @@ def introduce_parliament_module_rename_pas_tables( context.operations.rename_table( current_name, target_name) + + +@upgrade_task('Add type column to parliament models 3') +def add_type_column_to_parliament_models( + context: UpgradeContext +) -> None: + for table, type_name in ( + ('par_attendence', 'party_type'), + ('par_changes', 'change_type'), + ('par_commission_memberships', 'membership_type'), + ('par_commissions', 'commission_type'), + ('par_legislative_periods', 'legislative_period_type'), + ('par_parliamentarian_roles', 'role_type'), + ('par_parliamentarians', 'parliamentarian_type'), + ('par_parliamentary_groups', 'group_type'), + ('par_parties', 'party_type'), + ): + if not context.has_column(table, type_name): + context.operations.add_column( + table, + Column(type_name, Text, nullable=False, default='generic') + ) diff --git a/src/onegov/pas/models/attendence.py b/src/onegov/pas/models/attendence.py index d11576d4d0..e2c930439f 100644 --- a/src/onegov/pas/models/attendence.py +++ b/src/onegov/pas/models/attendence.py @@ -10,3 +10,4 @@ class PASAttendence(Attendence): } es_type_name = 'pas_attendence' + es_public = False diff --git a/src/onegov/pas/models/commission.py b/src/onegov/pas/models/commission.py index 6f59925aa3..3e4f1ac525 100644 --- a/src/onegov/pas/models/commission.py +++ b/src/onegov/pas/models/commission.py @@ -10,3 +10,5 @@ class PASCommission(Commission): } es_type_name = 'pas_commission' + es_public = False + diff --git a/src/onegov/pas/models/legislative_period.py b/src/onegov/pas/models/legislative_period.py index 0fc5f22687..d874979afb 100644 --- a/src/onegov/pas/models/legislative_period.py +++ b/src/onegov/pas/models/legislative_period.py @@ -10,3 +10,4 @@ class PASLegislativePeriod(LegislativePeriod): } es_type_name = 'pas_legislative_period' + es_public = False diff --git a/src/onegov/pas/models/parliamentary_group.py b/src/onegov/pas/models/parliamentary_group.py index 1f83abc5fd..1905afcdcb 100644 --- a/src/onegov/pas/models/parliamentary_group.py +++ b/src/onegov/pas/models/parliamentary_group.py @@ -10,3 +10,4 @@ class PASParliamentaryGroup(ParliamentaryGroup): } es_type_name = 'pas_parliamentary_group' + es_public = False diff --git a/src/onegov/pas/models/party.py b/src/onegov/pas/models/party.py index 97f1d9e0c4..1501f94b0c 100644 --- a/src/onegov/pas/models/party.py +++ b/src/onegov/pas/models/party.py @@ -4,8 +4,10 @@ class PASParty(Party): + __mapper_args__ = { 'polymorphic_identity': 'pas_party', } es_type_name = 'pas_party' + es_public = False diff --git a/tests/onegov/pas/test_cli.py b/tests/onegov/pas/test_cli.py index c4cd537c9f..2ba94b88fe 100644 --- a/tests/onegov/pas/test_cli.py +++ b/tests/onegov/pas/test_cli.py @@ -8,11 +8,11 @@ from onegov.org.cli import cli as org_cli from onegov.pas.cli import cli from onegov.pas.models import ( - Commission, - CommissionMembership, - Parliamentarian, - ParliamentaryGroup, - Party + PASCommission, + PASCommissionMembership, + PASParliamentarian, + PASParliamentaryGroup, + PASParty ) From 2416b196a81651474121bac640eff6c94a49a5b4 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 08:51:08 +0200 Subject: [PATCH 12/17] Adjust collections --- .../pas/collections/parliamentary_group.py | 18 +++++++++--------- src/onegov/pas/collections/party.py | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/onegov/pas/collections/parliamentary_group.py b/src/onegov/pas/collections/parliamentary_group.py index c340211bfe..3e08a3f703 100644 --- a/src/onegov/pas/collections/parliamentary_group.py +++ b/src/onegov/pas/collections/parliamentary_group.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.parliament.models import ParliamentaryGroup +from onegov.pas.models import PASParliamentaryGroup from sqlalchemy import or_ from typing import TYPE_CHECKING @@ -12,7 +12,7 @@ from typing import Self -class ParliamentaryGroupCollection(GenericCollection[ParliamentaryGroup]): +class ParliamentaryGroupCollection(GenericCollection[PASParliamentaryGroup]): def __init__( self, @@ -23,24 +23,24 @@ def __init__( self.active = active @property - def model_class(self) -> type[ParliamentaryGroup]: - return ParliamentaryGroup + def model_class(self) -> type[PASParliamentaryGroup]: + return PASParliamentaryGroup - def query(self) -> Query[ParliamentaryGroup]: + def query(self) -> Query[PASParliamentaryGroup]: query = super().query() if self.active is not None: if self.active: query = query.filter( or_( - ParliamentaryGroup.end.is_(None), - ParliamentaryGroup.end >= date.today() + PASParliamentaryGroup.end.is_(None), + PASParliamentaryGroup.end >= date.today() ) ) else: - query = query.filter(ParliamentaryGroup.end < date.today()) + query = query.filter(PASParliamentaryGroup.end < date.today()) - return query.order_by(ParliamentaryGroup.name) + return query.order_by(PASParliamentaryGroup.name) def for_filter( self, diff --git a/src/onegov/pas/collections/party.py b/src/onegov/pas/collections/party.py index 7f0e7df088..911b81a827 100644 --- a/src/onegov/pas/collections/party.py +++ b/src/onegov/pas/collections/party.py @@ -2,7 +2,7 @@ from datetime import date from onegov.core.collection import GenericCollection -from onegov.parliament.models import Party +from onegov.pas.models import PASParty from sqlalchemy import or_ from typing import TYPE_CHECKING @@ -12,7 +12,7 @@ from typing import Self -class PartyCollection(GenericCollection[Party]): +class PartyCollection(GenericCollection[PASParty]): def __init__( self, @@ -23,24 +23,24 @@ def __init__( self.active = active @property - def model_class(self) -> type[Party]: - return Party + def model_class(self) -> type[PASParty]: + return PASParty - def query(self) -> Query[Party]: + def query(self) -> Query[PASParty]: query = super().query() if self.active is not None: if self.active: query = query.filter( or_( - Party.end.is_(None), - Party.end >= date.today() + PASParty.end.is_(None), + PASParty.end >= date.today() ) ) else: - query = query.filter(Party.end < date.today()) + query = query.filter(PASParty.end < date.today()) - return query.order_by(Party.name) + return query.order_by(PASParty.name) def for_filter( self, From 2e02fd70ec7be327bb7eeb7a6d490012c159eebe Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 08:51:55 +0200 Subject: [PATCH 13/17] Adjust tests --- tests/onegov/pas/test_cli.py | 27 ++++------- tests/onegov/pas/test_export_pdf.py | 28 +++++------ tests/onegov/pas/test_import.py | 32 ++++++------- tests/onegov/pas/test_importers.py | 24 +++++----- tests/onegov/pas/test_models.py | 40 +++++++++------- tests/onegov/pas/test_report.py | 19 +++++--- tests/onegov/pas/test_utils.py | 74 ++++++++++++++--------------- tests/onegov/pas/test_views.py | 2 +- 8 files changed, 123 insertions(+), 123 deletions(-) diff --git a/tests/onegov/pas/test_cli.py b/tests/onegov/pas/test_cli.py index 2ba94b88fe..3d372db2ed 100644 --- a/tests/onegov/pas/test_cli.py +++ b/tests/onegov/pas/test_cli.py @@ -7,13 +7,6 @@ from onegov.org.cli import cli as org_cli from onegov.pas.cli import cli -from onegov.pas.models import ( - PASCommission, - PASCommissionMembership, - PASParliamentarian, - PASParliamentaryGroup, - PASParty -) def do_run_cli_import(cfg_path, file_type, commission_test_files): @@ -66,29 +59,29 @@ def test_import_commission_data( session_manager.set_current_schema('pas-zg') session = session_manager.session() # Check commission - commission = session.query(Commission).first() + commission = session.query(PASCommission).first() # Name should be inferred from the filename assert commission.name == 'commission test' assert commission.type == 'normal' # Check parties - parties = session.query(Party).all() + parties = session.query(PASParty).all() party_names = {p.name for p in parties} expected_parties = {'ALG', 'Die Mitte'} assert party_names == expected_parties # Check parliamentary groups - groups = session.query(ParliamentaryGroup).all() + groups = session.query(PASParliamentaryGroup).all() group_names = {g.name for g in groups} assert group_names == expected_parties # Check parliamentarians - parliamentarians = session.query(Parliamentarian).all() + parliamentarians = session.query(PASParliamentarian).all() assert len(parliamentarians) == 2 # Check specific parliamentarian vivianne = ( - session.query(Parliamentarian) + session.query(PASParliamentarian) .filter_by(personnel_number='5506') .one() ) @@ -97,8 +90,8 @@ def test_import_commission_data( assert vivianne.shipping_address == 'StrasseB' # Check memberships - vivianne_membership: CommissionMembership = ( - session.query(CommissionMembership) + vivianne_membership: PASCommissionMembership = ( + session.query(PASCommissionMembership) .filter_by(parliamentarian_id=vivianne.id) .one() ) @@ -110,9 +103,9 @@ def test_import_commission_data( # Check president role president = ( - session.query(CommissionMembership) - .join(Parliamentarian) - .filter(Parliamentarian.first_name == 'Lea') + session.query(PASCommissionMembership) + .join(PASParliamentarian) + .filter(PASParliamentarian.first_name == 'Lea') .one() ) assert president diff --git a/tests/onegov/pas/test_export_pdf.py b/tests/onegov/pas/test_export_pdf.py index e84801d4f1..9320657fbb 100644 --- a/tests/onegov/pas/test_export_pdf.py +++ b/tests/onegov/pas/test_export_pdf.py @@ -4,13 +4,13 @@ from onegov.pas.calculate_pay import calculate_rate from onegov.pas.collections import AttendenceCollection from onegov.pas.models import ( - Party, - Parliamentarian, - ParliamentarianRole, + PASParty, + PASParliamentarian, + PASParliamentarianRole, RateSet, - Commission, + PASCommission, SettlementRun, - Attendence, + PASAttendence, ) @@ -34,13 +34,13 @@ def test_parliamentarian_settlement_calculations(session): session.add(rate_set) # Create parliamentarian with president role - parliamentarian = Parliamentarian( + parliamentarian = PASParliamentarian( first_name='Jane', last_name='President', gender='female' ) - party = Party(name='Test Party') - role = ParliamentarianRole( + party = PASParty(name='Test Party') + role = PASParliamentarianRole( parliamentarian=parliamentarian, role='president', party=party, @@ -49,13 +49,13 @@ def test_parliamentarian_settlement_calculations(session): session.add_all([parliamentarian, role, party]) # Create commission - commission = Commission(name='Test Commission', type='normal') + commission = PASCommission(name='Test PASCommission', type='normal') session.add(commission) # Create various attendances to test different scenarios attendences = [ # Plenary session (always counts as half day) - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2024, 1, 15), duration=240, # 4 hours - should still count as half day @@ -63,14 +63,14 @@ def test_parliamentarian_settlement_calculations(session): ), # Commission meetings - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2024, 1, 20), duration=120, # 2 hours - initial rate only type='commission', commission=commission ), - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2024, 1, 21), duration=180, # 3 hours - initial + additional rate @@ -79,14 +79,14 @@ def test_parliamentarian_settlement_calculations(session): ), # Study sessions - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2024, 2, 1), duration=60, # 1 hour type='study', commission=commission ), - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2024, 2, 2), duration=90, # 1.5 hours diff --git a/tests/onegov/pas/test_import.py b/tests/onegov/pas/test_import.py index 460997063a..8ce622dfbd 100644 --- a/tests/onegov/pas/test_import.py +++ b/tests/onegov/pas/test_import.py @@ -9,11 +9,11 @@ from onegov.org.cli import cli as org_cli from onegov.pas.cli import cli from onegov.pas.models import ( - Commission, - CommissionMembership, - Parliamentarian, - ParliamentaryGroup, - Party + PASCommission, + PASCommissionMembership, + PASParliamentarian, + PASParliamentaryGroup, + PASParty ) @@ -73,30 +73,30 @@ def test_import_commission_data( session = session_manager.session() # Check commission - commission = session.query(Commission).first() - commission: Commission + commission = session.query(PASCommission).first() + commission: PASCommission # Name should be inferred from the filename assert commission.name == 'commission test' assert commission.type == 'normal' # Check parties - parties = session.query(Party).all() + parties = session.query(PASParty).all() party_names = {p.name for p in parties} expected_parties = {'ALG', 'Die Mitte'} assert party_names == expected_parties # Check parliamentary groups - groups = session.query(ParliamentaryGroup).all() + groups = session.query(PASParliamentaryGroup).all() group_names = {g.name for g in groups} assert group_names == expected_parties # Check parliamentarians - parliamentarians = session.query(Parliamentarian).all() + parliamentarians = session.query(PASParliamentarian).all() assert len(parliamentarians) == 2 # Check specific parliamentarian vivianne = ( - session.query(Parliamentarian) + session.query(PASParliamentarian) .filter_by(personnel_number='5506') .one() ) @@ -105,8 +105,8 @@ def test_import_commission_data( assert vivianne.shipping_address == 'StrasseB' # Check memberships - vivianne_memmbersh: CommissionMembership = ( - session.query(CommissionMembership) + vivianne_memmbersh: PASCommissionMembership = ( + session.query(PASCommissionMembership) .filter_by(parliamentarian_id=vivianne.id) .one() ) @@ -118,9 +118,9 @@ def test_import_commission_data( # Check president role president = ( - session.query(CommissionMembership) - .join(Parliamentarian) - .filter(Parliamentarian.first_name == 'Lea') + session.query(PASCommissionMembership) + .join(PASParliamentarian) + .filter(PASParliamentarian.first_name == 'Lea') .one() ) assert president diff --git a/tests/onegov/pas/test_importers.py b/tests/onegov/pas/test_importers.py index 92c2bd183e..903281f8fc 100644 --- a/tests/onegov/pas/test_importers.py +++ b/tests/onegov/pas/test_importers.py @@ -3,9 +3,9 @@ import pytest from onegov.pas.models import ( - Parliamentarian, - Party, - Commission, + PASParliamentarian, + PASParty, + PASCommission, ) from onegov.pas.importer.json_import import ( PeopleImporter, @@ -61,7 +61,7 @@ def test_people_importer_existing_parliamentarian(session, people_json): from uuid import UUID # Pre-populate the database with one parliamentarian from the fixture existing_person_data = people_json['results'][0] - existing_parliamentarian = Parliamentarian( + existing_parliamentarian = PASParliamentarian( external_kub_id=UUID(existing_person_data['id']), # Convert to UUID first_name='OldFirstName', # Use a different first name initially last_name=existing_person_data['officialName'], @@ -81,7 +81,7 @@ def test_people_importer_existing_parliamentarian(session, people_json): assert len(parliamentarian_map) == len(people_json['results']) # Check the updated parliamentarian - updated_parliamentarian = session.query(Parliamentarian).filter_by( + updated_parliamentarian = session.query(PASParliamentarian).filter_by( external_kub_id=UUID(existing_person_data['id']) # Use UUID for query ).one_or_none() @@ -101,7 +101,7 @@ def test_people_importer_existing_parliamentarian(session, people_json): existing_person_data['salutation'] # Ensure no duplicate parliamentarian was created - count = session.query(Parliamentarian).filter_by( + count = session.query(PASParliamentarian).filter_by( external_kub_id=UUID(existing_person_data['id']) # Use UUID for query ).count() assert count == 1 @@ -128,13 +128,13 @@ def test_organization_importer_existing(session, if o['organizationTypeTitle'] == 'Fraktion' ) # Assuming 'Fraktion' maps to Party - existing_commission = Commission( + existing_commission = PASCommission( external_kub_id=UUID(commission_data['id']), # Convert to UUID name='Old Commission Name', type='normal', ) # Fraktion maps to Party - existing_party = Party( + existing_party = PASParty( external_kub_id=UUID(fraktion_data['id']), # Convert to UUID name='Old Party Name', ) @@ -158,7 +158,7 @@ def test_organization_importer_existing(session, # 1. Check Commission Update updated_commission = ( - session.query(Commission) + session.query(PASCommission) .filter_by(external_kub_id=UUID(commission_data['id'])) # Use UUID .one_or_none() ) @@ -171,7 +171,7 @@ def test_organization_importer_existing(session, # Check Commission Count (ensure no duplicates) commission_count = ( - session.query(Commission) + session.query(PASCommission) .filter_by(external_kub_id=UUID(commission_data['id'])) # Use UUID .count() ) @@ -179,7 +179,7 @@ def test_organization_importer_existing(session, # 2. Check Party Update (from Fraktion) updated_party = ( - session.query(Party) + session.query(PASParty) .filter_by(external_kub_id=UUID(fraktion_data['id'])) # Use UUID .one_or_none() ) @@ -190,7 +190,7 @@ def test_organization_importer_existing(session, # Check Party Count (ensure no duplicates) party_count = ( - session.query(Party) + session.query(PASParty) .filter_by(external_kub_id=UUID(fraktion_data['id'])) # Use UUID .count() ) diff --git a/tests/onegov/pas/test_models.py b/tests/onegov/pas/test_models.py index 6bfb49a651..06a79292de 100644 --- a/tests/onegov/pas/test_models.py +++ b/tests/onegov/pas/test_models.py @@ -1,15 +1,19 @@ from freezegun import freeze_time from datetime import date from onegov.core.utils import Bunch -from onegov.pas.models import Attendence -from onegov.pas.models import Change -from onegov.pas.models import Commission -from onegov.pas.models import CommissionMembership -from onegov.pas.models import LegislativePeriod -from onegov.pas.models import Parliamentarian -from onegov.pas.models import ParliamentarianRole -from onegov.pas.models import ParliamentaryGroup -from onegov.pas.models import Party +from onegov.pas.models import ( + PASAttendence, + PASChange, + PASCommission, + PASCommissionMembership, + PASParliamentarian, + PASParliamentarianRole, + PASParliamentaryGroup, + PASParty, + PASLegislativePeriod, + RateSet, + SettlementRun +) from onegov.pas.models import RateSet from onegov.pas.models import SettlementRun @@ -17,7 +21,7 @@ @freeze_time('2022-06-06') def test_models(session): rate_set = RateSet(year=2022) - legislative_period = LegislativePeriod( + legislative_period = PASLegislativePeriod( name='2022-2024', start=date(2022, 1, 1), end=date(2022, 12, 31) @@ -28,13 +32,13 @@ def test_models(session): end=date(2022, 3, 31), active=True ) - parliamentary_group = ParliamentaryGroup(name='Group') - party = Party(name='Party') - commission = Commission( + parliamentary_group = PASParliamentaryGroup(name='Group') + party = PASParty(name='Party') + commission = PASCommission( name='Official Commission', type='official' ) - parliamentarian = Parliamentarian( + parliamentarian = PASParliamentarian( first_name='First', last_name='Last', gender='female', @@ -49,7 +53,7 @@ def test_models(session): session.add(parliamentarian) session.flush() - parliamentarian_role = ParliamentarianRole( + parliamentarian_role = PASParliamentarianRole( parliamentarian_id=parliamentarian.id, role='vice_president', party_id=party.id, @@ -57,12 +61,12 @@ def test_models(session): parliamentary_group_id=parliamentary_group.id, parliamentary_group_role='vote_counter' ) - commission_membership = CommissionMembership( + commission_membership = PASCommissionMembership( role='president', commission_id=commission.id, parliamentarian_id=parliamentarian.id ) - attendence = Attendence( + attendence = PASAttendence( date=date(2022, 1, 1), duration=30, type='commission', @@ -74,7 +78,7 @@ def test_models(session): session.add(attendence) session.flush() - change = Change.add( + change = PASChange.add( request=Bunch( current_username='user@example.org', current_user=Bunch(title='User'), diff --git a/tests/onegov/pas/test_report.py b/tests/onegov/pas/test_report.py index 52d151ec39..69b283b0a8 100644 --- a/tests/onegov/pas/test_report.py +++ b/tests/onegov/pas/test_report.py @@ -1,11 +1,16 @@ -from onegov.pas.models import Attendence, Commission, RateSet, SettlementRun,\ - Parliamentarian +from onegov.pas.models import ( + PASAttendence, + PASCommission, + PASParliamentarian, + RateSet, + SettlementRun +) from datetime import date def test_generate_parliamentarian_export(session): # Create parliamentarian - parliamentarian = Parliamentarian( + parliamentarian = PASParliamentarian( first_name='John', last_name='Doe', gender='male' ) session.add(parliamentarian) @@ -30,21 +35,21 @@ def test_generate_parliamentarian_export(session): session.add(rate_set) # Create test commission - commission = Commission(name='Test Commission', type='normal') + commission = PASCommission(name='Test PASCommission', type='normal') session.add(commission) session.flush() # Create some test attendances attendances = [ # 2 hour plenary session - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2023, 10, 15), duration=120, # minutes type='plenary', ), # 1.5 hour commission meeting - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2023, 11, 15), duration=90, # minutes @@ -52,7 +57,7 @@ def test_generate_parliamentarian_export(session): commission=commission, ), # 1 hour study time - Attendence( + PASAttendence( parliamentarian=parliamentarian, date=date(2023, 12, 15), duration=60, # minutes diff --git a/tests/onegov/pas/test_utils.py b/tests/onegov/pas/test_utils.py index 277058397a..056daac164 100644 --- a/tests/onegov/pas/test_utils.py +++ b/tests/onegov/pas/test_utils.py @@ -1,13 +1,11 @@ from datetime import date from onegov.pas.models import ( - Parliamentarian, - ParliamentarianRole, - Attendence, + PASAttendence, + PASParliamentarian, + PASParliamentarianRole, + PASParty, ) -from onegov.pas.models import ( - Party, -) from onegov.pas.utils import get_parties_with_settlements from onegov.pas.utils import get_parliamentarians_with_settlements from uuid import uuid4 @@ -19,21 +17,21 @@ def test_get_parliamentarians_with_settlements(session): end_date = date(2024, 12, 31) # Create parliamentarians - parl1 = Parliamentarian( + parl1 = PASParliamentarian( id=uuid4(), first_name='John', last_name='Smith', gender='male', ) - parl2 = Parliamentarian( + parl2 = PASParliamentarian( id=uuid4(), first_name='Jane', last_name='Doe', gender='female', ) - parl3 = Parliamentarian( + parl3 = PASParliamentarian( id=uuid4(), first_name='Bob', last_name='Johnson', @@ -44,7 +42,7 @@ def test_get_parliamentarians_with_settlements(session): session.flush() # Create roles for each parliamentarian - role1 = ParliamentarianRole( + role1 = PASParliamentarianRole( parliamentarian_id=parl1.id, start=date(2023, 1, 1), end=date(2025, 12, 31), @@ -53,7 +51,7 @@ def test_get_parliamentarians_with_settlements(session): parliamentary_group_role='member', ) - role2 = ParliamentarianRole( + role2 = PASParliamentarianRole( parliamentarian_id=parl2.id, start=date(2023, 1, 1), end=date(2025, 12, 31), @@ -62,8 +60,8 @@ def test_get_parliamentarians_with_settlements(session): parliamentary_group_role='member', ) - # Parl3 has no active role during this period - role3 = ParliamentarianRole( + # PASParl3 has no active role during this period + role3 = PASParliamentarianRole( parliamentarian_id=parl3.id, start=date(2020, 1, 1), end=date(2023, 12, 31), @@ -76,7 +74,7 @@ def test_get_parliamentarians_with_settlements(session): session.flush() # Create attendances - attendance1 = Attendence( + attendance1 = PASAttendence( id=uuid4(), parliamentarian_id=parl1.id, date=date(2024, 6, 1), @@ -88,7 +86,7 @@ def test_get_parliamentarians_with_settlements(session): # Parl3 has attendance but the role does not fall within the date range # of the attendance - attendance3 = Attendence( + attendance3 = PASAttendence( id=uuid4(), parliamentarian_id=parl3.id, date=date(2024, 6, 1), @@ -109,7 +107,7 @@ def test_get_parliamentarians_with_settlements(session): assert result[0].id == parl1.id # Add attendance for parl2 and test again - attendance2 = Attendence( + attendance2 = PASAttendence( id=uuid4(), parliamentarian_id=parl2.id, date=date(2024, 6, 1), @@ -142,21 +140,21 @@ def test_get_parties_with_settlements(session): end_date = date(2024, 12, 31) # Create parties - party_a = Party( + party_a = PASParty( id=uuid4(), - name='Party A', + name='PASParty A', start=date(2020, 1, 1), end=date(2026, 12, 31), ) - party_b = Party( + party_b = PASParty( id=uuid4(), - name='Party B', + name='PASParty B', start=date(2020, 1, 1), end=date(2026, 12, 31), ) - party_c = Party( + party_c = PASParty( id=uuid4(), - name='Party C', + name='PASParty C', start=date(2020, 1, 1), end=date(2026, 12, 31), ) @@ -165,7 +163,7 @@ def test_get_parties_with_settlements(session): session.flush() # Create parliamentarians - parl1 = Parliamentarian( + parl1 = PASParliamentarian( id=uuid4(), first_name='John', last_name='Smith', @@ -173,7 +171,7 @@ def test_get_parties_with_settlements(session): shipping_method='a', ) - parl2 = Parliamentarian( + parl2 = PASParliamentarian( id=uuid4(), first_name='Jane', last_name='Doe', @@ -181,7 +179,7 @@ def test_get_parties_with_settlements(session): shipping_method='a', ) - parl3 = Parliamentarian( + parl3 = PASParliamentarian( id=uuid4(), first_name='Bob', last_name='Johnson', @@ -193,8 +191,8 @@ def test_get_parties_with_settlements(session): session.flush() # Create roles - # Parl1 in Party A during the entire period - role1 = ParliamentarianRole( + # PASParl1 in Party A during the entire period + role1 = PASParliamentarianRole( parliamentarian_id=parl1.id, party_id=party_a.id, start=date(2023, 1, 1), @@ -204,8 +202,8 @@ def test_get_parties_with_settlements(session): parliamentary_group_role='member', ) - # Parl2 switches from Party B to Party C in the middle of the period - role2a = ParliamentarianRole( + # PASParl2 switches from Party B to Party C in the middle of the period + role2a = PASParliamentarianRole( parliamentarian_id=parl2.id, party_id=party_b.id, start=date(2023, 1, 1), @@ -215,7 +213,7 @@ def test_get_parties_with_settlements(session): parliamentary_group_role='member', ) - role2b = ParliamentarianRole( + role2b = PASParliamentarianRole( parliamentarian_id=parl2.id, party_id=party_c.id, start=date(2024, 7, 1), # Second half of 2024 @@ -225,8 +223,8 @@ def test_get_parties_with_settlements(session): parliamentary_group_role='member', ) - # Parl3 was in Party C but left before the period - role3 = ParliamentarianRole( + # PASParl3 was in Party C but left before the period + role3 = PASParliamentarianRole( parliamentarian_id=parl3.id, party_id=party_c.id, start=date(2020, 1, 1), @@ -240,9 +238,9 @@ def test_get_parties_with_settlements(session): session.flush() # Create attendances - # Parl1 has attendance during their party membership - one in first half, + # PASParl1 has attendance during their party membership - one in first half, # one in second half - attendance1a = Attendence( + attendance1a = PASAttendence( id=uuid4(), parliamentarian_id=parl1.id, date=date(2024, 3, 15), # During party A membership @@ -251,7 +249,7 @@ def test_get_parties_with_settlements(session): type='plenary', ) - attendance1b = Attendence( + attendance1b = PASAttendence( id=uuid4(), parliamentarian_id=parl1.id, date=date(2024, 9, 15), @@ -261,7 +259,7 @@ def test_get_parties_with_settlements(session): ) # Parl2 has attendances during both party memberships - attendance2a = Attendence( + attendance2a = PASAttendence( id=uuid4(), parliamentarian_id=parl2.id, date=date(2024, 3, 15), # During party B membership @@ -269,7 +267,7 @@ def test_get_parties_with_settlements(session): type='plenary', ) - attendance2b = Attendence( + attendance2b = PASAttendence( id=uuid4(), parliamentarian_id=parl2.id, date=date(2024, 9, 15), # During party C membership @@ -278,7 +276,7 @@ def test_get_parties_with_settlements(session): ) # Parl3 has attendance but was no longer in Party C - attendance3 = Attendence( + attendance3 = PASAttendence( id=uuid4(), parliamentarian_id=parl3.id, date=date(2024, 3, 15), diff --git a/tests/onegov/pas/test_views.py b/tests/onegov/pas/test_views.py index 62af23ae7f..a755d71c20 100644 --- a/tests/onegov/pas/test_views.py +++ b/tests/onegov/pas/test_views.py @@ -84,7 +84,7 @@ def test_views_manage(client_with_es): delete.append(page) - # Parties + # parties page = settings.click('Parteien') page = page.click(href='new') page.form['name'] = 'BB' From 36ec823e6ca847b98daec1f90f202f46e2adaaee Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 10:58:58 +0200 Subject: [PATCH 14/17] Rework upgrade step and polymorphic type --- src/onegov/parliament/models/attendence.py | 4 +- src/onegov/parliament/models/change.py | 12 ++++++ src/onegov/parliament/models/commission.py | 4 +- .../models/commission_membership.py | 4 +- .../parliament/models/legislative_period.py | 4 +- src/onegov/parliament/models/meeting.py | 11 +++++ .../parliament/models/parliamentarian.py | 4 +- .../parliament/models/parliamentarian_role.py | 4 +- .../parliament/models/parliamentary_group.py | 4 +- src/onegov/parliament/models/party.py | 4 +- .../parliament/models/political_business.py | 30 +++++++++++++- src/onegov/parliament/upgrade.py | 41 +++++++++++++------ 12 files changed, 95 insertions(+), 31 deletions(-) diff --git a/src/onegov/parliament/models/attendence.py b/src/onegov/parliament/models/attendence.py index 9beefb2608..ecd1d335dc 100644 --- a/src/onegov/parliament/models/attendence.py +++ b/src/onegov/parliament/models/attendence.py @@ -45,14 +45,14 @@ class Attendence(Base, TimestampMixin): __tablename__ = 'par_attendence' - attendence_type: Column[str] = Column( + poly_type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': attendence_type, + 'polymorphic_on': poly_type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/change.py b/src/onegov/parliament/models/change.py index 64f8e0cb2e..327e8e2e22 100644 --- a/src/onegov/parliament/models/change.py +++ b/src/onegov/parliament/models/change.py @@ -9,6 +9,7 @@ from sqlalchemy import Column from sqlalchemy import Enum from sqlalchemy import String +from sqlalchemy import Text from sqlalchemy.orm import object_session from uuid import uuid4 @@ -44,6 +45,17 @@ class Change(Base, ContentMixin, TimestampMixin): __tablename__ = 'par_changes' + type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': type, + 'polymorphic_identity': 'generic', + } + #: Internal ID id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] diff --git a/src/onegov/parliament/models/commission.py b/src/onegov/parliament/models/commission.py index fd2de5598a..61cc9eb60b 100644 --- a/src/onegov/parliament/models/commission.py +++ b/src/onegov/parliament/models/commission.py @@ -44,14 +44,14 @@ class Commission(Base, ContentMixin, TimestampMixin, ORMSearchable): __tablename__ = 'par_commissions' - commission_type: Column[str] = Column( + poly_type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': commission_type, + 'polymorphic_on': poly_type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/commission_membership.py b/src/onegov/parliament/models/commission_membership.py index 56a6286941..31f4259ca7 100644 --- a/src/onegov/parliament/models/commission_membership.py +++ b/src/onegov/parliament/models/commission_membership.py @@ -42,14 +42,14 @@ class CommissionMembership(Base, TimestampMixin): __tablename__ = 'par_commission_memberships' - membership_type: Column[str] = Column( + type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': membership_type, + 'polymorphic_on': type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/legislative_period.py b/src/onegov/parliament/models/legislative_period.py index e6216c7867..8d405ef2d6 100644 --- a/src/onegov/parliament/models/legislative_period.py +++ b/src/onegov/parliament/models/legislative_period.py @@ -19,14 +19,14 @@ class LegislativePeriod(Base, TimestampMixin, ORMSearchable): __tablename__ = 'par_legislative_periods' - legislative_period_type: Column[str] = Column( + type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': legislative_period_type, + 'polymorphic_on': type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/meeting.py b/src/onegov/parliament/models/meeting.py index df52153598..1073dc1370 100644 --- a/src/onegov/parliament/models/meeting.py +++ b/src/onegov/parliament/models/meeting.py @@ -27,6 +27,17 @@ class Meeting(Base, ContentMixin, ORMSearchable): __tablename__ = 'par_meetings' + type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': type, + 'polymorphic_identity': 'generic', + } + es_public = True es_properties = {'title_text': {'type': 'text'}} diff --git a/src/onegov/parliament/models/parliamentarian.py b/src/onegov/parliament/models/parliamentarian.py index 071d315ab1..d67cbd744b 100644 --- a/src/onegov/parliament/models/parliamentarian.py +++ b/src/onegov/parliament/models/parliamentarian.py @@ -67,14 +67,14 @@ class Parliamentarian(Base, ContentMixin, TimestampMixin, AssociatedFiles, __tablename__ = 'par_parliamentarians' - parliamentarian_type: Column[str] = Column( + type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': parliamentarian_type, + 'polymorphic_on': type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/parliamentarian_role.py b/src/onegov/parliament/models/parliamentarian_role.py index 688a18de1b..eb6c94bbeb 100644 --- a/src/onegov/parliament/models/parliamentarian_role.py +++ b/src/onegov/parliament/models/parliamentarian_role.py @@ -77,14 +77,14 @@ class ParliamentarianRole(Base, TimestampMixin): __tablename__ = 'par_parliamentarian_roles' - role_type: Column[str] = Column( + type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': role_type, + 'polymorphic_on': type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/parliamentary_group.py b/src/onegov/parliament/models/parliamentary_group.py index 6e2e1c5474..1a65a4f4f3 100644 --- a/src/onegov/parliament/models/parliamentary_group.py +++ b/src/onegov/parliament/models/parliamentary_group.py @@ -26,14 +26,14 @@ class ParliamentaryGroup(Base, ContentMixin, TimestampMixin, ORMSearchable): __tablename__ = 'par_parliamentary_groups' - group_type: Column[str] = Column( + type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': group_type, + 'polymorphic_on': type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/party.py b/src/onegov/parliament/models/party.py index 364ba2eb51..44dc2be7c9 100644 --- a/src/onegov/parliament/models/party.py +++ b/src/onegov/parliament/models/party.py @@ -26,14 +26,14 @@ class Party(Base, ContentMixin, TimestampMixin, ORMSearchable): __tablename__ = 'par_parties' #: The type of the party - party_type: Column[str] = Column( + type: Column[str] = Column( Text, nullable=False, default=lambda: 'generic' ) __mapper_args__ = { - 'polymorphic_on': party_type, + 'polymorphic_on': type, 'polymorphic_identity': 'generic', } diff --git a/src/onegov/parliament/models/political_business.py b/src/onegov/parliament/models/political_business.py index c1ee3a293e..59acc30b6b 100644 --- a/src/onegov/parliament/models/political_business.py +++ b/src/onegov/parliament/models/political_business.py @@ -79,12 +79,27 @@ } -class PoliticalBusiness(Base, MultiAssociatedFiles, ContentMixin, - ORMSearchable): +class PoliticalBusiness( + Base, + MultiAssociatedFiles, + ContentMixin, + ORMSearchable +): # Politisches Geschäft __tablename__ = 'par_political_businesses' + type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': type, + 'polymorphic_identity': 'generic', + } + es_public = True es_properties = { 'title': {'type': 'text'}, @@ -161,6 +176,17 @@ class PoliticalBusinessParticipation(Base, ContentMixin): __tablename__ = 'par_political_business_participants' + type: Column[str] = Column( + Text, + nullable=False, + default=lambda: 'generic' + ) + + __mapper_args__ = { + 'polymorphic_on': type, + 'polymorphic_identity': 'generic', + } + #: Internal ID id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] diff --git a/src/onegov/parliament/upgrade.py b/src/onegov/parliament/upgrade.py index 49341af303..c8b993922b 100644 --- a/src/onegov/parliament/upgrade.py +++ b/src/onegov/parliament/upgrade.py @@ -38,23 +38,38 @@ def introduce_parliament_module_rename_pas_tables( current_name, target_name) -@upgrade_task('Add type column to parliament models 3') +@upgrade_task('Add type column to parliament models', + requires='onegov.parliament:Introduce parliament module: ' + 'rename pas tables') def add_type_column_to_parliament_models( - context: UpgradeContext + context: UpgradeContext ) -> None: - for table, type_name in ( - ('par_attendence', 'party_type'), - ('par_changes', 'change_type'), - ('par_commission_memberships', 'membership_type'), - ('par_commissions', 'commission_type'), - ('par_legislative_periods', 'legislative_period_type'), - ('par_parliamentarian_roles', 'role_type'), - ('par_parliamentarians', 'parliamentarian_type'), - ('par_parliamentary_groups', 'group_type'), - ('par_parties', 'party_type'), + for table, type_name, poly_type in ( + ('par_attendence', 'poly_type', 'pas_attendence'), + ('par_changes', 'type', 'pas_change'), + ('par_commission_memberships', 'type', 'pas_commission_membership'), + ('par_commissions', 'poly_type', 'pas_commission'), + ('par_legislative_periods', 'type', 'pas_legislative_period'), + ('par_parliamentarian_roles', 'type', 'pas_parliamentarian_role'), + ('par_parliamentarians', 'type', 'pas_parliamentarian'), + ('par_parliamentary_groups', 'type', 'pas_parliamentary_group'), + ('par_parties', 'type', 'pas_party'), ): if not context.has_column(table, type_name): context.operations.add_column( table, - Column(type_name, Text, nullable=False, default='generic') + Column(type_name, Text, nullable=True) + ) + + context.operations.execute( + f"UPDATE {table} SET {type_name} = '{poly_type}'" + ) + + context.operations.execute( + f"ALTER TABLE {table} ALTER COLUMN {type_name} " + f"SET DEFAULT 'generic'" + ) + + context.operations.execute( + f'ALTER TABLE {table} ALTER COLUMN {type_name} SET NOT NULL' ) From a391296858aac18a77f89fbaa5cfe6f998092eac Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 11:22:29 +0200 Subject: [PATCH 15/17] Fix tests --- tests/onegov/pas/test_cli.py | 7 +++++++ tests/onegov/pas/test_models.py | 2 -- tests/onegov/pas/test_utils.py | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/onegov/pas/test_cli.py b/tests/onegov/pas/test_cli.py index 3d372db2ed..983cbabc32 100644 --- a/tests/onegov/pas/test_cli.py +++ b/tests/onegov/pas/test_cli.py @@ -7,6 +7,13 @@ from onegov.org.cli import cli as org_cli from onegov.pas.cli import cli +from onegov.pas.models import ( + PASCommission, + PASParty, + PASParliamentaryGroup, + PASParliamentarian, + PASCommissionMembership +) def do_run_cli_import(cfg_path, file_type, commission_test_files): diff --git a/tests/onegov/pas/test_models.py b/tests/onegov/pas/test_models.py index 06a79292de..f7edbfe846 100644 --- a/tests/onegov/pas/test_models.py +++ b/tests/onegov/pas/test_models.py @@ -14,8 +14,6 @@ RateSet, SettlementRun ) -from onegov.pas.models import RateSet -from onegov.pas.models import SettlementRun @freeze_time('2022-06-06') diff --git a/tests/onegov/pas/test_utils.py b/tests/onegov/pas/test_utils.py index 056daac164..43118bb821 100644 --- a/tests/onegov/pas/test_utils.py +++ b/tests/onegov/pas/test_utils.py @@ -238,8 +238,8 @@ def test_get_parties_with_settlements(session): session.flush() # Create attendances - # PASParl1 has attendance during their party membership - one in first half, - # one in second half + # PASParl1 has attendance during their party membership - one in first + # half, one in second half attendance1a = PASAttendence( id=uuid4(), parliamentarian_id=parl1.id, From e5818c8ff4cc62a2ef52196ff546180f4acc9976 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 11:28:17 +0200 Subject: [PATCH 16/17] Cleanup --- src/onegov/core/__init__.py | 1 + src/onegov/pas/models/commission.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onegov/core/__init__.py b/src/onegov/core/__init__.py index 285c42bd6f..e5f6229aca 100644 --- a/src/onegov/core/__init__.py +++ b/src/onegov/core/__init__.py @@ -38,6 +38,7 @@ 'onegov.newsletter', 'onegov.notice', 'onegov.page', + 'onegov.parliament', 'onegov.pay', 'onegov.pdf', 'onegov.people', diff --git a/src/onegov/pas/models/commission.py b/src/onegov/pas/models/commission.py index 3e4f1ac525..d839d0aad3 100644 --- a/src/onegov/pas/models/commission.py +++ b/src/onegov/pas/models/commission.py @@ -11,4 +11,3 @@ class PASCommission(Commission): es_type_name = 'pas_commission' es_public = False - From 9644460dd5df3a80fcb898a80fb421681a5a3a14 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 13 Jun 2025 12:07:04 +0200 Subject: [PATCH 17/17] Use models in corresponding views --- src/onegov/pas/views/parliamentarian_role.py | 14 +++++++------- src/onegov/pas/views/parliamentary_group.py | 14 +++++++------- src/onegov/pas/views/party.py | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/onegov/pas/views/parliamentarian_role.py b/src/onegov/pas/views/parliamentarian_role.py index 225f02b61d..9e590e4be0 100644 --- a/src/onegov/pas/views/parliamentarian_role.py +++ b/src/onegov/pas/views/parliamentarian_role.py @@ -7,7 +7,7 @@ from onegov.pas.collections import ParliamentarianRoleCollection from onegov.pas.forms import ParliamentarianRoleForm from onegov.pas.layouts import ParliamentarianRoleLayout -from onegov.parliament.models import ParliamentarianRole +from onegov.pas.models import PASParliamentarianRole from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -17,12 +17,12 @@ @PasApp.html( - model=ParliamentarianRole, + model=PASParliamentarianRole, template='parliamentarian_role.pt', permission=Private ) def view_parliamentarian_role( - self: ParliamentarianRole, + self: PASParliamentarianRole, request: TownRequest ) -> RenderData: @@ -36,14 +36,14 @@ def view_parliamentarian_role( @PasApp.form( - model=ParliamentarianRole, + model=PASParliamentarianRole, name='edit', template='form.pt', permission=Private, form=ParliamentarianRoleForm ) def edit_parliamentarian_role( - self: ParliamentarianRole, + self: PASParliamentarianRole, request: TownRequest, form: ParliamentarianRoleForm ) -> RenderData | Response: @@ -68,12 +68,12 @@ def edit_parliamentarian_role( @PasApp.view( - model=ParliamentarianRole, + model=PASParliamentarianRole, request_method='DELETE', permission=Private ) def delete_parliamentarian_role( - self: ParliamentarianRole, + self: PASParliamentarianRole, request: TownRequest ) -> None: diff --git a/src/onegov/pas/views/parliamentary_group.py b/src/onegov/pas/views/parliamentary_group.py index 9642e7444c..29ced6322e 100644 --- a/src/onegov/pas/views/parliamentary_group.py +++ b/src/onegov/pas/views/parliamentary_group.py @@ -8,7 +8,7 @@ from onegov.pas.forms import ParliamentaryGroupForm from onegov.pas.layouts import ParliamentaryGroupCollectionLayout from onegov.pas.layouts import ParliamentaryGroupLayout -from onegov.parliament.models import ParliamentaryGroup +from onegov.pas.models import PASParliamentaryGroup from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -82,12 +82,12 @@ def add_parliamentary_group( @PasApp.html( - model=ParliamentaryGroup, + model=PASParliamentaryGroup, template='parliamentary_group.pt', permission=Private ) def view_parliamentary_group( - self: ParliamentaryGroup, + self: PASParliamentaryGroup, request: TownRequest ) -> RenderData: @@ -101,14 +101,14 @@ def view_parliamentary_group( @PasApp.form( - model=ParliamentaryGroup, + model=PASParliamentaryGroup, name='edit', template='form.pt', permission=Private, form=ParliamentaryGroupForm ) def edit_parliamentary_group( - self: ParliamentaryGroup, + self: PASParliamentaryGroup, request: TownRequest, form: ParliamentaryGroupForm ) -> RenderData | Response: @@ -134,12 +134,12 @@ def edit_parliamentary_group( @PasApp.view( - model=ParliamentaryGroup, + model=PASParliamentaryGroup, request_method='DELETE', permission=Private ) def delete_parliamentary_group( - self: ParliamentaryGroup, + self: PASParliamentaryGroup, request: TownRequest ) -> None: diff --git a/src/onegov/pas/views/party.py b/src/onegov/pas/views/party.py index b7b009574e..f3af388e55 100644 --- a/src/onegov/pas/views/party.py +++ b/src/onegov/pas/views/party.py @@ -8,7 +8,7 @@ from onegov.pas.forms import PartyForm from onegov.pas.layouts import PartyCollectionLayout from onegov.pas.layouts import PartyLayout -from onegov.parliament.models import Party +from onegov.pas.models import PASParty from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -82,12 +82,12 @@ def add_party( @PasApp.html( - model=Party, + model=PASParty, template='party.pt', permission=Private ) def view_party( - self: Party, + self: PASParty, request: TownRequest ) -> RenderData: @@ -101,14 +101,14 @@ def view_party( @PasApp.form( - model=Party, + model=PASParty, name='edit', template='form.pt', permission=Private, form=PartyForm ) def edit_party( - self: Party, + self: PASParty, request: TownRequest, form: PartyForm ) -> RenderData | Response: @@ -134,12 +134,12 @@ def edit_party( @PasApp.view( - model=Party, + model=PASParty, request_method='DELETE', permission=Private ) def delete_party( - self: Party, + self: PASParty, request: TownRequest ) -> None: