feat(fahrzeug): Funkkenner-Feld ergänzt (BOS-Digitalfunk-Kennung)
CI / backend-tests (push) Failing after 1m53s
CI / frontend-build (push) Successful in 17s

Nutzer-Fund: funkkenner (z.B. OPTA-Nummer) fehlte in fahrzeugdetails komplett
- eigenes Feld, nicht dasselbe wie funkrufname (gesprochener Rufname vs.
formale Funk-Identifikationsnummer im Digitalfunknetz).

Migration 0018, Model/Schema/Frontend-Formular ergänzt. Auch im Kachel-
Backlog (arbeitskacheln/05_fleet.md, FLEET-002) nachgezogen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
This commit is contained in:
2026-09-05 15:37:32 +02:00
co-authored by Claude Sonnet 5
parent 11a62db3bd
commit 27c249993a
8 changed files with 192 additions and 6 deletions
@@ -0,0 +1,25 @@
"""fahrzeugdetails.funkkenner (Nutzer-Fund): BOS-Digitalfunk-Kennung (z.B.
OPTA-Nummer) ist ein eigenes Feld, nicht dasselbe wie funkrufname (gesprochener
Rufname wie "Florian München 1/44" vs. formale Funk-Identifikationsnummer im
Digitalfunknetz). Additiv, nullable.
Revision ID: 0018_funkkenner
Revises: 0017_granulare_rollen
Create Date: 2026-09-05
"""
from typing import Sequence, Union
from alembic import op
revision: str = "0018_funkkenner"
down_revision: Union[str, None] = "0017_granulare_rollen"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.execute("ALTER TABLE fahrzeugdetails ADD COLUMN funkkenner TEXT")
def downgrade() -> None:
op.execute("ALTER TABLE fahrzeugdetails DROP COLUMN funkkenner")
+3
View File
@@ -17,6 +17,9 @@ class Fahrzeugdetails(Base):
objekt_id: Mapped[int] = mapped_column(ForeignKey("objekt.id"), primary_key=True)
kennzeichen: Mapped[str | None] = mapped_column(String)
funkrufname: Mapped[str | None] = mapped_column(String)
# BOS-Digitalfunk-Kennung (z.B. OPTA-Nummer) - eigenes Feld, nicht dasselbe wie
# funkrufname (gesprochener Rufname vs. formale Funk-Identifikationsnummer).
funkkenner: Mapped[str | None] = mapped_column(String)
baujahr: Mapped[int | None] = mapped_column(Integer)
kilometerstand: Mapped[int | None] = mapped_column(Integer)
betriebsstunden: Mapped[Decimal | None] = mapped_column(Numeric)
+2
View File
@@ -38,6 +38,7 @@ class ObjektUpdate(BaseModel):
class FahrzeugdetailsUpsert(BaseModel):
kennzeichen: str | None = None
funkrufname: str | None = None
funkkenner: str | None = None
baujahr: int | None = None
kilometerstand: int | None = None
betriebsstunden: Decimal | None = None
@@ -50,6 +51,7 @@ class FahrzeugdetailsRead(BaseModel):
objekt_id: int
kennzeichen: str | None
funkrufname: str | None
funkkenner: str | None
baujahr: int | None
kilometerstand: int | None
betriebsstunden: Decimal | None
+7 -1
View File
@@ -15,12 +15,18 @@ async def test_fahrzeugdetails_upsert(client, objekt_mit_position, admin_user):
gesetzt = await client.put(
f"/api/v1/objekte/{objekt.id}/fahrzeugdetails",
json={"kennzeichen": "XX-YY 123", "kilometerstand": 42315, "naechste_hu": "2027-05-01"},
json={
"kennzeichen": "XX-YY 123",
"kilometerstand": 42315,
"naechste_hu": "2027-05-01",
"funkkenner": "OPTA-12345",
},
headers=auth_header(token),
)
assert gesetzt.status_code == 200
assert gesetzt.json()["kennzeichen"] == "XX-YY 123"
assert gesetzt.json()["kilometerstand"] == 42315
assert gesetzt.json()["funkkenner"] == "OPTA-12345"
aktualisiert = await client.put(
f"/api/v1/objekte/{objekt.id}/fahrzeugdetails",