generated from coulomb/repo-seed
288 lines
12 KiB
Python
288 lines
12 KiB
Python
from django.shortcuts import get_object_or_404, redirect, render
|
|
|
|
from vergabe_teilnahme.apps.ausschreibungen.models import Ausschreibung
|
|
from vergabe_teilnahme.apps.bibliothek.models import Nachweis
|
|
|
|
from .forms import AnforderungForm, LosForm
|
|
from .models import Anforderung, Los
|
|
|
|
|
|
def _is_htmx(request):
|
|
return request.headers.get('HX-Request') == 'true'
|
|
|
|
|
|
def _ausschreibung_breadcrumbs(ausschreibung, *extra):
|
|
crumbs = [
|
|
{'label': 'Ausschreibungen', 'url': '/ausschreibungen/'},
|
|
{'label': ausschreibung.titel, 'url': f'/ausschreibungen/{ausschreibung.pk}/'},
|
|
]
|
|
for label, url in extra:
|
|
crumbs.append({'label': label, 'url': url})
|
|
return crumbs
|
|
|
|
|
|
# ─── Lose ────────────────────────────────────────────────────────────────────
|
|
|
|
def lose_liste(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
lose = Los.objects.filter(ausschreibung=ausschreibung).order_by('losnummer')
|
|
return render(request, 'lose/liste.html', {
|
|
'ausschreibung': ausschreibung,
|
|
'lose': lose,
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung, ('Lose', None)),
|
|
})
|
|
|
|
|
|
def los_neu(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
form = LosForm(request.POST, ausschreibung=ausschreibung)
|
|
if form.is_valid():
|
|
los = form.save(commit=False)
|
|
los.ausschreibung = ausschreibung
|
|
los.save()
|
|
if _is_htmx(request):
|
|
return render(request, 'lose/partials/los_row.html', {'los': los, 'ausschreibung': ausschreibung})
|
|
return redirect('ausschreibungen:lose:liste', ausschreibung_id=ausschreibung_id)
|
|
else:
|
|
form = LosForm(ausschreibung=ausschreibung)
|
|
return render(request, 'lose/form.html', {
|
|
'form': form,
|
|
'ausschreibung': ausschreibung,
|
|
'titel': 'Los hinzufügen',
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Lose', f'/ausschreibungen/{ausschreibung_id}/lose/'),
|
|
('Neu', None)),
|
|
})
|
|
|
|
|
|
def los_detail(request, ausschreibung_id, los_pk):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
los = get_object_or_404(Los, pk=los_pk, ausschreibung=ausschreibung)
|
|
anforderungen = los.anforderungen.all().order_by('verbindlichkeit', 'titel')
|
|
return render(request, 'lose/detail.html', {
|
|
'ausschreibung': ausschreibung,
|
|
'los': los,
|
|
'anforderungen': anforderungen,
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Lose', f'/ausschreibungen/{ausschreibung_id}/lose/'),
|
|
(str(los), None)),
|
|
})
|
|
|
|
|
|
def los_bearbeiten(request, ausschreibung_id, los_pk):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
los = get_object_or_404(Los, pk=los_pk, ausschreibung=ausschreibung)
|
|
form = LosForm(request.POST or None, instance=los, ausschreibung=ausschreibung)
|
|
if request.method == 'POST' and form.is_valid():
|
|
form.save()
|
|
return redirect('ausschreibungen:lose:detail', ausschreibung_id=ausschreibung_id, los_pk=los_pk)
|
|
return render(request, 'lose/form.html', {
|
|
'form': form,
|
|
'ausschreibung': ausschreibung,
|
|
'los': los,
|
|
'titel': 'Los bearbeiten',
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Lose', f'/ausschreibungen/{ausschreibung_id}/lose/'),
|
|
(str(los), f'/ausschreibungen/{ausschreibung_id}/lose/{los_pk}/'),
|
|
('Bearbeiten', None)),
|
|
})
|
|
|
|
|
|
def los_loeschen(request, ausschreibung_id, los_pk):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
los = get_object_or_404(Los, pk=los_pk, ausschreibung=ausschreibung)
|
|
if request.method == 'POST':
|
|
los.delete()
|
|
return redirect('ausschreibungen:lose:liste', ausschreibung_id=ausschreibung_id)
|
|
return render(request, 'lose/loeschen_confirm.html', {
|
|
'ausschreibung': ausschreibung,
|
|
'los': los,
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Lose', f'/ausschreibungen/{ausschreibung_id}/lose/'),
|
|
(str(los), f'/ausschreibungen/{ausschreibung_id}/lose/{los_pk}/'),
|
|
('Löschen', None)),
|
|
})
|
|
|
|
|
|
# ─── Anforderungen ───────────────────────────────────────────────────────────
|
|
|
|
def anforderungen_liste(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
qs = Anforderung.objects.filter(ausschreibung=ausschreibung).select_related('los', 'zustaendiger')
|
|
|
|
verbindlichkeit = request.GET.get('verbindlichkeit', '')
|
|
if verbindlichkeit:
|
|
qs = qs.filter(verbindlichkeit=verbindlichkeit)
|
|
|
|
status_filter = request.GET.get('erfuellungsstatus', '')
|
|
if status_filter:
|
|
qs = qs.filter(erfuellungsstatus=status_filter)
|
|
|
|
los_filter = request.GET.get('los', '')
|
|
if los_filter == 'allgemein':
|
|
qs = qs.filter(los__isnull=True)
|
|
elif los_filter:
|
|
qs = qs.filter(los_id=los_filter)
|
|
|
|
lose = Los.objects.filter(ausschreibung=ausschreibung).order_by('losnummer')
|
|
|
|
grouped = {}
|
|
for los in lose:
|
|
grouped[los] = []
|
|
grouped[None] = []
|
|
|
|
for a in qs.order_by('verbindlichkeit', 'titel'):
|
|
grouped[a.los].append(a)
|
|
|
|
grouped = {k: v for k, v in grouped.items() if v}
|
|
|
|
ctx = {
|
|
'ausschreibung': ausschreibung,
|
|
'grouped': grouped,
|
|
'lose': lose,
|
|
'verbindlichkeit_choices': Anforderung.VERBINDLICHKEIT_CHOICES,
|
|
'erfuellung_choices': Anforderung.ERFUELLUNG_CHOICES,
|
|
'current_verbindlichkeit': verbindlichkeit,
|
|
'current_status': status_filter,
|
|
'current_los': los_filter,
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung, ('Anforderungen', None)),
|
|
}
|
|
|
|
if _is_htmx(request):
|
|
return render(request, 'lose/anforderungen_liste_partial.html', ctx)
|
|
return render(request, 'lose/anforderungen_liste.html', ctx)
|
|
|
|
|
|
def anforderung_neu(request, ausschreibung_id):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
form = AnforderungForm(request.POST, ausschreibung=ausschreibung)
|
|
if form.is_valid():
|
|
a = form.save(commit=False)
|
|
a.ausschreibung = ausschreibung
|
|
a.save()
|
|
return redirect('ausschreibungen:lose:anforderung_detail',
|
|
ausschreibung_id=ausschreibung_id, pk=a.pk)
|
|
else:
|
|
los_pk = request.GET.get('los')
|
|
initial = {'los': los_pk} if los_pk else {}
|
|
form = AnforderungForm(ausschreibung=ausschreibung, initial=initial)
|
|
return render(request, 'lose/anforderung_form.html', {
|
|
'form': form,
|
|
'ausschreibung': ausschreibung,
|
|
'titel': 'Anforderung anlegen',
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Anforderungen', f'/ausschreibungen/{ausschreibung_id}/lose/anforderungen/'),
|
|
('Neu', None)),
|
|
})
|
|
|
|
|
|
def anforderung_detail(request, ausschreibung_id, pk):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung=ausschreibung)
|
|
aufgaben = anforderung.aufgaben.all().order_by('prioritaet', 'frist')
|
|
return render(request, 'lose/anforderung_detail.html', {
|
|
'ausschreibung': ausschreibung,
|
|
'anforderung': anforderung,
|
|
'aufgaben': aufgaben,
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Anforderungen', f'/ausschreibungen/{ausschreibung_id}/lose/anforderungen/'),
|
|
(anforderung.titel[:50], None)),
|
|
})
|
|
|
|
|
|
def anforderung_bearbeiten(request, ausschreibung_id, pk):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung=ausschreibung)
|
|
form = AnforderungForm(request.POST or None, instance=anforderung, ausschreibung=ausschreibung)
|
|
if request.method == 'POST' and form.is_valid():
|
|
form.save()
|
|
return redirect('ausschreibungen:lose:anforderung_detail',
|
|
ausschreibung_id=ausschreibung_id, pk=pk)
|
|
return render(request, 'lose/anforderung_form.html', {
|
|
'form': form,
|
|
'ausschreibung': ausschreibung,
|
|
'anforderung': anforderung,
|
|
'titel': 'Anforderung bearbeiten',
|
|
'breadcrumbs': _ausschreibung_breadcrumbs(ausschreibung,
|
|
('Anforderungen', f'/ausschreibungen/{ausschreibung_id}/lose/anforderungen/'),
|
|
(anforderung.titel[:50], f'/ausschreibungen/{ausschreibung_id}/lose/anforderungen/{pk}/'),
|
|
('Bearbeiten', None)),
|
|
})
|
|
|
|
|
|
def anforderung_status(request, ausschreibung_id, pk):
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung_id=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
neuer_status = request.POST.get('erfuellungsstatus')
|
|
if neuer_status:
|
|
anforderung.erfuellungsstatus = neuer_status
|
|
anforderung.save(update_fields=['erfuellungsstatus'])
|
|
return render(request, 'lose/partials/erfuellungsstatus_widget.html', {'anforderung': anforderung})
|
|
|
|
|
|
# ─── Nachweise ───────────────────────────────────────────────────────────────
|
|
|
|
def nachweis_suche_modal(request, ausschreibung_id, pk):
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung_id=ausschreibung_id)
|
|
q = request.GET.get('q', '')
|
|
nachweise = Nachweis.objects.all()
|
|
if q:
|
|
nachweise = nachweise.filter(titel__icontains=q)
|
|
bereits_zugeordnet = anforderung.nachweise.values_list('pk', flat=True)
|
|
return render(request, 'lose/partials/nachweis_modal.html', {
|
|
'anforderung': anforderung,
|
|
'nachweise': nachweise[:20],
|
|
'bereits_zugeordnet': list(bereits_zugeordnet),
|
|
'q': q,
|
|
'ausschreibung_id': ausschreibung_id,
|
|
})
|
|
|
|
|
|
def nachweis_zuordnen(request, ausschreibung_id, pk):
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung_id=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
nachweis_pk = request.POST.get('nachweis_pk')
|
|
if nachweis_pk:
|
|
nachweis = get_object_or_404(Nachweis, pk=nachweis_pk)
|
|
anforderung.nachweise.add(nachweis)
|
|
return render(request, 'lose/partials/nachweise_liste.html', {
|
|
'anforderung': anforderung,
|
|
'ausschreibung_id': ausschreibung_id,
|
|
})
|
|
|
|
|
|
def nachweis_entfernen(request, ausschreibung_id, pk, nachweis_pk):
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung_id=ausschreibung_id)
|
|
if request.method == 'POST':
|
|
nachweis = get_object_or_404(Nachweis, pk=nachweis_pk)
|
|
anforderung.nachweise.remove(nachweis)
|
|
return render(request, 'lose/partials/nachweise_liste.html', {
|
|
'anforderung': anforderung,
|
|
'ausschreibung_id': ausschreibung_id,
|
|
})
|
|
|
|
|
|
# ─── Aufgabe aus Anforderung ─────────────────────────────────────────────────
|
|
|
|
def anforderung_aufgabe_erstellen(request, ausschreibung_id, pk):
|
|
ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id)
|
|
anforderung = get_object_or_404(Anforderung, pk=pk, ausschreibung=ausschreibung)
|
|
if request.method == 'POST':
|
|
from vergabe_teilnahme.apps.aufgaben.models import Aufgabe
|
|
Aufgabe.objects.create(
|
|
ausschreibung=ausschreibung,
|
|
los=anforderung.los,
|
|
anforderung=anforderung,
|
|
titel=f'Klärung: {anforderung.titel[:200]}',
|
|
typ='fachlich',
|
|
verantwortlicher=anforderung.zustaendiger,
|
|
)
|
|
return redirect('ausschreibungen:lose:anforderung_detail',
|
|
ausschreibung_id=ausschreibung_id, pk=pk)
|
|
return render(request, 'lose/aufgabe_erstellen_confirm.html', {
|
|
'ausschreibung': ausschreibung,
|
|
'anforderung': anforderung,
|
|
})
|