Quotation returned after succesful booking

This commit is contained in:
Ruidy Nemausat 2019-12-03 13:39:43 +01:00
parent cf9fb67232
commit be7bdec84f
6 changed files with 139 additions and 114 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ rental/__pycache__
rental/migrations rental/migrations
villafleurie/__pycache__ villafleurie/__pycache__
.DS_Store .DS_Store
.vscode/

102
README.md
View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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 %}

View file

@ -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)