from django.views.generic import CreateView, UpdateView, View, ListView, DetailView, FormView from django.shortcuts import redirect, get_object_or_404 from django.contrib import messages from django.urls import reverse, reverse_lazy from django.contrib.gis.geos import Point from django.contrib.gis.db.models.functions import Distance from django.conf import settings from django.utils import timezone from public.mixins import InConstructionMixin from partners.mixins import PartnerProfileRequiredMixin from clients.mixins import ClientProfileRequiredMixin from localauth.helpers import name_to_coords from partners.models import Establishment from payment.models import BillingAddress, Invoice, InvoiceItem, InvoicePayment from clients.models import ClientProfile from .models import Inquiry, Offer from .forms import InquiryProcessForm, OfferSelectionForm class InquiryCreateView(CreateView): model = Inquiry fields = ["destination_name", "budget", "arrival", "min_nights", "adults", "children"] def get(self, request, *args, **kwargs): return redirect("/") def form_valid(self, form): form.instance.destination_coords = self.clean_destination_coords() form.instance.destination_radius = 5000 return super().form_valid(form) def form_invalid(self, form, *args, **kwargs): for field in form: for error in field.errors: messages.error(self.request, f"{field.name}: {error}") return redirect("/") def get_success_url(self): return reverse("auction:process_inquiry", args=(self.object.uuid,)) def clean_destination_coords(self): lat, lon = name_to_coords(self.request.POST.get("destination_name")) return Point(lon, lat) class InquiryProcessView(InConstructionMixin, UpdateView): form_class = InquiryProcessForm model = Inquiry template_name = "auction/process.html" def get_object(self): return Inquiry.objects.get(uuid=self.kwargs["uuid"]) def get_initial(self): initial = super().get_initial() try: initial["country"] = self.request.user.clientprofile.country.code except: pass return initial def form_valid(self, form): profile, _ = ClientProfile.objects.get_or_create(user=self.request.user) profile.first_name = form.cleaned_data["first_name"] profile.last_name = form.cleaned_data["last_name"] profile.street = form.cleaned_data["street"] profile.city = form.cleaned_data["city"] profile.zip = form.cleaned_data["zip"] profile.state = form.cleaned_data["state"] profile.country = form.cleaned_data["country"] profile.save() form.instance.client = profile return super().form_valid(form) def form_invalid(self, form, *args, **kwargs): for field in form: for error in field.errors: messages.error(self.request, f"{field.name}: {error}") return redirect("/") def get_success_url(self): return reverse("auction:inquiry_payment", args=(self.object.uuid,)) class InquiryPaymentView(InConstructionMixin, View): def get(self, request, *args, **kwargs): inquiry = Inquiry.objects.get(uuid=kwargs["uuid"]) try: invoice = inquiry.invoice except Invoice.DoesNotExist: invoice = Invoice.from_inquiry(inquiry) payment_url = InvoicePayment.from_invoice(invoice, inquiry.gateway) return redirect(payment_url) class OfferSelectionView(InConstructionMixin, ClientProfileRequiredMixin, FormView, DetailView): model = Inquiry template_name = "auction/offer_select.html" form_class = OfferSelectionForm def get_object(self): return get_object_or_404(Inquiry, uuid=self.kwargs["uuid"], client=self.request.user.clientprofile) def form_valid(self, form): inquiry = self.get_object() offer = get_object_or_404(Offer, inquiry=inquiry, uuid=form.cleaned_data["offer"]) offer.accepted = timezone.now() offer.save() return super().form_valid(form) def get_success_url(self): return reverse_lazy("clients:booking_view", args=[self.kwargs["uuid"]]) class OfferSelectionTableView(InConstructionMixin, ClientProfileRequiredMixin, ListView): model = Offer content_type = "text/javascript" template_name = "auction/offer_table.js" def get_queryset(self): inquiry = get_object_or_404(Inquiry, uuid=self.kwargs["uuid"], client=self.request.user.clientprofile) return inquiry.offer_set.all() class OfferCreationView(InConstructionMixin, PartnerProfileRequiredMixin, CreateView): model = Offer template_name = "auction/offer_create.html" fields = ["roomcategory", "departure", "comment"] def dispatch(self, request, *args, **kwargs): self.establishment = self.get_establishment() self.inquiry = self.get_inquiry() if not self.establishment: messages.warning(request, "Um bieten zu können, muss zuerst eine Unterkunft im System hinterlegt werden!") return redirect("partners:establishment_register") return super().dispatch(request, *args, **kwargs) def get_establishment(self): establishment = self.kwargs.get("establishment", None) kwargs = {"owner": self.request.user.partnerprofile} if establishment: kwargs["id"] = establishment return get_object_or_404(Establishment, **kwargs) else: return Establishment.objects.filter(**kwargs).first() def get_inquiry(self): return get_object_or_404(Inquiry, uuid=self.kwargs.get("inquiry")) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["establishment"] = self.establishment context["inquiry"] = self.inquiry return context def form_valid(self, form): form.instance.inquiry = self.inquiry return super().form_valid(form) def get_success_url(self): messages.success(self.request, "Angebot erfolgreich erstellt! Viel Erfolg!") return reverse_lazy("auction:bidding", args=[self.establishment.id]) class BiddingListView(InConstructionMixin, PartnerProfileRequiredMixin, ListView): model = Inquiry template_name = "auction/bidding_list.html" def dispatch(self, request, *args, **kwargs): self.establishment = self.get_establishment() if not self.establishment: messages.warning(request, "Um bieten zu können, muss zuerst eine Unterkunft im System hinterlegt werden!") return redirect("partners:establishment_register") return super().dispatch(request, *args, **kwargs) def get_establishment(self): establishment = self.kwargs.get("id", None) kwargs = {"owner": self.request.user.partnerprofile} if establishment: kwargs["id"] = establishment return get_object_or_404(Establishment, **kwargs) else: return Establishment.objects.filter(**kwargs).first() def get_queryset(self): establishment = self.get_establishment() excluded = [offer.inquiry.id for offer in establishment.offer_set.all()] return Inquiry.objects.annotate(distance=Distance("destination_coords", establishment.coords)).exclude(activated__isnull=True).exclude(id__in=excluded) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["establishment"] = self.establishment return context