diff --git a/digitalglarus/forms.py b/digitalglarus/forms.py
index 10f73b31..03a5e6cd 100644
--- a/digitalglarus/forms.py
+++ b/digitalglarus/forms.py
@@ -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
diff --git a/digitalglarus/migrations/0009_booking_bookingorder_bookingprices.py b/digitalglarus/migrations/0009_booking_bookingorder_bookingprices.py
new file mode 100644
index 00000000..784c1f54
--- /dev/null
+++ b/digitalglarus/migrations/0009_booking_bookingorder_bookingprices.py
@@ -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()),
+ ],
+ ),
+ ]
diff --git a/digitalglarus/migrations/0010_auto_20160828_1745.py b/digitalglarus/migrations/0010_auto_20160828_1745.py
new file mode 100644
index 00000000..b526562f
--- /dev/null
+++ b/digitalglarus/migrations/0010_auto_20160828_1745.py
@@ -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',
+ ),
+ ]
diff --git a/digitalglarus/migrations/0011_bookingprice_special_price_offer.py b/digitalglarus/migrations/0011_bookingprice_special_price_offer.py
new file mode 100644
index 00000000..08a75e39
--- /dev/null
+++ b/digitalglarus/migrations/0011_bookingprice_special_price_offer.py
@@ -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,
+ ),
+ ]
diff --git a/digitalglarus/migrations/0012_booking_free_days.py b/digitalglarus/migrations/0012_booking_free_days.py
new file mode 100644
index 00000000..17d95319
--- /dev/null
+++ b/digitalglarus/migrations/0012_booking_free_days.py
@@ -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),
+ ),
+ ]
diff --git a/digitalglarus/migrations/0013_remove_booking_membership.py b/digitalglarus/migrations/0013_remove_booking_membership.py
new file mode 100644
index 00000000..7b2ffa24
--- /dev/null
+++ b/digitalglarus/migrations/0013_remove_booking_membership.py
@@ -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',
+ ),
+ ]
diff --git a/digitalglarus/mixins.py b/digitalglarus/mixins.py
new file mode 100644
index 00000000..6d555f24
--- /dev/null
+++ b/digitalglarus/mixins.py
@@ -0,0 +1,25 @@
+from django.db import models
+from membership.models import StripeCustomer
+from utils.models import BillingAddress
+
+
+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
+ return instance
diff --git a/digitalglarus/models.py b/digitalglarus/models.py
index e5b3ab88..e229fabd 100644
--- a/digitalglarus/models.py
+++ b/digitalglarus/models.py
@@ -6,9 +6,10 @@ 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
+# from membership.models import StripeCustomer
+# from utils.models import BillingAddress
class MembershipType(models.Model):
@@ -64,15 +65,8 @@ class Membership(models.Model):
return instance
-class MembershipOrder(models.Model):
+class MembershipOrder(Ordereable, models.Model):
membership = models.ForeignKey(Membership)
- 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)
@classmethod
def create(cls, data):
@@ -84,6 +78,70 @@ class MembershipOrder(models.Model):
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)
+
+ @classmethod
+ def create(cls, data):
+ instance = cls.objects.create(**data)
+ return instance
+
+ @classmethod
+ def get_ramaining_free_days(cls, user):
+ # ZERO_DAYS = 0
+ # ONE_DAY = 1
+ TWO_DAYS = 2
+
+ current_date = datetime.today()
+ current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
+ start_date__month=current_date.month)
+ free_days = TWO_DAYS - sum(map(lambda x: x.days, current_month_bookings))
+ return 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
+ def booking_price(cls, user, start_date, end_date):
+ """
+ Calculate the booking price for requested dates
+ How it does:
+ 1. Check if the user has booked the current month
+ 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()
+ price_per_day = booking_prices.price_per_day
+ booking_days = (end_date - start_date).days
+
+ free_days = cls.get_ramaining_free_days(user)
+ final_booking_price = (booking_days - free_days) * price_per_day
+ original_booking_price = (booking_days) * price_per_day
+
+ return original_booking_price, final_booking_price, free_days
+
+
+class BookingOrder(Ordereable, models.Model):
+ booking = models.OneToOneField(Booking)
+
+
class Supporter(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
diff --git a/digitalglarus/static/digitalglarus/js/booking.js b/digitalglarus/static/digitalglarus/js/booking.js
new file mode 100644
index 00000000..ed1929d4
--- /dev/null
+++ b/digitalglarus/static/digitalglarus/js/booking.js
@@ -0,0 +1,22 @@
+$( document ).ready(function() {
+
+ // $('#booking-date-range').daterangepicker();
+
+
+ $('#booking-date-range').daterangepicker({
+ autoUpdateInput: false,
+ locale: {
+ cancelLabel: 'Clear'
+ }
+ });
+
+
+ $('#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');
+ });
+
+});
\ No newline at end of file
diff --git a/digitalglarus/templates/digitalglarus/booking.html b/digitalglarus/templates/digitalglarus/booking.html
new file mode 100644
index 00000000..6a8d4374
--- /dev/null
+++ b/digitalglarus/templates/digitalglarus/booking.html
@@ -0,0 +1,53 @@
+{% extends "new_base_glarus.html" %}
+{% load staticfiles cms_tags bootstrap3%}
+{% block title %}crowdfunding{% endblock %}
+
+{% block content %}
+
+ Booking
+ Start coworking at Digital Glarus!
+
Membership costs only
+ 35CHF per month.
2 free working days included!
+
+
+
+
+ Booking
+
+
+ Billing Adress
+ Credit Card
+
+ Booking Summary
+ Dates {{start_date}} - {{end_date}}
+
+
+
+ Total days {{booking_days}}
+ {{original_price|floatformat}}CHF
+ {% if free_days %}
+ Free days {{free_days}}
+ -{{total_discount|floatformat}}CHF
+ {% endif %}
+
+ Total
+ {{discount_price|floatformat}}CHF
+
+
+ Digital Glarus Membership
+ {{membership_type.price}}CHF/month
+
(free working 2days included)
+
+ Our membership includes:
+
+
+