from datetime import date, timedelta from django import forms from django.contrib import messages from django.shortcuts import get_object_or_404, redirect, render from vergabe_teilnahme.apps.accounts.models import Mitarbeiter from .models import Entscheidungsregel, Leistungsblatt, Nachweis, Referenz # ── Forms ───────────────────────────────────────────────────────────────────── class NachweisForm(forms.ModelForm): class Meta: model = Nachweis fields = [ 'titel', 'kurzbeschreibung', 'dokumenttyp', 'kategorie', 'datei', 'version', 'gueltig_ab', 'gueltig_bis', 'eigentuemer', 'freigabestatus', 'vertraulichkeit', 'sprache', 'zugehoerige_standards', 'letzte_pruefung', 'fuer_oeffentliche', 'fuer_privatwirtschaftliche', ] widgets = { 'titel': forms.TextInput(attrs={'class': 'form-input'}), 'kurzbeschreibung': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'dokumenttyp': forms.TextInput(attrs={'class': 'form-input'}), 'kategorie': forms.TextInput(attrs={'class': 'form-input'}), 'version': forms.TextInput(attrs={'class': 'form-input'}), 'gueltig_ab': forms.DateInput(attrs={'type': 'date', 'class': 'form-input'}), 'gueltig_bis': forms.DateInput(attrs={'type': 'date', 'class': 'form-input'}), 'eigentuemer': forms.Select(attrs={'class': 'form-select'}), 'freigabestatus': forms.Select(attrs={'class': 'form-select'}), 'vertraulichkeit': forms.Select(attrs={'class': 'form-select'}), 'sprache': forms.TextInput(attrs={'class': 'form-input'}), 'zugehoerige_standards': forms.Textarea(attrs={'class': 'form-input', 'rows': 2}), 'letzte_pruefung': forms.DateInput(attrs={'type': 'date', 'class': 'form-input'}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['eigentuemer'].queryset = Mitarbeiter.objects.all() self.fields['eigentuemer'].required = False self.fields['gueltig_ab'].required = False self.fields['gueltig_bis'].required = False self.fields['letzte_pruefung'].required = False class ReferenzForm(forms.ModelForm): class Meta: model = Referenz fields = [ 'referenztitel', 'kunde', 'branche', 'oeffentlich_oder_privat', 'leistungsbeschreibung', 'eingesetzte_produkte', 'projektzeitraum', 'vertragsvolumen', 'ansprechpartner_referenzkunde', 'freigabestatus_verwendung', 'vertraulichkeit', 'whitepaper', 'kurzfassung', 'langfassung', 'verwendbar_fuer_ausschreibungen', 'einschraenkungen_verwendung', 'leistungsblaetter', ] widgets = { 'referenztitel': forms.TextInput(attrs={'class': 'form-input'}), 'kunde': forms.TextInput(attrs={'class': 'form-input'}), 'branche': forms.TextInput(attrs={'class': 'form-input'}), 'oeffentlich_oder_privat': forms.TextInput(attrs={'class': 'form-input'}), 'leistungsbeschreibung': forms.Textarea(attrs={'class': 'form-input', 'rows': 4}), 'eingesetzte_produkte': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'projektzeitraum': forms.TextInput(attrs={'class': 'form-input'}), 'vertragsvolumen': forms.NumberInput(attrs={'class': 'form-input'}), 'ansprechpartner_referenzkunde': forms.TextInput(attrs={'class': 'form-input'}), 'freigabestatus_verwendung': forms.Select(attrs={'class': 'form-select'}), 'vertraulichkeit': forms.TextInput(attrs={'class': 'form-input'}), 'kurzfassung': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'langfassung': forms.Textarea(attrs={'class': 'form-input', 'rows': 5}), 'einschraenkungen_verwendung': forms.Textarea(attrs={'class': 'form-input', 'rows': 2}), 'leistungsblaetter': forms.CheckboxSelectMultiple(), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['vertragsvolumen'].required = False self.fields['leistungsblaetter'].required = False class LeistungsblattForm(forms.ModelForm): class Meta: model = Leistungsblatt fields = [ 'produktfunktion', 'beschreibung', 'leistungsumfang', 'grenzen_ausschluesse', 'technische_voraussetzungen', 'typische_nachweise', 'version', 'eigentuemer', ] widgets = { 'produktfunktion': forms.TextInput(attrs={'class': 'form-input'}), 'beschreibung': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'leistungsumfang': forms.Textarea(attrs={'class': 'form-input', 'rows': 4}), 'grenzen_ausschluesse': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'technische_voraussetzungen': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'typische_nachweise': forms.Textarea(attrs={'class': 'form-input', 'rows': 2}), 'version': forms.TextInput(attrs={'class': 'form-input'}), 'eigentuemer': forms.Select(attrs={'class': 'form-select'}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['eigentuemer'].queryset = Mitarbeiter.objects.all() self.fields['eigentuemer'].required = False class EntscheidungsregelForm(forms.ModelForm): class Meta: model = Entscheidungsregel fields = [ 'regelname', 'beschreibung', 'kategorie', 'gewichtung', 'bewertungslogik', 'schwellenwert', 'empfehlung', 'begruendung', 'gueltig_von', 'gueltig_bis', 'aktiv', 'verantwortlicher', ] widgets = { 'regelname': forms.TextInput(attrs={'class': 'form-input'}), 'beschreibung': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'kategorie': forms.Select(attrs={'class': 'form-select'}), 'gewichtung': forms.NumberInput(attrs={'class': 'form-input', 'step': '0.1'}), 'bewertungslogik': forms.Textarea(attrs={'class': 'form-input', 'rows': 3}), 'schwellenwert': forms.NumberInput(attrs={'class': 'form-input'}), 'empfehlung': forms.RadioSelect(), 'begruendung': forms.Textarea(attrs={'class': 'form-input', 'rows': 2}), 'gueltig_von': forms.DateInput(attrs={'type': 'date', 'class': 'form-input'}), 'gueltig_bis': forms.DateInput(attrs={'type': 'date', 'class': 'form-input'}), 'verantwortlicher': forms.Select(attrs={'class': 'form-select'}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['verantwortlicher'].queryset = Mitarbeiter.objects.all() self.fields['verantwortlicher'].required = False self.fields['schwellenwert'].required = False self.fields['gueltig_von'].required = False self.fields['gueltig_bis'].required = False # ── Nachweis views ──────────────────────────────────────────────────────────── def nachweise_liste(request): heute = date.today() in_60_tagen = heute + timedelta(days=60) tab = request.GET.get('tab', 'alle') qs = Nachweis.objects.exclude(status='ersetzt') if tab == 'abgelaufen': qs = qs.filter(gueltig_bis__lt=heute) elif tab == 'bald_ablaufend': qs = qs.filter(gueltig_bis__lte=in_60_tagen, gueltig_bis__gte=heute) return render(request, 'bibliothek/nachweis_liste.html', { 'nachweise': qs, 'heute': heute, 'in_60_tagen': in_60_tagen, 'tab': tab, 'breadcrumbs': [{'label': 'Nachweise', 'url': None}], }) def nachweis_neu(request): if request.method == 'POST': form = NachweisForm(request.POST, request.FILES) if form.is_valid(): obj = form.save() messages.success(request, f'Nachweis „{obj.titel}" angelegt.') return redirect('bibliothek:nachweis_detail', pk=obj.pk) else: form = NachweisForm() return render(request, 'bibliothek/nachweis_form.html', { 'form': form, 'breadcrumbs': [ {'label': 'Nachweise', 'url': '/bibliothek/nachweise/'}, {'label': 'Neu', 'url': None}, ], }) def nachweis_detail(request, pk): nachweis = get_object_or_404(Nachweis, pk=pk) return render(request, 'bibliothek/nachweis_detail.html', { 'nachweis': nachweis, 'breadcrumbs': [ {'label': 'Nachweise', 'url': '/bibliothek/nachweise/'}, {'label': nachweis.titel, 'url': None}, ], }) def nachweis_bearbeiten(request, pk): nachweis = get_object_or_404(Nachweis, pk=pk) if request.method == 'POST': form = NachweisForm(request.POST, request.FILES, instance=nachweis) if form.is_valid(): form.save() messages.success(request, 'Gespeichert.') return redirect('bibliothek:nachweis_detail', pk=pk) else: form = NachweisForm(instance=nachweis) return render(request, 'bibliothek/nachweis_form.html', { 'form': form, 'nachweis': nachweis, 'breadcrumbs': [ {'label': 'Nachweise', 'url': '/bibliothek/nachweise/'}, {'label': nachweis.titel, 'url': f'/bibliothek/nachweise/{pk}/'}, {'label': 'Bearbeiten', 'url': None}, ], }) def nachweis_neue_version(request, pk): alter_nachweis = get_object_or_404(Nachweis, pk=pk) if request.method == 'POST': form = NachweisForm(request.POST, request.FILES) if form.is_valid(): alter_nachweis.status = 'ersetzt' alter_nachweis.save(update_fields=['status']) neuer = form.save(commit=False) # Parse version for auto-increment try: major, minor = alter_nachweis.version.split('.') neuer.version = f'{major}.{int(minor) + 1}' except (ValueError, AttributeError): neuer.version = alter_nachweis.version neuer.save() messages.success(request, f'Neue Version {neuer.version} angelegt.') return redirect('bibliothek:nachweis_detail', pk=neuer.pk) else: form = NachweisForm(instance=alter_nachweis) return render(request, 'bibliothek/nachweis_form.html', { 'form': form, 'nachweis': alter_nachweis, 'neue_version': True, 'breadcrumbs': [ {'label': 'Nachweise', 'url': '/bibliothek/nachweise/'}, {'label': alter_nachweis.titel, 'url': f'/bibliothek/nachweise/{pk}/'}, {'label': 'Neue Version', 'url': None}, ], }) # ── Referenz views ──────────────────────────────────────────────────────────── def referenzen_liste(request): q = request.GET.get('q', '').strip() qs = Referenz.objects.all() if q: qs = qs.filter( referenztitel__icontains=q ) | qs.filter( branche__icontains=q ) | qs.filter( leistungsbeschreibung__icontains=q ) qs = qs.distinct() return render(request, 'bibliothek/referenz_liste.html', { 'referenzen': qs, 'q': q, 'breadcrumbs': [{'label': 'Referenzen', 'url': None}], }) def referenz_neu(request): if request.method == 'POST': form = ReferenzForm(request.POST, request.FILES) if form.is_valid(): obj = form.save() messages.success(request, f'Referenz „{obj.referenztitel}" angelegt.') return redirect('bibliothek:referenz_detail', pk=obj.pk) else: form = ReferenzForm() return render(request, 'bibliothek/referenz_form.html', { 'form': form, 'breadcrumbs': [ {'label': 'Referenzen', 'url': '/bibliothek/referenzen/'}, {'label': 'Neu', 'url': None}, ], }) def referenz_detail(request, pk): ref = get_object_or_404(Referenz, pk=pk) return render(request, 'bibliothek/referenz_detail.html', { 'ref': ref, 'breadcrumbs': [ {'label': 'Referenzen', 'url': '/bibliothek/referenzen/'}, {'label': ref.referenztitel, 'url': None}, ], }) def referenz_bearbeiten(request, pk): ref = get_object_or_404(Referenz, pk=pk) if request.method == 'POST': form = ReferenzForm(request.POST, request.FILES, instance=ref) if form.is_valid(): form.save() messages.success(request, 'Gespeichert.') return redirect('bibliothek:referenz_detail', pk=pk) else: form = ReferenzForm(instance=ref) return render(request, 'bibliothek/referenz_form.html', { 'form': form, 'ref': ref, 'breadcrumbs': [ {'label': 'Referenzen', 'url': '/bibliothek/referenzen/'}, {'label': ref.referenztitel, 'url': f'/bibliothek/referenzen/{pk}/'}, {'label': 'Bearbeiten', 'url': None}, ], }) def referenz_zuordnen(request, ausschreibung_id): from vergabe_teilnahme.apps.ausschreibungen.models import Ausschreibung ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id) if request.method == 'POST': ref_id = request.POST.get('referenz_id') ref = get_object_or_404(Referenz, pk=ref_id) ausschreibung.referenzen.add(ref) messages.success(request, f'Referenz „{ref.referenztitel}" zugeordnet.') return redirect('ausschreibungen:detail', pk=ausschreibung_id) q = request.GET.get('q', '').strip() qs = Referenz.objects.filter(verwendbar_fuer_ausschreibungen=True) if q: qs = qs.filter(referenztitel__icontains=q) | qs.filter(branche__icontains=q) qs = qs.distinct() return render(request, 'bibliothek/partials/referenz_suche.html', { 'referenzen': qs, 'ausschreibung': ausschreibung, 'q': q, }) # ── Leistungsblatt views ────────────────────────────────────────────────────── def leistungsblaetter_liste(request): blaetter = Leistungsblatt.objects.all() return render(request, 'bibliothek/leistungsblatt_liste.html', { 'blaetter': blaetter, 'breadcrumbs': [{'label': 'Leistungsblätter', 'url': None}], }) def leistungsblatt_neu(request): if request.method == 'POST': form = LeistungsblattForm(request.POST) if form.is_valid(): obj = form.save() messages.success(request, f'Leistungsblatt „{obj.produktfunktion}" angelegt.') return redirect('bibliothek:leistungsblaetter_liste') else: form = LeistungsblattForm() return render(request, 'bibliothek/leistungsblatt_form.html', { 'form': form, 'breadcrumbs': [ {'label': 'Leistungsblätter', 'url': '/bibliothek/leistungsblaetter/'}, {'label': 'Neu', 'url': None}, ], }) def leistungsblatt_bearbeiten(request, pk): obj = get_object_or_404(Leistungsblatt, pk=pk) if request.method == 'POST': form = LeistungsblattForm(request.POST, instance=obj) if form.is_valid(): form.save() messages.success(request, 'Gespeichert.') return redirect('bibliothek:leistungsblaetter_liste') else: form = LeistungsblattForm(instance=obj) return render(request, 'bibliothek/leistungsblatt_form.html', { 'form': form, 'obj': obj, 'breadcrumbs': [ {'label': 'Leistungsblätter', 'url': '/bibliothek/leistungsblaetter/'}, {'label': 'Bearbeiten', 'url': None}, ], }) # ── Entscheidungsregel views ────────────────────────────────────────────────── def entscheidungsregeln_liste(request): regeln = Entscheidungsregel.objects.all() return render(request, 'bibliothek/entscheidungsregel_liste.html', { 'regeln': regeln, 'breadcrumbs': [{'label': 'Entscheidungsregeln', 'url': None}], }) def entscheidungsregel_neu(request): if request.method == 'POST': form = EntscheidungsregelForm(request.POST) if form.is_valid(): obj = form.save() messages.success(request, f'Entscheidungsregel „{obj.regelname}" angelegt.') return redirect('bibliothek:entscheidungsregeln_liste') else: form = EntscheidungsregelForm() return render(request, 'bibliothek/entscheidungsregel_form.html', { 'form': form, 'breadcrumbs': [ {'label': 'Entscheidungsregeln', 'url': '/bibliothek/entscheidungsregeln/'}, {'label': 'Neu', 'url': None}, ], }) def entscheidungsregel_bearbeiten(request, pk): obj = get_object_or_404(Entscheidungsregel, pk=pk) if request.method == 'POST': form = EntscheidungsregelForm(request.POST, instance=obj) if form.is_valid(): form.save() messages.success(request, 'Gespeichert.') return redirect('bibliothek:entscheidungsregeln_liste') else: form = EntscheidungsregelForm(instance=obj) return render(request, 'bibliothek/entscheidungsregel_form.html', { 'form': form, 'obj': obj, 'breadcrumbs': [ {'label': 'Entscheidungsregeln', 'url': '/bibliothek/entscheidungsregeln/'}, {'label': 'Bearbeiten', 'url': None}, ], }) def entscheidungsregel_toggle(request, pk): obj = get_object_or_404(Entscheidungsregel, pk=pk) if request.method == 'POST': obj.aktiv = not obj.aktiv obj.save(update_fields=['aktiv']) return render(request, 'bibliothek/partials/er_aktiv_toggle.html', {'obj': obj})