Fixed cc brand bug, Added button to print/save pdf to booking order detail view.Added booking order list.Added booking order list views. Added customised user navbar. Added “my bookings” link to navbar. Added membership active date range. Fixed function to calculate if a membership is active or not. Added membership order detail view. Added order membership view. Create order membership detail html.Added validation to not allow booking on already booked dates.
This commit is contained in:
parent
63dd0f3ea0
commit
d917c8a606
12 changed files with 397 additions and 33 deletions
|
@ -1,5 +1,7 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Supporter, DGGallery, DGPicture
|
from .models import Supporter, DGGallery, DGPicture, Booking, BookingPrice,\
|
||||||
|
MembershipOrder, Membership, MembershipType, BookingOrder
|
||||||
|
|
||||||
from utils.models import ContactMessage
|
from utils.models import ContactMessage
|
||||||
#
|
#
|
||||||
class DGPictureInline(admin.StackedInline):
|
class DGPictureInline(admin.StackedInline):
|
||||||
|
@ -10,4 +12,9 @@ class DGGalleryAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
admin.site.register(DGGallery, DGGalleryAdmin)
|
admin.site.register(DGGallery, DGGalleryAdmin)
|
||||||
admin.site.register(ContactMessage)
|
admin.site.register(ContactMessage)
|
||||||
admin.site.register(Supporter)
|
admin.site.register(Booking)
|
||||||
|
admin.site.register(BookingPrice)
|
||||||
|
admin.site.register(MembershipOrder)
|
||||||
|
admin.site.register(Membership)
|
||||||
|
admin.site.register(MembershipType)
|
||||||
|
admin.site.register(BookingOrder)
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
from utils.models import BillingAddress
|
from utils.models import BillingAddress
|
||||||
from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm
|
from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm
|
||||||
|
|
||||||
from .models import MembershipType
|
from .models import MembershipType
|
||||||
|
from .models import Booking
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(LoginFormMixin):
|
class LoginForm(LoginFormMixin):
|
||||||
|
@ -55,9 +58,10 @@ class BookingBillingForm(BillingAddressForm):
|
||||||
|
|
||||||
|
|
||||||
class BookingDateForm(forms.Form):
|
class BookingDateForm(forms.Form):
|
||||||
start_date = forms.DateField(required=False)
|
start_date = forms.DateField(required=False, widget=forms.HiddenInput())
|
||||||
end_date = forms.DateField(required=False)
|
end_date = forms.DateField(required=False, widget=forms.HiddenInput())
|
||||||
date_range = forms.CharField(required=False)
|
date_range = forms.CharField(required=False,
|
||||||
|
widget=forms.TextInput(attrs={'id': 'booking-date-range'}))
|
||||||
|
|
||||||
def clean_date_range(self):
|
def clean_date_range(self):
|
||||||
date_range = self.cleaned_data.get('date_range')
|
date_range = self.cleaned_data.get('date_range')
|
||||||
|
@ -70,9 +74,18 @@ class BookingDateForm(forms.Form):
|
||||||
|
|
||||||
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.")
|
||||||
|
|
||||||
|
q1 = Q(start_date__lte=start_date, end_date__gte=start_date)
|
||||||
|
q2 = Q(start_date__gt=start_date, start_date__lte=end_date)
|
||||||
|
if Booking.objects.filter(q1 | q2).exists():
|
||||||
|
raise forms.ValidationError("You already have a booking in these dates.")
|
||||||
|
|
||||||
return start_date, end_date
|
return start_date, end_date
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
# import pdb
|
||||||
|
# pdb.set_trace()
|
||||||
|
if self.cleaned_data.get('date_range'):
|
||||||
start_date, end_date = self.cleaned_data.get('date_range')
|
start_date, end_date = self.cleaned_data.get('date_range')
|
||||||
self.cleaned_data['start_date'] = start_date
|
self.cleaned_data['start_date'] = start_date
|
||||||
self.cleaned_data['end_date'] = end_date
|
self.cleaned_data['end_date'] = end_date
|
||||||
|
|
27
digitalglarus/migrations/0015_auto_20160908_0149.py
Normal file
27
digitalglarus/migrations/0015_auto_20160908_0149.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-09-08 01:49
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('digitalglarus', '0014_booking_final_price'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='bookingorder',
|
||||||
|
name='amount',
|
||||||
|
field=models.FloatField(default=35),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='membershiporder',
|
||||||
|
name='amount',
|
||||||
|
field=models.FloatField(default=35.0),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
32
digitalglarus/migrations/0016_auto_20160909_0110.py
Normal file
32
digitalglarus/migrations/0016_auto_20160909_0110.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-09-09 01:10
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('digitalglarus', '0015_auto_20160908_0149'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='bookingprice',
|
||||||
|
old_name='special_price_offer',
|
||||||
|
new_name='special_month_price',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='bookingorder',
|
||||||
|
name='original_price',
|
||||||
|
field=models.FloatField(default=20),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='bookingorder',
|
||||||
|
name='special_month_price',
|
||||||
|
field=models.FloatField(default=290),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -4,7 +4,7 @@ from membership.models import StripeCustomer
|
||||||
from utils.models import BillingAddress
|
from utils.models import BillingAddress
|
||||||
|
|
||||||
|
|
||||||
class MembershipRequired(object):
|
class MembershipRequiredMixin(object):
|
||||||
membership_redirect_url = None
|
membership_redirect_url = None
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
@ -12,11 +12,23 @@ class MembershipRequired(object):
|
||||||
if not Membership.is_digitalglarus_member(request.user):
|
if not Membership.is_digitalglarus_member(request.user):
|
||||||
return HttpResponseRedirect(self.membership_redirect_url)
|
return HttpResponseRedirect(self.membership_redirect_url)
|
||||||
|
|
||||||
return super(MembershipRequired, self).dispatch(request, *args, **kwargs)
|
return super(MembershipRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class IsNotMemberMixin(object):
|
||||||
|
already_member_redirect_url = None
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
from .models import Membership
|
||||||
|
if Membership.is_digitalglarus_member(request.user):
|
||||||
|
return HttpResponseRedirect(self.already_member_redirect_url)
|
||||||
|
|
||||||
|
return super(MembershipRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Ordereable(models.Model):
|
class Ordereable(models.Model):
|
||||||
customer = models.ForeignKey(StripeCustomer)
|
customer = models.ForeignKey(StripeCustomer)
|
||||||
|
amount = models.FloatField()
|
||||||
billing_address = models.ForeignKey(BillingAddress)
|
billing_address = models.ForeignKey(BillingAddress)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
approved = models.BooleanField(default=False)
|
approved = models.BooleanField(default=False)
|
||||||
|
|
|
@ -64,7 +64,8 @@ class Membership(models.Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_digitalglarus_member(cls, user):
|
def is_digitalglarus_member(cls, user):
|
||||||
past_month = (datetime.today() - relativedelta(months=1)).month
|
past_month = (datetime.today() - relativedelta(months=1)).month
|
||||||
has_booking_current_month = Q(membershiporder__created_at__month=datetime.today().month)
|
has_booking_current_month = Q(membershiporder__customer__user=user,
|
||||||
|
membershiporder__created_at__month=datetime.today().month)
|
||||||
has_booking_past_month = Q(membershiporder__customer__user=user,
|
has_booking_past_month = Q(membershiporder__customer__user=user,
|
||||||
membershiporder__created_at__month=past_month)
|
membershiporder__created_at__month=past_month)
|
||||||
return cls.objects.filter(has_booking_past_month | has_booking_current_month).exists()
|
return cls.objects.filter(has_booking_past_month | has_booking_current_month).exists()
|
||||||
|
@ -78,6 +79,25 @@ class Membership(models.Model):
|
||||||
class MembershipOrder(Ordereable, models.Model):
|
class MembershipOrder(Ordereable, models.Model):
|
||||||
membership = models.ForeignKey(Membership)
|
membership = models.ForeignKey(Membership)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def current_membership(cls, user):
|
||||||
|
last_payment = cls.objects.\
|
||||||
|
filter(customer__user=user).last()
|
||||||
|
start_date = last_payment.created_at
|
||||||
|
_, days_in_month = calendar.monthrange(start_date.year,
|
||||||
|
start_date.month)
|
||||||
|
start_date.replace(day=1)
|
||||||
|
end_date = start_date + timedelta(days=days_in_month)
|
||||||
|
return start_date, end_date
|
||||||
|
|
||||||
|
def get_membership_range_date(self):
|
||||||
|
start_date = self.created_at
|
||||||
|
_, days_in_month = calendar.monthrange(start_date.year,
|
||||||
|
start_date.month)
|
||||||
|
start_date.replace(day=1)
|
||||||
|
end_date = start_date + timedelta(days=days_in_month)
|
||||||
|
return start_date, end_date
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, data):
|
def create(cls, data):
|
||||||
stripe_charge = data.pop('stripe_charge', None)
|
stripe_charge = data.pop('stripe_charge', None)
|
||||||
|
@ -85,12 +105,13 @@ class MembershipOrder(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
|
||||||
|
|
||||||
|
|
||||||
class BookingPrice(models.Model):
|
class BookingPrice(models.Model):
|
||||||
price_per_day = models.FloatField()
|
price_per_day = models.FloatField()
|
||||||
special_price_offer = models.FloatField()
|
special_month_price = models.FloatField()
|
||||||
|
|
||||||
|
|
||||||
class Booking(models.Model):
|
class Booking(models.Model):
|
||||||
|
@ -124,7 +145,7 @@ class Booking(models.Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def booking_price(cls, user, start_date, end_date):
|
def booking_price(cls, user, start_date, end_date):
|
||||||
|
|
||||||
MAX_MONTH_PRICE = 290
|
MAX_MONTH_PRICE = BookingPrice.objects.last().special_month_price
|
||||||
MAX_MONTH_DAYS_PROMOTION = 31
|
MAX_MONTH_DAYS_PROMOTION = 31
|
||||||
MIN_MONTH_DAYS_PROMOTION = 19
|
MIN_MONTH_DAYS_PROMOTION = 19
|
||||||
|
|
||||||
|
@ -146,6 +167,8 @@ class Booking(models.Model):
|
||||||
|
|
||||||
class BookingOrder(Ordereable, models.Model):
|
class BookingOrder(Ordereable, models.Model):
|
||||||
booking = models.OneToOneField(Booking)
|
booking = models.OneToOneField(Booking)
|
||||||
|
original_price = models.FloatField()
|
||||||
|
special_month_price = models.FloatField()
|
||||||
|
|
||||||
def booking_days(self):
|
def booking_days(self):
|
||||||
return (self.booking.end_date - self.booking.start_date).days + 1
|
return (self.booking.end_date - self.booking.start_date).days + 1
|
||||||
|
|
|
@ -14,12 +14,17 @@
|
||||||
<h2 class="signup-lead">Start coworking at Digital Glarus! <br> Membership costs only
|
<h2 class="signup-lead">Start coworking at Digital Glarus! <br> Membership costs only
|
||||||
<strong>35CHF</strong> per month.<br> 2 free working days included!</h2>
|
<strong>35CHF</strong> per month.<br> 2 free working days included!</h2>
|
||||||
<hr class="primary">
|
<hr class="primary">
|
||||||
|
{% bootstrap_form_errors form layout='inline' %}
|
||||||
<div class="signup-form form-group row">
|
<div class="signup-form form-group row">
|
||||||
<input type="hidden" name="next" value="{{ request.GET.next }}">
|
<input type="hidden" name="next" value="{{ request.GET.next }}">
|
||||||
<form action="" method="post" class="form" novalidate>
|
<form action="" method="post" class="form" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input class="form-control" placeholder="Select your dates" type="text" id="booking-date-range" name="date_range">
|
{% bootstrap_form_errors form layout='inline' %}
|
||||||
|
{% for field in form %}
|
||||||
|
{% bootstrap_field field show_label=False %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<!-- <input class="form-control" placeholder="Select your dates" type="text" id="booking-date-range" name="date_range"> -->
|
||||||
<button type="submit" class="btn btn-primary btn-blue">Book</button>
|
<button type="submit" class="btn btn-primary btn-blue">Book</button>
|
||||||
</form>
|
</form>
|
||||||
<br>
|
<br>
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
{% 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 Membership Order 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: {{membership_start_date|date}} - {{membership_end_date|date}}<br>
|
||||||
|
</h2>
|
||||||
|
<h2 class="col-xs-6 payment-total text-left">Membership month {{order.created_at|date:"F"}}</h2>
|
||||||
|
<h2 class="order-sum">{{order.amount|floatformat}}CHF</h2>
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="col-xs-6 payment-total text-left"> Total</h2>
|
||||||
|
<h2 class="order-result">{{order.amount|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: {{membership_start_date|date}} - {{membership_end_date|date}}<br><br></h2>
|
||||||
|
|
||||||
|
<h2 class="col-xs-6 payment-total">Membership month {{order.created_at|date:"F"}}</h2>
|
||||||
|
<h2 class="order-sum">{{order.amount|floatformat}}CHF</h2>
|
||||||
|
<hr class="greyline">
|
||||||
|
<h2 class="col-xs-6 payment-total">Total</h2>
|
||||||
|
<h2 class="order-result">{{order.amount|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">{{membership_start_date|date}}-{{membership_end_date|date}}</h2>
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="order-head">Booking history</h2>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Valid Month</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Invoice</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for order in orders%}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{order.id}}</th>
|
||||||
|
<td>{{order.created_at|date:"F"}}</td>
|
||||||
|
<td>{{order.created_at|date}}</td>
|
||||||
|
<td><a class="btn btn-xs btn-primary btn-darkgrey" href="{% url 'digitalglarus:membership_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 %}
|
|
@ -25,6 +25,8 @@
|
||||||
<link href="{% static 'digitalglarus/css/ungleich.css' %}" rel="stylesheet">
|
<link href="{% static 'digitalglarus/css/ungleich.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'digitalglarus/css/history.css' %}" rel="stylesheet">
|
<link href="{% static 'digitalglarus/css/history.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'digitalglarus/css/price.css' %}" rel="stylesheet">
|
<link href="{% static 'digitalglarus/css/price.css' %}" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" />
|
||||||
|
|
||||||
<!-- <link href="css/bootstrap.min.css" rel="stylesheet"> -->
|
<!-- <link href="css/bootstrap.min.css" rel="stylesheet"> -->
|
||||||
<link href="{% static 'digitalglarus/css/lib/animate.min.css' %}" rel="stylesheet">
|
<link href="{% static 'digitalglarus/css/lib/animate.min.css' %}" rel="stylesheet">
|
||||||
<!-- <link href="{% static 'css/membership.css' %}" rel="stylesheet"> -->
|
<!-- <link href="{% static 'css/membership.css' %}" rel="stylesheet"> -->
|
||||||
|
@ -53,7 +55,32 @@
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||||
<style id="igtranslator-color" type="text/css"></style></head>
|
<style id="igtranslator-color" type="text/css"></style>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
|
||||||
|
.navbar-default .nav .dropdown.open .dropdown-toggle {
|
||||||
|
background: none !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.navbar-default .nav .dropdown li a{
|
||||||
|
color:#0f1221;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-default .nav li a .glyphicon-user{
|
||||||
|
|
||||||
|
font-size: 15px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0px;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<body id="page-top" class="index">
|
<body id="page-top" class="index">
|
||||||
|
|
||||||
|
@ -89,13 +116,39 @@
|
||||||
<li>
|
<li>
|
||||||
<a class="page-scroll" href="#contact">Contact</a>
|
<a class="page-scroll" href="#contact">Contact</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<li class="dropdown home-dropdown">
|
||||||
|
<a class="dropdown-toggle" role="button" data-toggle="dropdown" href="#">
|
||||||
|
<i class="glyphicon glyphicon-user"></i>{{request.user.name}} <span class="caret"></span>
|
||||||
|
</a>
|
||||||
|
<ul id="g-account-menu" class="dropdown-menu" role="menu">
|
||||||
<li>
|
<li>
|
||||||
<a class="page-scroll" href="{% url 'digitalglarus:login' %}">Log In</a>
|
<a href="{% url 'digitalglarus:booking_orders_list' %}">
|
||||||
|
<i class="fa fa-home" aria-hidden="true"></i> {% trans "Bookings"%}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="page-scroll" href="{% url 'digitalglarus:signup' %}">Sign Up</a>
|
<a href="{% url 'digitalglarus:membership_orders_list' %}"><i class="fa fa-heart-o" aria-hidden="true"></i> {% trans "Membership"%}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'digitalglarus:logout' %}">
|
||||||
|
<i class="fa fa-lock" aria-hidden="true"></i>
|
||||||
|
{% trans "Logout"%}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
<a class="page-scroll" href="{% url 'digitalglarus:login' %}">Login</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<!-- <li>
|
||||||
|
<a class="page-scroll" href="{% url 'digitalglarus:signup' %}">Sign Up</a>
|
||||||
|
</li>
|
||||||
|
--> </ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.navbar-collapse -->
|
<!-- /.navbar-collapse -->
|
||||||
</div>
|
</div>
|
||||||
|
@ -174,8 +227,6 @@
|
||||||
-->
|
-->
|
||||||
<!-- Include Date Range Picker -->
|
<!-- Include Date Range Picker -->
|
||||||
<script type="text/javascript" src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
|
<script type="text/javascript" src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" />
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Booking JavaScript -->
|
<!-- Booking JavaScript -->
|
||||||
<script src="{% static 'digitalglarus/js/booking.js' %}"></script>
|
<script src="{% static 'digitalglarus/js/booking.js' %}"></script>
|
||||||
|
|
|
@ -5,7 +5,7 @@ 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, OrdersBookingDetailView,\
|
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
|
||||||
BookingOrdersListView
|
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView
|
||||||
# from membership.views import LoginRegistrationView
|
# from membership.views import LoginRegistrationView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -30,6 +30,10 @@ urlpatterns = [
|
||||||
name='membership_activated'),
|
name='membership_activated'),
|
||||||
url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(),
|
url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(),
|
||||||
name='membership_pricing'),
|
name='membership_pricing'),
|
||||||
|
url(_(r'membership/orders/(?P<pk>\d+)/?$'), OrdersMembershipDetailView.as_view(),
|
||||||
|
name='membership_orders_detail'),
|
||||||
|
url(_(r'membership/orders/?$'), MembershipOrdersListView.as_view(),
|
||||||
|
name='membership_orders_list'),
|
||||||
url(_(r'supporters/?$'), views.supporters, name='supporters'),
|
url(_(r'supporters/?$'), views.supporters, name='supporters'),
|
||||||
url(r'calendar_api/(?P<month>\d+)/(?P<year>\d+)?$', views.CalendarApi.as_view(),name='calendar_api_1'),
|
url(r'calendar_api/(?P<month>\d+)/(?P<year>\d+)?$', views.CalendarApi.as_view(),name='calendar_api_1'),
|
||||||
url(r'calendar_api/', views.CalendarApi.as_view(),name='calendar_api'),
|
url(r'calendar_api/', views.CalendarApi.as_view(),name='calendar_api'),
|
||||||
|
|
|
@ -34,7 +34,7 @@ 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
|
from .mixins import MembershipRequiredMixin, IsNotMemberMixin
|
||||||
|
|
||||||
|
|
||||||
class IndexView(TemplateView):
|
class IndexView(TemplateView):
|
||||||
|
@ -44,7 +44,7 @@ class IndexView(TemplateView):
|
||||||
class LoginView(LoginViewMixin):
|
class LoginView(LoginViewMixin):
|
||||||
template_name = "digitalglarus/login.html"
|
template_name = "digitalglarus/login.html"
|
||||||
form_class = LoginForm
|
form_class = LoginForm
|
||||||
success_url = reverse_lazy('digitalglarus:landing')
|
success_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||||
|
|
||||||
|
|
||||||
class SignupView(SignupViewMixin):
|
class SignupView(SignupViewMixin):
|
||||||
|
@ -77,7 +77,7 @@ class HistoryView(TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class BookingSelectDatesView(LoginRequiredMixin, MembershipRequired, FormView):
|
class BookingSelectDatesView(LoginRequiredMixin, MembershipRequiredMixin, 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')
|
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||||
|
@ -102,7 +102,7 @@ class BookingSelectDatesView(LoginRequiredMixin, MembershipRequired, FormView):
|
||||||
return super(BookingSelectDatesView, self).form_valid(form)
|
return super(BookingSelectDatesView, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class BookingPaymentView(LoginRequiredMixin, MembershipRequired, FormView):
|
class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
||||||
template_name = "digitalglarus/booking_payment.html"
|
template_name = "digitalglarus/booking_payment.html"
|
||||||
form_class = BookingBillingForm
|
form_class = BookingBillingForm
|
||||||
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
|
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||||
|
@ -199,7 +199,10 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequired, FormView):
|
||||||
'booking': booking,
|
'booking': booking,
|
||||||
'customer': customer,
|
'customer': customer,
|
||||||
'billing_address': billing_address,
|
'billing_address': billing_address,
|
||||||
'stripe_charge': charge
|
'stripe_charge': charge,
|
||||||
|
'amount': final_price,
|
||||||
|
'original_price': normal_price,
|
||||||
|
'special_month_price': BookingPrice.objects.last().special_month_price
|
||||||
}
|
}
|
||||||
order = BookingOrder.create(order_data)
|
order = BookingOrder.create(order_data)
|
||||||
|
|
||||||
|
@ -208,8 +211,6 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequired, FormView):
|
||||||
# '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 HttpResponseRedirect(self.get_success_url(order.id))
|
||||||
return super(BookingPaymentView, self).form_valid(form)
|
|
||||||
# return HttpResponseRedirect(reverse('digitalglarus:membership_activated'))
|
|
||||||
|
|
||||||
|
|
||||||
class MembershipPricingView(TemplateView):
|
class MembershipPricingView(TemplateView):
|
||||||
|
@ -224,10 +225,11 @@ class MembershipPricingView(TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class MembershipPaymentView(LoginRequiredMixin, FormView):
|
class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView):
|
||||||
template_name = "digitalglarus/membership_payment.html"
|
template_name = "digitalglarus/membership_payment.html"
|
||||||
login_url = reverse_lazy('digitalglarus:signup')
|
login_url = reverse_lazy('digitalglarus:signup')
|
||||||
form_class = MembershipBillingForm
|
form_class = MembershipBillingForm
|
||||||
|
already_member_redirect_url = reverse_lazy('digitalglarus:membership_orders_list')
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
self.membership_type = MembershipType.objects.get(name='standard')
|
self.membership_type = MembershipType.objects.get(name='standard')
|
||||||
|
@ -291,7 +293,8 @@ class MembershipPaymentView(LoginRequiredMixin, FormView):
|
||||||
'membership': membership,
|
'membership': membership,
|
||||||
'customer': customer,
|
'customer': customer,
|
||||||
'billing_address': billing_address,
|
'billing_address': billing_address,
|
||||||
'stripe_charge': charge
|
'stripe_charge': charge,
|
||||||
|
'amount': membership_type.first_month_price
|
||||||
}
|
}
|
||||||
MembershipOrder.create(order_data)
|
MembershipOrder.create(order_data)
|
||||||
|
|
||||||
|
@ -319,6 +322,45 @@ class MembershipActivatedView(TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class MembershipOrdersListView(LoginRequiredMixin, ListView):
|
||||||
|
template_name = "digitalglarus/membership_orders_list.html"
|
||||||
|
context_object_name = "orders"
|
||||||
|
login_url = reverse_lazy('digitalglarus:login')
|
||||||
|
model = MembershipOrder
|
||||||
|
paginate_by = 10
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(MembershipOrdersListView, self).get_context_data(**kwargs)
|
||||||
|
start_date, end_date = MembershipOrder.current_membership(self.request.user)
|
||||||
|
context.update({
|
||||||
|
'membership_start_date': start_date,
|
||||||
|
'membership_end_date': end_date,
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = super(MembershipOrdersListView, self).get_queryset()
|
||||||
|
queryset = queryset.filter(customer__user=self.request.user)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class OrdersMembershipDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
template_name = "digitalglarus/membership_orders_detail.html"
|
||||||
|
context_object_name = "order"
|
||||||
|
login_url = reverse_lazy('digitalglarus:login')
|
||||||
|
# permission_required = ['view_hostingorder']
|
||||||
|
model = MembershipOrder
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(OrdersMembershipDetailView, self).get_context_data(**kwargs)
|
||||||
|
start_date, end_date = self.object.get_membership_range_date()
|
||||||
|
context.update({
|
||||||
|
'membership_start_date': start_date,
|
||||||
|
'membership_end_date': end_date,
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class OrdersBookingDetailView(LoginRequiredMixin, DetailView):
|
class OrdersBookingDetailView(LoginRequiredMixin, DetailView):
|
||||||
template_name = "digitalglarus/booking_orders_detail.html"
|
template_name = "digitalglarus/booking_orders_detail.html"
|
||||||
context_object_name = "order"
|
context_object_name = "order"
|
||||||
|
|
Loading…
Reference in a new issue