Flow improvements
Dynamic displaying of received offers
This commit is contained in:
parent
f51350f28f
commit
81f7d6eb66
20 changed files with 256 additions and 45 deletions
|
@ -1,3 +1,6 @@
|
||||||
from django.contrib import admin
|
from urlaubsauktion.admin import joker_admin as admin
|
||||||
|
|
||||||
# Register your models here.
|
from .models import Inquiry, Offer
|
||||||
|
|
||||||
|
admin.register(Inquiry)
|
||||||
|
admin.register(Offer)
|
|
@ -1,8 +1,11 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from clients.models import ClientProfile
|
from clients.models import ClientProfile
|
||||||
from partners.models import Establishment
|
from partners.models import Establishment, RoomCategory
|
||||||
|
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -37,10 +40,19 @@ class Inquiry(models.Model):
|
||||||
self.activated = timezone.now()
|
self.activated = timezone.now()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expiry(self):
|
||||||
|
if self.activated:
|
||||||
|
return self.activated + relativedelta(days=settings.INQUIRY_RUNTIME)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expired(self):
|
||||||
|
return self.expiry and (self.expiry < timezone.now())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active(self):
|
def active(self):
|
||||||
try:
|
try:
|
||||||
return bool(self.activated)
|
return bool(self.activated) and not self.expired
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -52,9 +64,18 @@ class Inquiry(models.Model):
|
||||||
return qset[0]
|
return qset[0]
|
||||||
|
|
||||||
class Offer(models.Model):
|
class Offer(models.Model):
|
||||||
|
uuid = models.UUIDField(default=uuid.uuid4, unique=True)
|
||||||
inquiry = models.ForeignKey(Inquiry, models.PROTECT)
|
inquiry = models.ForeignKey(Inquiry, models.PROTECT)
|
||||||
establishment = models.ForeignKey(Establishment, models.PROTECT)
|
roomcategory = models.ForeignKey(RoomCategory, models.PROTECT)
|
||||||
nights = models.IntegerField()
|
departure = models.DateField()
|
||||||
comment = models.TextField(null=True, blank=True)
|
comment = models.TextField(null=True, blank=True)
|
||||||
accepted = models.BooleanField(default=False)
|
accepted = models.BooleanField(default=False)
|
||||||
hidden = models.BooleanField(default=False)
|
hidden = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def establishment(self):
|
||||||
|
return self.roomcategory.establishment
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nights(self):
|
||||||
|
return (self.departure - self.inquiry.arrival).days
|
|
@ -1,7 +1,7 @@
|
||||||
from django.views.generic import CreateView, UpdateView, View, ListView, DetailView
|
from django.views.generic import CreateView, UpdateView, View, ListView, DetailView
|
||||||
from django.shortcuts import redirect, get_object_or_404
|
from django.shortcuts import redirect, get_object_or_404
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.urls import reverse
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.contrib.gis.geos import Point
|
from django.contrib.gis.geos import Point
|
||||||
from django.contrib.gis.db.models.functions import Distance
|
from django.contrib.gis.db.models.functions import Distance
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -110,14 +110,16 @@ class OfferSelectionTableView(InConstructionMixin, ListView):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
inquiry = get_object_or_404(Inquiry, uuid=self.kwargs["uuid"])
|
inquiry = get_object_or_404(Inquiry, uuid=self.kwargs["uuid"])
|
||||||
|
return inquiry.offer_set.all()
|
||||||
|
|
||||||
class OfferCreationView(InConstructionMixin, PartnerProfileRequiredMixin, CreateView):
|
class OfferCreationView(InConstructionMixin, PartnerProfileRequiredMixin, CreateView):
|
||||||
model = Offer
|
model = Offer
|
||||||
template_name = "auction/offer_create.html"
|
template_name = "auction/offer_create.html"
|
||||||
fields = []
|
fields = ["roomcategory", "departure", "comment"]
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.establishment = self.get_establishment()
|
self.establishment = self.get_establishment()
|
||||||
|
self.inquiry = self.get_inquiry()
|
||||||
|
|
||||||
if not self.establishment:
|
if not self.establishment:
|
||||||
messages.warning(request, "Um bieten zu können, muss zuerst eine Unterkunft im System hinterlegt werden!")
|
messages.warning(request, "Um bieten zu können, muss zuerst eine Unterkunft im System hinterlegt werden!")
|
||||||
|
@ -135,12 +137,23 @@ class OfferCreationView(InConstructionMixin, PartnerProfileRequiredMixin, Create
|
||||||
else:
|
else:
|
||||||
return Establishment.objects.filter(**kwargs).first()
|
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):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context["establishment"] = self.establishment
|
context["establishment"] = self.establishment
|
||||||
context["inquiry"] = get_object_or_404(Inquiry, uuid=self.kwargs.get("inquiry"))
|
context["inquiry"] = self.inquiry
|
||||||
return context
|
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):
|
class BiddingListView(InConstructionMixin, PartnerProfileRequiredMixin, ListView):
|
||||||
model = Inquiry
|
model = Inquiry
|
||||||
template_name = "auction/bidding_list.html"
|
template_name = "auction/bidding_list.html"
|
||||||
|
@ -166,7 +179,8 @@ class BiddingListView(InConstructionMixin, PartnerProfileRequiredMixin, ListView
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
establishment = self.get_establishment()
|
establishment = self.get_establishment()
|
||||||
return Inquiry.objects.annotate(distance=Distance("destination_coords", establishment.coords)).exclude(activated__isnull=True)
|
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):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -35,3 +35,7 @@ JOKER_COUNTRIES = ["AT"]
|
||||||
CURRENCY_SYMBOL = "€"
|
CURRENCY_SYMBOL = "€"
|
||||||
CURRENCY_CODE = "EUR"
|
CURRENCY_CODE = "EUR"
|
||||||
CURRENCY_NAME = "Euro"
|
CURRENCY_NAME = "Euro"
|
||||||
|
|
||||||
|
# Run time of inquiries in days
|
||||||
|
|
||||||
|
INQUIRY_RUNTIME = 7
|
|
@ -1,3 +1,7 @@
|
||||||
from django.contrib import admin
|
from urlaubsauktion.admin import joker_admin as admin
|
||||||
|
|
||||||
# Register your models here.
|
from .models import PartnerProfile, Establishment, RoomCategory
|
||||||
|
|
||||||
|
admin.register(PartnerProfile)
|
||||||
|
admin.register(Establishment)
|
||||||
|
admin.register(RoomCategory)
|
|
@ -18,7 +18,7 @@ class Establishment(LocationMixin, ImageMixin, PhoneMixin):
|
||||||
superior = models.BooleanField("Superior", default=False)
|
superior = models.BooleanField("Superior", default=False)
|
||||||
verified = models.BooleanField(default=False)
|
verified = models.BooleanField(default=False)
|
||||||
active = models.BooleanField(default=True)
|
active = models.BooleanField(default=True)
|
||||||
featureset = models.OneToOneField(FeatureSet, models.PROTECT, null=True)
|
featureset = models.OneToOneField(FeatureSet, models.PROTECT, null=True, blank=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user(self):
|
def user(self):
|
||||||
|
@ -32,7 +32,16 @@ class Establishment(LocationMixin, ImageMixin, PhoneMixin):
|
||||||
def booking_set(self):
|
def booking_set(self):
|
||||||
return self.offer_set.filter(accepted=True)
|
return self.offer_set.filter(accepted=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def offer_set(self):
|
||||||
|
querysets = []
|
||||||
|
for roomcategory in self.roomcategory_set.all():
|
||||||
|
querysets.append(roomcategory.offer_set.all())
|
||||||
|
|
||||||
|
return querysets[0].union(*querysets[1:])
|
||||||
|
|
||||||
class RoomCategory(ImageMixin):
|
class RoomCategory(ImageMixin):
|
||||||
establishment = models.ForeignKey(Establishment, models.CASCADE)
|
establishment = models.ForeignKey(Establishment, models.CASCADE)
|
||||||
name = models.CharField(max_length=64)
|
name = models.CharField("Name", max_length=64)
|
||||||
average_price = models.DecimalField(max_digits=10, decimal_places=2)
|
average_price = models.DecimalField("Durchschnittspreis / Nacht", max_digits=10, decimal_places=2)
|
||||||
|
active = models.BooleanField(default=True)
|
|
@ -5,8 +5,8 @@ register = template.Library()
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def stars(number, superior=False, color=""):
|
def stars(number, superior=False, color=""):
|
||||||
number = int(number)
|
number = int(number)
|
||||||
if not 1 <= number <= 5:
|
if not 0 <= number <= 5:
|
||||||
raise ValueError("Number of stars must be between 1 and 5.")
|
raise ValueError("Number of stars must be between 0 and 5.")
|
||||||
|
|
||||||
output = ""
|
output = ""
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ def stars(number, superior=False, color=""):
|
||||||
def hearts(number, color=""):
|
def hearts(number, color=""):
|
||||||
number = int(number)
|
number = int(number)
|
||||||
if not 1 <= number <= 5:
|
if not 1 <= number <= 5:
|
||||||
raise ValueError("Number of hearts must be between 1 and 5.")
|
raise ValueError("Number of hearts must be between 0 and 5.")
|
||||||
|
|
||||||
output = ""
|
output = ""
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.urls import path, reverse_lazy
|
from django.urls import path, reverse_lazy
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
from .views import PartnerRegistrationView, PartnerProfileView, OffersListView, EstablishmentsListView, EstablishmentRequestView, PartnerDashboardView, EstablishmentVerificationView
|
from .views import PartnerRegistrationView, PartnerProfileView, OffersListView, EstablishmentsListView, EstablishmentRequestView, PartnerDashboardView, EstablishmentVerificationView, RoomCategoryListView
|
||||||
|
|
||||||
app_name = "partners"
|
app_name = "partners"
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ urlpatterns = [
|
||||||
path('register/', PartnerRegistrationView.as_view(), name="register"),
|
path('register/', PartnerRegistrationView.as_view(), name="register"),
|
||||||
path('profile/', PartnerProfileView.as_view(), name="profile"),
|
path('profile/', PartnerProfileView.as_view(), name="profile"),
|
||||||
path('establishments/', EstablishmentsListView.as_view(), name="establishments"),
|
path('establishments/', EstablishmentsListView.as_view(), name="establishments"),
|
||||||
|
path('establishments/<int:id>/', RoomCategoryListView.as_view(), name="roomcategories"),
|
||||||
path('establishments/validate/', EstablishmentVerificationView.as_view(), name="establishment_verify"),
|
path('establishments/validate/', EstablishmentVerificationView.as_view(), name="establishment_verify"),
|
||||||
path('establishments/register/', EstablishmentRequestView.as_view(), name="establishment_register"),
|
path('establishments/register/', EstablishmentRequestView.as_view(), name="establishment_register"),
|
||||||
path('offers/', OffersListView.as_view(), name="offers"),
|
path('offers/', OffersListView.as_view(), name="offers"),
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_list_or_404, redirect, get_object_or_404
|
from django.shortcuts import get_list_or_404, redirect, get_object_or_404
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
from .models import PartnerProfile, Establishment
|
from .models import PartnerProfile, Establishment, RoomCategory
|
||||||
from .mixins import PartnerProfileRequiredMixin
|
from .mixins import PartnerProfileRequiredMixin
|
||||||
from .forms import VerificationForm
|
from .forms import VerificationForm
|
||||||
|
|
||||||
|
@ -82,6 +82,46 @@ class EstablishmentsListView(InConstructionMixin, PartnerProfileRequiredMixin, L
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.request.user.partnerprofile.establishment_set.all()
|
return self.request.user.partnerprofile.establishment_set.all()
|
||||||
|
|
||||||
|
class RoomCategoryListView(InConstructionMixin, PartnerProfileRequiredMixin, CreateView, ListView):
|
||||||
|
model = RoomCategory
|
||||||
|
template_name = "partners/roomcategory_list.html"
|
||||||
|
fields = ["name", "average_price"]
|
||||||
|
|
||||||
|
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.establishment
|
||||||
|
return RoomCategory.objects.filter(establishment=establishment)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["establishment"] = self.establishment
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.establishment = self.establishment
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse_lazy("partners:roomcategories", args=[self.establishment.id])
|
||||||
|
|
||||||
class EstablishmentRequestView(InConstructionMixin, PartnerProfileRequiredMixin, CreateView):
|
class EstablishmentRequestView(InConstructionMixin, PartnerProfileRequiredMixin, CreateView):
|
||||||
model = Establishment
|
model = Establishment
|
||||||
template_name = "partners/establishment_register.html"
|
template_name = "partners/establishment_register.html"
|
||||||
|
@ -112,4 +152,4 @@ class EstablishmentVerificationView(SuperUserRequiredMixin, FormView):
|
||||||
|
|
||||||
messages.success(self.request, "Unterkunft %s bestätigt!" % eobj[0].name)
|
messages.success(self.request, "Unterkunft %s bestätigt!" % eobj[0].name)
|
||||||
|
|
||||||
return HttpResponseRedirect(resolve_url("partners:establishment_verify"))
|
return HttpResponseRedirect(reverse_lazy("partners:establishment_verify"))
|
|
@ -16,4 +16,5 @@ phonenumbers
|
||||||
googlemaps
|
googlemaps
|
||||||
Babel
|
Babel
|
||||||
staticmap
|
staticmap
|
||||||
|
django-mathfilters
|
||||||
git+https://kumig.it/kumisystems/PyInvoice
|
git+https://kumig.it/kumisystems/PyInvoice
|
|
@ -15,7 +15,11 @@
|
||||||
<div class="row d-flex justify-content-center">
|
<div class="row d-flex justify-content-center">
|
||||||
<div class="col-md-12 col-lg-12 col-lg-offset-2">
|
<div class="col-md-12 col-lg-12 col-lg-offset-2">
|
||||||
<h2>{% trans "Verfügbare Anfragen" %}</h2>
|
<h2>{% trans "Verfügbare Anfragen" %}</h2>
|
||||||
<div>für {{ establishment.name }}</div>
|
<div>für <select id="id_establishment" name="establishment" class="">
|
||||||
|
{% for e in request.user.partnerprofile.establishment_set.all %}
|
||||||
|
<option value="{{ e.id }}" {% if e == establishment %}selected{% endif %}>{{ e.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select> </div>
|
||||||
<table id="biddingtable">
|
<table id="biddingtable">
|
||||||
<thead>
|
<thead>
|
||||||
<td>ID</td>
|
<td>ID</td>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load mapimage %}
|
{% load mapimage %}
|
||||||
{% load dbsetting %}
|
{% load dbsetting %}
|
||||||
|
{% load mathfilters %}
|
||||||
{% block "content" %}
|
{% block "content" %}
|
||||||
<!--================== PAGE-COVER ================-->
|
<!--================== PAGE-COVER ================-->
|
||||||
<section class="page-cover" id="cover-hotel-booking">
|
<section class="page-cover" id="cover-hotel-booking">
|
||||||
|
@ -51,6 +52,10 @@
|
||||||
<td>{% trans "Anreisedatum" %}</td>
|
<td>{% trans "Anreisedatum" %}</td>
|
||||||
<td>{{ inquiry.arrival|date:"SHORT_DATE_FORMAT" }}</td>
|
<td>{{ inquiry.arrival|date:"SHORT_DATE_FORMAT" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Aufenthaltsdauer" %}</td>
|
||||||
|
<td>{% if inquiry.min_nights == 0 %}Egal!{% elif inquiry.min_nights == 1 %}Kurztrip (2 – 3 Nächte){% else %}min. 3 Nächte{% endif %}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans "Erwachsene" %}</td>
|
<td>{% trans "Erwachsene" %}</td>
|
||||||
<td>{{ inquiry.adults }}</td>
|
<td>{{ inquiry.adults }}</td>
|
||||||
|
@ -112,7 +117,9 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{% trans "Zimmerkategorie" %}</label>
|
<label>{% trans "Zimmerkategorie" %}</label>
|
||||||
<select class="form-control" id="id_roomcategory" name="roomcategory">
|
<select class="form-control" id="id_roomcategory" name="roomcategory">
|
||||||
<option value="0">Standardzimmer</option>
|
{% for roomcategory in establishment.roomcategory_set.all %}
|
||||||
|
<option value="{{ roomcategory.id }}">{{ roomcategory.name }} (€ {{ roomcategory.average_price }}/Nacht – {{ inquiry.budget|intdiv:roomcategory.average_price }} Nächte)</option>
|
||||||
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- end columns -->
|
</div><!-- end columns -->
|
||||||
|
@ -145,10 +152,10 @@
|
||||||
</div><!-- end row -->
|
</div><!-- end row -->
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label><input type="checkbox" {% if request.user.is_authenticated %}required{% else %}disabled{% endif %} id="id_terms" name="terms"> {% trans "Ich erkläre mich einverstanden mit den" %} <a href="#">{% trans "Allgemeinen Geschäftsbedingungen" %}</a> {% trans "und der" %} <a href="#">{% trans "Datenschutzerklärung" %}</a>. Ich verstehe insbesondere, dass ich an dieses Angebot gebunden bin und dieses nach Annahme durch die anfragende Person nicht mehr zurückziehen kann.</label>
|
<label><input type="checkbox" required id="id_terms" name="terms"> {% trans "Ich erkläre mich einverstanden mit den" %} <a href="#">{% trans "Allgemeinen Geschäftsbedingungen" %}</a> {% trans "und der" %} <a href="#">{% trans "Datenschutzerklärung" %}</a>. Ich verstehe insbesondere, dass ich an dieses Angebot gebunden bin und dieses nach Annahme durch die anfragende Person nicht mehr zurückziehen kann.</label>
|
||||||
</div><!-- end checkbox -->
|
</div><!-- end checkbox -->
|
||||||
<div class="col-md-12 text-center" id="result_msg"></div>
|
<div class="col-md-12 text-center" id="result_msg"></div>
|
||||||
<button type="submit" onclick="setPaymentMethod(); return true;" class="btn btn-orange" name="submit" id="submit">{% trans "Zahlung durchführen" %}</button>
|
<button type="submit" class="btn btn-orange" name="submit" id="submit">{% trans "Angebot erstellen" %}</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div><!-- end columns -->
|
</div><!-- end columns -->
|
||||||
|
|
|
@ -14,7 +14,13 @@
|
||||||
<div class="col-md-12 col-lg-8 col-lg-offset-2">
|
<div class="col-md-12 col-lg-8 col-lg-offset-2">
|
||||||
<div class="payment-success-text">
|
<div class="payment-success-text">
|
||||||
<h1>Angebote vergleichen</h1>
|
<h1>Angebote vergleichen</h1>
|
||||||
|
{% if object.offer_set.all %}
|
||||||
<div id="offers" style="text-align: center;"></div>
|
<div id="offers" style="text-align: center;"></div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-warning alert-dismissible text-center" role="alert">
|
||||||
|
Leider sind zu deiner Anfrage bislang noch keine Angebote eingegangen. Komm doch einfach später nochmal vorbei!
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div><!-- end columns -->
|
</div><!-- end columns -->
|
||||||
</div><!-- end row -->
|
</div><!-- end row -->
|
||||||
|
|
|
@ -6,30 +6,40 @@
|
||||||
{
|
{
|
||||||
from: "",
|
from: "",
|
||||||
tableHeader: [
|
tableHeader: [
|
||||||
['Habbo Hotel<br/>{% autoescape off %}{% stars 3 1 orange %}{% endautoescape %}<br/><img style="max-height:100px;max-width:100%;" src="https://logoeps.com/wp-content/uploads/2012/12/habbo-logo-vector.png"></img>'],
|
{% for offer in object_list %}['{{ offer.roomcategory.establishment.name }}<br/>{% autoescape off %}{% stars offer.roomcategory.establishment.stars offer.roomcategory.establishment.superior orange %}{% endautoescape %}{% if offer.roomcategory.establishment.image %}<br/><img style="max-height:100px;max-width:100%;" src="{{ offer.roomcategory.establishment.image.url }}"></img>{% endif %}'],{% endfor %}
|
||||||
['Kumi Systems<br/>{% autoescape off %}{% stars 1 0 orange %}{% endautoescape %}<br/><img style="max-height:100px;max-width:100%;" src="https://kumi.systems/wp-content/uploads/2020/12/schrift_logo.png"></img>'],
|
|
||||||
],
|
],
|
||||||
rows : [
|
rows : [
|
||||||
{
|
{
|
||||||
rowVal: [["1. Mai 2021", "1. Mai 2021"],["3. Mai 2021", "10. Mai 2021"],["2 Nächte", "9 Nächte"]],
|
rowVal: [
|
||||||
|
[{% for offer in object_list %}'{{ offer.inquiry.arrival }}',{% endfor %}],
|
||||||
|
[{% for offer in object_list %}'{{ offer.departure }}',{% endfor %}],
|
||||||
|
[{% for offer in object_list %}'{{ offer.nights }} Nächte',{% endfor %}]
|
||||||
|
],
|
||||||
rowDesc: ["Anreise", "Abreise", "Dauer"]
|
rowDesc: ["Anreise", "Abreise", "Dauer"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rowVal: [[{% autoescape off %}'{% hearts 3 red %} (304)', '{% hearts 5 red %} (1)'{% endautoescape %}]],
|
rowVal: [
|
||||||
|
[{% for offer in object_list %}{% autoescape off %}'{% hearts 3 red %} (304)'{% endautoescape %},{% endfor %}]
|
||||||
|
],
|
||||||
rowDesc: ["Bewertungen"]
|
rowDesc: ["Bewertungen"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rowVal: [['Doppelzimmer Luxus', 'Wohnzimmer'], ["1 King-Size Bett", "1 Couch"]],
|
rowVal: [
|
||||||
|
[{% for offer in object_list %}'{{ offer.roomcategory.name }}',{% endfor %}],
|
||||||
|
[{% for offer in object_list %}' ',{% endfor %}]
|
||||||
|
],
|
||||||
rowDesc: ["Zimmerart", "Betten"]
|
rowDesc: ["Zimmerart", "Betten"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rowVal: [['Romantikpaket inkl. Frühstück am Bett, 2x 60 Minuten Hot-Stone-Massage, 0,75l Prosecco, Obstschale, Zugang zum Spa', 'Gratis Arbeitsgelegenheit inklusive!']],
|
rowVal: [
|
||||||
|
[{% for offer in object_list %}'{{ offer.comment }}',{% endfor %}]
|
||||||
|
],
|
||||||
rowDesc: ["Zusätzliche Angaben"]
|
rowDesc: ["Zusätzliche Angaben"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rowVal: [
|
rowVal: [
|
||||||
[200, 200],
|
[{% for offer in object_list %}'€ {{ offer.inquiry.budget }}',{% endfor %}],
|
||||||
['<button class="btn btn-orange btn-block">Zahlungspflichtig buchen!</button>', '<button class="btn btn-orange btn-block">Zahlungspflichtig buchen!</button>']
|
[{% for offer in object_list %}'<a href="#{{ offer.uuid }}" class="btn btn-orange btn-block">Zahlungspflichtig buchen!</button>',{% endfor %}]
|
||||||
],
|
],
|
||||||
rowDesc: ["Fixpreis", ""]
|
rowDesc: ["Fixpreis", ""]
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,10 @@
|
||||||
<td>{% trans "Anreisedatum" %}</td>
|
<td>{% trans "Anreisedatum" %}</td>
|
||||||
<td>{{ object.arrival|date:"SHORT_DATE_FORMAT" }}</td>
|
<td>{{ object.arrival|date:"SHORT_DATE_FORMAT" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Aufenthaltsdauer" %}</td>
|
||||||
|
<td>{% if object.min_nights == 0 %}Egal!{% elif object.min_nights == 1 %}Kurztrip (2 – 3 Nächte){% else %}min. 3 Nächte{% endif %}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans "Erwachsene" %}</td>
|
<td>{% trans "Erwachsene" %}</td>
|
||||||
<td>{{ object.adults }}</td>
|
<td>{{ object.adults }}</td>
|
||||||
|
@ -254,7 +258,7 @@
|
||||||
<img src="{% static "frontend/images/paypal.png" %}" class="img-fluid" alt="stripe" />
|
<img src="{% static "frontend/images/paypal.png" %}" class="img-fluid" alt="stripe" />
|
||||||
<div class="paypal-text">
|
<div class="paypal-text">
|
||||||
<p>{% trans "Die Zahlung per Kreditkarte wird durch unseren Zahlungsdienstleister Stripe abgewickelt." %}</p>
|
<p>{% trans "Die Zahlung per Kreditkarte wird durch unseren Zahlungsdienstleister Stripe abgewickelt." %}</p>
|
||||||
<p>{% trans "Der gebotene Betrag wird autorisiert und erst bei verbindlicher Buchung einer Reise tatsächlich von Ihrer Kreditkarte abgebucht." %}</p>
|
<p>{% trans "Der gebotene Betrag wird autorisiert und erst bei verbindlicher Buchung einer Reise tatsächlich von Ihrer Kreditkarte abgebucht. Bei Auslaufen oder Stornierung Ihres Angebots wird der Betrag ohne Abzug wieder freigegeben." %}</p>
|
||||||
</div><!-- end paypal-text -->
|
</div><!-- end paypal-text -->
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
|
@ -28,19 +28,29 @@
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% for inquiry in object_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="dash-list-icon booking-list-date"><div class="b-date"><h3>12</h3><p>April 2021</p></div></td>
|
<td class="dash-list-icon booking-list-date"><div class="b-date"><h3>{{ inquiry.arrival.day }}</h3><p>{{ inquiry.arrival|date:"E Y" }}</p></div></td>
|
||||||
<td class="dash-list-text booking-list-detail">
|
<td class="dash-list-text booking-list-detail">
|
||||||
<h3>Habbo Hotel</h3>
|
<h3>{% if inquiry.accepted %}{{ inquiry.accepted.name }} ({{ inquiry.destination_name }}){% else %}{{ inquiry.destination_name }}{% endif %}</h3>
|
||||||
<ul class="list-unstyled booking-info">
|
<ul class="list-unstyled booking-info">
|
||||||
<li><span>Ankunft:</span> 12. April 2021</li>
|
<li><span>Ankunft:</span> {{ inquiry.arrival }}</li>
|
||||||
<li><span>Abreise:</span> 19. April 2021</li>
|
<li><span>{% if inquiry.accepted %}Abreise{% else %}Dauer{% endif %}:</span> {% if inquiry.accepted %}{{ inquiry.accepted.departure }}{% elif inquiry.min_nights == 0 %}Egal!{% elif inquiry.min_nights == 1 %}Kurztrip (2 – 3 Nächte){% elif inquiry.min_nights == 2 %}min. 3 Nächte{% endif %}</li>
|
||||||
<li><span>Preis:</span> € 500,00</li>
|
<li><span>Preis:</span> € {{ inquiry.budget }}</li>
|
||||||
|
<li><span>Status:</span> {% if inquiry.accepted %}Fixiert{% elif inquiry.active %}In Gebotsphase ({{ inquiry.offer_set.all|length }} Gebote){% else %}Inaktiv{% endif %}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<button class="btn btn-orange">Details</button>
|
{% if inquiry.accepted %}
|
||||||
|
<button class="btn btn-orange">Buchungsdetails</button>
|
||||||
|
{% elif inquiry.active %}
|
||||||
|
<a href="{% url "auction:offer_selection" inquiry.uuid %}" class="btn btn-orange">Gebote ansehen</a>
|
||||||
|
{% elif inquiry.expired %}
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url "auction:process_inquiry" inquiry.uuid %}" class="btn btn-orange">Zahlung abschließen</a>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="dash-list-btn"><button class="btn btn-orange">Stornieren</button><button class="btn">PDF-Bestätigung</button></td>
|
<td class="dash-list-btn"><button class="btn btn-orange">Stornieren</button><button class="btn">PDF-Bestätigung</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div><!-- end table-responsive -->
|
</div><!-- end table-responsive -->
|
||||||
|
|
|
@ -35,9 +35,9 @@
|
||||||
<li><span>Buchungen:</span> {{ establishment.bookings | length }}</li>
|
<li><span>Buchungen:</span> {{ establishment.bookings | length }}</li>
|
||||||
<li><span>Status:</span> {% if establishment.is_active %}aktiv{% else %}inaktiv{% endif %}</li>
|
<li><span>Status:</span> {% if establishment.is_active %}aktiv{% else %}inaktiv{% endif %}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<button class="btn btn-orange">Details</button>
|
<a href="{% url "partners:roomcategories" establishment.id %}" class="btn btn-orange">Zimmer und Ausstattung bearbeiten</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="dash-list-btn"><a href="{% url "partners:bidding" 1 %}" class="btn btn-orange">Bieten</a><button class="btn">Deaktivieren</button></td>
|
<td class="dash-list-btn"><a href="{% url "auction:bidding" establishment.id %}" class="btn btn-orange">Bieten</a><button class="btn">Deaktivieren</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "clients/base.html" %}
|
{% extends "partners/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap4 %}
|
{% load bootstrap4 %}
|
||||||
{% block "dashboardcontent" %}
|
{% block "dashboardcontent" %}
|
||||||
|
|
71
templates/partners/roomcategory_list.html
Normal file
71
templates/partners/roomcategory_list.html
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
{% extends "partners/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap4 %}
|
||||||
|
{% block "dashboardcontent" %}
|
||||||
|
<div class="col-12 col-md-10 col-lg-10 dashboard-content booking-trips">
|
||||||
|
<h2 class="dash-content-title">Deine Zimmerkategorien</h2>
|
||||||
|
<div class="dash-content-title"><small>für {{ establishment.name }}</small></div>
|
||||||
|
<div class="dash-content-title"><button class="btn" data-toggle="modal" data-target="#create-category">Kategorie hinzufügen</button></div>
|
||||||
|
<div class="dashboard-listing booking-listing">
|
||||||
|
<div class="dash-listing-heading">
|
||||||
|
<div class="custom-radio">
|
||||||
|
<input type="radio" id="radio01" name="radio" checked/>
|
||||||
|
<label for="radio01"><span></span>Alle Kategorien</label>
|
||||||
|
</div><!-- end custom-radio -->
|
||||||
|
|
||||||
|
<div class="custom-radio">
|
||||||
|
<input type="radio" id="radio02" name="radio" />
|
||||||
|
<label for="radio02"><span></span>Aktiv</label>
|
||||||
|
</div><!-- end custom-radio -->
|
||||||
|
|
||||||
|
<div class="custom-radio">
|
||||||
|
<input type="radio" id="radio03" name="radio" />
|
||||||
|
<label for="radio03"><span></span>Inaktiv</label>
|
||||||
|
</div><!-- end custom-radio -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<tbody>
|
||||||
|
{% for roomcategory in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td class="dash-list-text booking-list-detail">
|
||||||
|
<h3>{{ roomcategory.name }}</h3>
|
||||||
|
<ul class="list-unstyled booking-info">
|
||||||
|
<li><span>Durchschnittspreis:</span> {{ roomcategory.average_price }}</li>
|
||||||
|
<li><span>Buchungen:</span> {{ roomcategory.bookings | length }}</li>
|
||||||
|
<li><span>Status:</span> {% if roomcategory.active %}aktiv{% else %}inaktiv{% endif %}</li>
|
||||||
|
</ul>
|
||||||
|
<a href="{% url "partners:roomcategories" establishment.id %}" class="btn btn-orange">Zimmer und Ausstattung bearbeiten</button>
|
||||||
|
</td>
|
||||||
|
<td class="dash-list-btn"><a href="{% url "auction:bidding" establishment.id %}" class="btn btn-orange">Bieten</a><button class="btn">Deaktivieren</button></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div><!-- end table-responsive -->
|
||||||
|
</div><!-- end booking-listings -->
|
||||||
|
|
||||||
|
</div><!-- end columns -->
|
||||||
|
{% endblock %}
|
||||||
|
{% block "modal" %}
|
||||||
|
<div id="create-category" class="modal custom-modal fade" role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">Profildaten</h3>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
|
</div><!-- end modal-header -->
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% bootstrap_form form %}
|
||||||
|
<button class="btn btn-orange btn-block">Anwenden</button>
|
||||||
|
</form>
|
||||||
|
</div><!-- end modal-bpdy -->
|
||||||
|
</div><!-- end modal-content -->
|
||||||
|
</div><!-- end modal-dialog -->
|
||||||
|
</div><!-- end edit-profile -->
|
||||||
|
{% endblock %}
|
|
@ -14,6 +14,7 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django.contrib.gis',
|
||||||
'phonenumber_field',
|
'phonenumber_field',
|
||||||
'localauth',
|
'localauth',
|
||||||
'public',
|
'public',
|
||||||
|
@ -24,6 +25,7 @@ INSTALLED_APPS = [
|
||||||
'auction',
|
'auction',
|
||||||
'bootstrap4',
|
'bootstrap4',
|
||||||
'django_countries',
|
'django_countries',
|
||||||
|
'mathfilters',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
Loading…
Reference in a new issue