Now booking is only for users with memberships. Added method to know if a membership is active or not. Added new formula for booking pricing. handling border cases when an user want to book. Added booking order detail view. Added booking order detail html.
This commit is contained in:
parent
2eb2c90b1f
commit
e3d1761d45
14 changed files with 345 additions and 45 deletions
|
@ -68,7 +68,7 @@ class BookingDateForm(forms.Form):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise forms.ValidationError("Submit valid dates.")
|
raise forms.ValidationError("Submit valid dates.")
|
||||||
|
|
||||||
if start_date >= end_date:
|
if start_date > end_date:
|
||||||
raise forms.ValidationError("Your end date must be greather than your start date.")
|
raise forms.ValidationError("Your end date must be greather than your start date.")
|
||||||
return start_date, end_date
|
return start_date, end_date
|
||||||
|
|
||||||
|
|
21
digitalglarus/migrations/0014_booking_final_price.py
Normal file
21
digitalglarus/migrations/0014_booking_final_price.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-09-02 03:49
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('digitalglarus', '0013_remove_booking_membership'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='booking',
|
||||||
|
name='final_price',
|
||||||
|
field=models.FloatField(default=250),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,8 +1,20 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
from membership.models import StripeCustomer
|
from membership.models import StripeCustomer
|
||||||
from utils.models import BillingAddress
|
from utils.models import BillingAddress
|
||||||
|
|
||||||
|
|
||||||
|
class MembershipRequired(object):
|
||||||
|
membership_redirect_url = None
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
from .models import Membership
|
||||||
|
if not Membership.is_digitalglarus_member(request.user):
|
||||||
|
return HttpResponseRedirect(self.membership_redirect_url)
|
||||||
|
|
||||||
|
return super(MembershipRequired, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Ordereable(models.Model):
|
class Ordereable(models.Model):
|
||||||
customer = models.ForeignKey(StripeCustomer)
|
customer = models.ForeignKey(StripeCustomer)
|
||||||
billing_address = models.ForeignKey(BillingAddress)
|
billing_address = models.ForeignKey(BillingAddress)
|
||||||
|
@ -22,4 +34,5 @@ class Ordereable(models.Model):
|
||||||
instance.stripe_charge_id = stripe_charge.id
|
instance.stripe_charge_id = stripe_charge.id
|
||||||
instance.last4 = stripe_charge.source.last4
|
instance.last4 = stripe_charge.source.last4
|
||||||
instance.cc_brand = stripe_charge.source.brand
|
instance.cc_brand = stripe_charge.source.brand
|
||||||
|
instance.save()
|
||||||
return instance
|
return instance
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
|
||||||
import calendar
|
import calendar
|
||||||
from datetime import datetime, date, timedelta
|
from datetime import datetime, date, timedelta
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from cms.models import CMSPlugin
|
from cms.models import CMSPlugin
|
||||||
from filer.fields.image import FilerImageField
|
from filer.fields.image import FilerImageField
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
@ -59,6 +61,14 @@ class MembershipType(models.Model):
|
||||||
class Membership(models.Model):
|
class Membership(models.Model):
|
||||||
type = models.ForeignKey(MembershipType)
|
type = models.ForeignKey(MembershipType)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_digitalglarus_member(cls, user):
|
||||||
|
past_month = (datetime.today() - relativedelta(months=1)).month
|
||||||
|
has_booking_current_month = Q(membershiporder__created_at__month=datetime.today().month)
|
||||||
|
has_booking_past_month = Q(membershiporder__customer__user=user,
|
||||||
|
membershiporder__created_at__month=past_month)
|
||||||
|
return cls.objects.filter(has_booking_past_month | has_booking_current_month).exists()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, data):
|
def create(cls, data):
|
||||||
instance = cls.objects.create(**data)
|
instance = cls.objects.create(**data)
|
||||||
|
@ -88,6 +98,7 @@ class Booking(models.Model):
|
||||||
end_date = models.DateField()
|
end_date = models.DateField()
|
||||||
price = models.FloatField()
|
price = models.FloatField()
|
||||||
free_days = models.IntegerField(default=0)
|
free_days = models.IntegerField(default=0)
|
||||||
|
final_price = models.FloatField()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, data):
|
def create(cls, data):
|
||||||
|
@ -95,52 +106,50 @@ class Booking(models.Model):
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ramaining_free_days(cls, user):
|
def get_ramaining_free_days(cls, user, start_date, end_date):
|
||||||
# ZERO_DAYS = 0
|
|
||||||
# ONE_DAY = 1
|
|
||||||
TWO_DAYS = 2
|
TWO_DAYS = 2
|
||||||
|
|
||||||
|
start_month = start_date.month
|
||||||
|
end_month = end_date.month
|
||||||
|
months = abs(start_month - (end_month + 12) if end_month < start_month
|
||||||
|
else end_month - start_month)
|
||||||
current_date = datetime.today()
|
current_date = datetime.today()
|
||||||
current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
|
current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
|
||||||
start_date__month=current_date.month)
|
start_date__month=current_date.month)
|
||||||
free_days = TWO_DAYS - sum(map(lambda x: x.days, current_month_bookings))
|
free_days_this_month = TWO_DAYS - sum(map(lambda x: x.free_days, current_month_bookings))
|
||||||
return free_days
|
total_free_days = months * TWO_DAYS + free_days_this_month
|
||||||
|
return total_free_days
|
||||||
# free_days = ZERO_DAYS if current_month_bookings.count() > 2 else TWO_DAYS
|
|
||||||
# if current_month_bookings.count() == 1:
|
|
||||||
# booking = current_month_bookings.get()
|
|
||||||
# booked_days = (booking.end_date - booking.start_date).days
|
|
||||||
# free_days = ONE_DAY if booked_days == 1 else ZERO_DAYS
|
|
||||||
# return free_days
|
|
||||||
|
|
||||||
# free_days = ZERO_DAYS if current_month_bookings.count() > 2 else TWO_DAYS
|
|
||||||
# return free_days
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def booking_price(cls, user, start_date, end_date):
|
def booking_price(cls, user, start_date, end_date):
|
||||||
"""
|
|
||||||
Calculate the booking price for requested dates
|
MAX_MONTH_PRICE = 290
|
||||||
How it does:
|
MAX_MONTH_DAYS_PROMOTION = 31
|
||||||
1. Check if the user has booked the current month
|
MIN_MONTH_DAYS_PROMOTION = 19
|
||||||
2. Get how many days user wants to book
|
|
||||||
3. Get price per day from BookingPrices instance
|
|
||||||
4. Get available free days
|
|
||||||
5. Calculate price by this formula -> (booking_days - free_days) * price_per_day
|
|
||||||
"""
|
|
||||||
booking_prices = BookingPrice.objects.last()
|
booking_prices = BookingPrice.objects.last()
|
||||||
price_per_day = booking_prices.price_per_day
|
price_per_day = booking_prices.price_per_day
|
||||||
booking_days = (end_date - start_date).days
|
booking_days = (end_date - start_date).days + 1
|
||||||
|
months = booking_days // MAX_MONTH_DAYS_PROMOTION
|
||||||
|
remanent_days = booking_days % MAX_MONTH_DAYS_PROMOTION
|
||||||
|
months_prices = months * MAX_MONTH_PRICE
|
||||||
|
remanent_days_price = remanent_days * price_per_day \
|
||||||
|
if remanent_days <= MIN_MONTH_DAYS_PROMOTION else MAX_MONTH_PRICE
|
||||||
|
normal_price = months_prices + remanent_days_price
|
||||||
|
|
||||||
free_days = cls.get_ramaining_free_days(user)
|
free_days = cls.get_ramaining_free_days(user, start_date, end_date)
|
||||||
final_booking_price = (booking_days - free_days) * price_per_day
|
final_booking_price = normal_price - (free_days * price_per_day)
|
||||||
original_booking_price = (booking_days) * price_per_day
|
|
||||||
|
|
||||||
return original_booking_price, final_booking_price, free_days
|
return normal_price, final_booking_price, free_days
|
||||||
|
|
||||||
|
|
||||||
class BookingOrder(Ordereable, models.Model):
|
class BookingOrder(Ordereable, models.Model):
|
||||||
booking = models.OneToOneField(Booking)
|
booking = models.OneToOneField(Booking)
|
||||||
|
|
||||||
|
def booking_days(self):
|
||||||
|
return (self.booking.end_date - self.booking.start_date).days + 1
|
||||||
|
|
||||||
|
|
||||||
class Supporter(models.Model):
|
class Supporter(models.Model):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
$( document ).ready(function() {
|
$( document ).ready(function() {
|
||||||
|
|
||||||
|
|
||||||
// $('#booking-date-range').daterangepicker();
|
// $('#booking-date-range').daterangepicker();
|
||||||
|
|
||||||
|
var tomorrow = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
|
||||||
|
// var tomorrow = today.setDate(today.getDate() + 1);
|
||||||
$('#booking-date-range').daterangepicker({
|
$('#booking-date-range').daterangepicker({
|
||||||
autoUpdateInput: false,
|
autoUpdateInput: false,
|
||||||
locale: {
|
locale: {
|
||||||
cancelLabel: 'Clear'
|
cancelLabel: 'Clear'
|
||||||
}
|
},
|
||||||
|
minDate: tomorrow,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
21
digitalglarus/static/digitalglarus/js/utils.js
Normal file
21
digitalglarus/static/digitalglarus/js/utils.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
$( document ).ready(function() {
|
||||||
|
|
||||||
|
|
||||||
|
function printDiv(divName) {
|
||||||
|
var printContents = document.getElementById(divName).innerHTML;
|
||||||
|
var originalContents = document.body.innerHTML;
|
||||||
|
|
||||||
|
document.body.innerHTML = printContents;
|
||||||
|
|
||||||
|
window.print();
|
||||||
|
|
||||||
|
document.body.innerHTML = originalContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$('.print').on('click', function(e){
|
||||||
|
printDiv(e.target.getAttribute("data-print") );
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,88 @@
|
||||||
|
{% extends "new_base_glarus.html" %}
|
||||||
|
{% load staticfiles bootstrap3 i18n %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
.invoice-title{
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section id="price">
|
||||||
|
<div class="signup-container">
|
||||||
|
<div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown">
|
||||||
|
<div class="payment-box">
|
||||||
|
<h2 class="section-heading payment-head">Your Booking Detail</h2>
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print" data-print="price">Get PDF</btn></h2>
|
||||||
|
|
||||||
|
<h2 class="order-head">Order Number</h2>
|
||||||
|
<h2 class="member-name">#{{order.id}}</h2>
|
||||||
|
|
||||||
|
<h2 class="order-head">Billed to :</h2>
|
||||||
|
<h2 class="history-name">{{user.name}}<br>
|
||||||
|
{{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br>
|
||||||
|
{{order.billing_address.city}}, {{order.billing_address.country}}.
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<h2 class="order-head">Payment Method</h2>
|
||||||
|
<h2 class="history-name">
|
||||||
|
{{order.cc_brand}} ending **** {{order.last4}}<br>
|
||||||
|
{{user.email}}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="order-head">Order Summary</h2>
|
||||||
|
<h2 class="history-name">
|
||||||
|
Dates: {{start_date}} - {{end_date}}<br>
|
||||||
|
</h2>
|
||||||
|
<h2 class="col-xs-6 payment-total text-left">Total days {{booking_days}}</h2>
|
||||||
|
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
|
||||||
|
{% if free_days %}
|
||||||
|
<h2 class="col-xs-6 payment-total text-left">Free days {{free_days}} </h2>
|
||||||
|
<h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2>
|
||||||
|
{% endif %}
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="col-xs-6 payment-total text-left"> Total</h2>
|
||||||
|
<h2 class="order-result">{{final_price|floatformat}}CHF</h2>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown">
|
||||||
|
<div class="order-summary">
|
||||||
|
<div class="header text-center">
|
||||||
|
<h2 class="order-name">Order Summary</h2>
|
||||||
|
</div>
|
||||||
|
<div class="order-box">
|
||||||
|
<h2 class="col-xs-6 order-item" style="padding-bottom:10px">Dates: {{start_date}} - {{end_date}}<br></h2>
|
||||||
|
|
||||||
|
<h2 class="col-xs-6 payment-total">Total days {{booking_days}}</h2>
|
||||||
|
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
|
||||||
|
{% if free_days %}
|
||||||
|
<h2 class="col-xs-6 payment-total">Free days {{free_days}}</h2>
|
||||||
|
<h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2>
|
||||||
|
{% endif %}
|
||||||
|
<hr class="greyline">
|
||||||
|
<h2 class="col-xs-6 payment-total">Total</h2>
|
||||||
|
<h2 class="order-result">{{final_price|floatformat}}CHF</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- stripe key data -->
|
||||||
|
{% if stripe_key %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function () {window.stripeKey = "{{stripe_key}}";})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,68 @@
|
||||||
|
{% extends "new_base_glarus.html" %}
|
||||||
|
{% load staticfiles bootstrap3 i18n %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<!-- Services Section -->
|
||||||
|
<section id="price">
|
||||||
|
<div class="signup-container">
|
||||||
|
<div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown">
|
||||||
|
<div class="payment-box">
|
||||||
|
<h2 class="section-heading payment-head">Your Order History</h2>
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="order-head">Member Name</h2>
|
||||||
|
<h2 class="member-name">{{request.user.name}}</h2>
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="order-head">Active Membership</h2>
|
||||||
|
<h2 class="member-name">2016.11.13-2016.12.13</h2>
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="order-head">Booking history</h2>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Booking dates</th>
|
||||||
|
<th>Days</th>
|
||||||
|
<th>Invoice</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for order in orders%}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{order.id}}</th>
|
||||||
|
<td>{{order.booking.start_date}}-{{order.booking.end_date}}</td>
|
||||||
|
<td>{{order.booking_days}}</td>
|
||||||
|
<td><a class="btn btn-xs btn-primary btn-darkgrey" href="{% url 'digitalglarus:booking_orders_detail' order.id %}">View</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2 class="order-head">Billing Adress<btn class="btn btn-primary btn-grey btn-edit">Edit</btn></h2>
|
||||||
|
<h2 class="history-name">Nico Schottelius<br>
|
||||||
|
In der Au 7 8762 Schwanden<br>
|
||||||
|
Switzerland
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown">
|
||||||
|
<div class="order-summary">
|
||||||
|
<h2 class="thankyou">Thank You!</h2>
|
||||||
|
<div class="order-box">
|
||||||
|
<span class="glyphicon glyphicon-heart icon-up"></span>
|
||||||
|
<h2 class="signup-lead text-center">Digital Glarus lives with your love!<br>
|
||||||
|
Our coworking space is here because of your love and support.</h2>
|
||||||
|
|
||||||
|
<hr class="greyline">
|
||||||
|
|
||||||
|
<p class="order-bottom-text text-center">This box is here just to thank you</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -28,6 +28,16 @@
|
||||||
<!-- <h2 class="membership-amount">35CHF</h2> -->
|
<!-- <h2 class="membership-amount">35CHF</h2> -->
|
||||||
<hr class="greyline-long">
|
<hr class="greyline-long">
|
||||||
<h2 class="billing-head">Billing Adress</h2>
|
<h2 class="billing-head">Billing Adress</h2>
|
||||||
|
<h2 class="membership-lead">
|
||||||
|
Your Digital Glarus Membership enables
|
||||||
|
you to use our coworking space and it includes
|
||||||
|
2 working days for the month you signed up.
|
||||||
|
The membership fee is a monthly subscription.
|
||||||
|
Additional day costs
|
||||||
|
15CHF per day. More than 17 days a month it
|
||||||
|
will charge only 290CHF/month.
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="signup-form form-group row">
|
<div class="signup-form form-group row">
|
||||||
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
|
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="signup-form form-group row">
|
<div class="signup-form form-group row">
|
||||||
|
|
||||||
<div class="button-booking-box form-inline row">
|
<div class="button-booking-box form-inline row">
|
||||||
<button type="submit" class="btn btn-primary btn-blue">Go to Booking</button>
|
<a class="btn btn-primary btn-blue" href={% url 'digitalglarus:booking' %}>Go to Booking</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="notice-box text-left">
|
<div class="notice-box text-left">
|
||||||
<p class="order-bottom-text">Your membership will be automatically renewed each month. For deactivating go to<a href=#>my page</a></p>
|
<p class="order-bottom-text">Your membership will be automatically renewed each month. For deactivating go to<a href=#>my page</a></p>
|
||||||
|
|
|
@ -180,6 +180,9 @@
|
||||||
<!-- Booking JavaScript -->
|
<!-- Booking JavaScript -->
|
||||||
<script src="{% static 'digitalglarus/js/booking.js' %}"></script>
|
<script src="{% static 'digitalglarus/js/booking.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- Utils JavaScript -->
|
||||||
|
<script src="{% static 'digitalglarus/js/utils.js' %}"></script>
|
||||||
|
|
||||||
<!-- Custom Fonts -->
|
<!-- Custom Fonts -->
|
||||||
<link href="//fonts.googleapis.com/css?family=Raleway" rel="stylesheet" type="text/css">
|
<link href="//fonts.googleapis.com/css?family=Raleway" rel="stylesheet" type="text/css">
|
||||||
<link href="{% static 'digitalglarus/font-awesome-4.1.0/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
|
<link href="{% static 'digitalglarus/font-awesome-4.1.0/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
|
||||||
|
|
|
@ -4,7 +4,8 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from . import views
|
from . import views
|
||||||
from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\
|
from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\
|
||||||
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
|
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
|
||||||
MembershipPricingView, BookingSelectDatesView, BookingPaymentView
|
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
|
||||||
|
BookingOrdersListView
|
||||||
# from membership.views import LoginRegistrationView
|
# from membership.views import LoginRegistrationView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -20,6 +21,10 @@ urlpatterns = [
|
||||||
url(_(r'history/?$'), HistoryView.as_view(), name='history'),
|
url(_(r'history/?$'), HistoryView.as_view(), name='history'),
|
||||||
url(_(r'booking/?$'), BookingSelectDatesView.as_view(), name='booking'),
|
url(_(r'booking/?$'), BookingSelectDatesView.as_view(), name='booking'),
|
||||||
url(_(r'booking/payment/?$'), BookingPaymentView.as_view(), name='booking_payment'),
|
url(_(r'booking/payment/?$'), BookingPaymentView.as_view(), name='booking_payment'),
|
||||||
|
url(_(r'booking/orders/(?P<pk>\d+)/?$'), OrdersBookingDetailView.as_view(),
|
||||||
|
name='booking_orders_detail'),
|
||||||
|
url(_(r'booking/orders/?$'), BookingOrdersListView.as_view(),
|
||||||
|
name='booking_orders_list'),
|
||||||
url(_(r'membership/payment/?$'), MembershipPaymentView.as_view(), name='membership_payment'),
|
url(_(r'membership/payment/?$'), MembershipPaymentView.as_view(), name='membership_payment'),
|
||||||
url(_(r'membership/activated/?$'), MembershipActivatedView.as_view(),
|
url(_(r'membership/activated/?$'), MembershipActivatedView.as_view(),
|
||||||
name='membership_activated'),
|
name='membership_activated'),
|
||||||
|
|
|
@ -13,13 +13,13 @@ from django.utils.translation import get_language
|
||||||
from djangocms_blog.models import Post
|
from djangocms_blog.models import Post
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.views.generic import View, DetailView
|
from django.views.generic import View, DetailView, ListView
|
||||||
|
|
||||||
from .models import Supporter
|
from .models import Supporter
|
||||||
from utils.forms import ContactUsForm
|
from utils.forms import ContactUsForm
|
||||||
from django.views.generic.edit import FormView
|
from django.views.generic.edit import FormView
|
||||||
from membership.calendar.calendar import BookCalendar
|
from membership.calendar.calendar import BookCalendar
|
||||||
from membership.models import Calendar as CalendarModel, CustomUser, StripeCustomer
|
from membership.models import Calendar as CalendarModel, StripeCustomer
|
||||||
|
|
||||||
|
|
||||||
from utils.views import LoginViewMixin, SignupViewMixin, \
|
from utils.views import LoginViewMixin, SignupViewMixin, \
|
||||||
|
@ -34,6 +34,8 @@ from .forms import LoginForm, SignupForm, MembershipBillingForm, BookingDateForm
|
||||||
from .models import MembershipType, Membership, MembershipOrder, Booking, BookingPrice,\
|
from .models import MembershipType, Membership, MembershipOrder, Booking, BookingPrice,\
|
||||||
BookingOrder
|
BookingOrder
|
||||||
|
|
||||||
|
from .mixins import MembershipRequired
|
||||||
|
|
||||||
|
|
||||||
class IndexView(TemplateView):
|
class IndexView(TemplateView):
|
||||||
template_name = "digitalglarus/old_index.html"
|
template_name = "digitalglarus/old_index.html"
|
||||||
|
@ -75,9 +77,10 @@ class HistoryView(TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class BookingSelectDatesView(LoginRequiredMixin, FormView):
|
class BookingSelectDatesView(LoginRequiredMixin, MembershipRequired, FormView):
|
||||||
template_name = "digitalglarus/booking.html"
|
template_name = "digitalglarus/booking.html"
|
||||||
form_class = BookingDateForm
|
form_class = BookingDateForm
|
||||||
|
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||||
login_url = reverse_lazy('digitalglarus:login')
|
login_url = reverse_lazy('digitalglarus:login')
|
||||||
success_url = reverse_lazy('digitalglarus:booking_payment')
|
success_url = reverse_lazy('digitalglarus:booking_payment')
|
||||||
|
|
||||||
|
@ -85,7 +88,7 @@ class BookingSelectDatesView(LoginRequiredMixin, FormView):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
start_date = form.cleaned_data.get('start_date')
|
start_date = form.cleaned_data.get('start_date')
|
||||||
end_date = form.cleaned_data.get('end_date')
|
end_date = form.cleaned_data.get('end_date')
|
||||||
booking_days = (end_date - start_date).days
|
booking_days = (end_date - start_date).days + 1
|
||||||
original_price, discount_price, free_days = Booking.\
|
original_price, discount_price, free_days = Booking.\
|
||||||
booking_price(user, start_date, end_date)
|
booking_price(user, start_date, end_date)
|
||||||
self.request.session.update({
|
self.request.session.update({
|
||||||
|
@ -99,10 +102,11 @@ class BookingSelectDatesView(LoginRequiredMixin, FormView):
|
||||||
return super(BookingSelectDatesView, self).form_valid(form)
|
return super(BookingSelectDatesView, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class BookingPaymentView(LoginRequiredMixin, FormView):
|
class BookingPaymentView(LoginRequiredMixin, MembershipRequired, FormView):
|
||||||
template_name = "digitalglarus/booking_payment.html"
|
template_name = "digitalglarus/booking_payment.html"
|
||||||
form_class = BookingBillingForm
|
form_class = BookingBillingForm
|
||||||
success_url = reverse_lazy('digitalglarus:booking_payment')
|
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||||
|
# success_url = reverse_lazy('digitalglarus:booking_payment')
|
||||||
booking_needed_fields = ['original_price', 'discount_price', 'booking_days', 'free_days',
|
booking_needed_fields = ['original_price', 'discount_price', 'booking_days', 'free_days',
|
||||||
'start_date', 'end_date']
|
'start_date', 'end_date']
|
||||||
|
|
||||||
|
@ -114,6 +118,9 @@ class BookingPaymentView(LoginRequiredMixin, FormView):
|
||||||
|
|
||||||
return super(BookingPaymentView, self).dispatch(request, *args, **kwargs)
|
return super(BookingPaymentView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_success_url(self, order_id):
|
||||||
|
return reverse('digitalglarus:booking_orders_datail', kwargs={'pk': order_id})
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
form_kwargs = super(BookingPaymentView, self).get_form_kwargs()
|
form_kwargs = super(BookingPaymentView, self).get_form_kwargs()
|
||||||
form_kwargs.update({
|
form_kwargs.update({
|
||||||
|
@ -147,7 +154,7 @@ class BookingPaymentView(LoginRequiredMixin, FormView):
|
||||||
start_date = data.get('start_date')
|
start_date = data.get('start_date')
|
||||||
end_date = data.get('end_date')
|
end_date = data.get('end_date')
|
||||||
|
|
||||||
original_price, discount_price, free_days = Booking.\
|
normal_price, final_price, free_days = Booking.\
|
||||||
booking_price(self.request.user, start_date, end_date)
|
booking_price(self.request.user, start_date, end_date)
|
||||||
|
|
||||||
# Get or create stripe customer
|
# Get or create stripe customer
|
||||||
|
@ -159,7 +166,7 @@ class BookingPaymentView(LoginRequiredMixin, FormView):
|
||||||
|
|
||||||
# Make stripe charge to a customer
|
# Make stripe charge to a customer
|
||||||
stripe_utils = StripeUtils()
|
stripe_utils = StripeUtils()
|
||||||
charge_response = stripe_utils.make_charge(amount=original_price,
|
charge_response = stripe_utils.make_charge(amount=final_price,
|
||||||
customer=customer.stripe_id)
|
customer=customer.stripe_id)
|
||||||
charge = charge_response.get('response_object')
|
charge = charge_response.get('response_object')
|
||||||
|
|
||||||
|
@ -182,7 +189,8 @@ class BookingPaymentView(LoginRequiredMixin, FormView):
|
||||||
'end_date': end_date,
|
'end_date': end_date,
|
||||||
'start_date': start_date,
|
'start_date': start_date,
|
||||||
'free_days': free_days,
|
'free_days': free_days,
|
||||||
'price': discount_price,
|
'price': normal_price,
|
||||||
|
'final_price': final_price,
|
||||||
}
|
}
|
||||||
booking = Booking.create(booking_data)
|
booking = Booking.create(booking_data)
|
||||||
|
|
||||||
|
@ -193,12 +201,13 @@ class BookingPaymentView(LoginRequiredMixin, FormView):
|
||||||
'billing_address': billing_address,
|
'billing_address': billing_address,
|
||||||
'stripe_charge': charge
|
'stripe_charge': charge
|
||||||
}
|
}
|
||||||
BookingOrder.create(order_data)
|
order = BookingOrder.create(order_data)
|
||||||
|
|
||||||
# request.session.update({
|
# request.session.update({
|
||||||
# 'membership_price': membership.type.first_month_price,
|
# 'membership_price': membership.type.first_month_price,
|
||||||
# 'membership_dates': membership.type.first_month_formated_range
|
# 'membership_dates': membership.type.first_month_formated_range
|
||||||
# })
|
# })
|
||||||
|
return HttpResponseRedirect(self.get_success_url(order.id))
|
||||||
return super(BookingPaymentView, self).form_valid(form)
|
return super(BookingPaymentView, self).form_valid(form)
|
||||||
# return HttpResponseRedirect(reverse('digitalglarus:membership_activated'))
|
# return HttpResponseRedirect(reverse('digitalglarus:membership_activated'))
|
||||||
|
|
||||||
|
@ -310,6 +319,53 @@ class MembershipActivatedView(TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class OrdersBookingDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
template_name = "digitalglarus/booking_orders_detail.html"
|
||||||
|
context_object_name = "order"
|
||||||
|
login_url = reverse_lazy('digitalglarus:login')
|
||||||
|
# permission_required = ['view_hostingorder']
|
||||||
|
model = BookingOrder
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
|
||||||
|
context = super(OrdersBookingDetailView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
bookig_order = self.object
|
||||||
|
booking = bookig_order.booking
|
||||||
|
|
||||||
|
start_date = booking.start_date
|
||||||
|
end_date = booking.end_date
|
||||||
|
free_days = booking.free_days
|
||||||
|
|
||||||
|
booking_days = (end_date - start_date).days + 1
|
||||||
|
original_price = booking.price
|
||||||
|
final_price = booking.final_price
|
||||||
|
context.update({
|
||||||
|
'original_price': original_price,
|
||||||
|
'total_discount': original_price - final_price,
|
||||||
|
'final_price': final_price,
|
||||||
|
'booking_days': booking_days,
|
||||||
|
'free_days': free_days,
|
||||||
|
'start_date': start_date.strftime('%m/%d/%Y'),
|
||||||
|
'end_date': end_date.strftime('%m/%d/%Y'),
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class BookingOrdersListView(LoginRequiredMixin, ListView):
|
||||||
|
template_name = "digitalglarus/booking_orders_list.html"
|
||||||
|
context_object_name = "orders"
|
||||||
|
login_url = reverse_lazy('digitalglarus:login')
|
||||||
|
model = BookingOrder
|
||||||
|
paginate_by = 10
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = super(BookingOrdersListView, self).get_queryset()
|
||||||
|
queryset = queryset.filter(customer__user=self.request.user)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
############## OLD VIEWS
|
############## OLD VIEWS
|
||||||
class CalendarApi(View):
|
class CalendarApi(View):
|
||||||
def get(self,request,month,year):
|
def get(self,request,month,year):
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, AbstractUser, PermissionsMixin
|
from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, AbstractUser, PermissionsMixin
|
||||||
|
|
Loading…
Reference in a new issue