from datetime import date, timedelta from django.shortcuts import get_object_or_404, redirect, render from django.utils import timezone from vergabe_teilnahme.apps.accounts.models import Mitarbeiter from .models import Ausschreibung def _is_htmx(request): return request.headers.get('HX-Request') == 'true' def dashboard(request): from vergabe_teilnahme.apps.aufgaben.models import Aufgabe heute = date.today() in_14_tagen = heute + timedelta(days=14) ctx = { 'kritische_fristen': Ausschreibung.objects.filter( abgabe_bis__date__lte=in_14_tagen, abgabe_bis__date__gte=heute, status__lt=10, ).order_by('abgabe_bis')[:10], 'ohne_entscheidung': Ausschreibung.objects.filter( teilnahmeentscheidung='offen', erstellt_am__lte=timezone.now() - timedelta(days=3), status__lt=10, ).order_by('erstellt_am')[:10], 'ueberfaellige_aufgaben': Aufgabe.objects.filter( frist__lt=heute, status__in=['offen', 'in_bearbeitung', 'wartend_intern', 'wartend_sub', 'wartend_ausschreiber'], ).select_related('ausschreibung').order_by('frist')[:15], 'laufende_ausschreibungen': Ausschreibung.objects.filter( status__range=(1, 9), ).order_by('-geaendert_am')[:10], 'breadcrumbs': [{'label': 'Übersicht', 'url': None}], } return render(request, 'ausschreibungen/dashboard.html', ctx) def ausschreibung_liste(request): qs = Ausschreibung.objects.all() status_filter = request.GET.get('status') if status_filter: qs = qs.filter(status=status_filter) archiviert = request.GET.get('archiviert', '0') == '1' qs = qs.filter(archiviert=archiviert) bid_manager_filter = request.GET.get('bid_manager') if bid_manager_filter: qs = qs.filter(bid_manager=bid_manager_filter) qs = qs.select_related('bid_manager').order_by('-geaendert_am') ctx = { 'ausschreibungen': qs, 'status_choices': Ausschreibung.STATUS_CHOICES, 'mitarbeiter': Mitarbeiter.objects.all(), 'archiviert': archiviert, 'current_status': status_filter or '', 'current_bid_manager': bid_manager_filter or '', 'breadcrumbs': [{'label': 'Ausschreibungen', 'url': None}], } if _is_htmx(request): return render(request, 'ausschreibungen/liste_partial.html', ctx) return render(request, 'ausschreibungen/liste.html', ctx) def ausschreibung_neu(request): from .forms import AusschreibungForm historisch = request.GET.get('historisch') == '1' if request.method == 'POST': form = AusschreibungForm(request.POST) if form.is_valid(): a = form.save() return redirect('ausschreibungen:detail', pk=a.pk) else: form = AusschreibungForm() return render(request, 'ausschreibungen/form.html', { 'form': form, 'historisch': historisch, 'titel': 'Neue Ausschreibung', 'breadcrumbs': [ {'label': 'Ausschreibungen', 'url': '/ausschreibungen/'}, {'label': 'Neu', 'url': None}, ], }) def ausschreibung_detail(request, pk): from vergabe_teilnahme.apps.core.services import build_phase_nav, get_deadline_warnings a = get_object_or_404(Ausschreibung, pk=pk) ctx = { 'ausschreibung': a, 'ausschreibung_id': pk, 'phases': build_phase_nav(a), 'warnungen': get_deadline_warnings(a), 'breadcrumbs': [ {'label': 'Ausschreibungen', 'url': '/ausschreibungen/'}, {'label': a.titel, 'url': None}, ], } return render(request, 'ausschreibungen/detail.html', ctx) def ausschreibung_bearbeiten(request, pk): from .forms import AusschreibungForm a = get_object_or_404(Ausschreibung, pk=pk) form = AusschreibungForm(request.POST or None, instance=a) if request.method == 'POST' and form.is_valid(): form.save() return redirect('ausschreibungen:detail', pk=pk) return render(request, 'ausschreibungen/form.html', { 'form': form, 'titel': 'Ausschreibung bearbeiten', 'ausschreibung': a, 'breadcrumbs': [ {'label': 'Ausschreibungen', 'url': '/ausschreibungen/'}, {'label': a.titel, 'url': f'/ausschreibungen/{pk}/'}, {'label': 'Bearbeiten', 'url': None}, ], }) def ausschreibung_status(request, pk): a = get_object_or_404(Ausschreibung, pk=pk) if request.method == 'POST': neuer_status = request.POST.get('status') if neuer_status and neuer_status.isdigit(): a.status = int(neuer_status) a.save(update_fields=['status', 'geaendert_am']) return render(request, 'ausschreibungen/partials/status_widget.html', {'ausschreibung': a}) def ausschreibung_entscheidung(request, pk): from .services import entscheidungsregel_auswertung a = get_object_or_404(Ausschreibung, pk=pk) if request.method == 'POST': a.teilnahmeentscheidung = request.POST.get('teilnahmeentscheidung', 'offen') a.entscheidungsbegruendung = request.POST.get('begruendung', a.entscheidungsbegruendung) if a.teilnahmeentscheidung in ['teilnahme', 'ablehnung']: a.status = max(a.status, 3) a.save() return redirect('ausschreibungen:detail', pk=pk) from vergabe_teilnahme.apps.lose.models import Anforderung ausschlusskriterien = Anforderung.objects.filter( ausschreibung=a, ausschlusskriterium=True, erfuellungsstatus='nicht_erfuellbar', ).select_related('los') ctx = { 'ausschreibung': a, 'regelergebnis': entscheidungsregel_auswertung(a), 'ausschlusskriterien_nicht_erfuellbar': ausschlusskriterien, 'breadcrumbs': [ {'label': 'Ausschreibungen', 'url': '/ausschreibungen/'}, {'label': a.titel, 'url': f'/ausschreibungen/{pk}/'}, {'label': 'Teilnahmeentscheidung', 'url': None}, ], } return render(request, 'ausschreibungen/entscheidung.html', ctx) def freigaben_uebersicht(request, pk): from django.contrib.contenttypes.models import ContentType from vergabe_teilnahme.apps.core.models import Freigabe a = get_object_or_404(Ausschreibung, pk=pk) ct = ContentType.objects.get_for_model(a) freigaben = Freigabe.objects.filter( content_type=ct, object_id=pk ).select_related('freigebende_person').order_by('-timestamp') erteilte_typen = set(freigaben.filter(status='erteilt').values_list('freigabe_typ', flat=True)) erforderliche_typen = {'teilnahme', 'preis', 'abgabe'} fehlende_typen = erforderliche_typen - erteilte_typen ctx = { 'ausschreibung': a, 'freigaben': freigaben, 'fehlende_typen': fehlende_typen, 'ct_id': ct.pk, 'freigabe_typ_choices': Freigabe.TYP_CHOICES, 'breadcrumbs': [ {'label': 'Ausschreibungen', 'url': '/ausschreibungen/'}, {'label': a.titel, 'url': f'/ausschreibungen/{pk}/'}, {'label': 'Freigaben', 'url': None}, ], } return render(request, 'ausschreibungen/freigaben.html', ctx) def ausschreibung_archivieren(request, pk): a = get_object_or_404(Ausschreibung, pk=pk) if request.method == 'POST': a.archiviert = True a.status = 13 a.save(update_fields=['archiviert', 'status', 'geaendert_am']) return redirect('ausschreibungen:liste') return render(request, 'ausschreibungen/archivieren_confirm.html', { 'ausschreibung': a, 'breadcrumbs': [ {'label': 'Ausschreibungen', 'url': '/ausschreibungen/'}, {'label': a.titel, 'url': f'/ausschreibungen/{pk}/'}, {'label': 'Archivieren', 'url': None}, ], })