feat(aufgaben): Verknüpfungen, implizite Fälligkeit, Issue-Facade (WP-0015)

- Aufgabe.erstellt_am für implizite 7-Tage-Fälligkeit
- frist_effektiv property; ist_ueberfaellig nutzt sie
- AufgabenVerknuepfung (GenericForeignKey) mit HTMX-Panel
- ExternalIssue (OneToOne) mit IssueAdapter-ABC und HTMX-Panel
- link_registry.py und issue_facade.py als zentrale Registries
- 8 neue Tests, 76 gesamt grün

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-05-14 04:18:28 +02:00
parent a0c0ddf2eb
commit 816c281f6a
19 changed files with 713 additions and 19 deletions

View file

@ -1,6 +1,6 @@
from django import forms
from .models import Aufgabe, Bieterfrage
from .models import Aufgabe, Bieterfrage, ExternalIssue
class AufgabeForm(forms.ModelForm):
@ -63,3 +63,31 @@ class BieterfragenForm(forms.ModelForm):
self.fields['anforderung'].required = False
self.fields['dokument'].required = False
self.fields['verfasser'].required = False
class AufgabenVerknuepfungForm(forms.Form):
ziel_typ = forms.ChoiceField(choices=[], label='Typ')
ziel_id = forms.IntegerField(label='Objekt-ID', widget=forms.HiddenInput())
kommentar = forms.CharField(
widget=forms.Textarea(attrs={'class': 'form-input', 'rows': 2, 'placeholder': 'Kommentar (optional)'}),
required=False,
label='Kommentar',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
from .link_registry import ziel_choices
self.fields['ziel_typ'].choices = [('', '— Typ wählen —')] + ziel_choices()
self.fields['ziel_typ'].widget.attrs.update({'class': 'form-input'})
class ExternalIssueForm(forms.ModelForm):
class Meta:
model = ExternalIssue
fields = ['system', 'issue_url', 'issue_key', 'notizen']
widgets = {
'system': forms.Select(attrs={'class': 'form-input'}),
'issue_url': forms.URLInput(attrs={'class': 'form-input', 'placeholder': 'https://...'}),
'issue_key': forms.TextInput(attrs={'class': 'form-input', 'placeholder': 'z.B. GH-42'}),
'notizen': forms.Textarea(attrs={'class': 'form-input', 'rows': 2}),
}