diff --git a/digitalglarus/migrations/0008_auto_20160820_1959.py b/digitalglarus/migrations/0008_auto_20160820_1959.py new file mode 100644 index 00000000..d71350b5 --- /dev/null +++ b/digitalglarus/migrations/0008_auto_20160820_1959.py @@ -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, + ), + ] diff --git a/digitalglarus/models.py b/digitalglarus/models.py index 612e1c02..e5b3ab88 100644 --- a/digitalglarus/models.py +++ b/digitalglarus/models.py @@ -1,7 +1,14 @@ + +import calendar +from datetime import datetime, date, timedelta from django.db import models from cms.models import CMSPlugin from filer.fields.image import FilerImageField from django.core.urlresolvers import reverse +from django.utils.functional import cached_property + +from membership.models import StripeCustomer +from utils.models import BillingAddress class MembershipType(models.Model): @@ -13,25 +20,69 @@ class MembershipType(models.Model): name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20) price = models.FloatField() + @cached_property + def days_left(self): + current_date = date.today() + _, days_in_month = calendar.monthrange(current_date.year, current_date.month) + pass_days = current_date.day + days_left = days_in_month - pass_days + 1 + return days_left + + @cached_property + def first_month_price(self): + current_date = date.today() + _, days_in_month = calendar.monthrange(current_date.year, current_date.month) + pass_days = current_date.day + days_left = days_in_month - pass_days + 1 + percentage = days_left / days_in_month + membership_price = self.price + final_price = membership_price * percentage + return final_price + + @cached_property + def first_month_range(self): + current_date = date.today() + _, days_in_month = calendar.monthrange(current_date.year, current_date.month) + pass_days = current_date.day + days_left = days_in_month - pass_days + end_date = current_date + timedelta(days=days_left) + return current_date, end_date + + @cached_property + def first_month_formated_range(self): + start_date, end_date = self.first_month_range + return "{} - {}".format(datetime.strftime(start_date, "%b, %d %Y"), + datetime.strftime(end_date, "%b, %d %Y")) + class Membership(models.Model): type = models.ForeignKey(MembershipType) @classmethod - def create(cls, data, user): + def create(cls, data): instance = cls.objects.create(**data) - instance.assign_permissions(user) return instance class MembershipOrder(models.Model): membership = models.ForeignKey(Membership) + customer = models.ForeignKey(StripeCustomer) + billing_address = models.ForeignKey(BillingAddress) created_at = models.DateTimeField(auto_now_add=True) approved = models.BooleanField(default=False) last4 = models.CharField(max_length=4) cc_brand = models.CharField(max_length=10) stripe_charge_id = models.CharField(max_length=100, null=True) + @classmethod + def create(cls, data): + stripe_charge = data.pop('stripe_charge', None) + instance = cls.objects.create(**data) + instance.stripe_charge_id = stripe_charge.id + instance.last4 = stripe_charge.source.last4 + instance.cc_brand = stripe_charge.source.brand + return instance + class Supporter(models.Model): name = models.CharField(max_length=200) @@ -44,9 +95,6 @@ class Supporter(models.Model): return reverse('dgSupporters_view', args=[self.pk]) - - - class DGGallery(models.Model): parent = models.ForeignKey('self', blank=True, null=True) name = models.CharField(max_length=30) diff --git a/digitalglarus/templates/digitalglarus/membership_activated.html b/digitalglarus/templates/digitalglarus/membership_activated.html new file mode 100644 index 00000000..891ea27f --- /dev/null +++ b/digitalglarus/templates/digitalglarus/membership_activated.html @@ -0,0 +1,57 @@ +{% extends "new_base_glarus.html" %} +{% load staticfiles cms_tags bootstrap3%} +{% block title %}crowdfunding{% endblock %} + +{% block content %} + + + + + + + + Membership Activated + + Your Digital Glarus membership is successfully activated for the following date. + + {{membership_dates}} + Now you can book your next coworking! + + + + + + Go to Booking + + + Your membership will be automatically renewed each month. For deactivating go tomy page + + + + + + + + + + + + + + + + + Digital Glarus + In der Au 7 Schwanden 8762 Switzerland + info@digitalglarus.ch + + (044) 534-66-22 + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/digitalglarus/templates/digitalglarus/membership_payment.html b/digitalglarus/templates/digitalglarus/membership_payment.html index 0345bda0..bde934de 100644 --- a/digitalglarus/templates/digitalglarus/membership_payment.html +++ b/digitalglarus/templates/digitalglarus/membership_payment.html @@ -8,6 +8,16 @@ padding: 0 !important; margin: 0 !important; } + + .form-control#id_country{ + -webkit-appearance: none; + -moz-appearance: none; + background-position: right 50%; + background-repeat: no-repeat; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAMCAYAAABSgIzaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDZFNDEwNjlGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDZFNDEwNkFGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NkU0MTA2N0Y3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0NkU0MTA2OEY3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuGsgwQAAAA5SURBVHjaYvz//z8DOYCJgUxAf42MQIzTk0D/M+KzkRGPoQSdykiKJrBGpOhgJFYTWNEIiEeAAAMAzNENEOH+do8AAAAASUVORK5CYII=); + padding: .5em; + padding-right: 1.5em + } @@ -23,9 +33,13 @@ Additional day costs 15CHF per day. More than 17 days a month it will charge only 290CHF/month. + + You will be charged on the first of the month until you + cancel your subscription. Previous charges won't be refunded. + Member Name - Nico Schottelius + {{request.user.name}} Billing Adress @@ -44,20 +58,14 @@ - - - - - - @@ -75,7 +83,7 @@ - + CV CODE @@ -84,7 +92,7 @@ - Purchase membership + Purchase membership @@ -115,25 +123,25 @@ Digital Glarus Membership - valid 2016.09.08 - 2016.10.08 + valid {{membership_type.first_month_formated_range}} + 1 person - Today's Total - 0.00CHF + Today's Total for {{membership_type.days_left}} days + {{membership_type.first_month_price|floatformat}}CHF Total - 35CHF + {{membership_type.first_month_price|floatformat}}CHF + I accept the Digital Glarus Terms and Conditions, Community Guidelines and Privacy Policy - Continue to Review - You can checkout on the next page diff --git a/digitalglarus/urls.py b/digitalglarus/urls.py index 88e1ba75..e81bd8b5 100644 --- a/digitalglarus/urls.py +++ b/digitalglarus/urls.py @@ -3,7 +3,7 @@ from django.utils.translation import ugettext_lazy as _ from . import views from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\ - PasswordResetView, PasswordResetConfirmView, MembershipPaymentView + PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView # from membership.views import LoginRegistrationView urlpatterns = [ @@ -15,7 +15,9 @@ urlpatterns = [ url(r'reset-password-confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', PasswordResetConfirmView.as_view(), name='reset_password_confirm'), url(_(r'history/?$'), HistoryView.as_view(), name='history'), - url(_(r'membership/payment?$'), MembershipPaymentView.as_view(), name='membership_payment'), + url(_(r'membership/payment/?$'), MembershipPaymentView.as_view(), name='membership_payment'), + url(_(r'membership/activated/?$'), MembershipActivatedView.as_view(), + name='membership_activated'), url(_(r'supporters/?$'), views.supporters, name='supporters'), url(r'calendar_api/(?P\d+)/(?P\d+)?$', views.CalendarApi.as_view(),name='calendar_api_1'), url(r'calendar_api/', views.CalendarApi.as_view(),name='calendar_api'), diff --git a/digitalglarus/views.py b/digitalglarus/views.py index 00d3f87e..d0edcd05 100644 --- a/digitalglarus/views.py +++ b/digitalglarus/views.py @@ -13,7 +13,7 @@ from django.utils.translation import get_language from djangocms_blog.models import Post from django.contrib import messages from django.http import JsonResponse -from django.views.generic import View +from django.views.generic import View, DetailView from .models import Supporter from utils.forms import ContactUsForm @@ -29,7 +29,7 @@ from utils.stripe_utils import StripeUtils from .forms import LoginForm, SignupForm, MembershipBillingForm -from .models import MembershipType +from .models import MembershipType, Membership, MembershipOrder class IndexView(TemplateView): @@ -78,22 +78,24 @@ class MembershipPaymentView(LoginRequiredMixin, FormView): form_class = MembershipBillingForm def get_form_kwargs(self): - membership_type = MembershipType.objects.get(name='standard') + self.membership_type = MembershipType.objects.get(name='standard') form_kwargs = super(MembershipPaymentView, self).get_form_kwargs() form_kwargs.update({ - 'initial': {'membership_type': membership_type.id} + 'initial': { + 'membership_type': self.membership_type.id + } }) return form_kwargs def get_context_data(self, **kwargs): context = super(MembershipPaymentView, self).get_context_data(**kwargs) context.update({ - 'stripe_key': settings.STRIPE_API_PUBLIC_KEY + 'stripe_key': settings.STRIPE_API_PUBLIC_KEY, + 'membership_type': self.membership_type }) return context def post(self, request, *args, **kwargs): - import pdb;pdb.set_trace() form = self.get_form() if form.is_valid(): @@ -111,7 +113,7 @@ class MembershipPaymentView(LoginRequiredMixin, FormView): # Make stripe charge to a customer stripe_utils = StripeUtils() - charge_response = stripe_utils.make_charge(amount=membership_type.price, + charge_response = stripe_utils.make_charge(amount=membership_type.first_month_price, customer=customer.stripe_id) charge = charge_response.get('response_object') @@ -124,10 +126,46 @@ class MembershipPaymentView(LoginRequiredMixin, FormView): return render(request, self.template_name, context) charge = charge_response.get('response_object') + + # Create Billing Address + billing_address = form.save() + + # Create membership plan + membership_data = {'type': membership_type} + membership = Membership.create(membership_data) + + # Create membership order + order_data = { + 'membership': membership, + 'customer': customer, + 'billing_address': billing_address, + 'stripe_charge': charge + } + MembershipOrder.create(order_data) + + request.session.update({ + 'membership_price': membership.type.first_month_price, + 'membership_dates': membership.type.first_month_formated_range + }) + return HttpResponseRedirect(reverse('digitalglarus:membership_activated')) + else: return self.form_invalid(form) +class MembershipActivatedView(TemplateView): + template_name = "digitalglarus/membership_activated.html" + + def get_context_data(self, **kwargs): + context = super(MembershipActivatedView, self).get_context_data(**kwargs) + membership_price = self.request.session.get('membership_price') + membership_dates = self.request.session.get('membership_dates') + context.update({ + 'membership_price': membership_price, + 'membership_dates': membership_dates, + }) + return context + ############## OLD VIEWS class CalendarApi(View):
Your membership will be automatically renewed each month. For deactivating go tomy page
You can checkout on the next page