from __future__ import annotations
from onegov.core.orm import Base
from onegov.core.orm.mixins import content_property
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.mixins import TimestampMixin
from onegov.core.orm.types import UUID
from onegov.search import ORMSearchable
from sqlalchemy import Boolean, Column, Date, Text
from sqlalchemy.ext.hybrid import hybrid_property
from uuid import uuid4
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import uuid
from datetime import date
from onegov.core.orm.mixins import dict_property
[docs]
class SettlementRun(Base, ContentMixin, TimestampMixin, ORMSearchable):
""" Abrechnungslauf """
[docs]
__tablename__ = 'pas_settlements'
[docs]
es_properties = {'name': {'type': 'text', 'weight': 'A'}}
@property
[docs]
def es_suggestion(self) -> str:
return self.name
@property
[docs]
def title(self) -> str:
return self.name
#: Internal ID
[docs]
id: Column[uuid.UUID] = Column(
UUID, # type:ignore[arg-type]
primary_key=True,
default=uuid4
)
#: the name
[docs]
name: Column[str] = Column(
Text,
nullable=False
)
#: The start date
[docs]
start: Column[date] = Column(
Date,
nullable=False
)
#: The end date
[docs]
end: Column[date] = Column(
Date,
nullable=False
)
#: Whether this settlement run is closed
[docs]
closed: Column[bool] = Column(
Boolean,
nullable=False,
default=False
)
#: The description
[docs]
description: dict_property[str | None] = content_property()
if TYPE_CHECKING:
else:
@hybrid_property
def active(self) -> bool:
return not self.closed
@active.setter
def active(self, value: bool) -> None:
self.closed = not value
@active.expression
def active(cls):
return ~cls.closed
@classmethod
[docs]
def get_run_number_for_year(cls, input_date: date) -> int:
"""
Computes the run number for a given date within a year.
As per customer requirement: No rule mandates 4 payments yearly,
but wages must be reported by the 10th.
Run breakdown:
- Q1: January to March
- Q2: April to June
- Q3: July to September
- Q4: October to November
- Q5: December
Why 5 runs?
The decision to split the fourth quarter ensures that settlement
runs are confined to a single calendar year. This avoids situations
where a settlement overlaps into two different years, which could
cause issues due to differing cost-of-living adjustments (COLA)
applicable to each year. Handling settlements across two fiscal years
would increase complexity.
Thus, we have 5 yearly runs.
"""
month = input_date.month
if 1 <= month <= 3: # January to March
return 1
elif 4 <= month <= 6: # April to June
return 2
elif 7 <= month <= 9: # July to September
return 3
elif 10 <= month <= 11: # October to November
return 4
elif month == 12: # December
return 5
else:
raise ValueError(
f'Invalid month: {month}. Date must be within a valid year.'
)
[docs]
def __repr__(self) -> str:
return f'<SettlementRun {self.name} {self.start} {self.end} >'