minor advance in booking system

This commit is contained in:
Ruidy Nemausat 2019-12-06 17:04:18 +01:00
parent c412e2abdc
commit 527e7fd973
7 changed files with 291 additions and 143 deletions

1
.gitignore vendored
View file

@ -8,4 +8,5 @@ rental/static/
.vscode/
Procfile
heroku.yml
rental/client_secrets.json

1
calendar.dat Normal file
View file

@ -0,0 +1 @@
{"access_token": "ya29.Il-0B4bh7Yq32B8mvoTT0EiAbYtzr1snXN_AwfcJzzaXu_L74OpPkkH7UgxQIzh3ZkiF_7fQq5VwZ5lIPE8ag5iei_D58rDeFdvT6x3V0MC9uOAyTBsejAlh2aJl9hY1Lg", "client_id": "1068382961407-1dudhnc4e9d7ham53nr6b7ak3c4dlvme.apps.googleusercontent.com", "client_secret": "F9zmMyRRiTUEAMfRiv8A2l1d", "refresh_token": "1//09MUSHKoeusLDCgYIARAAGAkSNwF-L9IrNOqe0TCFB9n1MZZwuAQNtfkdXAv7x4bUs2AxMwfmTdccxSMhCMEwjaXRUD2WR_EXiss", "token_expiry": "2019-12-06T16:13:57Z", "token_uri": "https://accounts.google.com/o/oauth2/token", "user_agent": null, "revoke_uri": "https://oauth2.googleapis.com/revoke", "id_token": null, "id_token_jwt": null, "token_response": {"access_token": "ya29.Il-0B4bh7Yq32B8mvoTT0EiAbYtzr1snXN_AwfcJzzaXu_L74OpPkkH7UgxQIzh3ZkiF_7fQq5VwZ5lIPE8ag5iei_D58rDeFdvT6x3V0MC9uOAyTBsejAlh2aJl9hY1Lg", "expires_in": 3600, "scope": "https://www.googleapis.com/auth/calendar.readonly", "token_type": "Bearer"}, "scopes": ["https://www.googleapis.com/auth/calendar.readonly"], "token_info_uri": "https://oauth2.googleapis.com/tokeninfo", "invalid": false, "_class": "OAuth2Credentials", "_module": "oauth2client.client"}

138
rental/bookings.py Normal file
View file

@ -0,0 +1,138 @@
from __future__ import print_function
from googleapiclient import sample_tools
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
import os.path
import pickle
import datetime
from oauth2client import client
import sys
# from rental.models import Reservation
def get_bookings(place):
"""
returns a list of all related place reservations
"""
booked_dates = Reservation.objects.all()
return [booking for booking in booked_dates if booking.place.name == f"{place.name}"]
def check_availability(place, start_date, end_date):
"""
check if the related place is available during a given period
"""
bookings = get_bookings(place)
for booking in bookings:
if (booking.start <= start_date <= booking.end) or (booking.start <= end_date <= booking.end):
return False
return True
"""Simple command-line sample for the Calendar API.
Command-line application that retrieves the list of the user's calendars."""
def main1(argv):
# Authenticate and construct service.
service, _ = sample_tools.init(
argv, 'calendar', 'v3', __doc__, __file__,
scope='https://www.googleapis.com/auth/calendar.readonly')
try:
page_token = None
while True:
calendar_list = service.calendarList().list(
pageToken=page_token).execute()
for calendar_list_entry in calendar_list['items']:
print(calendar_list_entry['summary'])
page_token = calendar_list.get('nextPageToken')
if not page_token:
break
# Call the Calendar API
calendar_list = service.calendarList().list(
pageToken=page_token).execute()
# print(calendar_list)
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
print('Getting the upcoming 10 T2 arrivals')
events_result = service.events().list(calendarId='burik7aclvhc7vsboh06c179uo@group.calendar.google.com', timeMin=now,
maxResults=10, singleEvents=True,
orderBy='startTime').execute()
events = events_result.get('items', [])
if not events:
print('No upcoming events found.')
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
end = event['end'].get('dateTime', event['end'].get('date'))
print(start, end, event['summary'])
print('Getting the upcoming 10 T3 arrivals')
events_result = service.events().list(calendarId='fu7h30p0gk4a2p4nvo7nsbgpok@group.calendar.google.com', timeMin=now,
maxResults=10, singleEvents=True,
orderBy='startTime').execute()
events = events_result.get('items', [])
if not events:
print('No upcoming events found.')
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
end = event['end'].get('dateTime', event['end'].get('date'))
print(start, end, event['summary'])
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run'
'the application to re-authorize.')
# If modifying these scopes, delete the file token.pickle.
# SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
# def main():
# """Shows basic usage of the Google Calendar API.
# Prints the start and name of the next 10 events on the user's calendar.
# """
# creds = None
# # The file token.pickle stores the user's access and refresh tokens, and is
# # created automatically when the authorization flow completes for the first
# # time.
# if os.path.exists('token.pickle'):
# with open('token.pickle', 'rb') as token:
# creds = pickle.load(token)
# # If there are no (valid) credentials available, let the user log in.
# if not creds or not creds.valid:
# if creds and creds.expired and creds.refresh_token:
# creds.refresh(Request())
# else:
# flow = InstalledAppFlow.from_client_secrets_file(
# 'credentials.json', SCOPES)
# creds = flow.run_local_server(port=0)
# # Save the credentials for the next run
# with open('token.pickle', 'wb') as token:
# pickle.dump(creds, token)
# service = build('calendar', 'v3', credentials=creds)
# # Call the Calendar API
# now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
# print('Getting the upcoming 10 events')
# events_result = service.events().list(calendarId='primary', timeMin=now,
# maxResults=10, singleEvents=True,
# orderBy='startTime').execute()
# events = events_result.get('items', [])
# if not events:
# print('No upcoming events found.')
# for event in events:
# start = event['start'].get('dateTime', event['start'].get('date'))
# print(start, event['summary'])
if __name__ == '__main__':
main1(sys.argv)
# main()

View file

@ -1,19 +0,0 @@
from rental.models import Reservation
def get_bookings(place):
"""
returns a list of all related place reservations
"""
booked_dates = Reservation.objects.all()
return [booking for booking in booked_dates if booking.place.name == f"{place.name}"]
def check_availability(place, start_date, end_date):
"""
check if the related place is available during a given period
"""
bookings = get_bookings(place)
for booking in bookings:
if (booking.start <= start_date <= booking.end) or (booking.start <= end_date <= booking.end):
return False
return True

View file

@ -28,6 +28,7 @@ class Place(models.Model):
thumbnail = models.ForeignKey(
Image, on_delete=models.CASCADE, blank=True, null=True)
images = models.ManyToManyField(Image, related_name="places", blank=True)
calendar = models.CharField(max_length=350, blank=True, null=True)
class Guest(models.Model):

View file

@ -1,154 +1,180 @@
{% extends 'rental/base.html'%}
{% load static %}
{% extends 'rental/base.html'%} {% load static %} {% block content %}
{% block content %}
<!--/ Intro Single star /-->
<section class="intro-single">
<div class="container">
<div class="row">
<div class="col-md-12 col-lg-8">
<div class="title-single-box">
<h1 class="title-single">{{ place.subname }} {{ place.name }} </h1>
<span class="color-text-a">VillaFleurie</span>
</div>
</div>
<div class="col-md-12 col-lg-4">
<nav aria-label="breadcrumb" class="breadcrumb-box d-flex justify-content-lg-end">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'rental:index' %}">Accueil</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'rental:list_place' %}">Hébergements</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
{{ place.name }}
</li>
</ol>
</nav>
<section class="intro-single">
<div class="container">
<div class="row">
<div class="col-md-12 col-lg-8">
<div class="title-single-box">
<h1 class="title-single">{{ place.subname }} {{ place.name }}</h1>
<span class="color-text-a">VillaFleurie</span>
</div>
</div>
<div class="col-md-12 col-lg-4">
<nav
aria-label="breadcrumb"
class="breadcrumb-box d-flex justify-content-lg-end"
>
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'rental:index' %}">Accueil</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'rental:list_place' %}">Hébergements</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
{{ place.name }}
</li>
</ol>
</nav>
</div>
</div>
</section>
<!--/ Intro Single End /-->
</div>
</section>
<!--/ Property Single Star /-->
<section class="property-single nav-arrow-b">
<div class="container">
<div class="row">
<div class="col-sm-12">
<div id="property-single-carousel" class="owl-carousel owl-arrow gallery-property">
{% for image in images %}
<div class="carousel-item-b">
<img src="{{ image.img.url }}" alt="{{image.alt}}">
</div>
{% endfor %}
<section class="property-single nav-arrow-b">
<div class="container">
<div class="row">
<div class="col-sm-12">
<div
id="property-single-carousel"
class="owl-carousel owl-arrow gallery-property"
>
{% for image in images %}
<div class="carousel-item-b">
<img src="{{ image.img.url }}" alt="{{image.alt}}" />
</div>
<div class="row justify-content-between">
<div class="col-md-5 col-lg-4">
<div class="property-price d-flex justify-content-center foo">
<div class="card-header-c d-flex">
<div class="card-box-ico">
<span class="ion-money"></span>
</div>
<div class="card-title-c align-self-center">
<h5 class="title-c"> {{ place.price }} </h5>
</div>
{% endfor %}
</div>
<div class="row justify-content-between">
<div class="col-md-5 col-lg-4">
<div class="property-price d-flex justify-content-center foo">
<div class="card-header-c d-flex">
<div class="card-box-ico">
<span class="ion-money"></span>
</div>
</div>
<div class="property-summary">
<div class="row">
<div class="col-sm-12">
<div class="col-md-12 mb-1">
<a href="#reservation"><button class="btn btn-a">Réserver maintenant</button></a>
</div>
</div>
</div>
</div>
<div class="property-summary">
<div class="row">
<div class="col-sm-12">
<div class="title-box-d section-t4">
<h3 class="title-d">Résumé</h3>
</div>
</div>
</div>
<div class="summary-list">
<ul class="list">
<li class="d-flex justify-content-between">
<strong>Localisation :</strong>
<span>Le Gosier, Guadeloupe</span>
</li>
<li class="d-flex justify-content-between">
<strong>Status :</strong>
<span>Disponible</span>
</li>
<li class="d-flex justify-content-between">
<strong>Surface :</strong>
<span>{{ place.surface}}
<sup>2</sup>
</span>
</li>
<li class="d-flex justify-content-between">
<strong>Lits :</strong>
<span>{{ place.beds }}</span>
</li>
<li class="d-flex justify-content-between">
<strong>Nombre de voyageurs maximum :</strong>
<span>{{ place.max_occupation}}</span>
</li>
</ul>
<div class="card-title-c align-self-center">
<h5 class="title-c">{{ place.price }}</h5>
</div>
</div>
</div>
<div class="col-md-7 col-lg-7 section-md-t3">
<div class="col-sm-12">
<div class="title-box-d section-t4">
<a href="#reservation" class="btn btn-a">Réserver</a>
</div>
</div>
<div class="property-summary">
<div class="row">
<div class="col-sm-12">
<div class="title-box-d">
<h3 class="title-d">Description</h3>
<div class="title-box-d section-t4">
<h3 class="title-d">Résumé</h3>
</div>
</div>
</div>
<div class="property-description">
<p class="description color-text-a">
{{ place.description |safe}}
</p>
<p class="description color-text-a no-margin">
{{ place.info |safe}}
</p>
<div class="summary-list">
<ul class="list">
<li class="d-flex justify-content-between">
<strong>Localisation :</strong>
<span>Le Gosier, Guadeloupe</span>
</li>
<li class="d-flex justify-content-between">
<strong>Status :</strong>
<span>Disponible</span>
</li>
<li class="d-flex justify-content-between">
<strong>Surface :</strong>
<span
>{{ place.surface}}
<sup>2</sup>
</span>
</li>
<li class="d-flex justify-content-between">
<strong>Lits :</strong>
<span>{{ place.beds }}</span>
</li>
<li class="d-flex justify-content-between">
<strong>Nombre de voyageurs maximum :</strong>
<span>{{ place.max_occupation}}</span>
</li>
</ul>
</div>
</div>
<iframe
src="{{place.calendar | safe}}"
style="border-width:0"
width="400"
height="400"
frameborder="0"
scrolling="no"
></iframe>
</div>
<div class="col-md-7 col-lg-7 section-md-t3">
<div class="row">
<div class="col-sm-12">
<div class="title-box-d">
<h3 class="title-d">Description</h3>
</div>
</div>
</div>
<div class="property-description">
<p class="description color-text-a">
{{ place.description |safe}}
</p>
<p class="description color-text-a no-margin">
{{ place.info |safe}}
</p>
</div>
</div>
</div>
<div class="col-md-10 offset-md-1">
<ul class="nav nav-pills-a nav-pills mb-3 section-t3" id="pills-tab" role="tablist">
<!-- <li class="nav-item">
</div>
<div class="col-md-10 offset-md-1">
<ul
class="nav nav-pills-a nav-pills mb-3 section-t3"
id="pills-tab"
role="tablist"
>
<!-- <li class="nav-item">
<a class="nav-link active" id="pills-video-tab" data-toggle="pill" href="#pills-video" role="tab"
aria-controls="pills-video" aria-selected="true">Video</a>
</li> -->
<li class="nav-item">
<a class="nav-link active" id="pills-map-tab" data-toggle="pill" href="#pills-map" role="tab" aria-controls="pills-map"
aria-selected="false">Localisation</a>
</li>
</ul>
<div class="tab-content" id="pills-tabContent">
<!-- <div class="tab-pane fade show active" id="pills-video" role="tabpanel" aria-labelledby="pills-video-tab">
<li class="nav-item">
<a
class="nav-link active"
id="pills-map-tab"
data-toggle="pill"
href="#pills-map"
role="tab"
aria-controls="pills-map"
aria-selected="false"
>Localisation</a
>
</li>
</ul>
<div class="tab-content" id="pills-tabContent">
<!-- <div class="tab-pane fade show active" id="pills-video" role="tabpanel" aria-labelledby="pills-video-tab">
<iframe src="https://player.vimeo.com/video/73221098" width="100%" height="460" frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div> -->
<div class="tab-pane fade show active" id="pills-map" role="tabpanel" aria-labelledby="pills-map-tab">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3831.2547874074585!2d-61.48954768556058!3d16.207335988795712!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8c134f148764f5d5%3A0x981bb218cee8b16c!2sVillaFleurie!5e0!3m2!1sfr!2sde!4v1573125589212!5m2!1sfr!2sde"
width="100%" height="460" frameborder="0" style="border:0;" allowfullscreen=""></iframe>
</div>
<div
class="tab-pane fade show active"
id="pills-map"
role="tabpanel"
aria-labelledby="pills-map-tab"
>
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3831.2547874074585!2d-61.48954768556058!3d16.207335988795712!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8c134f148764f5d5%3A0x981bb218cee8b16c!2sVillaFleurie!5e0!3m2!1sfr!2sde!4v1573125589212!5m2!1sfr!2sde"
width="100%"
height="460"
frameborder="0"
style="border:0;"
allowfullscreen=""
></iframe>
</div>
</div>
{% include 'rental/reservation_form.html' %}
</div>
{% include 'rental/reservation_form.html' %}
</div>
</section>
<!--/ Property Single End /-->
</div>
</section>
{% endblock %}

View file

@ -6,7 +6,7 @@ from django.views.generic.base import TemplateView
from .forms import ReservationForm
from django.db import IntegrityError
from rental.pricing import get_reservation_price
from rental.calendar import check_availability
from rental.bookings import check_availability
def index(request):