feat: Stunden-Auszahlung Feature (/hr/payouts)
- Backend: Model HoursPayout, Schema, Router GET/POST/DELETE
- GET /hr/payouts: HR/Admin sehen alle, Employee/Manager nur eigene
- POST /hr/payouts: reduziert OvertimeBalance.taken_hours sofort
- DELETE /hr/payouts/{id}: storniert und bucht Stunden zurück
- AuditLog-Einträge bei Anlegen und Stornieren
- Migration 0030: hours_payouts Tabelle
- Frontend: /hr/payouts Seite (lila, 💸) mit Filter, Tabelle, Modal
- Modal zeigt verfügbares Überstundenguthaben + Warnung bei Überziehung
- Navigation: Stunden-Auszahlung (HR/COMPANY_ADMIN/SUPER_ADMIN)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ from app.models.smtp_config import SmtpConfig
|
||||
from app.models.caldav_config import CaldavCompanyConfig, CaldavUserConfig
|
||||
from app.models.kiosk_device import KioskDevice, KioskAuthMethod
|
||||
from app.models.special_assignment import SpecialAssignment, AssignmentMode
|
||||
from app.models.hours_payout import HoursPayout
|
||||
|
||||
__all__ = [
|
||||
"Company",
|
||||
@@ -38,4 +39,5 @@ __all__ = [
|
||||
"KioskAuthMethod",
|
||||
"SpecialAssignment",
|
||||
"AssignmentMode",
|
||||
"HoursPayout",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Stunden-Auszahlung: HR/Admin weist Überstunden-Stunden zur Lohn-Auszahlung an."""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, Numeric, Text, func
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.user import User
|
||||
from app.models.company import Company
|
||||
|
||||
|
||||
class HoursPayout(Base):
|
||||
"""Ein Auszahlungsvorgang für Überstunden-Stunden."""
|
||||
__tablename__ = "hours_payouts"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
company_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), ForeignKey("companies.id", ondelete="CASCADE"),
|
||||
nullable=False, index=True
|
||||
)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"),
|
||||
nullable=False, index=True
|
||||
)
|
||||
hours: Mapped[Decimal] = mapped_column(Numeric(6, 2), nullable=False) # ausgezahlte Stunden
|
||||
period_year: Mapped[int | None] = mapped_column(Integer) # Abrechnungsmonat Jahr
|
||||
period_month: Mapped[int | None] = mapped_column(Integer) # Abrechnungsmonat Monat
|
||||
note: Mapped[str | None] = mapped_column(Text) # Notiz für Buchhaltung
|
||||
created_by: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"),
|
||||
nullable=False
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), index=True
|
||||
)
|
||||
|
||||
user: Mapped["User"] = relationship("User", foreign_keys=[user_id], lazy="noload")
|
||||
creator: Mapped["User"] = relationship("User", foreign_keys=[created_by], lazy="noload")
|
||||
company: Mapped["Company"] = relationship("Company", lazy="noload")
|
||||
Reference in New Issue
Block a user