generated from coulomb/repo-seed
Vollständigkeitsprüfung mit Freigaben-Check, Abgabe dokumentieren mit Nachweis-Upload, Nachbetrachtung mit Kickoff-Aufgabe (gewonnen) und Alpine.js-gesteuerter Verlustanalyse (verloren). 5 Tests grün. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
121 lines
4.8 KiB
Python
121 lines
4.8 KiB
Python
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 vergabe_teilnahme.apps.ausschreibungen.models import Ausschreibung
|
|
from vergabe_teilnahme.apps.core.models import Freigabe
|
|
from vergabe_teilnahme.apps.dokumente.models import Dokument
|
|
|
|
|
|
def abgabe_vollstaendigkeit(ausschreibung):
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
ct = ContentType.objects.get_for_model(ausschreibung)
|
|
freigaben = Freigabe.objects.filter(content_type=ct, object_id=ausschreibung.pk)
|
|
|
|
def hat_freigabe(typ):
|
|
return freigaben.filter(freigabe_typ=typ, status='erteilt').exists()
|
|
|
|
return {
|
|
'dokumente_gesamt': Dokument.objects.filter(ausschreibung=ausschreibung).count(),
|
|
'dokumente_freigegeben': Dokument.objects.filter(
|
|
ausschreibung=ausschreibung, status__in=['freigegeben', 'final_abgegeben']).count(),
|
|
'teilnahme_freigabe': hat_freigabe('teilnahme'),
|
|
'preis_freigabe': hat_freigabe('preis'),
|
|
'recht_freigabe': hat_freigabe('recht'),
|
|
'abgabe_freigabe': hat_freigabe('abgabe'),
|
|
'entscheidung_getroffen': ausschreibung.teilnahmeentscheidung == 'teilnahme',
|
|
}
|
|
|
|
|
|
def abgabe_checkliste(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
vollstaendigkeit = abgabe_vollstaendigkeit(ausschreibung)
|
|
dokumente = Dokument.objects.filter(ausschreibung=ausschreibung).order_by('kategorie', 'bezeichnung')
|
|
|
|
punkte = [
|
|
('entscheidung_getroffen', 'Teilnahmeentscheidung getroffen'),
|
|
('teilnahme_freigabe', 'Teilnahme-Freigabe erteilt'),
|
|
('preis_freigabe', 'Preis-Freigabe erteilt'),
|
|
('recht_freigabe', 'Rechtliche Freigabe erteilt'),
|
|
('abgabe_freigabe', 'Abgabe-Freigabe erteilt'),
|
|
]
|
|
erfuellt = sum(1 for k, _ in punkte if vollstaendigkeit.get(k))
|
|
gesamt = len(punkte)
|
|
|
|
ctx = {
|
|
'ausschreibung': ausschreibung,
|
|
'vollstaendigkeit': vollstaendigkeit,
|
|
'punkte': [(label, vollstaendigkeit.get(key)) for key, label in punkte],
|
|
'erfuellt': erfuellt,
|
|
'gesamt': gesamt,
|
|
'dokumente': dokumente,
|
|
}
|
|
return render(request, 'nachbetrachtung/abgabe.html', ctx)
|
|
|
|
|
|
class AbgabeForm(forms.Form):
|
|
abgabe_zeitpunkt = forms.DateTimeField(
|
|
widget=forms.DateTimeInput(attrs={'type': 'datetime-local', 'class': 'form-input'}),
|
|
label='Abgabezeitpunkt',
|
|
)
|
|
abgabe_plattform = forms.CharField(
|
|
max_length=200, required=False,
|
|
widget=forms.TextInput(attrs={'class': 'form-input'}),
|
|
label='Abgabeplattform',
|
|
)
|
|
verantwortlicher = forms.ModelChoiceField(
|
|
queryset=Mitarbeiter.objects.all(),
|
|
required=False,
|
|
widget=forms.Select(attrs={'class': 'form-select'}),
|
|
label='Verantwortlicher',
|
|
)
|
|
abgabenachweis = forms.FileField(
|
|
required=False,
|
|
widget=forms.FileInput(attrs={'class': 'form-input'}),
|
|
label='Abgabenachweis (Eingangsbestätigung)',
|
|
)
|
|
kommentar = forms.CharField(
|
|
required=False,
|
|
widget=forms.Textarea(attrs={'class': 'form-input', 'rows': 3}),
|
|
label='Kommentar',
|
|
)
|
|
|
|
|
|
def abgabe_dokumentieren(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
form = AbgabeForm(request.POST, request.FILES)
|
|
if form.is_valid():
|
|
if form.cleaned_data.get('abgabenachweis'):
|
|
Dokument.objects.create(
|
|
ausschreibung=ausschreibung,
|
|
datei=form.cleaned_data['abgabenachweis'],
|
|
kategorie='abgabenachweis',
|
|
status='final_abgegeben',
|
|
finale_abgabeversion=True,
|
|
)
|
|
ausschreibung.status = 9
|
|
ausschreibung.save(update_fields=['status', 'geaendert_am'])
|
|
messages.success(request, 'Abgabe dokumentiert.')
|
|
return redirect('ausschreibungen:detail', pk=ausschreibung_id)
|
|
else:
|
|
form = AbgabeForm()
|
|
return render(request, 'nachbetrachtung/abgabe_formular.html', {
|
|
'form': form,
|
|
'ausschreibung': ausschreibung,
|
|
})
|
|
|
|
|
|
def abgabe_problem(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
kommentar = request.POST.get('kommentar', '')
|
|
ausschreibung.status = 7
|
|
ausschreibung.save(update_fields=['status', 'geaendert_am'])
|
|
messages.warning(request, f'Problem bei Abgabe vermerkt. {kommentar}')
|
|
return redirect('ausschreibungen:nachbetrachtung:abgabe:checkliste',
|
|
ausschreibung_id=ausschreibung_id)
|
|
return render(request, 'nachbetrachtung/abgabe_problem.html', {'ausschreibung': ausschreibung})
|