Merge pull request #120 from levivm/feature/new_digitalglarus

Feature/new digitalglarus
This commit is contained in:
Levi Velázquez 2016-09-05 19:48:40 -05:00 committed by GitHub
commit e245c1d092
24 changed files with 1290 additions and 49 deletions

View file

@ -1,6 +1,6 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from datetime import datetime
from utils.models import BillingAddress
from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm
@ -34,3 +34,46 @@ class MembershipBillingForm(BillingAddressForm):
'postal_code': _('Postal Code'),
'country': _('Country'),
}
class BookingBillingForm(BillingAddressForm):
token = forms.CharField(widget=forms.HiddenInput())
start_date = forms.DateField(widget=forms.HiddenInput())
end_date = forms.DateField(widget=forms.HiddenInput())
price = forms.FloatField(widget=forms.HiddenInput())
class Meta:
model = BillingAddress
fields = ['start_date', 'end_date', 'price', 'street_address',
'city', 'postal_code', 'country']
labels = {
'street_address': _('Street Address'),
'city': _('City'),
'postal_code': _('Postal Code'),
'country': _('Country'),
}
class BookingDateForm(forms.Form):
start_date = forms.DateField(required=False)
end_date = forms.DateField(required=False)
date_range = forms.CharField(required=False)
def clean_date_range(self):
date_range = self.cleaned_data.get('date_range')
dates = date_range.replace(' ', '').split('-')
try:
start_date, end_date = [datetime.strptime(date_string, "%m/%d/%Y").date()
for date_string in dates]
except ValueError:
raise forms.ValidationError("Submit valid dates.")
if start_date > end_date:
raise forms.ValidationError("Your end date must be greather than your start date.")
return start_date, end_date
def clean(self):
start_date, end_date = self.cleaned_data.get('date_range')
self.cleaned_data['start_date'] = start_date
self.cleaned_data['end_date'] = end_date
return self.cleaned_data

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-20 19:59
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('utils', '0002_billingaddress'),
('membership', '0006_auto_20160526_0445'),
('digitalglarus', '0007_auto_20160820_0408'),
]
operations = [
migrations.AddField(
model_name='membershiporder',
name='billing_address',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='utils.BillingAddress'),
preserve_default=False,
),
migrations.AddField(
model_name='membershiporder',
name='customer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='membership.StripeCustomer'),
preserve_default=False,
),
]

View file

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-25 05:11
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('utils', '0002_billingaddress'),
('membership', '0006_auto_20160526_0445'),
('digitalglarus', '0008_auto_20160820_1959'),
]
operations = [
migrations.CreateModel(
name='Booking',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start_date', models.DateField()),
('end_date', models.DateField()),
('price', models.FloatField()),
('membership', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='digitalglarus.Membership')),
],
),
migrations.CreateModel(
name='BookingOrder',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('approved', models.BooleanField(default=False)),
('last4', models.CharField(max_length=4)),
('cc_brand', models.CharField(max_length=10)),
('stripe_charge_id', models.CharField(max_length=100, null=True)),
('billing_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='utils.BillingAddress')),
('booking', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='digitalglarus.Booking')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='membership.StripeCustomer')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='BookingPrices',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('price_per_day', models.FloatField()),
],
),
]

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-28 17:45
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0009_booking_bookingorder_bookingprices'),
]
operations = [
migrations.RenameModel(
old_name='BookingPrices',
new_name='BookingPrice',
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-28 21:35
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0010_auto_20160828_1745'),
]
operations = [
migrations.AddField(
model_name='bookingprice',
name='special_price_offer',
field=models.FloatField(default=290.0),
preserve_default=False,
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-30 03:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0011_bookingprice_special_price_offer'),
]
operations = [
migrations.AddField(
model_name='booking',
name='free_days',
field=models.IntegerField(default=0),
),
]

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-30 04:56
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0012_booking_free_days'),
]
operations = [
migrations.RemoveField(
model_name='booking',
name='membership',
),
]

View 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,
),
]

38
digitalglarus/mixins.py Normal file
View file

@ -0,0 +1,38 @@
from django.db import models
from django.http import HttpResponseRedirect
from membership.models import StripeCustomer
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):
customer = models.ForeignKey(StripeCustomer)
billing_address = models.ForeignKey(BillingAddress)
created_at = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
last4 = models.CharField(max_length=4)
cc_brand = models.CharField(max_length=10)
stripe_charge_id = models.CharField(max_length=100, null=True)
class Meta:
abstract = True
@classmethod
def create(cls, data):
stripe_charge = data.pop('stripe_charge', None)
instance = cls.objects.create(**data)
instance.stripe_charge_id = stripe_charge.id
instance.last4 = stripe_charge.source.last4
instance.cc_brand = stripe_charge.source.brand
instance.save()
return instance

View file

@ -1,7 +1,17 @@
import calendar
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
from django.db import models
from django.db.models import Q
from cms.models import CMSPlugin
from filer.fields.image import FilerImageField
from django.core.urlresolvers import reverse
from django.utils.functional import cached_property
from .mixins import Ordereable
# from membership.models import StripeCustomer
# from utils.models import BillingAddress
class MembershipType(models.Model):
@ -13,24 +23,132 @@ class MembershipType(models.Model):
name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20)
price = models.FloatField()
@cached_property
def days_left(self):
current_date = date.today()
_, days_in_month = calendar.monthrange(current_date.year, current_date.month)
pass_days = current_date.day
days_left = days_in_month - pass_days + 1
return days_left
@cached_property
def first_month_price(self):
current_date = date.today()
_, days_in_month = calendar.monthrange(current_date.year, current_date.month)
pass_days = current_date.day
days_left = days_in_month - pass_days + 1
percentage = days_left / days_in_month
membership_price = self.price
final_price = membership_price * percentage
return final_price
@cached_property
def first_month_range(self):
current_date = date.today()
_, days_in_month = calendar.monthrange(current_date.year, current_date.month)
pass_days = current_date.day
days_left = days_in_month - pass_days
end_date = current_date + timedelta(days=days_left)
return current_date, end_date
@cached_property
def first_month_formated_range(self):
start_date, end_date = self.first_month_range
return "{} - {}".format(datetime.strftime(start_date, "%b, %d %Y"),
datetime.strftime(end_date, "%b, %d %Y"))
class Membership(models.Model):
type = models.ForeignKey(MembershipType)
@classmethod
def create(cls, data, user):
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
def create(cls, data):
instance = cls.objects.create(**data)
instance.assign_permissions(user)
return instance
class MembershipOrder(models.Model):
class MembershipOrder(Ordereable, models.Model):
membership = models.ForeignKey(Membership)
created_at = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
last4 = models.CharField(max_length=4)
cc_brand = models.CharField(max_length=10)
stripe_charge_id = models.CharField(max_length=100, null=True)
@classmethod
def create(cls, data):
stripe_charge = data.pop('stripe_charge', None)
instance = cls.objects.create(**data)
instance.stripe_charge_id = stripe_charge.id
instance.last4 = stripe_charge.source.last4
instance.cc_brand = stripe_charge.source.brand
return instance
class BookingPrice(models.Model):
price_per_day = models.FloatField()
special_price_offer = models.FloatField()
class Booking(models.Model):
start_date = models.DateField()
end_date = models.DateField()
price = models.FloatField()
free_days = models.IntegerField(default=0)
final_price = models.FloatField()
@classmethod
def create(cls, data):
instance = cls.objects.create(**data)
return instance
@classmethod
def get_ramaining_free_days(cls, user, start_date, end_date):
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_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
start_date__month=current_date.month)
free_days_this_month = TWO_DAYS - sum(map(lambda x: x.free_days, current_month_bookings))
total_free_days = months * TWO_DAYS + free_days_this_month
return total_free_days
@classmethod
def booking_price(cls, user, start_date, end_date):
MAX_MONTH_PRICE = 290
MAX_MONTH_DAYS_PROMOTION = 31
MIN_MONTH_DAYS_PROMOTION = 19
booking_prices = BookingPrice.objects.last()
price_per_day = booking_prices.price_per_day
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, start_date, end_date)
final_booking_price = normal_price - (free_days * price_per_day)
return normal_price, final_booking_price, free_days
class BookingOrder(Ordereable, models.Model):
booking = models.OneToOneField(Booking)
def booking_days(self):
return (self.booking.end_date - self.booking.start_date).days + 1
class Supporter(models.Model):
@ -44,9 +162,6 @@ class Supporter(models.Model):
return reverse('dgSupporters_view', args=[self.pk])
class DGGallery(models.Model):
parent = models.ForeignKey('self', blank=True, null=True)
name = models.CharField(max_length=30)

View file

@ -0,0 +1,25 @@
$( document ).ready(function() {
// $('#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({
autoUpdateInput: false,
locale: {
cancelLabel: 'Clear'
},
minDate: tomorrow,
});
$('#booking-date-range').on('apply.daterangepicker', function(ev, picker) {
$(this).val(picker.startDate.format('MM/DD/YYYY') + ' - ' + picker.endDate.format('MM/DD/YYYY'));
});
$('#booking-date-range').on('cancel.daterangepicker', function(ev, picker) {
$(this).val('Select your dates');
});
});

View 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") );
});
});

View file

@ -0,0 +1,53 @@
{% extends "new_base_glarus.html" %}
{% load staticfiles cms_tags bootstrap3%}
{% block title %}crowdfunding{% endblock %}
{% block content %}
<section id="price">
<div class="signup-container">
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
<div class="col-xs-12 col-sm-6 col-lg-4 text-center wow fadeInDown">
<div class="signup-box">
<span class="glyphicon glyphicon-plus"></span>
<h2 class="section-heading">Booking</h2>
<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>
<hr class="primary">
<div class="signup-form form-group row">
<input type="hidden" name="next" value="{{ request.GET.next }}">
<form action="" method="post" class="form" novalidate>
{% csrf_token %}
<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>
</form>
<br>
<div class="notice-box">
</div>
</div>
</div>
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"></div>
</div>
</div>
</section>
<section id="contact">
<div class="fill">
<div class="row" class="wow fadeInDown">
<div class="col-lg-12 text-center wow fadeInDown">
<div class="col-md-4 map-title">
Digital Glarus<br>
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland
<br>info@digitalglarus.ch
<br>
(044) 534-66-22
<p>&nbsp;</p>
</span>
</div>
<p>&nbsp;</p>
</div>
</div>
</div>
</section>
{% endblock %}

View file

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

View file

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

View file

@ -0,0 +1,186 @@
{% extends "new_base_glarus.html" %}
{% load staticfiles bootstrap3 i18n %}
{% block content %}
<style type="text/css">
.nopadding {
padding: 0 !important;
margin: 0 !important;
}
.form-control#id_country{
-webkit-appearance: none;
-moz-appearance: none;
background-position: right 50%;
background-repeat: no-repeat;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAMCAYAAABSgIzaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDZFNDEwNjlGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDZFNDEwNkFGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NkU0MTA2N0Y3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0NkU0MTA2OEY3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuGsgwQAAAA5SURBVHjaYvz//z8DOYCJgUxAf42MQIzTk0D/M+KzkRGPoQSdykiKJrBGpOhgJFYTWNEIiEeAAAMAzNENEOH+do8AAAAASUVORK5CYII=);
padding: .5em;
padding-right: 1.5em
}
</style>
<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">Booking</h2>
<!-- <h2 class="membership-amount">35CHF</h2> -->
<hr class="greyline-long">
<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">
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
{% bootstrap_form_errors form type='non_fields'%}
{{form.errors}}
<br>
</form>
</div>
<h2 class="billing-head">Credit Card</h2>
<div class="signup-form form-group row">
<form role="form" id="payment-form" novalidate>
<div class="row">
<div class="col-xs-9 col-md-12">
<div class="form-group">
<input type="text" class="form-control" name="cardName" placeholder="Name on card" required autofocus data-stripe="name" />
</div>
</div>
</div>
<div class="row">
<div class="col-xs-9 col-md-12">
<div class="form-group">
<input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required data-stripe="number" />
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-md-6 nopadding">
<label for="expMonth">EXPIRATION DATE</label><br/>
<div class="col-xs-6 col-lg-6 col-md-6">
<div class="form-group">
<input type="text" class="form-control" name="expMonth" placeholder="MM" required data-stripe="exp_month" />
</div>
</div>
<div class="col-xs-6 col-lg-6 col-md-6 pl-ziro">
<div class="form-group">
<input type="text" class="form-control" name="expYear" placeholder="YY" required data-stripe="exp_year" />
</div>
</div>
</div>
<div class="col-xs-4 col-md-6 pull-right">
<div class="form-group">
<label for="cvCode">CV CODE</label>
<input type="password" class="form-control" name="cvCode" placeholder="CV" required data-stripe="cvc" />
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button class="btn btn-primary btn-lg btn-blck " type="submit">Book</button>
</div>
</div>
<div class="row" style="display:none;">
<div class="col-xs-12">
<p class="payment-errors"></p>
</div>
</div>
{% if paymentError %}
<div class="row">
<div class="col-xs-12">
<p>
{% bootstrap_alert paymentError alert_type='danger' %}
</p>
</div>
</div>
{% endif %}
</form>
<br>
</div>
</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">Booking Summary</h2>
</div>
<div class="order-box">
<h3 class="col-xs-6 order-item">Dates {{start_date}} - {{end_date}}</h3>
<br/>
<hr class="greyline">
<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"><span class="text-danger">-{{total_discount|floatformat}}CHF</span></h2>
{% endif %}
<hr class="greyline">
<h2 class="col-xs-6 payment-total">Total</h2>
<h2 class="order-result">{{discount_price|floatformat}}CHF</h2>
<div class="text-center">
<label class="custom-control custom-checkbox">
<br/>
<input type="checkbox" class="custom-control-input">
<span class="custom-control-indicator"></span>
<span class="custom-control-description">I accept the Digital Glarus <a href=#>Terms and Conditions</a>, <a href=#>Community Guidelines</a> and <a href=#>Privacy Policy</a></span>
</label>
<div class="button-box">
</div>
<div class="button-box">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="contact">
<div class="fill">
<div class="row" class="wow fadeInDown">
<div class="col-lg-12 text-center wow fadeInDown">
<div class="col-md-4 map-title">
Digital Glarus<br>
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland
<br>info@digitalglarus.ch
<br>
(044) 534-66-22
<p>&nbsp;</p>
</span>
</div>
<p>&nbsp;</p>
</div>
</div>
</div>
</section>
<!-- stripe key data -->
{% if stripe_key %}
<script type="text/javascript">
(function () {window.stripeKey = "{{stripe_key}}";})();
</script>
{%endif%}
{% endblock %}

View file

@ -0,0 +1,57 @@
{% extends "new_base_glarus.html" %}
{% load staticfiles cms_tags bootstrap3%}
{% block title %}crowdfunding{% endblock %}
{% block content %}
<section id="price">
<div class="signup-container">
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
<div class="col-xs-12 col-sm-6 col-lg-4 text-center wow fadeInDown">
<!-- <span class="glyphicon glyphicon-user"></span> -->
<div class="payment-box">
<h2 class="billing-head">Membership Activated</h2>
<hr class="greyline-long">
<h2 class="membership-lead">Your Digital Glarus membership is successfully activated for the following date.</h2>
<div class="date-box">
<h2 class="date-oneline">{{membership_dates}}</h2>
<h2 class="activation-lead">Now you can book your next coworking!</h2>
</div>
<!--<hr class="primary">-->
<div class="signup-form form-group row">
<div class="button-booking-box form-inline row">
<a class="btn btn-primary btn-blue" href={% url 'digitalglarus:booking' %}>Go to Booking</a>
</div>
<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>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="contact">
<div class="fill">
<div class="row" class="wow fadeInDown">
<div class="col-lg-12 text-center wow fadeInDown">
<div class="col-md-4 map-title">
Digital Glarus<br>
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland
<br>info@digitalglarus.ch
<br>
(044) 534-66-22
<p>&nbsp;</p>
</span>
</div>
<p>&nbsp;</p>
</div>
</div>
</div>
</section>
{% endblock %}

View file

@ -8,6 +8,16 @@
padding: 0 !important;
margin: 0 !important;
}
.form-control#id_country{
-webkit-appearance: none;
-moz-appearance: none;
background-position: right 50%;
background-repeat: no-repeat;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAMCAYAAABSgIzaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDZFNDEwNjlGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDZFNDEwNkFGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NkU0MTA2N0Y3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0NkU0MTA2OEY3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuGsgwQAAAA5SURBVHjaYvz//z8DOYCJgUxAf42MQIzTk0D/M+KzkRGPoQSdykiKJrBGpOhgJFYTWNEIiEeAAAMAzNENEOH+do8AAAAASUVORK5CYII=);
padding: .5em;
padding-right: 1.5em
}
</style>
<section id="price">
@ -23,9 +33,13 @@
Additional day costs
15CHF per day. More than 17 days a month it
will charge only 290CHF/month.</h2>
<h2 class="membership-lead">
You will be charged on the first of the month until you
cancel your subscription. Previous charges won't be refunded.
</h2>
<hr class="greyline-long">
<h2 class="billing-head">Member Name</h2>
<h2 class="member-name">Nico Schottelius</h2>
<h2 class="member-name">{{request.user.name}}</h2>
<hr class="greyline-long">
<h2 class="billing-head">Billing Adress</h2>
<div class="signup-form form-group row">
@ -44,20 +58,14 @@
<div class="row">
<div class="col-xs-9 col-md-12">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" name="cardName" placeholder="Name on card" required autofocus data-stripe="name" />
<span class="input-group-addon"><i class="fa fa-user" aria-hidden="true"></i></span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-9 col-md-12">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required data-stripe="number" />
<span class="input-group-addon"><i class="fa fa-credit-card"></i></span>
</div>
</div>
</div>
</div>
@ -75,7 +83,7 @@
</div>
</div>
</div>
<div class="col-xs-4 col-md-6 pull-right nopadding">
<div class="col-xs-4 col-md-6 pull-right">
<div class="form-group">
<label for="cvCode">CV CODE</label>
<input type="password" class="form-control" name="cvCode" placeholder="CV" required data-stripe="cvc" />
@ -84,7 +92,7 @@
</div>
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success btn-lg btn-block" type="submit">Purchase membership</button>
<button class="btn btn-primary btn-lg btn-blck " type="submit">Purchase membership</button>
</div>
</div>
<div class="row" style="display:none;">
@ -115,25 +123,25 @@
<div class="order-box">
<h2 class="col-xs-6 order-item">Digital Glarus Membership</h2>
<br>
<h2 class="col-xs-6 order-duration">valid 2016.09.08 - 2016.10.08</h2>
<h2 class="col-xs-6 order-duration">valid {{membership_type.first_month_formated_range}}</h2>
<br/>
<h2 class="order-person">1 person</h2>
<h2 class="col-xs-6 payment-total">Today's Total</h2>
<h2 class="order-sum">0.00CHF</h2>
<h2 class="col-xs-6 payment-total">Today's Total for {{membership_type.days_left}} days </h2>
<h2 class="order-sum">{{membership_type.first_month_price|floatformat}}CHF</h2>
<hr class="greyline">
<h2 class="col-xs-6 payment-total">Total</h2>
<h2 class="order-result">35CHF</h2>
<h2 class="order-result">{{membership_type.first_month_price|floatformat}}CHF</h2>
<div class="text-center">
<label class="custom-control custom-checkbox">
<br/>
<input type="checkbox" class="custom-control-input">
<span class="custom-control-indicator"></span>
<span class="custom-control-description">I accept the Digital Glarus <a href=#>Terms and Conditions</a>, <a href=#>Community Guidelines</a> and <a href=#>Privacy Policy</a></span>
</label>
<div class="button-box">
<button type="submit" class="btn btn-primary">Continue to Review</button>
</div>
<div class="button-box">
<p class="order-bottom-text">You can checkout on the next page</p>
</div>
</div>
</div>

View file

@ -0,0 +1,87 @@
{% extends "new_base_glarus.html" %}
{% load staticfiles cms_tags bootstrap3%}
{% block title %}crowdfunding{% endblock %}
{% block content %}
<section id="price">
<div class="container">
<div class="row col-md-3 text-center wow fadeInDown"></div>
<div class="row col-md-6 text-center wow fadeInDown">
<div class="price-box">
<span class="glyphicon glyphicon-star"></span>
<h2 class="section-heading">Digital Glarus Membership</h2>
<h2 class="price"><strong>{{membership_type.price}}CHF</strong>/month<br> (free working 2days included)</h2>
<hr class="primary">
<img src="{% static 'digitalglarus/img/graph.png' %}" width="450" height="396" class="img-responsive center-block graph"><br>
<div class="price-exp-box"
<p class="carousel-text text-left supporter-black">
Get your Digital Glarus Membership for only
<strong>{{membership_type.price}}CHF</strong>
and get 2 working days for free!
The membership fee is a monthly subscription and
with every payment you help us to create a better
workspace.
You want to work more than 2 days per month in our
coworking space? Great! It's only <strong> 15CHF</strong>
per additional day.
You want more? That's really cool!
If you work 17 days a month or EVERY DAY of a month,
you can do so for <strong> 290CHF</strong>/month..
And the best? The discount is
applied automatically!
Just become a member, book your
working day and we will take care of the rest.
</p>
<div class="text-center">
<a class="btn btn-primary btn-blue" href="{% url 'digitalglarus:membership_payment' %}">become a member</a>
</div>
</div>
</div>
</div>
<div class="row col-md-3 text-center wow fadeInDown"></div>
</div>
</section>
<!--membership includes-->
<section id="membership-includes">
<div class="container">
<div class="intro-price text-center wow fadeInDown">
<div class="intro-headline-small">
<span class="intro-headline-small">
Become our member
</span>
</div>
<h3 class="intro-smaller">Our membership includes:</h3>
<div class="col-lg-12 price-list">
<li class="list-group-item row price-list">
<div class="price-list"><span class="glyphicon glyphicon-ok "></span>Super-fast Internet</div>
<div class="price-list"><span class="glyphicon glyphicon-ok glyphicon-inverse"></span>Any workspace in our common areas</div>
<div class="price-list"><span class="glyphicon glyphicon-ok "></span>Free 2 working day passes</div>
<div class="price-list"><span class="glyphicon glyphicon-ok glyphicon-inverse"></span>Access to any of our great workshops</div>
<div class="price-list"><span class="glyphicon glyphicon-ok "></span>Special invitation to our fondue nights, cooking & hacking sessions, coworking & cohiking, and many more cool stuff.</div>
</li>
</div>
</div>
</div>
</div>
</section>
<section id="contact">
<div class="fill">
<div class="row" class="wow fadeInDown">
<div class="col-lg-12 text-center wow fadeInDown">
<div class="col-md-4 map-title">
Digital Glarus<br>
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland
<br>info@digitalglarus.ch
<br>
(044) 534-66-22
<p>&nbsp;</p>
</span>
</div>
<p>&nbsp;</p>
</div>
</div>
</div>
</section>
{% endblock %}

View file

@ -18,7 +18,7 @@
<div class="signup-form form-group row">
<form action="{% url 'digitalglarus:signup' %}" method="post" class="form" novalidate>
{% csrf_token %}
<input type="hidden" name="" value="{{ request.GET.next }}">
<input type="hidden" name="next" value="{{ request.GET.next }}">
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}

View file

@ -93,7 +93,7 @@
<a class="page-scroll" href="{% url 'digitalglarus:login' %}">Log In</a>
</li>
<li>
<a class="page-scroll" href="{% url 'digitalglarus:login' %}">Sign Up</a>
<a class="page-scroll" href="{% url 'digitalglarus:signup' %}">Sign Up</a>
</li>
</ul>
</div>
@ -167,11 +167,27 @@
<!-- Custom Fonts -->
<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="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Kaushan+Script" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic,700italic" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Roboto+Slab:400,100,300,700" rel="stylesheet" type="text/css">
<!-- Include Required Prerequisites -->
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<!-- <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap/latest/css/bootstrap.css" />
-->
<!-- Include Date Range Picker -->
<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 -->
<script src="{% static 'digitalglarus/js/booking.js' %}"></script>
<!-- Utils JavaScript -->
<script src="{% static 'digitalglarus/js/utils.js' %}"></script>
<!-- Custom Fonts -->
<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="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Kaushan+Script" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic,700italic" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Roboto+Slab:400,100,300,700" rel="stylesheet" type="text/css">
</html>

View file

@ -3,7 +3,9 @@ from django.utils.translation import ugettext_lazy as _
from . import views
from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
BookingOrdersListView
# from membership.views import LoginRegistrationView
urlpatterns = [
@ -11,11 +13,23 @@ urlpatterns = [
url(_(r'contact/?$'), ContactView.as_view(), name='contact'),
url(_(r'login/?$'), LoginView.as_view(), name='login'),
url(_(r'signup/?$'), SignupView.as_view(), name='signup'),
url(r'^logout/?$', 'django.contrib.auth.views.logout',
{'next_page': '/digitalglarus/login?logged_out=true'}, name='logout'),
url(r'reset-password/?$', PasswordResetView.as_view(), name='reset_password'),
url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
PasswordResetConfirmView.as_view(), name='reset_password_confirm'),
url(_(r'history/?$'), HistoryView.as_view(), name='history'),
url(_(r'membership/payment?$'), MembershipPaymentView.as_view(), name='membership_payment'),
url(_(r'booking/?$'), BookingSelectDatesView.as_view(), name='booking'),
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/activated/?$'), MembershipActivatedView.as_view(),
name='membership_activated'),
url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(),
name='membership_pricing'),
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/', views.CalendarApi.as_view(),name='calendar_api'),

View file

@ -13,13 +13,13 @@ from django.utils.translation import get_language
from djangocms_blog.models import Post
from django.contrib import messages
from django.http import JsonResponse
from django.views.generic import View
from django.views.generic import View, DetailView, ListView
from .models import Supporter
from utils.forms import ContactUsForm
from django.views.generic.edit import FormView
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, \
@ -28,8 +28,13 @@ from utils.forms import PasswordResetRequestForm
from utils.stripe_utils import StripeUtils
from .forms import LoginForm, SignupForm, MembershipBillingForm
from .models import MembershipType
from .forms import LoginForm, SignupForm, MembershipBillingForm, BookingDateForm,\
BookingBillingForm
from .models import MembershipType, Membership, MembershipOrder, Booking, BookingPrice,\
BookingOrder
from .mixins import MembershipRequired
class IndexView(TemplateView):
@ -63,7 +68,7 @@ class PasswordResetConfirmView(PasswordResetConfirmViewMixin):
class HistoryView(TemplateView):
template_name = "digitalglarus/history.html"
def get_context_data(self, **kwargs):
def get_context_data(self, *args, **kwargs):
context = super(HistoryView, self).get_context_data(**kwargs)
supporters = Supporter.objects.all()
context.update({
@ -72,28 +77,177 @@ class HistoryView(TemplateView):
return context
class BookingSelectDatesView(LoginRequiredMixin, MembershipRequired, FormView):
template_name = "digitalglarus/booking.html"
form_class = BookingDateForm
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
login_url = reverse_lazy('digitalglarus:login')
success_url = reverse_lazy('digitalglarus:booking_payment')
def form_valid(self, form):
user = self.request.user
start_date = form.cleaned_data.get('start_date')
end_date = form.cleaned_data.get('end_date')
booking_days = (end_date - start_date).days + 1
original_price, discount_price, free_days = Booking.\
booking_price(user, start_date, end_date)
self.request.session.update({
'original_price': original_price,
'discount_price': discount_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 super(BookingSelectDatesView, self).form_valid(form)
class BookingPaymentView(LoginRequiredMixin, MembershipRequired, FormView):
template_name = "digitalglarus/booking_payment.html"
form_class = BookingBillingForm
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',
'start_date', 'end_date']
def dispatch(self, request, *args, **kwargs):
from_booking = all(field in request.session.keys()
for field in self.booking_needed_fields)
if not from_booking:
return HttpResponseRedirect(reverse('digitalglarus:booking'))
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):
form_kwargs = super(BookingPaymentView, self).get_form_kwargs()
form_kwargs.update({
'initial': {
'start_date': self.request.session.get('start_date'),
'end_date': self.request.session.get('end_date'),
'price': self.request.session.get('discount_price'),
}
})
return form_kwargs
def get_context_data(self, *args, **kwargs):
context = super(BookingPaymentView, self).get_context_data(*args, **kwargs)
booking_data = {key: self.request.session.get(key)
for key in self.booking_needed_fields}
booking_price_per_day = BookingPrice.objects.get().price_per_day
total_discount = booking_price_per_day * booking_data.get('free_days')
booking_data.update({
'booking_price_per_day': booking_price_per_day,
'total_discount': total_discount,
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
})
context.update(booking_data)
return context
def form_valid(self, form):
data = form.cleaned_data
context = self.get_context_data()
token = data.get('token')
start_date = data.get('start_date')
end_date = data.get('end_date')
normal_price, final_price, free_days = Booking.\
booking_price(self.request.user, start_date, end_date)
# Get or create stripe customer
customer = StripeCustomer.get_or_create(email=self.request.user.email,
token=token)
if not customer:
form.add_error("__all__", "Invalid credit card")
return self.render_to_response(self.get_context_data(form=form))
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge_response = stripe_utils.make_charge(amount=final_price,
customer=customer.stripe_id)
charge = charge_response.get('response_object')
# Check if the payment was approved
if not charge:
context.update({
'paymentError': charge_response.get('error'),
'form': form
})
return render(self.request, self.template_name, context)
charge = charge_response.get('response_object')
# Create Billing Address
billing_address = form.save()
# Create membership plan
booking_data = {
'start_date': start_date,
'end_date': end_date,
'start_date': start_date,
'free_days': free_days,
'price': normal_price,
'final_price': final_price,
}
booking = Booking.create(booking_data)
# Create membership order
order_data = {
'booking': booking,
'customer': customer,
'billing_address': billing_address,
'stripe_charge': charge
}
order = BookingOrder.create(order_data)
# request.session.update({
# 'membership_price': membership.type.first_month_price,
# 'membership_dates': membership.type.first_month_formated_range
# })
return HttpResponseRedirect(self.get_success_url(order.id))
return super(BookingPaymentView, self).form_valid(form)
# return HttpResponseRedirect(reverse('digitalglarus:membership_activated'))
class MembershipPricingView(TemplateView):
template_name = "digitalglarus/membership_pricing.html"
def get_context_data(self, **kwargs):
context = super(MembershipPricingView, self).get_context_data(**kwargs)
membership_type = MembershipType.objects.last()
context.update({
'membership_type': membership_type
})
return context
class MembershipPaymentView(LoginRequiredMixin, FormView):
template_name = "digitalglarus/membership_payment.html"
login_url = reverse_lazy('digitalglarus:login')
login_url = reverse_lazy('digitalglarus:signup')
form_class = MembershipBillingForm
def get_form_kwargs(self):
membership_type = MembershipType.objects.get(name='standard')
self.membership_type = MembershipType.objects.get(name='standard')
form_kwargs = super(MembershipPaymentView, self).get_form_kwargs()
form_kwargs.update({
'initial': {'membership_type': membership_type.id}
'initial': {
'membership_type': self.membership_type.id
}
})
return form_kwargs
def get_context_data(self, **kwargs):
context = super(MembershipPaymentView, self).get_context_data(**kwargs)
context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
'stripe_key': settings.STRIPE_API_PUBLIC_KEY,
'membership_type': self.membership_type
})
return context
def post(self, request, *args, **kwargs):
import pdb;pdb.set_trace()
form = self.get_form()
if form.is_valid():
@ -111,7 +265,7 @@ class MembershipPaymentView(LoginRequiredMixin, FormView):
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge_response = stripe_utils.make_charge(amount=membership_type.price,
charge_response = stripe_utils.make_charge(amount=membership_type.first_month_price,
customer=customer.stripe_id)
charge = charge_response.get('response_object')
@ -124,10 +278,93 @@ class MembershipPaymentView(LoginRequiredMixin, FormView):
return render(request, self.template_name, context)
charge = charge_response.get('response_object')
# Create Billing Address
billing_address = form.save()
# Create membership plan
membership_data = {'type': membership_type}
membership = Membership.create(membership_data)
# Create membership order
order_data = {
'membership': membership,
'customer': customer,
'billing_address': billing_address,
'stripe_charge': charge
}
MembershipOrder.create(order_data)
request.session.update({
'membership_price': membership.type.first_month_price,
'membership_dates': membership.type.first_month_formated_range
})
return HttpResponseRedirect(reverse('digitalglarus:membership_activated'))
else:
return self.form_invalid(form)
class MembershipActivatedView(TemplateView):
template_name = "digitalglarus/membership_activated.html"
def get_context_data(self, **kwargs):
context = super(MembershipActivatedView, self).get_context_data(**kwargs)
membership_price = self.request.session.get('membership_price')
membership_dates = self.request.session.get('membership_dates')
context.update({
'membership_price': membership_price,
'membership_dates': membership_dates,
})
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
class CalendarApi(View):

View file

@ -1,5 +1,8 @@
from datetime import datetime
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, AbstractUser, PermissionsMixin