Merge pull request #137 from levivm/feature/new_digitalglarus

Feature/new digitalglarus
This commit is contained in:
Levi Velázquez 2016-10-23 18:22:05 -05:00 committed by GitHub
commit 2362413b60
69 changed files with 4954 additions and 184 deletions

View file

@ -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)

117
digitalglarus/forms.py Normal file
View file

@ -0,0 +1,117 @@
from django import forms
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from datetime import datetime
from utils.models import BillingAddress
from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm
from .models import MembershipType, MembershipOrder
from .models import Booking
class LoginForm(LoginFormMixin):
email = forms.CharField(widget=forms.EmailInput())
password = forms.CharField(widget=forms.PasswordInput())
class SignupForm(SignupFormMixin):
confirm_password = forms.CharField(widget=forms.PasswordInput())
password = forms.CharField(widget=forms.PasswordInput())
name = forms.CharField(label='name',
widget=forms.TextInput(attrs={'placeholder': 'Full name'}))
class MembershipBillingForm(BillingAddressForm):
token = forms.CharField(widget=forms.HiddenInput())
membership_type = forms.ModelChoiceField(queryset=MembershipType.objects.all(),
widget=forms.HiddenInput())
class Meta:
model = BillingAddress
fields = ['membership_type', 'street_address', 'city', 'postal_code', 'country']
labels = {
'street_address': _('Street Address'),
'city': _('City'),
'postal_code': _('Postal Code'),
'country': _('Country'),
}
class MembershipOrderForm(forms.ModelForm):
class Meta:
model = MembershipOrder
fields = ['membership', 'customer', 'billing_address',
'last4', 'cc_brand', 'stripe_charge_id', 'amount']
# def save(self, commit=True):
# instance = super(MembershipOrderForm, self).save(commit=False)
# # if commit:
# # DonatorStatus.create(self.cleaned_data['donator'].user)
# # instance.save()
# return instance
class BookingBillingForm(BillingAddressForm):
token = forms.CharField(widget=forms.HiddenInput(), required=False)
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,
widget=forms.TextInput(attrs={'id': 'booking-date-1',
'value': 'Select your date'}))
end_date = forms.DateField(required=False,
widget=forms.TextInput(attrs={'id': 'booking-date-2'}))
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(BookingDateForm, self).__init__(*args, **kwargs)
def clean_start_date(self):
start_date = self.cleaned_data.get('start_date')
if not start_date:
raise forms.ValidationError("This field is required.")
return start_date
def clean_end_date(self):
end_date = self.cleaned_data.get('end_date')
if not end_date:
raise forms.ValidationError("This field is required.")
return end_date
def clean(self):
start_date = self.cleaned_data.get('start_date')
end_date = self.cleaned_data.get('end_date')
if not start_date or not end_date:
return self.cleaned_data
if start_date > end_date:
raise forms.ValidationError("Your end date must be greather than your start date.")
q1 = Q(bookingorder__customer__user=self.user,
start_date__lte=start_date, end_date__gte=start_date)
q2 = Q(bookingorder__customer__user=self.user,
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 self.cleaned_data

View file

@ -0,0 +1,97 @@
from django.core.management.base import BaseCommand
from datetime import datetime
from django.utils import translation
from utils.stripe_utils import StripeUtils
from utils.mailer import BaseEmail
from digitalglarus.models import MembershipOrder
from digitalglarus.forms import MembershipOrderForm
# from membership.U
# from nosystemd.models import DonatorStatus, Donation
# from nosystemd.forms import DonationForm
class Command(BaseCommand):
help = 'Make the monthly stripe charge to all donators'
CURRENCY = 'usd'
def handle(self, *args, **options):
translation.activate('en-us')
memberships_orders = MembershipOrder.objects.filter(membership__active=True)
current_month = datetime.now().month
current_year = datetime.now().year
print("--------- STARTING MEMBERSHIP CHARGING SCRIPT ---------")
print("Memberhips date: %s-%s" % (current_month, current_year))
for membership_order in memberships_orders:
member = membership_order.customer
try:
MembershipOrder.objects.get(created_at__month=current_month,
created_at__year=current_year,
customer=member)
except MembershipOrder.DoesNotExist:
try:
current_membership_price = membership_order.membership.type.price
last_membership_order = MembershipOrder.objects.filter(customer=member).last()
# Make stripe charge to a customer
stripe_utils = StripeUtils()
stripe_utils.CURRENCY = self.CURRENCY
charge_response = stripe_utils.make_charge(amount=current_membership_price,
customer=member.stripe_id)
charge = charge_response.get('response_object')
# Check if the payment was approved
if not charge:
# There is an error trying to creating the stripe charge
context = {
'paymentError': charge_response.get('error'),
}
print("--------- STRIPE PAYMENT ERROR ---------")
print(context)
print("-------------------------")
continue
# Create a donation
charge = charge_response.get('response_object')
membership_order_data = {
'cc_brand': charge.source.brand,
'stripe_charge_id': charge.id,
'last4': charge.source.last4,
'membership': last_membership_order.membership.id,
'billing_address': last_membership_order.billing_address.id,
'customer': member.id,
'amount': current_membership_price
}
membership_order_form = MembershipOrderForm(membership_order_data)
if membership_order_form.is_valid():
membership_order = membership_order_form.save()
context = {
'order': membership_order,
'base_url': "{0}://{1}".format('https', 'dynamicweb.ungleich.ch')
}
email_data = {
'subject': 'Your monthly membership has been charged',
'to': member.user.email,
'context': context,
'template_name': 'membership_monthly_charge',
'template_path': 'digitalglarus/emails/'
}
email = BaseEmail(**email_data)
email.send()
print("--------- PAYMENT DONATION SUCCESSFULL ---------")
print("Member: %s" % member.user.email)
print("Amount: %s %s" % (current_membership_price, self.CURRENCY))
print("-----------------------------------------------")
except Exception as e:
print("--------- ERROR ---------")
print(e)
print("-------------------------")
continue

View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-08-20 04:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0006_delete_message'),
]
operations = [
migrations.CreateModel(
name='Membership',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
migrations.CreateModel(
name='MembershipOrder',
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)),
('membership', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='digitalglarus.Membership')),
],
),
migrations.CreateModel(
name='MembershipType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(choices=[('standard', 'Standard')], max_length=20)),
('price', models.FloatField()),
],
),
migrations.AddField(
model_name='membership',
name='type',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='digitalglarus.MembershipType'),
),
]

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

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

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

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-09-13 01:51
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0016_auto_20160909_0110'),
]
operations = [
migrations.AddField(
model_name='membership',
name='active',
field=models.BooleanField(default=True),
),
]

View file

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-09-28 04:24
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0017_membership_active'),
]
operations = [
migrations.AddField(
model_name='bookingorder',
name='membership_required_months',
field=models.IntegerField(default=0),
preserve_default=False,
),
migrations.AddField(
model_name='bookingorder',
name='membership_required_months_price',
field=models.FloatField(default=0),
preserve_default=False,
),
]

View file

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-09-29 03:24
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0018_auto_20160928_0424'),
]
operations = [
migrations.AlterField(
model_name='bookingorder',
name='membership_required_months',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='bookingorder',
name='membership_required_months_price',
field=models.FloatField(default=0),
),
]

View file

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-10-13 02:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0019_auto_20160929_0324'),
]
operations = [
migrations.AlterField(
model_name='bookingorder',
name='cc_brand',
field=models.CharField(blank=True, max_length=10),
),
migrations.AlterField(
model_name='bookingorder',
name='last4',
field=models.CharField(blank=True, max_length=4),
),
migrations.AlterField(
model_name='membershiporder',
name='cc_brand',
field=models.CharField(blank=True, max_length=10),
),
migrations.AlterField(
model_name='membershiporder',
name='last4',
field=models.CharField(blank=True, max_length=4),
),
]

View file

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-10-17 19:58
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0020_auto_20161013_0253'),
]
operations = [
migrations.AddField(
model_name='membership',
name='end_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 0, 209303, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='membership',
name='start_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 7, 361473, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='membershiporder',
name='end_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 15, 657240, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='membershiporder',
name='start_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 16, 897120, tzinfo=utc)),
preserve_default=False,
),
]

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-10-23 02:18
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0021_auto_20161017_1958'),
]
operations = [
migrations.RemoveField(
model_name='bookingorder',
name='membership_required_months',
),
migrations.RemoveField(
model_name='bookingorder',
name='membership_required_months_price',
),
]

52
digitalglarus/mixins.py Normal file
View file

@ -0,0 +1,52 @@
from django.db import models
from django.http import HttpResponseRedirect
from membership.models import StripeCustomer
from utils.models import BillingAddress
class MembershipRequiredMixin(object):
membership_redirect_url = None
def dispatch(self, request, *args, **kwargs):
from .models import Membership
if not Membership.is_digitalglarus_active_member(request.user):
return HttpResponseRedirect(self.membership_redirect_url)
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_active_member(request.user):
return HttpResponseRedirect(self.already_member_redirect_url)
return super(IsNotMemberMixin, self).dispatch(request, *args, **kwargs)
class Ordereable(models.Model):
customer = models.ForeignKey(StripeCustomer)
amount = models.FloatField()
billing_address = models.ForeignKey(BillingAddress)
created_at = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
last4 = models.CharField(max_length=4, blank=True)
cc_brand = models.CharField(max_length=10, blank=True)
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)
if not stripe_charge:
return instance
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,234 @@
import calendar
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
from django.db import models from django.db import models
from django.db.models import Q
from cms.models import CMSPlugin from cms.models import CMSPlugin
from filer.fields.image import FilerImageField from filer.fields.image import FilerImageField
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
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):
STANDARD = 'standard'
MEMBERSHIP_TYPES = (
(STANDARD, 'Standard'),
)
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)
active = models.BooleanField(default=True)
start_date = models.DateField()
end_date = models.DateField()
@classmethod
def get_by_user(cls, user):
return cls.objects.\
filter(membershiporder__customer__user=user).last()
@classmethod
def create(cls, data):
instance = cls.objects.create(**data)
return instance
@classmethod
def is_digitalglarus_active_member(cls, user):
past_month = (datetime.today() - relativedelta(months=1)).month
has_order_current_month = Q(membershiporder__customer__user=user,
membershiporder__created_at__month=datetime.today().month)
has_order_past_month = Q(membershiporder__customer__user=user,
membershiporder__created_at__month=past_month)
active_membership = Q(active=True)
return cls.objects.filter(has_order_past_month | has_order_current_month).\
filter(active_membership).exists()
def update_dates(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
self.save()
def deactivate(self):
self.active = False
self.save()
class MembershipOrder(Ordereable, models.Model):
membership = models.ForeignKey(Membership)
start_date = models.DateField()
end_date = models.DateField()
@classmethod
def current_membership_dates(cls, user):
last_membership_payment = cls.objects.\
filter(customer__user=user).last()
if not last_membership_payment:
return [None, None]
return last_membership_payment.start_date, last_membership_payment.end_date
@classmethod
def next_membership_dates(cls, user):
current_start_date, current_end_date = cls.current_membership_dates(user)
if not current_start_date or not current_end_date:
return [None, None]
next_start_date = current_end_date + relativedelta(months=1)
_, days_in_month = calendar.monthrange(next_start_date.year,
next_start_date.month)
next_start_date = next_start_date.replace(day=1)
next_end_date = next_start_date + timedelta(days=days_in_month)
return next_start_date, next_end_date
def first_membership_range_date(self):
start_date = self.created_at
_, days_in_month = calendar.monthrange(start_date.year,
start_date.month)
pass_days = start_date.day
days_left = days_in_month - pass_days
end_date = start_date + timedelta(days=days_left)
return start_date, end_date
def get_membership_order_cc_data(self):
return {
'last4': self.last4,
'cc_brand': self.cc_brand,
}
def get_membership_range_date(self):
return self.start_date, self.end_date
@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
class BookingPrice(models.Model):
price_per_day = models.FloatField()
special_month_price = 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
ONE_DAY = 1
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))
if start_date == end_date and free_days_this_month == TWO_DAYS:
free_days_this_month = ONE_DAY
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 = BookingPrice.objects.last().special_month_price
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)
original_price = models.FloatField()
special_month_price = models.FloatField()
@classmethod
def user_has_not_bookings(cls, user):
return cls.objects.filter(customer__user=user).exists()
def get_booking_cc_data(self):
return {
'last4': self.last4,
'cc_brand': self.cc_brand,
} if self.last4 and self.cc_brand else None
def booking_days(self):
return (self.booking.end_date - self.booking.start_date).days + 1
class Supporter(models.Model): class Supporter(models.Model):
@ -15,7 +242,6 @@ class Supporter(models.Model):
return reverse('dgSupporters_view', args=[self.pk]) return reverse('dgSupporters_view', args=[self.pk])
class DGGallery(models.Model): class DGGallery(models.Model):
parent = models.ForeignKey('self', blank=True, null=True) parent = models.ForeignKey('self', blank=True, null=True)
name = models.CharField(max_length=30) name = models.CharField(max_length=30)

View file

@ -241,6 +241,8 @@ fieldset[disabled] .btn-xl.active {
.navbar-default .navbar-collapse { .navbar-default .navbar-collapse {
border-color: rgba(255,255,255,.02); border-color: rgba(255,255,255,.02);
padding-right: 100px;
text-align: right;
} }
.navbar-default .navbar-toggle { .navbar-default .navbar-toggle {
@ -259,7 +261,7 @@ fieldset[disabled] .btn-xl.active {
.navbar-default .nav li a { .navbar-default .nav li a {
text-transform: uppercase; text-transform: uppercase;
font-family: Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif; font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-weight: 400; font-weight: 400;
letter-spacing: 1px; letter-spacing: 1px;
color: #fff; color: #fff;
@ -1170,11 +1172,11 @@ footer {
} }
.map-caption{ .map-caption{
text-transform: none; text-transform:uppercase;
font-size: 13px;
font-family:"Montserrat","Helvetica Neue",Helvetica, Arial,sans-serif; font-family:"Montserrat","Helvetica Neue",Helvetica, Arial,sans-serif;
font-weight: 400; font-weight: 400;
color: #ffffff; color: #ffffff;
font-size: 14px;
letter-spacing: 1px; letter-spacing: 1px;
text-align:center; text-align:center;
} }

View file

@ -0,0 +1,622 @@
@charset "UTF-8";
/* CSS Document */
#membership-includes {
text-align: center;
color: #fff;
background-attachment: scroll;
background-image: url(../img/header_bg_5.png);
background-position: center center;
background-repeat: none;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
-o-background-size: cover;
}
.intro-headline-small{
font-family: 'Raleway' , "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif;
font-size: 46px;
font-style: normal;
font-weight: 200;
text-transform: none;
text-transform: uppercase;
color: #FFF;
}
.intro-smaller {
font-family: 'Raleway' ,'Montserrat' ,"Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif;
font-size: 16px;
font-style: normal;
font-weight: 100;
text-transform: none;
color: #FFF;
}
.intro-price {
padding-top: 70px;
padding-bottom: 50px;
}
.ul{
columns: 2;
padding: 15px 0;
font-size: 18px;
font-weight: 300;
color: #fff;
margin: 40px 0;
}
.price-list{
background-color: transparent;
font-size: 18px;
border: 0;
padding-top: 15px;
padding-bottom: 15px;
}
.price{
text-transform: none;
}
#price {
background-image: url(../img/bg-price.png);
background-position: center center;
background-repeat: none;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
-o-background-size: cover;
}
.price-box{
padding-left: 15px;
padding-right: 15px;
padding-top: 15px;
padding-bottom: 30px;
margin-top: 80px;
margin-bottom: 30px;
margin-left: 10px;
margin-right: 10px;
color: inherit;
background-color: #fff;
}
.graph{
padding-top: 30px;
}
.glyphicon-ok{
margin-right: 0.5em;
}
.glyphicon-plus{
font-size: 42px;
display: block;
text-align: center;
margin: 40px auto 20px;
color: #88c7d7;
}
.signup-container {
padding: 0;
margin: 0;
overflow-x: hidden;
}
.greyline{
border-color: #ddd;
border-width: 1px;
max-width: 600px;
}
.greyline-long{
border-color: #ddd;
border-width: 1px;
max-width: 95%;
}
.signup-form {
padding: 2em;
padding-top: 1em;
padding-bottom: 0.1em;
margin-bottom: 0px;
}
.signup-lead {
font-size: 16px;
line-height: 1.4em;
text-transform: none;
}
.form-control {
margin-bottom: 1em;
border-image-source: initial;
border-image-slice: initial;
border-image-width: initial;
border-image-outset: initial;
border-image-repeat: initial;
min-height: 20px;
background: rgb(255, 255, 255);
border-width: 1px;
border-style: solid;
border-color: rgba(37, 39, 41, 0.498039);
padding: 10.5px 10px;
transition: all 0.15s ease-in-out;
}
.notice-box {
padding-top: 1.5em;
padding-bottom: 2em;
}
.signup-text {
color: #777;
margin: 0;
line-height: 1.5;
font-size: 13px;
text-transform: none;
font-family: "Helvetica Neue" ,"Helvetica Neue" ,"Open Sans" ,"Arial" , sans-serif;
color: #999;
}
.signup-text a {
font-weight : 400;
margin-left: 0.5em;
color: #31708f;
}
.signup-notice a {
font-weight : 400;
margin-left: 0.5em;
color: #31708f;
}
.signup-box {
padding-left: 15px;
padding-right: 15px;
padding-top: 15px;
padding-bottom: 15px;
margin-top: 80px;
margin-bottom: 30px;
margin-left: 10px;
margin-right: 10px;
color: inherit;
background-color: #fff;
}
.signup-notice {
padding-top: 0.5em;
font-size: 12px;
color: #777;
}
.glyphicon-user{
font-size: 42px;
display: block;
text-align: center;
margin: 40px auto 20px;
color: #88c7d7;
}
.glyphicon-ok {
font-size: 28px;
display: block;
text-align: center;
margin-bottom: 20px;
color: #88c7d7;
margin-top: 0px;
}
}
.membership-amount{
font-size: 18px;
text-align: right;
width: 100%;
}
.payment-box{
padding-top: 3em;
padding-left: 30px;
padding-right: 30px;
padding-bottom: 15px;
margin-top: 80px;
margin-bottom: 30px;
margin-left: 10px;
margin-right: 10px;
color: inherit;
background-color: #fff;
}
.payment-head{
font-weight: 600;
padding-left: 15px;
text-align: left;
}
.membership-lead {
font-size: 16px;
line-height: 1.4em;
text-transform: none;
text-align: left;
padding-left: 15px;
padding-right: 15px;
font-family: helvetica neue, helvitica, open-sans, sans-serif;
font-weight: 200;
}
.order-name{
font-size: 18px;
text-transform: uppercase;
margin: 0;
font-weight: 700;
padding-top: 15px;
padding-bottom: 15px;
letter-spacing: 1px;
}
.order-person{
text-align: right;
margin-top: 0;
margin-bottom: 15px;
font-size: 20px;
color: #494949;
text-transform: none;
}
.order-item{
font-size: 18px;
text-transform: none;
font-weight: 400;
text-align: left;
width: 100%;
letter-spacing: 0.1px;
}
.order-duration {
padding-bottom: 1em;
color: #999;
font-size: 16px;
text-transform: none;
font-weight: 200;
text-align: left;
width: 100%;
margin-top: 5px;
}
.header{
padding: 12px 15px;
margin-bottom: 0;
border-bottom: 2px solid #f7f7f7;
background-color: #a1cfd7;
}
.payment-total{
font-size: 16px;
text-transform: none;
margin: 0;
font-weight: 200;
letter-spacing: 1px;
}
.order-sum {
text-align: right;
margin-top: 0;
margin-bottom: 15px;
font-size: 20px;
color: #494949;
}
.order-result {
font-family: open-sans, montserrat, Helvetica Neue, Helvetica, sans-serif;
margin-top: 0;
margin-bottom: 15px;
font-size: 28px;
color: #494949;
text-align: right;
}
.order-bottom-text {
padding-top: 0.5em;
color: #777;
padding-left: 15px;
font-size: 13px;
}
.order-bottom-text a {
font-weight : 400;
margin-left: 0.5em;
color: #31708f;
}
.order-summary {
background-color:#fff;
margin-top: 80px;
}
.order-box{
padding-top: 0;
padding-left: 20px;
padding-right: 20px;
padding-bottom: 15px;
margin-top: 0;
margin-bottom: 30px;
margin-left: 10px;
margin-right: 10px;
color: inherit;
background-color: #fff;
}
.billing-head {
padding-left: 15px;
margin-top: 0px;
margin-bottom: 0px;
font-weight: 400;
font-size: 21px;
text-align: left;
text-transform: none;
}
.reset-head {
padding-left: 15px;
margin-top: 0px;
margin-bottom: 0px;
font-weight: 400;
font-size: 24px;
text-align: left;
text-transform: none;
}
.form-control {
color: #000;
border-radius: 0px;
box-shadow: none;
}
.custom-control-description {
color: #999;
font-weight: 300;
font-family: "helvetica neue", "helvetica", "sans-serif" ;
letter-spacing: 0.5px;
font-size: 12px;
line-height: 1;
}
.custom-control-description a {
color: #31708f;
}
.custom-control {
text-align: left;
}
.button-box {
margin-top: 20px;
}
.date-box {
padding-top: 1.5em;
padding-bottom: 0.5em;
}
.date-oneline {
font-size: 16px;
text-transform: none;
margin: 0;
font-weight: 400;
letter-spacing: 1px;
color: #555;
}
.btn-grey {
background-color: #b2b7b9;;
border-color: #b2b7b9;;
}
.btn-grey:hover,
.btn-grey:focus,
.btn-grey:active,
.btn-grey.active,
.open .dropdown-toggle.btn-grey {
text-transform: uppercase;
font-weight: 400;
border-color: #ddd;
color: #fff;
background-color: #ddd;
}
.btn-blue:hover,
.btn-blue:focus,
.btn-blue:active,
.btn-blue.active,
.open .dropdown-toggle.btn-grey {
background-color: #5699b9;
border-color: #5699b9;
}
.loggedin-head {
padding-left: 15px;
margin-top: 0px;
margin-bottom: 0px;
font-weight: 400;
font-size: 21px;
text-align: center;
text-transform: none;
padding-top: 10px;
}
.loggedin-lead {
font-size: 16px;
line-height: 1.4em;
text-transform: none;
text-align: center;
padding-left: 15px;
padding-right: 15px;
font-family: helvetica neue, helvitica, open-sans, sans-serif;
font-weight: 200;
}
.activation-lead {
font-size: 15px;
line-height: 1.4em;
text-transform: none;
text-align: center;
padding-left: 15px;
padding-right: 15px;
padding-bottom: 0;
font-family: helvetica neue, helvitica, open-sans, sans-serif;
font-weight: 200;
color: #777;
}
.button-booking-box {
margin-top: 0;
}
.member-name{
font-size: 16px;
text-transform: none;
font-weight: 400;
text-align: left;
width: 100%;
letter-spacing: 0.1px;
text-align: left;
padding-left: 15px;
line-height: 0.35em;
}
.history-name{
font-size: 16px;
text-transform: none;
font-weight: 400;
text-align: left;
width: 100%;
letter-spacing: 0.1px;
text-align: left;
padding-left: 15px;
line-height: 1.4em;
}
.button-center-box {
margin-top: 20px;
text-align: center;
}
.table td, .table th {
padding: .75rem;
vertical-align: top;
border-top: 1px solid #eceeef;
}
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
padding: .75rem;
vertical-align: top;
border-top: 1px solid #eceeef;
border-bottom: 1px solid #eceeef;
color: #777;
}
.table{
margin-top: 1em;
}
.order-head {
font-size: 18px;
text-transform: uppercase;
margin: 0;
font-weight: 900;
padding-top: 15px;
letter-spacing: 1px;
text-align: left;
padding-left: 15px;
color: #88c7d7;
}
th {
text-align: center;
}
.table td {
color: #999;
}
.btn-edit {
font-size: 10px;
padding-left: 8px;
padding-right: 8px;
padding-top: 2px;
padding-bottom: 2px;
background-color: #b2b7b9;
border-color: #b2b7b9;
color: #fff;
font-weight: 200;
margin-left: 1em;
}
.edit-button {
text-align:left;
padding-left: 15px;
padding-top: 10px;
}
.btn-deactivate {
font-size: 11px;
padding-left: 10px;
padding-right: 10px;
padding-top: 4px;
padding-bottom: 4px;
color: #fff;
font-weight: 200;
}
.btn-darkgrey {
display: inline;
padding: .2em .6em .3em;
font-size: 75%;
font-weight: 400;
line-height: 1;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: .25em;
background-color: #777;
border-color: #777;
text-transform: none;
}
.btn-darkgrey:hover,
.btn-darkgrey:focus,
.btn-darkgrey:active,
.btn-darkgrey.active,
.open .dropdown-toggle.btn-darkgrey {
text-transform: none;
font-weight: 400;
border-color: #88c7d7;
color: #fff;
background-color: #88c7d7;
}
.thankyou {
font-size: 30px;
text-align: center;
padding-top: 45px;
}
.icon-up{
margin-top: 30px;
}
.price-exp-box {
padding-left: 15px;
padding-right: 15px;
padding-top: 15px;
padding-bottom: 0px;
margin-top: 0px;
margin-bottom: 30px;
margin-left: 10px;
margin-right: 10px;
color: inherit;
background-color: #fff;
text-align: left;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View file

@ -0,0 +1,28 @@
$( document ).ready(function() {
// $('#booking-date-range').daterangepicker();
var tomorrow = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
$('#booking-date-1').datetimepicker({
minDate: tomorrow,
format: 'MM/DD/YYYY',
// defaultDate: false
});
$('#booking-date-1').val('');
$('#booking-date-2').datetimepicker({
useCurrent: false, //Important! See issue #1075
format: 'MM/DD/YYYY',
});
$("#booking-date-1").on("dp.change", function (e) {
$('#booking-date-2').data("DateTimePicker").minDate(e.date);
});
$("#booking-date-2").on("dp.change", function (e) {
$('#booking-date-1').data("DateTimePicker").maxDate(e.date);
});
});

View file

@ -13,7 +13,7 @@ var cbpAnimatedHeader = (function() {
var docElem = document.documentElement, var docElem = document.documentElement,
header = document.querySelector( '.navbar-default' ), header = document.querySelector( '.navbar-default' ),
didScroll = false, didScroll = false,
changeHeaderOn = 300; changeHeaderOn = 20;
function init() { function init() {
window.addEventListener( 'scroll', function( event ) { window.addEventListener( 'scroll', function( event ) {

View file

@ -0,0 +1,133 @@
$( document ).ready(function() {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
var submit_form_btn = $('#payment_button');
submit_form_btn.on('click', submit_payment);
function submit_payment(e){
$('#billing-form').submit();
// $form.submit();
}
var $form = $('#payment-form');
$form.submit(payWithStripe);
/* If you're using Stripe for payments */
function payWithStripe(e) {
console.log("submiting");
e.preventDefault();
/* Visual feedback */
$form.find('[type=submit]').html('Validating <i class="fa fa-spinner fa-pulse"></i>');
var PublishableKey = window.stripeKey;
Stripe.setPublishableKey(PublishableKey);
Stripe.card.createToken($form, function stripeResponseHandler(status, response) {
if (response.error) {
/* Visual feedback */
$form.find('[type=submit]').html('Try again');
/* Show Stripe errors on the form */
$form.find('.payment-errors').text(response.error.message);
$form.find('.payment-errors').closest('.row').show();
} else {
/* Visual feedback */
$form.find('[type=submit]').html('Processing <i class="fa fa-spinner fa-pulse"></i>');
/* Hide Stripe errors on the form */
$form.find('.payment-errors').closest('.row').hide();
$form.find('.payment-errors').text("");
// response contains id and card, which contains additional card details
var token = response.id;
// AJAX
//set token on a hidden input
$('#id_token').val(token);
$('#billing-form').submit();
}
});
}
/* Form validation */
$.validator.addMethod("month", function(value, element) {
return this.optional(element) || /^(01|02|03|04|05|06|07|08|09|10|11|12)$/.test(value);
}, "Please specify a valid 2-digit month.");
$.validator.addMethod("year", function(value, element) {
return this.optional(element) || /^[0-9]{2}$/.test(value);
}, "Please specify a valid 2-digit year.");
validator = $form.validate({
rules: {
cardNumber: {
required: true,
creditcard: true,
digits: true
},
expMonth: {
required: true,
month: true
},
expYear: {
required: true,
year: true
},
cvCode: {
required: true,
digits: true
}
},
highlight: function(element) {
$(element).closest('.form-control').removeClass('success').addClass('error');
},
unhighlight: function(element) {
$(element).closest('.form-control').removeClass('error').addClass('success');
},
errorPlacement: function(error, element) {
$(element).closest('.form-group').append(error);
}
});
paymentFormReady = function() {
if ($form.find('[name=cardNumber]').hasClass("success") &&
$form.find('[name=expMonth]').hasClass("success") &&
$form.find('[name=expYear]').hasClass("success") &&
$form.find('[name=cvCode]').val().length > 1) {
return true;
} else {
return false;
}
}
$form.find('[type=submit]').prop('disabled', true);
var readyInterval = setInterval(function() {
if (paymentFormReady()) {
$form.find('[type=submit]').prop('disabled', false);
clearInterval(readyInterval);
}
}, 250);
});

View file

@ -0,0 +1,23 @@
$( 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,61 @@
{% 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">
<div class="col-md-12">
<input type="hidden" name="next" value="{{ request.GET.next }}">
<form action="" method="post" class="form" novalidate>
{% csrf_token %}
{% bootstrap_form_errors form type='non_fields'%}
{% 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"> -->
<br/>
<button type="submit" class="btn btn-primary btn-blue">Book</button>
</form>
<br>
<div class="notice-box">
</div>
</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,94 @@
{% 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 hidden-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 text-danger">-{{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>
<p class="">
View my bookings <br/><a class="btn btn-primary btn-sm btn-blck " href="{% url 'digitalglarus:booking_orders_list' %}">Go to my page</a>
</p>
</div>
</div>
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown hidden-print">
<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 text-danger">-{{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,73 @@
{% 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<a class="btn btn-primary btn-grey btn-edit" href="{% url 'digitalglarus:user_billing_address' %}">Edit</a></h2>
<h2 class="history-name">
{{request.user.name}}
</h2>
<h2 class="history-name">
{{billing_address.street_address}},{{billing_address.postal_code}}<br>
{{billing_address.city}}, {{billing_address.country}}.
</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>
</section>
{% endblock %}

View file

@ -0,0 +1,215 @@
{% 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
}
.order-bottom-text a{
margin-left: 0px;
}
</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="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>
{% if is_free %}
<h2 class="billing-head">Billing Adress</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'%}
<br>
</form>
</div>
<hr class="greyline-long">
<br/>
<h2 class="billing-head">Your Booking is TOTALLY FREE</h2>
<br/><br/>
{% else %}
<h2 class="billing-head">Billing Adress</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'%}
<br>
</form>
</div>
{% if credit_card_data %}
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
<h2 class="billing-head">Credit Card</h2>
<h2 class="membership-lead">Last 4: *****{{credit_card_data.last4}}</h2>
<h2 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h2>
<input type="hidden" name="credit_card_needed" value="false"/>
</form>
{% else %}
<h2 class="billing-head">Credit Card (Last used)</h2>
<div class="signup-form form-group row">
<form role="form" id="payment-form" novalidate>
<div class="row">
<div class="col-xs-12 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-12 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" 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>
{% endif %}
{% endif %}
</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>
<p class="order-bottom-text">
<a href="{{request.META.HTTP_REFERER}}">Change dates</a>
</p>
<hr class="greyline">
<h2 class="col-xs-6 payment-total">Total days: {{booking_days}} </h2>
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
<br/>
{% 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">{{final_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 class="row">
<div class="col-xs-12">
<button id="payment_button" class="btn btn-primary btn-md btn-blck " type="submit">Book</button>
</div>
</div>
</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,55 @@
{% 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="payment-box">
<h2 class="billing-head">Set your new password</h2>
<hr class="greyline-long">
<div class="signup-form form-group row">
<form action="" method="post" class="form" novalidate>
{% csrf_token %}
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
<p>{{form.non_field_errors|striptags}}</p>
<button type="submit" class="btn btn-primary btn-blue">Reset</button>
</form>
<br>
<div class="notice-box">
<p class="order-bottom-text">Still have trouble? Contact us for technical support.</p>
</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,136 @@
{% load static from staticfiles %}
<!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Oxygen Invoice</title>
</head>
<body bgcolor="#f7f7f7" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; color: white; margin: 0;">
<style type="text/css">
@media only screen and (max-width: 480px) {
table[class*="container-for-gmail-android"] {
min-width: 290px !important; width: 100% !important;
}
img[class="force-width-gmail"] {
display: none !important; width: 0 !important; height: 0 !important;
}
table[class="w320"] {
width: 320px !important;
}
td[class*="mobile-header-padding-left"] {
width: 160px !important; padding-left: 0 !important;
}
td[class*="mobile-header-padding-right"] {
width: 160px !important; padding-right: 0 !important;
}
td[class="header-lg"] {
font-size: 24px !important; padding-bottom: 5px !important;
}
td[class="content-padding"] {
padding: 5px 0 5px !important;
}
td[class="button"] {
padding: 5px 5px 30px !important;
}
td[class*="free-text"] {
padding: 10px 18px 30px !important;
}
td[class~="mobile-hide-img"] {
display: none !important; height: 0 !important; width: 0 !important; line-height: 0 !important;
}
td[class~="item"] {
width: 140px !important; vertical-align: top !important;
}
td[class~="quantity"] {
width: 50px !important;
}
td[class~="price"] {
width: 90px !important;
}
td[class="item-table"] {
padding: 30px 20px !important;
}
td[class="mini-container-left"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
td[class="mini-container-right"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
}
</style>
<table align="center" cellpadding="0" cellspacing="0" class="container-for-gmail-android" width="100%" style="border-collapse: collapse !important; min-width: 600px; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="left" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #ffffff url(http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg) repeat-x;" bgcolor="#ffffff">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" background="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; background: transparent;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td width="100%" height="80" valign="top" style="text-align: center; vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; line-height: 21px;" align="center">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="mso-width-percent:1000;height:80px; v-text-anchor:middle;">
<v:fill type="tile" src="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" color="#ffffff" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
<a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
</td>
<td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
</td>
</tr></table>
</center>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->
</td>
</tr></table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7; padding: 20px 0 5px;" class="content-padding" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="header-lg" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 32px; color: #4d4d4d; text-align: center; line-height: normal; font-weight: 700; padding: 35px 0 0;" align="center">
Thank you for your subscription.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="free-text" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; width: 100% !important; padding: 10px 60px 0px;" align="center">
Your monthly membership for period {{membership_start_date|date}} - {{membership_start_date|date}} has been charged. <br/> You can view your invoice clicking on the button below.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="button" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center">
<div style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f">
<w:anchorlock/>
<center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center>
</v:roundrect>
<![endif]--><a href="{{ base_url }}{% url 'digitalglarus:membership_orders_detail' order.id %}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">View Invoice</a>
</div>
</td>
</tr>
</table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="height: 100px; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7;" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 25px 0;" align="center">
<strong style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">ungleich</strong><br style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
</td>
</tr></table>
</center>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,136 @@
{% load static from staticfiles %}
<!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Oxygen Invoice</title>
</head>
<body bgcolor="#f7f7f7" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; color: white; margin: 0;">
<style type="text/css">
@media only screen and (max-width: 480px) {
table[class*="container-for-gmail-android"] {
min-width: 290px !important; width: 100% !important;
}
img[class="force-width-gmail"] {
display: none !important; width: 0 !important; height: 0 !important;
}
table[class="w320"] {
width: 320px !important;
}
td[class*="mobile-header-padding-left"] {
width: 160px !important; padding-left: 0 !important;
}
td[class*="mobile-header-padding-right"] {
width: 160px !important; padding-right: 0 !important;
}
td[class="header-lg"] {
font-size: 24px !important; padding-bottom: 5px !important;
}
td[class="content-padding"] {
padding: 5px 0 5px !important;
}
td[class="button"] {
padding: 5px 5px 30px !important;
}
td[class*="free-text"] {
padding: 10px 18px 30px !important;
}
td[class~="mobile-hide-img"] {
display: none !important; height: 0 !important; width: 0 !important; line-height: 0 !important;
}
td[class~="item"] {
width: 140px !important; vertical-align: top !important;
}
td[class~="quantity"] {
width: 50px !important;
}
td[class~="price"] {
width: 90px !important;
}
td[class="item-table"] {
padding: 30px 20px !important;
}
td[class="mini-container-left"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
td[class="mini-container-right"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
}
</style>
<table align="center" cellpadding="0" cellspacing="0" class="container-for-gmail-android" width="100%" style="border-collapse: collapse !important; min-width: 600px; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="left" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #ffffff url(http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg) repeat-x;" bgcolor="#ffffff">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" background="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; background: transparent;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td width="100%" height="80" valign="top" style="text-align: center; vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; line-height: 21px;" align="center">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="mso-width-percent:1000;height:80px; v-text-anchor:middle;">
<v:fill type="tile" src="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" color="#ffffff" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
<a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
</td>
<td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
</td>
</tr></table>
</center>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->
</td>
</tr></table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7; padding: 20px 0 5px;" class="content-padding" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="header-lg" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 32px; color: #4d4d4d; text-align: center; line-height: normal; font-weight: 700; padding: 35px 0 0;" align="center">
Thank you for your subscription.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="free-text" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; width: 100% !important; padding: 10px 60px 0px;" align="center">
Your monthly membership for period {{membership_start_date|date}} - {{membership_start_date|date}} has been charged. <br/> You can view your invoice clicking on the button below.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="button" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center">
<div style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f">
<w:anchorlock/>
<center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center>
</v:roundrect>
<![endif]--><a href="{{ base_url }}{% url 'digitalglarus:membership_orders_detail' order.id %}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">View Invoice</a>
</div>
</td>
</tr>
</table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="height: 100px; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7;" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 25px 0;" align="center">
<strong style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">ungleich</strong><br style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
</td>
</tr></table>
</center>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,136 @@
{% load static from staticfiles %}
<!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Oxygen Invoice</title>
</head>
<body bgcolor="#f7f7f7" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; color: white; margin: 0;">
<style type="text/css">
@media only screen and (max-width: 480px) {
table[class*="container-for-gmail-android"] {
min-width: 290px !important; width: 100% !important;
}
img[class="force-width-gmail"] {
display: none !important; width: 0 !important; height: 0 !important;
}
table[class="w320"] {
width: 320px !important;
}
td[class*="mobile-header-padding-left"] {
width: 160px !important; padding-left: 0 !important;
}
td[class*="mobile-header-padding-right"] {
width: 160px !important; padding-right: 0 !important;
}
td[class="header-lg"] {
font-size: 24px !important; padding-bottom: 5px !important;
}
td[class="content-padding"] {
padding: 5px 0 5px !important;
}
td[class="button"] {
padding: 5px 5px 30px !important;
}
td[class*="free-text"] {
padding: 10px 18px 30px !important;
}
td[class~="mobile-hide-img"] {
display: none !important; height: 0 !important; width: 0 !important; line-height: 0 !important;
}
td[class~="item"] {
width: 140px !important; vertical-align: top !important;
}
td[class~="quantity"] {
width: 50px !important;
}
td[class~="price"] {
width: 90px !important;
}
td[class="item-table"] {
padding: 30px 20px !important;
}
td[class="mini-container-left"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
td[class="mini-container-right"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
}
</style>
<table align="center" cellpadding="0" cellspacing="0" class="container-for-gmail-android" width="100%" style="border-collapse: collapse !important; min-width: 600px; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="left" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #ffffff url(http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg) repeat-x;" bgcolor="#ffffff">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" background="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; background: transparent;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td width="100%" height="80" valign="top" style="text-align: center; vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; line-height: 21px;" align="center">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="mso-width-percent:1000;height:80px; v-text-anchor:middle;">
<v:fill type="tile" src="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" color="#ffffff" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
<a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
</td>
<td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
</td>
</tr></table>
</center>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->
</td>
</tr></table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7; padding: 20px 0 5px;" class="content-padding" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="header-lg" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 32px; color: #4d4d4d; text-align: center; line-height: normal; font-weight: 700; padding: 35px 0 0;" align="center">
Thank you for your subscription.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="free-text" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; width: 100% !important; padding: 10px 60px 0px;" align="center">
Your monthly membership for {{order.created_at|date:"F"}} has been charged. <br/> You can view your invoice clicking on the button below.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="button" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center">
<div style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f">
<w:anchorlock/>
<center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center>
</v:roundrect>
<![endif]--><a href="{{ base_url }}{% url 'digitalglarus:membership_orders_detail' order.id %}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">View Invoice</a>
</div>
</td>
</tr>
</table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="height: 100px; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7;" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 25px 0;" align="center">
<strong style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">ungleich</strong><br style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
</td>
</tr></table>
</center>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,136 @@
{% load static from staticfiles %}
<!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Oxygen Invoice</title>
</head>
<body bgcolor="#f7f7f7" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; color: white; margin: 0;">
<style type="text/css">
@media only screen and (max-width: 480px) {
table[class*="container-for-gmail-android"] {
min-width: 290px !important; width: 100% !important;
}
img[class="force-width-gmail"] {
display: none !important; width: 0 !important; height: 0 !important;
}
table[class="w320"] {
width: 320px !important;
}
td[class*="mobile-header-padding-left"] {
width: 160px !important; padding-left: 0 !important;
}
td[class*="mobile-header-padding-right"] {
width: 160px !important; padding-right: 0 !important;
}
td[class="header-lg"] {
font-size: 24px !important; padding-bottom: 5px !important;
}
td[class="content-padding"] {
padding: 5px 0 5px !important;
}
td[class="button"] {
padding: 5px 5px 30px !important;
}
td[class*="free-text"] {
padding: 10px 18px 30px !important;
}
td[class~="mobile-hide-img"] {
display: none !important; height: 0 !important; width: 0 !important; line-height: 0 !important;
}
td[class~="item"] {
width: 140px !important; vertical-align: top !important;
}
td[class~="quantity"] {
width: 50px !important;
}
td[class~="price"] {
width: 90px !important;
}
td[class="item-table"] {
padding: 30px 20px !important;
}
td[class="mini-container-left"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
td[class="mini-container-right"] {
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
}
}
</style>
<table align="center" cellpadding="0" cellspacing="0" class="container-for-gmail-android" width="100%" style="border-collapse: collapse !important; min-width: 600px; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="left" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #ffffff url(http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg) repeat-x;" bgcolor="#ffffff">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" background="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; background: transparent;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td width="100%" height="80" valign="top" style="text-align: center; vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; line-height: 21px;" align="center">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="mso-width-percent:1000;height:80px; v-text-anchor:middle;">
<v:fill type="tile" src="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" color="#ffffff" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
<a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
</td>
<td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
</td>
</tr></table>
</center>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->
</td>
</tr></table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7; padding: 20px 0 5px;" class="content-padding" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="header-lg" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 32px; color: #4d4d4d; text-align: center; line-height: normal; font-weight: 700; padding: 35px 0 0;" align="center">
Thank you for your subscription.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="free-text" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; width: 100% !important; padding: 10px 60px 0px;" align="center">
Your monthly membership for {{order.created_at|date:"F"}} has been charged. <br/> You can view your invoice clicking on the button below.
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td class="button" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center">
<div style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f">
<w:anchorlock/>
<center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center>
</v:roundrect>
<![endif]--><a href="{{ base_url }}{% url 'digitalglarus:membership_orders_detail' order.id %}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">View Invoice</a>
</div>
</td>
</tr>
</table>
</center>
</td>
</tr>
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td align="center" valign="top" width="100%" style="height: 100px; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7;" bgcolor="#f7f7f7">
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
<td style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 25px 0;" align="center">
<strong style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">ungleich</strong><br style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
</td>
</tr></table>
</center>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,13 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ base_url }}{% url 'digitalglarus:reset_password_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}

View file

@ -0,0 +1,13 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ base_url }}{% url 'digitalglarus:reset_password_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}

View file

@ -20,7 +20,8 @@
<div class="container-fluid darkened-container"> <div class="container-fluid darkened-container">
<h3 class="intro-small"> <h3 class="intro-small">
Book a date today and dive in</h3> Book a date today and dive in</h3>
<form class="form-inline"> <a href="{% url 'digitalglarus:booking' %}" class="btn btn-primary">Join now</a>
<!-- <form class="form-inline">
<div class="form-group"> <div class="form-group">
<label class="sr-only" for="exampleInputPassword3">Pick a date</label> <label class="sr-only" for="exampleInputPassword3">Pick a date</label>
<input type="password" class="form-control" id="exampleInputPassword3" placeholder="Pick a date"> <input type="password" class="form-control" id="exampleInputPassword3" placeholder="Pick a date">
@ -30,7 +31,7 @@
</div> </div>
</div> </div>
<button type="submit" class="btn btn-primary">book a date</button> <button type="submit" class="btn btn-primary">book a date</button>
</form> </form> -->
</div> </div>
</header> </header>
@ -187,7 +188,7 @@
Join our community. Be our member now! Join our community. Be our member now!
<br> <br>
<br> <br>
<a href="http://startbootstrap.com/template-overviews/creative/" class="btn btn-default btn-primary sr-button"> Sign Up </a> <a href="{% url 'digitalglarus:signup' %}" class="btn btn-default btn-primary sr-button"> Sign Up </a>
</div> </div>
</div> </div>
</aside> </aside>

View file

@ -0,0 +1,80 @@
{% extends "new_base_glarus.html" %}
{% load staticfiles bootstrap3 i18n %}
{% 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-user"></span>
<h2 class="section-heading">Log In</h2>
{% if not messages %}
<h2 class="signup-lead">Welcome!<br></h2>
{% endif %}
{% if messages %}
<ul class="list-unstyled">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<hr class="primary">
{% block messages %}
{% if request.GET.logged_out %}
<div class="alert"> <!-- singular -->
<a class="close" data-dismiss="alert">×</a>
{% trans "You haven been logged out"%}
</div>
{% endif %}
{% endblock %}
<div class="signup-form form-group row">
<form action="{% url 'digitalglarus:login' %}" method="post" class="form" novalidate>
{% csrf_token %}
<input type="hidden" name="" value="{{ request.GET.next }}">
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
<p>{{form.non_field_errors|striptags}}</p>
<p class="signup-notice">By logging in you agree to our<a href=#terms>Terms of Service</a>.</p>
<button type="submit" class="btn btn-primary btn-blue">Login</button>
</form>
<br>
<div class="notice-box">
<p class="signup-text">Forgot password?<a href="{% url 'digitalglarus:reset_password' %}">Find ID/Password</a></p>
<p class="signup-text">Not a member yet?<a href="{% url 'digitalglarus:signup' %}?{{request.GET.next}}">Sign up </a>now.</p>
</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,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="{% url 'digitalglarus:membership_deactivate' %}">deactivate 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

@ -0,0 +1,106 @@
{% extends "new_base_glarus.html" %}
{% load staticfiles cms_tags bootstrap3%}
{% block title %}crowdfunding{% endblock %}
{% block content %}
<style type="text/css">
#cancel-subscription-modal{
margin-top:10%;
}
#cancel-subscription-modal .modal-header{
border-bottom: none;
}
#cancel-subscription-modal .modal-footer{
border-top: none;
text-align: center;
}
</style>
<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 Deactivation</h2>
<hr class="greyline-long">
<h2 class="membership-lead">Are you sure do you want to cancel your membership with us ?</h2>
<div class="date-box">
</div>
<!--<hr class="primary">-->
<div class="signup-form form-group row">
<div class="button-booking-box form-inline row">
<form method="POST" action="">
{% csrf_token %}
<button type="button" class="btn btn-primary btn-blue" data-toggle="modal" data-target="#cancel-subscription-modal">Cancel my Membership</button>
<a class="btn btn-primary btn-blue" href="{{request.META.HTTP_REFERER}}">Go back</a>
<div class="modal fade bs-example-modal-sm" id="cancel-subscription-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Cancel Subscription</h4>
</div>
<div class="modal-body">
<p>Do you want to cancel your subscription?</p>
</div>
<div class="modal-footer text-center">
<button type="button" class="btn btn-primary btn-grey" data-dismiss="modal">No</button>
<button type="submit" class="btn btn-primary">Yes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</form>
</div>
<div class="notice-box text-left">
<p class="order-bottom-text">
Your membership wouldn't be automatically renewed each month.
</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

@ -0,0 +1,54 @@
{% 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 Deactivated</h2>
<hr class="greyline-long">
<h2 class="membership-lead">Your Digital Glarus membership has been deactivated.</h2>
<div class="date-box">
</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:membership_orders_list' %}>Go to your membership orders</a>
</div>
<div class="notice-box text-left">
</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

@ -0,0 +1,81 @@
{% 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 invoice for {{order.created_at|date:"Y-m"}}</h2>
<hr class="greyline-long">
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print hidden-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>
<br/>
<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 %}

View file

@ -0,0 +1,126 @@
{% 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 Membership 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">Current Membership</h2>
{% if membership_start_date and membership_end_date%}
<h2 class="member-name">{{membership_start_date|date}}-{{membership_end_date|date}}</h2>
{% else %}
<h2 class="member-name">You don't have an active membership</h2>
{% endif %}
<hr class="greyline-long">
<h2 class="order-head">Orders 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<a class="btn btn-primary btn-grey btn-edit" href="{% url 'digitalglarus:user_billing_address' %}">Edit</a></h2>
<h2 class="history-name">
{{request.user.name}}
</h2>
{% if billing_address %}
<h2 class="history-name">
{{billing_address.street_address}},{{billing_address.postal_code}}<br>
{{billing_address.city}}, {{billing_address.country}}.
</h2>
{% else %}
<h2 class="history-name">
Edit your billing address
</h2>
{% endif %}
<hr class="greyline-long">
<h2 class="order-head">Your Next Membership</h2>
{% if next_membership_start_date and next_membership_end_date%}
<h2 class="history-name">
Dates: {{next_membership_start_date|date}} - {{next_membership_end_date|date}}<br>
</h2>
{% else %}
<h2 class="history-name">
You are not a member yet
</h2>
{% endif %}
<div class="edit-button">
<a class="btn btn-primary btn-grey btn-deactivate print" href="{% url 'digitalglarus:membership_deactivate' %}">Deactivate</a>
</div>
<hr class="greyline-long">
<div class="row">
<div class="col-md-12 notice-box">
<p class="order-bottom-text">You will be charged on the first of the month until you
cancel your subscription. Previous charges won't be refunded.</p>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown">
<div class="order-summary">
{% if messages %}
<div class="order-box">
<h2 class="thankyou">Message</h2>
<hr class="greyline">
{% for message in messages %}
<h2 class="signup-lead text-center">{{ message }}</h2>
{% endfor %}
</div>
{% else %}
<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>
{% endif %}
</div>
</div>
</div>
</section>
{% 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">Membership</h2>
<!-- <h2 class="membership-amount">35CHF</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>
<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">{{request.user.name}}</h2>
<hr class="greyline-long">
<h2 class="billing-head">Billing Adress</h2>
<div class="signup-form form-group row">
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:membership_payment' %}" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
{% bootstrap_form_errors form type='non_fields'%}
<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-12 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-12 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">
<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="col-xs-12">
<button class="btn btn-primary btn-md btn-blck " type="submit">Purchase membership</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">Order Summary</h2>
</div>
<div class="order-box">
<h2 class="col-xs-6 order-item">Digital Glarus Membership</h2>
<br>
<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 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">{{membership_type.first_month_price|floatformat}}CHF</h2>
<div class="text-center">
<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,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-2 text-center wow fadeInDown"></div>
<div class="row col-md-8 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-2 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

@ -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">
<div class="payment-box">
<h2 class="billing-head">Reset Password</h2>
<hr class="greyline-long">
<h2 class="membership-lead">To have your password reset, enter your email address below.
We will then send an email containing a link to reset your password.</h2>
<div class="signup-form form-group row">
<form action="{% url 'digitalglarus:reset_password' %}" method="post" class="form" novalidate>
{% csrf_token %}
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
<p>{{form.non_field_errors|striptags}}</p>
<button type="submit" class="btn btn-primary btn-blue">Send Email</button>
</form>
<br>
<div class="notice-box">
<p class="order-bottom-text">Still have trouble? Contact us for technical support.</p>
</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,59 @@
{% 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">Sign up</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">
<form action="{% url 'digitalglarus:signup' %}" method="post" class="form" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.GET.next }}">
{% for field in form %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
<p>{{form.non_field_errors|striptags}}</p>
<button type="submit" class="btn btn-primary btn-blue">Signup</button>
</form>
<br>
<div class="notice-box">
<p class="signup-text">Already a member?<a href="{% url 'digitalglarus:login' %}">Log in</a></p>
</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,91 @@
{% 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">Billing Address</h2>
<!-- <h2 class="membership-amount">35CHF</h2> -->
<hr class="greyline-long">
<h2 class="billing-head">Billing Adress</h2>
<div class="signup-form form-group row">
<form role="form" id="billing-address-form" method="post" action="{% url 'digitalglarus:user_billing_address' %}" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%}
{% endfor %}
{% bootstrap_form_errors form type='non_fields'%}
<input type="hidden" name="next" value="{{request.META.HTTP_REFERER}}">
<br>
<div class="row">
<div class="col-xs-12">
{% if messages %}
{% for message in messages %}
<h2 class="signup-lead text-center">{{ message }}</h2>
{% endfor %}
{% endif %}
<button id="payment_button" class="btn btn-primary btn-md btn-blck " type="submit">Save</button>
</div>
</div>
</form>
</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

@ -1,6 +1,5 @@
{% load static %} {% load static %}
{% load bootstrap3 %} {% load staticfiles cms_tags menu_tags sekizai_tags menu_tags bootstrap3 %}
{% load staticfiles cms_tags menu_tags sekizai_tags menu_tags %}
{% load i18n %} {% load i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -25,6 +24,11 @@
<link href="{% static 'digitalglarus/css/agency.css' %}" rel="stylesheet"> <link href="{% static 'digitalglarus/css/agency.css' %}" rel="stylesheet">
<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 rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" />
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.42/css/bootstrap-datetimepicker.min.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 +57,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">
@ -78,7 +107,7 @@
<a href="#page-top"></a> <a href="#page-top"></a>
</li> </li>
<li> <li>
<a class="page-scroll" href="#portfolio">booking & price</a> <a class="page-scroll" href="{% url 'digitalglarus:booking' %}">booking & price</a>
</li> </li>
<li> <li>
<a class="page-scroll" href="{% url 'digitalglarus:history' %}">history</a> <a class="page-scroll" href="{% url 'digitalglarus:history' %}">history</a>
@ -89,13 +118,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:login' %}">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>
@ -136,15 +191,24 @@
<!-- jQuery --> <!-- jQuery -->
<script src="{% static 'digitalglarus/js/jquery.js' %}"></script> <script src="{% static 'digitalglarus/js/jquery.js' %}"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery.validation/1.13.1/jquery.validate.min.js"></script>
<!-- Bootstrap Core JavaScript --> <!-- Bootstrap Core JavaScript -->
<script src="{% static 'digitalglarus/js/bootstrap.min.js' %}"></script> <script src="{% static 'digitalglarus/js/bootstrap.min.js' %}"></script>
<!-- Plugin JavaScript --> <!-- Plugin JavaScript -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
<script src="{% static 'digitalglarus/js/classie.js' %}"></script> <script src="{% static 'digitalglarus/js/classie.js' %}"></script>
<script src="{% static 'digitalglarus/js/cbpAnimatedHeader.js' %}"></script> <script src="{% static 'digitalglarus/js/cbpAnimatedHeader.js' %}"></script>
<!-- Stripe Lib -->
<script type="text/javascript" src="//js.stripe.com/v2/"></script>
<!-- Proccess payment lib -->
<script src="{% static 'digitalglarus/js/payment.js' %}"></script>
<!-- Contact Form JavaScript --> <!-- Contact Form JavaScript -->
<script src="{% static 'digitalglarus/js/jqBootstrapValidation.js' %}"></script> <script src="{% static 'digitalglarus/js/jqBootstrapValidation.js' %}"></script>
@ -156,11 +220,30 @@
<script src="{% static 'digitalglarus/js/ungleich.js' %}"></script> <script src="{% static 'digitalglarus/js/ungleich.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"> <!-- Include Required Prerequisites -->
<link href="//fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css"> <script type="text/javascript" src="//cdn.jsdelivr.net/jquery/1/jquery.min.js"></script>
<link href="//fonts.googleapis.com/css?family=Kaushan+Script" rel="stylesheet" type="text/css"> <script type="text/javascript" src="//cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<link href="//fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic,700italic" rel="stylesheet" type="text/css"> <!-- <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap/latest/css/bootstrap.css" />
<link href="//fonts.googleapis.com/css?family=Roboto+Slab:400,100,300,700" rel="stylesheet" type="text/css"> -->
<!-- Include Date Range Picker -->
<script type="text/javascript" src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.42/js/bootstrap-datetimepicker.min.js
"></script>
<!-- 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> </html>

View file

@ -1,11 +1,25 @@
import json import json
from model_mommy import mommy
from unittest import mock
from django.test import TestCase from django.test import TestCase
from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.urlresolvers import resolve from django.core.urlresolvers import resolve
from cms.test_utils.testcases import CMSTestCase from cms.test_utils.testcases import CMSTestCase
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from cms.api import create_page from cms.api import create_page
from membership.models import CustomUser, StripeCustomer
from utils.tests import BaseTestCase
from .views import LoginView, SignupView, PasswordResetView, PasswordResetConfirmView,\
MembershipPricingView, MembershipPaymentView
from .models import MembershipType, MembershipOrder
class ContactViewTest(TestCase): class ContactViewTest(TestCase):
def setUp(self): def setUp(self):
@ -38,14 +52,243 @@ class ViewsTest(CMSTestCase):
self.assertEqual(res2.status_code, 200) self.assertEqual(res2.status_code, 200)
class CalendarApiTestCase(TestCase): class MembershipPricingViewTest(BaseTestCase):
def test_api_response(self):
calendar_api_url_1 = reverse('digitalglarus:calendar_api_1', kwargs={'month': '3', 'year': '2016'})
res1 = self.client.get(calendar_api_url_1)
pd = json.loads(res1.content.decode('utf-8'))
self.assertEqual(pd['month'], '3')
self.assertEqual(pd['year'], '2016')
# TODO:check post def setUp(self):
# calendar_api_url = reverse('digitalglarus:calendar_api') super(MembershipPricingViewTest, self).setUp()
# res = self.client.get(calendar_api_url)
self.membership_type = mommy.make(MembershipType)
self.url = reverse('digitalglarus:membership_pricing')
self.view = MembershipPricingView
self.expected_template = 'digitalglarus/membership_pricing.html'
def test_url_resolve_to_view_correctly(self):
found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__)
def test_get(self):
# Anonymous user should get data
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['membership_type'], self.membership_type)
self.assertTemplateUsed(response, self.expected_template)
class MembershipPaymentViewTest(BaseTestCase):
def setUp(self):
super(MembershipPaymentViewTest, self).setUp()
self.membership_type = mommy.make(MembershipType)
self.url = reverse('digitalglarus:membership_payment')
self.view = MembershipPaymentView
self.expected_template = 'digitalglarus/membership_payment.html'
# post data
self.billing_address = {
'street_address': 'street name',
'city': 'MyCity',
'postal_code': '32123123123123',
'country': 'VE',
'token': 'a23kfmslwxhkwis',
'membership_type': self.membership_type.id
}
def test_url_resolve_to_view_correctly(self):
found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__)
def test_get(self):
# Anonymous user should get redirect to login
response = self.client.get(self.url)
expected_url = "%s?next=%s" % (reverse('digitalglarus:signup'),
reverse('digitalglarus:membership_payment'))
self.assertRedirects(response, expected_url=expected_url,
status_code=302, target_status_code=200)
# Logged user should get the page
response = self.customer_client.get(self.url, follow=True)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['stripe_key'],
settings.STRIPE_API_PUBLIC_KEY)
self.assertEqual(response.context['membership_type'],
self.membership_type)
@mock.patch('utils.stripe_utils.StripeUtils.create_customer')
def test_post(self, stripe_mocked_call):
# Anonymous user should get redirect to login
# response = self.client.post(self.url)
# expected_url = "%s?next=%s" % (reverse('digitalglarus:signup'),
# reverse('digitalglarus:membership_payment'))
# self.assertRedirects(response, expected_url=expected_url,
# status_code=302, target_status_code=200)
# Customer user should be able to pay
stripe_mocked_call.return_value = {
'paid': True,
'response_object': self.stripe_mocked_customer,
'error': None
}
response = self.customer_client.post(self.url, self.billing_address)
self.assertEqual(response.status_code, 200)
self.assertTrue(StripeCustomer.objects.filter(user__email=self.customer.email).exists())
stripe_customer = StripeCustomer.objects.get(user__email=self.customer.email)
self.assertEqual(stripe_customer.user, self.customer)
self.assertTrue(MembershipOrder.objects.filter(customer=stripe_customer).exists())
membership_order = MembershipOrder.objects.filter(customer=stripe_customer).first()
session_data = {
'membership_price': membership_order.membership.type.first_month_price,
'membership_dates': membership_order.membership.type.first_month_formated_range
}
self.assertEqual(session_data.get('membership_price'),
self.session_data.get('membership_price'))
self.assertEqual(session_data.get('membership_dates'),
self.session_data.get('membership_dates'))
# self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists())
# hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0]
# vm_plan = {
# 'cores': hosting_order.vm_plan.cores,
# 'memory': hosting_order.vm_plan.memory,
# 'disk_size': hosting_order.vm_plan.disk_size,
# 'price': hosting_order.vm_plan.price,
# 'hosting_company': hosting_order.vm_plan.vm_type.hosting_company,
# 'configuration': hosting_order.vm_plan.configuration
# }
# self.assertEqual(vm_plan, self.session_data.get('vm_specs'))
class LoginViewTest(TestCase):
def setUp(self):
self.url = reverse('digitalglarus:login')
self.view = LoginView
self.expected_template = 'digitalglarus/login.html'
self.user = mommy.make('membership.CustomUser')
self.password = 'fake_password'
self.user.set_password(self.password)
self.user.save()
def test_url_resolve_to_view_correctly(self):
found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__)
def test_get(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, self.expected_template)
def test_anonymous_user_can_login(self):
data = {
'email': self.user.email,
'password': self.password
}
response = self.client.post(self.url, data=data, follow=True)
self.assertEqual(response.context['user'], self.user)
self.assertEqual(response.status_code, 200)
class SignupViewTest(TestCase):
def setUp(self):
self.url = reverse('digitalglarus:signup')
self.expected_template = 'digitalglarus/signup.html'
self.view = SignupView
self.signup_data = {
'name': 'ungleich',
'email': 'test@ungleich.com',
'password': 'fake_password',
'confirm_password': 'fake_password',
}
def test_url_resolve_to_view_correctly(self):
found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__)
def test_get(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, self.expected_template)
def test_anonymous_user_can_signup(self):
response = self.client.post(self.url, data=self.signup_data, follow=True)
self.user = CustomUser.objects.get(email=self.signup_data.get('email'))
self.assertEqual(response.context['user'], self.user)
self.assertEqual(response.status_code, 200)
class PasswordResetViewTest(BaseTestCase):
def setUp(self):
super(PasswordResetViewTest, self).setUp()
self.url = reverse('digitalglarus:reset_password')
self.view = PasswordResetView
self.expected_template = 'digitalglarus/reset_password.html'
self.user = mommy.make('membership.CustomUser')
self.password = 'fake_password'
self.user.set_password(self.password)
self.user.save()
self.post_data = {
'email': self.user.email
}
def test_url_resolve_to_view_correctly(self):
found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__)
def test_get(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, self.expected_template)
def test_post(self):
response = self.client.post(self.url, data=self.post_data, follow=True)
self.assertEqual(response.status_code, 200)
def test_test_generate_email_context(self):
context = self.setup_view(self.view()).\
test_generate_email_context(self.user)
self.assertEqual(context.get('user'), self.user)
self.assertEqual(context.get('site_name'), 'ungleich')
self.assertEqual(len(context.get('token')), 24)
class PasswordResetConfirmViewTest(BaseTestCase):
def setUp(self):
super(PasswordResetConfirmViewTest, self).setUp()
self.view = PasswordResetConfirmView
self.expected_template = 'digitalglarus/confirm_reset_password.html'
self.user = mommy.make('membership.CustomUser')
self.password = 'fake_password'
self.user.set_password(self.password)
self.user.save()
self.token = default_token_generator.make_token(self.user)
self.uid = urlsafe_base64_encode(force_bytes(self.user.pk))
self.url = reverse('digitalglarus:reset_password_confirm',
kwargs={'token': self.token, 'uidb64': self.uid})
self.post_data = {
'new_password1': 'new_password',
'new_password2': 'new_password'
}
def test_url_resolve_to_view_correctly(self):
found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__)
def test_get(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, self.expected_template)
def test_post(self):
response = self.client.post(self.url, data=self.post_data, follow=True)
self.assertEqual(response.status_code, 200)
self.assertTrue(not response.context['form'].errors)

View file

@ -2,14 +2,44 @@ from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from . import views from . import views
from .views import ContactView, IndexView, AboutView, HistoryView from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\
from membership.views import LoginRegistrationView PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, \
MembershipDeactivateView, MembershipDeactivateSuccessView, UserBillingAddressView
# from membership.views import LoginRegistrationView
urlpatterns = [ urlpatterns = [
url(_(r'^$'), IndexView.as_view(), name='landing'), url(_(r'^$'), IndexView.as_view(), name='landing'),
url(_(r'contact/?$'), ContactView.as_view(), name='contact'), url(_(r'contact/?$'), ContactView.as_view(), name='contact'),
url(_(r'login/?$'), LoginRegistrationView.as_view(), name='login'), 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'history/?$'), HistoryView.as_view(), name='history'),
url(_(r'users/billing_address/?$'), UserBillingAddressView.as_view(), name='user_billing_address'),
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/deactivate/?$'), MembershipDeactivateView.as_view(),
name='membership_deactivate'),
url(_(r'membership/deactivate/success/?$'), MembershipDeactivateSuccessView.as_view(),
name='membership_deactivate_success'),
url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(),
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'),

View file

@ -1,26 +1,585 @@
import json
import datetime import datetime
from django.conf import settings
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.forms import ModelForm from django.forms import ModelForm
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView from django.views.generic import TemplateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import get_language from django.utils.translation import get_language
from djangocms_blog.models import Post from djangocms_blog.models import Post
from django.contrib import messages from django.contrib import messages
from django.http import JsonResponse from django.http import JsonResponse
from django.views.generic import View from django.views.generic import View, DetailView, ListView
from .models import Supporter from .models import Supporter
from utils.forms import ContactUsForm from utils.forms import ContactUsForm
from utils.mailer import BaseEmail
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from membership.calendar.calendar import BookCalendar from membership.calendar.calendar import BookCalendar
from membership.models import Calendar as CalendarModel from membership.models import Calendar as CalendarModel, StripeCustomer
import json
from django.contrib.auth import logout
from utils.views import LoginViewMixin, SignupViewMixin, \
PasswordResetViewMixin, PasswordResetConfirmViewMixin
from utils.forms import PasswordResetRequestForm, UserBillingAddressForm
from utils.stripe_utils import StripeUtils
from utils.models import UserBillingAddress
from .forms import LoginForm, SignupForm, MembershipBillingForm, BookingDateForm,\
BookingBillingForm
from .models import MembershipType, Membership, MembershipOrder, Booking, BookingPrice,\
BookingOrder
from .mixins import MembershipRequiredMixin, IsNotMemberMixin
class IndexView(TemplateView):
template_name = "digitalglarus/index.html"
class LoginView(LoginViewMixin):
template_name = "digitalglarus/login.html"
form_class = LoginForm
def get_success_url(self):
# redirect to membership orders list if user has at least one.
if self.request.user \
and MembershipOrder.objects.filter(customer__user=self.request.user):
return reverse_lazy('digitalglarus:membership_orders_list')
return reverse_lazy('digitalglarus:membership_pricing')
class SignupView(SignupViewMixin):
template_name = "digitalglarus/signup.html"
form_class = SignupForm
success_url = reverse_lazy('digitalglarus:login')
class PasswordResetView(PasswordResetViewMixin):
template_name = 'digitalglarus/reset_password.html'
success_url = reverse_lazy('digitalglarus:login')
form_class = PasswordResetRequestForm
template_email_path = 'digitalglarus/emails/'
class PasswordResetConfirmView(PasswordResetConfirmViewMixin):
template_name = 'digitalglarus/confirm_reset_password.html'
success_url = reverse_lazy('digitalglarus:login')
class HistoryView(TemplateView):
template_name = "digitalglarus/history.html"
def get_context_data(self, *args, **kwargs):
context = super(HistoryView, self).get_context_data(**kwargs)
supporters = Supporter.objects.all()
context.update({
'supporters': supporters
})
return context
class BookingSelectDatesView(LoginRequiredMixin, MembershipRequiredMixin, 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 get_form_kwargs(self):
kwargs = super(BookingSelectDatesView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
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
price_per_day = BookingPrice.objects.get().price_per_day
original_price, final_price, free_days = Booking.\
booking_price(user, start_date, end_date)
total_discount = price_per_day * free_days
self.request.session.update({
'original_price': original_price,
'final_price': final_price,
'total_discount': total_discount,
'booking_price_per_day': price_per_day,
'booking_days': booking_days,
'free_days': free_days,
'start_date': start_date.strftime('%m/%d/%Y'),
'end_date': end_date.strftime('%m/%d/%Y'),
'is_free': final_price == 0
})
return super(BookingSelectDatesView, self).form_valid(form)
class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, 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', 'final_price', 'booking_days', 'free_days',
'start_date', 'end_date', 'booking_price_per_day',
'total_discount', 'is_free']
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_detail', kwargs={'pk': order_id})
def get_form_kwargs(self):
current_billing_address = self.request.user.billing_addresses.first()
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('final_price'),
'street_address': current_billing_address.street_address,
'city': current_billing_address.city,
'postal_code': current_billing_address.postal_code,
'country': current_billing_address.country,
}
})
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}
user = self.request.user
last_booking_order = BookingOrder.objects.filter(customer__user=user).last()
last_membership_order = MembershipOrder.objects.filter(customer__user=user).last()
credit_card_data = last_booking_order.get_booking_cc_data() if last_booking_order \
and last_booking_order.get_booking_cc_data() \
else last_membership_order.get_membership_order_cc_data()
booking_data.update({
'credit_card_data': credit_card_data if credit_card_data else None,
'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')
is_free = context.get('is_free')
normal_price, final_price, free_days = Booking.\
booking_price(self.request.user, start_date, end_date)
charge = None
# if not credit_card_needed:
# 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))
# If booking is not free, make the stripe charge
if not is_free:
# 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 for Membership Order
billing_address = form.save()
# Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count():
data.update({
'user': customer.user.id
})
billing_address_user_form = UserBillingAddressForm(data)
billing_address_user_form.is_valid()
billing_address_user_form.save()
# Create Booking
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 Booking order
order_data = {
'booking': booking,
'customer': customer,
'billing_address': billing_address,
'stripe_charge': charge,
'amount': final_price,
'original_price': normal_price,
'special_month_price': BookingPrice.objects.last().special_month_price,
}
order = BookingOrder.create(order_data)
return HttpResponseRedirect(self.get_success_url(order.id))
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, IsNotMemberMixin, FormView):
template_name = "digitalglarus/membership_payment.html"
login_url = reverse_lazy('digitalglarus:signup')
form_class = MembershipBillingForm
already_member_redirect_url = reverse_lazy('digitalglarus:membership_orders_list')
def get_form_kwargs(self):
self.membership_type = MembershipType.objects.get(name='standard')
form_kwargs = super(MembershipPaymentView, self).get_form_kwargs()
form_kwargs.update({
'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,
'membership_type': self.membership_type
})
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
data = form.cleaned_data
context = self.get_context_data()
token = data.get('token')
membership_type = data.get('membership_type')
# 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=membership_type.first_month_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(request, self.template_name, context)
charge = charge_response.get('response_object')
# Create Billing Address
billing_address = form.save()
# Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count():
data.update({
'user': customer.user.id
})
billing_address_user_form = UserBillingAddressForm(data)
billing_address_user_form.is_valid()
billing_address_user_form.save()
# Get membership dates
membership_start_date, membership_end_date = membership_type.first_month_range
# Create membership plan
membership_data = {
'type': membership_type,
'start_date': membership_start_date,
'end_date': membership_end_date
}
membership = Membership.create(membership_data)
# Create membership order
order_data = {
'membership': membership,
'customer': customer,
'billing_address': billing_address,
'stripe_charge': charge,
'amount': membership_type.first_month_price,
'start_date': membership_start_date,
'end_date': membership_end_date
}
membership_order = MembershipOrder.create(order_data)
request.session.update({
'membership_price': membership.type.first_month_price,
'membership_dates': membership.type.first_month_formated_range
})
context = {
'membership': membership,
'order': membership_order,
'membership_start_date': membership_start_date,
'membership_end_date': membership_end_date,
'base_url': "{0}://{1}".format(request.scheme, request.get_host())
}
email_data = {
'subject': 'Your membership has been charged',
'to': request.user.email,
'context': context,
'template_name': 'membership_charge',
'template_path': 'digitalglarus/emails/'
}
email = BaseEmail(**email_data)
email.send()
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 MembershipDeactivateView(LoginRequiredMixin, UpdateView):
template_name = "digitalglarus/membership_deactivated.html"
model = Membership
success_message = "Your membership has been deactivated :("
success_url = reverse_lazy('digitalglarus:membership_orders_list')
login_url = reverse_lazy('digitalglarus:login')
fields = '__all__'
def get_object(self):
membership_order = MembershipOrder.objects.\
filter(customer__user=self.request.user).last()
if not membership_order:
raise AttributeError("Membership does not exists")
membership = membership_order.membership
return membership
def post(self, *args, **kwargs):
membership = self.get_object()
membership.deactivate()
messages.add_message(self.request, messages.SUCCESS, self.success_message)
return HttpResponseRedirect(self.success_url)
class UserBillingAddressView(LoginRequiredMixin, UpdateView):
model = UserBillingAddress
form_class = UserBillingAddressForm
template_name = "digitalglarus/user_billing_address.html"
success_url = reverse_lazy('digitalglarus:user_billing_address')
success_message = "Billing Address Updated"
def get_success_url(self):
next_url = self.request.POST.get('next') if self.request.POST.get('next')\
else self.success_url
return next_url
def form_valid(self, form):
"""
If the form is valid, save the associated model.
"""
messages.add_message(self.request, messages.SUCCESS, self.success_message)
self.object = form.save()
return super(UserBillingAddressView, self).form_valid(form)
def get_form_kwargs(self):
current_billing_address = self.request.user.billing_addresses.first()
form_kwargs = super(UserBillingAddressView, self).get_form_kwargs()
if not current_billing_address:
return form_kwargs
form_kwargs.update({
'initial': {
'street_address': current_billing_address.street_address,
'city': current_billing_address.city,
'postal_code': current_billing_address.postal_code,
'country': current_billing_address.country,
}
})
return form_kwargs
def get_object(self):
current_billing_address = self.request.user.billing_addresses.filter(current=True).last()
if not current_billing_address:
raise AttributeError("Billing Address does not exists")
return current_billing_address
class MembershipDeactivateSuccessView(LoginRequiredMixin, TemplateView):
template_name = "digitalglarus/membership_deactivated_success.html"
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_dates(self.request.user)
next_start_date, next_end_date = MembershipOrder.next_membership_dates(self.request.user)
current_billing_address = self.request.user.billing_addresses.filter(current=True).last()
context.update({
'membership_start_date': start_date,
'membership_end_date': end_date,
'next_membership_start_date': next_start_date,
'next_membership_end_date': next_end_date,
'billing_address': current_billing_address
})
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):
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_context_data(self, **kwargs):
context = super(BookingOrdersListView, self).get_context_data(**kwargs)
current_billing_address = self.request.user.billing_addresses.filter(current=True).last()
context.update({
'billing_address': current_billing_address
})
return context
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): class CalendarApi(View):
def get(self,request,month,year): def get(self,request,month,year):
calendar = BookCalendar(request.user,requested_month=month).formatmonth(int(year),int(month)) calendar = BookCalendar(request.user,requested_month=month).formatmonth(int(year),int(month))
@ -46,22 +605,6 @@ class ContactView(FormView):
return super(ContactView, self).form_valid(form) return super(ContactView, self).form_valid(form)
class IndexView(TemplateView):
template_name = "digitalglarus/old_index.html"
class HistoryView(TemplateView):
template_name = "digitalglarus/history.html"
def get_context_data(self, **kwargs):
context = super(HistoryView, self).get_context_data(**kwargs)
supporters = Supporter.objects.all()
context.update({
'supporters': supporters
})
return context
class AboutView(TemplateView): class AboutView(TemplateView):
template_name = "digitalglarus/about.html" template_name = "digitalglarus/about.html"

View file

@ -7,6 +7,7 @@ ADMINS = (
) )
# ('Sanghee Kim', 'sanghee.kim@ungleich.ch'), # ('Sanghee Kim', 'sanghee.kim@ungleich.ch'),
DEBUG=False
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

View file

@ -56,7 +56,7 @@ $( document ).ready(function() {
//set token on a hidden input //set token on a hidden input
$('#id_token').val(token); $('#id_token').val(token);
$('#donation-form').submit(); $('#billing-form').submit();
} }
}); });
} }

View file

@ -17,7 +17,7 @@ from stored_messages.api import mark_read
from membership.models import CustomUser, StripeCustomer from membership.models import CustomUser, StripeCustomer
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
from utils.forms import BillingAddressForm, PasswordResetRequestForm from utils.forms import BillingAddressForm, PasswordResetRequestForm
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin
from utils.mailer import BaseEmail from utils.mailer import BaseEmail
from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder
from .forms import HostingUserSignupForm, HostingUserLoginForm from .forms import HostingUserSignupForm, HostingUserLoginForm
@ -137,31 +137,10 @@ class IndexView(View):
return render(request, self.template_name, context) return render(request, self.template_name, context)
class LoginView(FormView): class LoginView(LoginViewMixin):
template_name = 'hosting/login.html' template_name = "hosting/login.html"
success_url = reverse_lazy('hosting:orders')
form_class = HostingUserLoginForm form_class = HostingUserLoginForm
moodel = CustomUser success_url = reverse_lazy('hosting:orders')
def get_success_url(self):
next_url = self.request.session.get('next', self.success_url)
return next_url
def form_valid(self, form):
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
auth_user = authenticate(email=email, password=password)
if auth_user:
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
return HttpResponseRedirect(self.get_success_url())
def get(self, request, *args, **kwargs):
if self.request.user.is_authenticated():
return HttpResponseRedirect(reverse('hosting:notifications'))
return super(LoginView, self).get(request, *args, **kwargs)
class SignupView(CreateView): class SignupView(CreateView):
@ -196,32 +175,6 @@ class PasswordResetConfirmView(PasswordResetConfirmViewMixin):
template_name = 'hosting/confirm_reset_password.html' template_name = 'hosting/confirm_reset_password.html'
success_url = reverse_lazy('hosting:login') success_url = reverse_lazy('hosting:login')
# def post(self, request, uidb64=None, token=None, *arg, **kwargs):
# try:
# uid = urlsafe_base64_decode(uidb64)
# user = CustomUser.objects.get(pk=uid)
# except (TypeError, ValueError, OverflowError, CustomUser.DoesNotExist):
# user = None
# form = self.form_class(request.POST)
# if user is not None and default_token_generator.check_token(user, token):
# if form.is_valid():
# new_password = form.cleaned_data['new_password2']
# user.set_password(new_password)
# user.save()
# messages.success(request, 'Password has been reset.')
# return self.form_valid(form)
# else:
# messages.error(request, 'Password reset has not been unsuccessful.')
# form.add_error(None, 'Password reset has not been unsuccessful.')
# return self.form_invalid(form)
# else:
# messages.error(request, 'The reset password link is no longer valid.')
# form.add_error(None, 'Password reset has not been unsuccessful.')
# return self.form_invalid(form)
class NotificationsView(LoginRequiredMixin, TemplateView): class NotificationsView(LoginRequiredMixin, TemplateView):
template_name = 'hosting/notifications.html' template_name = 'hosting/notifications.html'

View file

@ -1,5 +1,8 @@
from datetime import datetime from datetime import datetime
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, AbstractUser, PermissionsMixin from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, AbstractUser, PermissionsMixin
@ -21,7 +24,6 @@ def get_anonymous_user_instance(User):
validation_slug=make_password(None)) validation_slug=make_password(None))
class MyUserManager(BaseUserManager): class MyUserManager(BaseUserManager):
def create_user(self, email, name, password=None): def create_user(self, email, name, password=None):
""" """
@ -86,6 +88,10 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
else: else:
return None return None
@classmethod
def get_all_members(cls):
return cls.objects.filter(stripecustomer__membershiporder__isnull=False)
@classmethod @classmethod
def validate_url(cls, validation_slug): def validate_url(cls, validation_slug):
user = cls.objects.filter(validation_slug=validation_slug).first() user = cls.objects.filter(validation_slug=validation_slug).first()

View file

@ -4,19 +4,6 @@
{% block content %} {% block content %}
<style type="text/css">
.navbar-default {
background-color: black;
}
section.login {
margin-top: 10%;
margin-bottom: 8%;
}
</style>
<section class="login"> <section class="login">
<div class="container"> <div class="container">
<div class="row"> <div class="row">

View file

@ -9,7 +9,6 @@ from nosystemd.models import DonatorStatus, Donation
from nosystemd.forms import DonationForm from nosystemd.forms import DonationForm
class Command(BaseCommand): class Command(BaseCommand):
help = 'Make the monthly stripe charge to all donators' help = 'Make the monthly stripe charge to all donators'
CURRENCY = 'usd' CURRENCY = 'usd'

View file

@ -1,17 +1,17 @@
from django.views.generic import TemplateView, CreateView, FormView, DetailView, UpdateView,\ from django.views.generic import TemplateView, FormView, DetailView, UpdateView,\
ListView ListView
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import render from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy, reverse from django.core.urlresolvers import reverse_lazy, reverse
from django.contrib.auth import authenticate, login
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from membership.models import CustomUser, StripeCustomer from membership.models import StripeCustomer
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin,\
SignupViewMixin
from utils.forms import PasswordResetRequestForm from utils.forms import PasswordResetRequestForm
from utils.mailer import BaseEmail from utils.mailer import BaseEmail
@ -36,53 +36,16 @@ class LandingView(TemplateView):
return context return context
class LoginView(FormView): class LoginView(LoginViewMixin):
template_name = "nosystemd/login.html" template_name = "nosystemd/login.html"
form_class = LoginForm form_class = LoginForm
success_url = reverse_lazy('nosystemd:landing') success_url = reverse_lazy('nosystemd:landing')
def get_success_url(self):
next_url = self.request.session.get('next', self.success_url)
return next_url
def form_valid(self, form): class SignupView(SignupViewMixin):
email = form.cleaned_data.get('email') template_name = "nosystemd/signup.html"
password = form.cleaned_data.get('password')
auth_user = authenticate(email=email, password=password)
if auth_user:
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
return HttpResponseRedirect(self.get_success_url())
def get(self, request, *args, **kwargs):
if self.request.user.is_authenticated():
return HttpResponseRedirect(reverse('nosystemd:landing'))
return super(LoginView, self).get(request, *args, **kwargs)
class SignupView(CreateView):
template_name = 'nosystemd/signup.html'
model = CustomUser
form_class = SignupForm form_class = SignupForm
success_url = reverse_lazy('nosystemd:landing')
def get_success_url(self):
next_url = self.request.POST.get('next', reverse('nosystemd:login'))
return next_url
def form_valid(self, form):
name = form.cleaned_data.get('name')
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
CustomUser.register(name, password, email)
auth_user = authenticate(email=email, password=password)
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
class PasswordResetView(PasswordResetViewMixin): class PasswordResetView(PasswordResetViewMixin):

View file

@ -1,5 +1,5 @@
from django import forms from django import forms
from .models import ContactMessage, BillingAddress from .models import ContactMessage, BillingAddress, UserBillingAddress
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -109,6 +109,19 @@ class BillingAddressForm(forms.ModelForm):
} }
class UserBillingAddressForm(forms.ModelForm):
user = forms.ModelChoiceField(queryset=CustomUser.objects.all(),
widget=forms.HiddenInput())
class Meta:
model = UserBillingAddress
fields = ['street_address', 'city', 'postal_code', 'country', 'user']
labels = {
'street_address': _('Street Address'),
'city': _('City'),
'postal_code': _('Postal Code'),
'Country': _('Country'),
}
class ContactUsForm(forms.ModelForm): class ContactUsForm(forms.ModelForm):
error_css_class = 'autofocus' error_css_class = 'autofocus'

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-10-13 02:53
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('utils', '0003_userbillingaddress'),
]
operations = [
migrations.AlterField(
model_name='userbillingaddress',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='billing_addresses', to=settings.AUTH_USER_MODEL),
),
]

View file

@ -1,20 +1,45 @@
from django.db import models from django.db import models
from django.core import serializers
from django.forms.models import model_to_dict
from membership.models import CustomUser
from .fields import CountryField from .fields import CountryField
# Create your models here. # Create your models here.
class BaseBillingAddress(models.Model):
class BillingAddress(models.Model):
street_address = models.CharField(max_length=100) street_address = models.CharField(max_length=100)
city = models.CharField(max_length=50) city = models.CharField(max_length=50)
postal_code = models.CharField(max_length=50) postal_code = models.CharField(max_length=50)
country = CountryField() country = CountryField()
class Meta:
abstract = True
class BillingAddress(BaseBillingAddress):
def __str__(self): def __str__(self):
return self.street_address return self.street_address
class UserBillingAddress(BaseBillingAddress):
user = models.ForeignKey(CustomUser, related_name='billing_addresses')
current = models.BooleanField(default=True)
def __str__(self):
return self.street_address
def to_dict(self):
return {
'Street Address': self.street_address,
'City': self.city,
'Postal Code': self.postal_code,
'Country': self.country,
}
class ContactMessage(models.Model): class ContactMessage(models.Model):
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
email = models.EmailField() email = models.EmailField()

View file

@ -1,10 +1,10 @@
from django.views.generic import FormView from django.views.generic import FormView, CreateView
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login
from membership.models import CustomUser from membership.models import CustomUser
@ -12,6 +12,55 @@ from .mailer import BaseEmail
from .forms import SetPasswordForm from .forms import SetPasswordForm
class SignupViewMixin(CreateView):
model = CustomUser
success_url = None
def get_success_url(self):
next_url = self.request.POST.get('next') if self.request.POST.get('next')\
else self.success_url
return next_url
def form_valid(self, form):
name = form.cleaned_data.get('name')
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
CustomUser.register(name, password, email)
auth_user = authenticate(email=email, password=password)
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
class LoginViewMixin(FormView):
success_url = None
def get_success_url(self):
next_url = self.request.session.get('next', self.success_url)
return next_url
def form_valid(self, form):
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
auth_user = authenticate(email=email, password=password)
if auth_user:
login(self.request, auth_user)
return HttpResponseRedirect(self.get_success_url())
return HttpResponseRedirect(self.get_success_url())
def get(self, request, *args, **kwargs):
if self.request.user.is_authenticated():
return HttpResponseRedirect(self.get_success_url())
return super(LoginViewMixin, self).get(request, *args, **kwargs)
class PasswordResetViewMixin(FormView): class PasswordResetViewMixin(FormView):
# template_name = 'hosting/reset_password.html' # template_name = 'hosting/reset_password.html'
# form_class = PasswordResetRequestForm # form_class = PasswordResetRequestForm
@ -72,11 +121,11 @@ class PasswordResetConfirmViewMixin(FormView):
messages.success(request, 'Password has been reset.') messages.success(request, 'Password has been reset.')
return self.form_valid(form) return self.form_valid(form)
else: else:
messages.error(request, 'Password reset has not been unsuccessful.') messages.error(request, 'Password reset has not been successful.')
form.add_error(None, 'Password reset has not been unsuccessful.') form.add_error(None, 'Password reset has not been successful.')
return self.form_invalid(form) return self.form_invalid(form)
else: else:
messages.error(request, 'The reset password link is no longer valid.') messages.error(request, 'The reset password link is no longer valid.')
form.add_error(None, 'Password reset has not been unsuccessful.') form.add_error(None, 'The reset password link is no longer valid.')
return self.form_invalid(form) return self.form_invalid(form)