mirror of
https://github.com/rjNemo/villafleurie
synced 2026-06-12 13:26:47 +00:00
Quotation returned after succesful booking
This commit is contained in:
parent
cf9fb67232
commit
be7bdec84f
6 changed files with 139 additions and 114 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,3 +4,4 @@ rental/__pycache__
|
||||||
rental/migrations
|
rental/migrations
|
||||||
villafleurie/__pycache__
|
villafleurie/__pycache__
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vscode/
|
||||||
|
|
|
||||||
102
README.md
102
README.md
|
|
@ -7,76 +7,88 @@
|
||||||
## Projet
|
## Projet
|
||||||
|
|
||||||
Créer un site vitrine présentant l'activité de Villafleurie :
|
Créer un site vitrine présentant l'activité de Villafleurie :
|
||||||
* location de logements : T2 et T3
|
|
||||||
* navette entre l'aéroport, la gare maritime et la résidence
|
- location de logements : T2 et T3
|
||||||
* découverte de l'archipel
|
- navette entre l'aéroport, la gare maritime et la résidence
|
||||||
|
- découverte de l'archipel
|
||||||
|
|
||||||
Le visiteur doit pouvoir :
|
Le visiteur doit pouvoir :
|
||||||
* connaitre les disponibilité de chaque logement,
|
|
||||||
* leur tarif,
|
- connaitre les disponibilité de chaque logement,
|
||||||
* pouvoir contacter les propriétaires,
|
- leur tarif,
|
||||||
* et pouvoir réserver
|
- pouvoir contacter les propriétaires,
|
||||||
|
- et pouvoir réserver
|
||||||
|
|
||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
### Pages
|
### Pages
|
||||||
|
|
||||||
1. Page d'accueil
|
1. Page d'accueil
|
||||||
* Landing page
|
|
||||||
* CTA = "Réserver maintenant"
|
- Landing page
|
||||||
|
- CTA = "Réserver maintenant"
|
||||||
|
|
||||||
2. Page logement
|
2. Page logement
|
||||||
* photos,
|
|
||||||
* disponibilités,
|
- photos,
|
||||||
* tarif pour la période sélectionnée,
|
- disponibilités,
|
||||||
|
- tarif pour la période sélectionnée,
|
||||||
|
|
||||||
3. Page réservation
|
3. Page réservation
|
||||||
* Entrer ses coordonnées
|
|
||||||
* Prépayer la réservation ou la caution,
|
- Entrer ses coordonnées
|
||||||
|
- Prépayer la réservation ou la caution,
|
||||||
|
|
||||||
4. Page remerciements
|
4. Page remerciements
|
||||||
* Expliquer les prochaines étapes
|
|
||||||
|
- Expliquer les prochaines étapes
|
||||||
|
|
||||||
5. Page contact
|
5. Page contact
|
||||||
6. Page légale
|
6. Page légale
|
||||||
|
|
||||||
### Données
|
### Données
|
||||||
|
|
||||||
1. Logement :
|
1. Logement :
|
||||||
* nom,
|
|
||||||
* photos,
|
- nom,
|
||||||
* description,
|
- photos,
|
||||||
* calendrier,
|
- description,
|
||||||
* tarif
|
- calendrier,
|
||||||
|
- tarif
|
||||||
|
|
||||||
2. Client :
|
2. Client :
|
||||||
* nom,
|
|
||||||
* mail,
|
- nom,
|
||||||
* téléphone,
|
- mail,
|
||||||
* _réservation_
|
- téléphone,
|
||||||
|
- _réservation_
|
||||||
|
|
||||||
3. Réservation :
|
3. Réservation :
|
||||||
* _client_,
|
|
||||||
* _logement_,
|
- _client_,
|
||||||
* dates de calendrier,
|
- _logement_,
|
||||||
|
- dates de calendrier,
|
||||||
|
|
||||||
4. Témoignages :
|
4. Témoignages :
|
||||||
* _client_,
|
|
||||||
* _reservation_,
|
- _client_,
|
||||||
* témoignage
|
- _reservation_,
|
||||||
|
- témoignage
|
||||||
|
|
||||||
## TO DO
|
## TO DO
|
||||||
|
|
||||||
* Page service : navette + location
|
- Page service : navette + location
|
||||||
* Gestion du calendrier
|
- Gestion du calendrier
|
||||||
..* Google calendar pour afficher les disponibilités
|
.._ Google calendar pour afficher les disponibilités
|
||||||
.. * Check si les dates choisies sont libres
|
.._ Check si les dates choisies sont libres
|
||||||
* Module calcul prix réservation, afficher le résultat sur la page remerciement
|
- Envoyer devis réservation par mail et notification aux hôtes
|
||||||
ou envoyer devis par mail …
|
- Ajout page/module de paiement
|
||||||
* Ajout page/module de paiement
|
- ajouter les témoignages depuis Booking, AirBnb, ajouter le lien
|
||||||
* ajouter les témoignages depuis Booking, AirBnb, ajouter le lien
|
- changer la couleur des liens hypertextes
|
||||||
* changer la couleur des liens hypertextes
|
- changer l'adresse de l'admin
|
||||||
* changer l'adresse de l'admin
|
- ajouter un diaporama en bas de page de location ?
|
||||||
* ajouter un diaporama en bas de page de location ?
|
- deploy on Heroku or somewhere else … don't care
|
||||||
* deploy on Heroku or somewhere else … don't care
|
- change placeholders for dates
|
||||||
* change placeholders for dates
|
- factoriser le code de réservation
|
||||||
* factoriser le code de réservation
|
|
||||||
|
|
||||||
|
|
||||||
## BUGS
|
## BUGS
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ class Image(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.alt
|
return self.alt
|
||||||
|
|
||||||
img=models.ImageField(upload_to='img/', null=True,blank=True)
|
img = models.ImageField(upload_to='img/', null=True, blank=True)
|
||||||
alt=models.CharField(max_length=100)
|
alt = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
class Place(models.Model):
|
class Place(models.Model):
|
||||||
|
|
@ -17,17 +17,18 @@ class Place(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
name=models.CharField(max_length=10, unique=True)
|
name = models.CharField(max_length=10, unique=True)
|
||||||
description=models.TextField(blank=True)
|
description = models.TextField(blank=True)
|
||||||
info=models.TextField(blank=True)
|
info = models.TextField(blank=True)
|
||||||
subname=models.CharField(max_length=100, blank=True)
|
subname = models.CharField(max_length=100, blank=True)
|
||||||
tagline=models.CharField(max_length=100, blank=True)
|
tagline = models.CharField(max_length=100, blank=True)
|
||||||
price=models.DecimalField(max_digits=6, decimal_places=2, null=True)
|
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
|
||||||
surface=models.IntegerField(null=True,blank=True)
|
surface = models.IntegerField(null=True, blank=True)
|
||||||
beds=models.IntegerField(null=True,blank=True)
|
beds = models.IntegerField(null=True, blank=True)
|
||||||
max_occupation=models.IntegerField(null=True,blank=True)
|
max_occupation = models.IntegerField(null=True, blank=True)
|
||||||
thumbnail=models.ForeignKey(Image, on_delete=models.CASCADE, blank=True, null=True)
|
thumbnail = models.ForeignKey(
|
||||||
images=models.ManyToManyField(Image, related_name = "places", blank=True)
|
Image, on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
images = models.ManyToManyField(Image, related_name="places", blank=True)
|
||||||
|
|
||||||
|
|
||||||
class Guest(models.Model):
|
class Guest(models.Model):
|
||||||
|
|
@ -37,9 +38,9 @@ class Guest(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
name=models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
email=models.EmailField(unique=True)
|
email = models.EmailField(unique=True)
|
||||||
phone=PhoneNumberField(blank=True)
|
phone = PhoneNumberField(blank=True)
|
||||||
|
|
||||||
|
|
||||||
class Reservation(models.Model):
|
class Reservation(models.Model):
|
||||||
|
|
@ -49,23 +50,26 @@ class Reservation(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Réservation du {} par {}".format(self.place, self.guest)
|
return "Réservation du {} par {}".format(self.place, self.guest)
|
||||||
|
|
||||||
place=models.ForeignKey(Place,on_delete=models.CASCADE)
|
place = models.ForeignKey(Place, on_delete=models.CASCADE)
|
||||||
guest=models.ForeignKey(Guest,on_delete=models.CASCADE)
|
guest = models.ForeignKey(Guest, on_delete=models.CASCADE)
|
||||||
message=models.TextField(blank=True)
|
message = models.TextField(blank=True)
|
||||||
start=models.DateField()
|
start = models.DateField()
|
||||||
end=models.DateField()
|
end = models.DateField()
|
||||||
|
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
|
||||||
|
|
||||||
|
|
||||||
class Testimonial(models.Model):
|
class Testimonial(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name="Témoignage"
|
verbose_name = "Témoignage"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.author
|
return f"Témoignage de {self.author}"
|
||||||
|
|
||||||
author=models.CharField(max_length=100)
|
author = models.CharField(max_length=100)
|
||||||
text=models.TextField()
|
text = models.TextField()
|
||||||
picture=models.ImageField(upload_to='img/',null=True,blank=True)
|
picture = models.ImageField(upload_to='img/', null=True, blank=True)
|
||||||
link=models.URLField(null=True,blank=True)
|
link = models.URLField(null=True, blank=True)
|
||||||
guest=models.OneToOneField(Guest,on_delete=models.CASCADE,blank=True,null=True)
|
guest = models.OneToOneField(
|
||||||
reservation=models.OneToOneField(Reservation,on_delete=models.CASCADE,blank=True,null=True)
|
Guest, on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
reservation = models.OneToOneField(
|
||||||
|
Reservation, on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
"""
|
def get_reservation_price(place, start, end):
|
||||||
Compute booking price as a function of place and dates
|
"""
|
||||||
"""
|
Compute booking price as a function of place and dates
|
||||||
from models import Place
|
"""
|
||||||
from datetime import *
|
nights = (end - start).days
|
||||||
from django.shortcuts import get_object_or_404
|
return place.price * nights
|
||||||
|
|
||||||
place_name = 'T2'
|
|
||||||
start = datetime(2019, 11, 14)
|
|
||||||
end = datetime(2019, 11, 20)
|
|
||||||
|
|
||||||
stay = end-start
|
if __name__ == '__main__':
|
||||||
nights = stay.days
|
from rental.models import Place
|
||||||
|
from datetime import *
|
||||||
def quotation(place_name, nights):
|
from django.shortcuts import get_object_or_404
|
||||||
|
place_name = 'T2'
|
||||||
place = get_object_or_404(Place, name=place_name)
|
place = get_object_or_404(Place, name=place_name)
|
||||||
return place.price_per_night * (end - start)
|
start = datetime(2019, 11, 14)
|
||||||
|
end = datetime(2019, 11, 20)
|
||||||
x = quotation(place_name, nights)
|
x = get_reservation_price(place_name, start, end)
|
||||||
print(x)
|
print(x)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,24 @@
|
||||||
{% extends 'rental/base.html' %}
|
{% extends 'rental/base.html' %} {% load static %} {% block content %}
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<section class="intro-single">
|
<section class="intro-single">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 col-lg-8">
|
<div class="col-md-12 col-lg-8">
|
||||||
<div class="title-single-box">
|
<div class="title-single-box">
|
||||||
<h1 class="title-single">Merci pour votre réservation </h1>
|
<h1 class="title-single">Merci pour votre réservation</h1>
|
||||||
<span class="color-text-a">Nous avons enregistré la réservation de {{ guest.name }} du {{ place.name }}.<br/> Nous nous recontactons rapidement ! </span>
|
<span class="color-text-a"
|
||||||
|
>Nous avons enregistré la réservation du {{reservation.place.name}}
|
||||||
|
sous le nom de {{reservation.guest.name}} pour un montant de
|
||||||
|
{{reservation.price}}.<br />
|
||||||
|
Nous nous recontactons rapidement !
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12 col-lg-4">
|
<div class="col-md-12 col-lg-4">
|
||||||
<nav aria-label="breadcrumb" class="breadcrumb-box d-flex justify-content-lg-end">
|
<nav
|
||||||
|
aria-label="breadcrumb"
|
||||||
|
class="breadcrumb-box d-flex justify-content-lg-end"
|
||||||
|
>
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'rental:index' %}">Accueil</a>
|
<a href="{% url 'rental:index' %}">Accueil</a>
|
||||||
|
|
@ -31,14 +36,15 @@
|
||||||
<div class="property-summary">
|
<div class="property-summary">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="col-md-12 mb-1">
|
<div class="col-md-12 mb-1">
|
||||||
<a href="{% url 'rental:index' %}"><button class="btn btn-a">Retour à l'accueil</button></a>
|
<a href="{% url 'rental:index' %}"
|
||||||
</div>
|
><button class="btn btn-a">Retour à l'accueil</button></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,15 @@ from django.urls import reverse_lazy
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from .forms import ReservationForm
|
from .forms import ReservationForm
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
|
from rental.pricing import get_reservation_price
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
places = Place.objects.all()
|
places = Place.objects.all()
|
||||||
temoignages = Testimonial.objects.all()
|
temoignages = Testimonial.objects.all()
|
||||||
context = {
|
context = {
|
||||||
'places' : places,
|
'places': places,
|
||||||
'temoignages' : temoignages
|
'temoignages': temoignages
|
||||||
}
|
}
|
||||||
return render(request, 'rental/index.html', context)
|
return render(request, 'rental/index.html', context)
|
||||||
|
|
||||||
|
|
@ -24,8 +25,8 @@ def liste_location(request):
|
||||||
imgs = place.images.all()
|
imgs = place.images.all()
|
||||||
images.append(imgs)
|
images.append(imgs)
|
||||||
context = {
|
context = {
|
||||||
'places' : places,
|
'places': places,
|
||||||
'images' : images
|
'images': images
|
||||||
}
|
}
|
||||||
return render(request, 'rental/list_place.html', context)
|
return render(request, 'rental/list_place.html', context)
|
||||||
|
|
||||||
|
|
@ -34,11 +35,12 @@ def location(request, place_name='T2'):
|
||||||
place = get_object_or_404(Place, name=place_name)
|
place = get_object_or_404(Place, name=place_name)
|
||||||
images = place.images.all()
|
images = place.images.all()
|
||||||
context = {
|
context = {
|
||||||
'place' : place,
|
'place': place,
|
||||||
'images' : images
|
'images': images
|
||||||
}
|
}
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = ReservationForm(request.POST)#, error_class=ParagraphErrorList)
|
# , error_class=ParagraphErrorList)
|
||||||
|
form = ReservationForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
name = form.cleaned_data['name']
|
name = form.cleaned_data['name']
|
||||||
email = form.cleaned_data['email']
|
email = form.cleaned_data['email']
|
||||||
|
|
@ -58,16 +60,17 @@ def location(request, place_name='T2'):
|
||||||
guest = guest.first()
|
guest = guest.first()
|
||||||
|
|
||||||
place = get_object_or_404(Place, name=place_name)
|
place = get_object_or_404(Place, name=place_name)
|
||||||
|
price = get_reservation_price(place, start, end)
|
||||||
reservation = Reservation.objects.create(
|
reservation = Reservation.objects.create(
|
||||||
guest=guest,
|
guest=guest,
|
||||||
place=place,
|
place=place,
|
||||||
message=message,
|
message=message,
|
||||||
start=start,
|
start=start,
|
||||||
end=end
|
end=end,
|
||||||
|
price=price
|
||||||
)
|
)
|
||||||
context = {
|
context = {
|
||||||
'guest': guest,
|
'reservation': reservation
|
||||||
'place': place
|
|
||||||
}
|
}
|
||||||
return render(request, 'rental/merci.html', context)
|
return render(request, 'rental/merci.html', context)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
|
|
@ -82,7 +85,8 @@ def location(request, place_name='T2'):
|
||||||
|
|
||||||
def reservation(request):
|
def reservation(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = ReservationForm(request.POST)#, error_class=ParagraphErrorList)
|
# , error_class=ParagraphErrorList)
|
||||||
|
form = ReservationForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
name = form.cleaned_data['name']
|
name = form.cleaned_data['name']
|
||||||
email = form.cleaned_data['email']
|
email = form.cleaned_data['email']
|
||||||
|
|
@ -117,7 +121,7 @@ def reservation(request):
|
||||||
form.errors['internal'] = "Une erreur interne est apparue. Merci de recommencer votre requête."
|
form.errors['internal'] = "Une erreur interne est apparue. Merci de recommencer votre requête."
|
||||||
else:
|
else:
|
||||||
form = ReservationForm()
|
form = ReservationForm()
|
||||||
context = {'form' : form}
|
context = {'form': form}
|
||||||
context['errors'] = form.errors.items()
|
context['errors'] = form.errors.items()
|
||||||
return render(request, 'rental/reservation.html', context)
|
return render(request, 'rental/reservation.html', context)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue