Source code for translator_directory.models.time_report

from __future__ import annotations

from decimal import Decimal
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 sqlalchemy import Column, Date, Enum, ForeignKey, Integer, Numeric, Text
from sqlalchemy.orm import relationship


from typing import TYPE_CHECKING, Literal

if TYPE_CHECKING:
    import uuid
    from datetime import date
    from .translator import Translator
    from onegov.user import User

[docs] TimeReportStatus = Literal['pending', 'confirmed']
[docs] class TranslatorTimeReport(Base, TimestampMixin):
[docs] __tablename__ = 'translator_time_reports'
[docs] id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] primary_key=True, default=uuid4, )
[docs] translator_id: Column[uuid.UUID] = Column( UUID, # type:ignore[arg-type] ForeignKey('translators.id', ondelete='CASCADE'), nullable=False, )
[docs] translator: relationship[Translator] = relationship( 'Translator', back_populates='time_reports' )
[docs] created_by_id: Column[uuid.UUID | None] = Column( UUID, # type:ignore[arg-type] ForeignKey('users.id', ondelete='SET NULL'), nullable=True, )
[docs] created_by: relationship[User | None] = relationship('User')
[docs] assignment_type: Column[str | None] = Column(Text)
#: The duration in minutes
[docs] duration: Column[int] = Column(Integer, nullable=False)
[docs] case_number: Column[str | None] = Column(Text)
[docs] assignment_date: Column[date] = Column(Date, nullable=False)
[docs] hourly_rate: Column[Decimal] = Column( Numeric(precision=10, scale=2), nullable=False, )
[docs] surcharge_percentage: Column[Decimal] = Column( Numeric(precision=5, scale=2), nullable=False, default=0, )
[docs] travel_compensation: Column[Decimal] = Column( Numeric(precision=10, scale=2), nullable=False, default=0, )
[docs] total_compensation: Column[Decimal] = Column( Numeric(precision=10, scale=2), nullable=False, )
[docs] notes: Column[str | None] = Column(Text)
[docs] status: Column[TimeReportStatus] = Column( Enum('pending', 'confirmed', name='time_report_status'), # type: ignore[arg-type] nullable=False, default='pending', )
@property
[docs] def duration_hours(self) -> Decimal: """Return duration in hours for display.""" return Decimal(self.duration) / Decimal(60)
@property
[docs] def base_compensation(self) -> Decimal: """Calculate compensation without travel.""" return ( self.hourly_rate * self.duration_hours * (1 + self.surcharge_percentage / Decimal(100)) )
@property
[docs] def meal_allowance(self) -> Decimal: """Return meal allowance if duration >= 6 hours.""" return Decimal('40.0') if self.duration_hours >= 6 else Decimal('0')
@property
[docs] def title(self) -> str: """Return a readable title for this time report.""" date_str = self.assignment_date.strftime('%Y-%m-%d') if self.assignment_type: return f'{self.assignment_type} - {date_str}' return f'Time Report - {date_str}'