From e5d2d7445014b15fadaf96e36bf845e9b929a878 Mon Sep 17 00:00:00 2001 From: Tomislav R Date: Fri, 11 Mar 2016 19:42:45 +0100 Subject: [PATCH] payment app --- dynamicweb/settings/base.py | 20 +++- membership/forms.py | 42 ++++++- membership/migrations/0001_initial.py | 42 +++++++ membership/migrations/__init__.py | 0 membership/models.py | 15 ++- membership/payment.py | 46 ++++++++ membership/templates/confirm.html | 20 +++- membership/templates/creditcard.html | 162 ++++++++++++++++---------- membership/templates/error.html | 12 +- membership/templates/membership.html | 4 +- membership/templates/success.html | 2 +- membership/templates/validated.html | 16 ++- membership/urls.py | 7 +- membership/views.py | 88 ++++++++++++-- requirements.txt | 4 +- 15 files changed, 379 insertions(+), 101 deletions(-) create mode 100644 membership/migrations/0001_initial.py create mode 100644 membership/migrations/__init__.py create mode 100644 membership/payment.py diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py index 5d9af85a..89aad881 100644 --- a/dynamicweb/settings/base.py +++ b/dynamicweb/settings/base.py @@ -120,10 +120,10 @@ TEMPLATES = [ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(PROJECT_DIR, 'membership/'), # membership template - os.path.join(PROJECT_DIR,'templates/'), - os.path.join(PROJECT_DIR,'templates/digitalglarus/partials'), - os.path.join(PROJECT_DIR,'templates/cms'), - os.path.join(PROJECT_DIR,'templates/digitalglarus'), + os.path.join(PROJECT_DIR, 'templates/'), + os.path.join(PROJECT_DIR, 'templates/digitalglarus/partials'), + os.path.join(PROJECT_DIR, 'templates/cms'), + os.path.join(PROJECT_DIR, 'templates/digitalglarus'), ], 'APP_DIRS': True, 'OPTIONS': { @@ -412,3 +412,15 @@ META_USE_SITES = True PARLER_LANGUAGES = {1: ({'code': 'en-us'}, {'code': 'de'},)} AUTH_USER_MODEL = 'membership.CustomUser' + + +# PAYMENT + +STRIPE_API_PUBLIC_KEY = 'pk_test_uvWyHNJgVL2IB8kjfgJkGjg4' # used in frontend to call from user browser +STRIPE_API_PRIVATE_KEY = 'sk_test_uIPMdgXoRGydrcD7fkwcn7dj' # used in backend payment +STRIPE_DESCRIPTION_ON_PAYMENT = "Payment for ungleich GmbH services" + +# EMAIL MESSAGES +REGISTRATION_MESSAGE = {'subject': "Validation mail", + 'message': 'Please validate Your account under this link http://localhost:8000/en-us/validate/{}', + 'from': 'test@test.com'} diff --git a/membership/forms.py b/membership/forms.py index 04827be1..7ce2a1d4 100644 --- a/membership/forms.py +++ b/membership/forms.py @@ -1,14 +1,50 @@ __author__ = 'tomislav' from django import forms +from django.utils.translation import ugettext_lazy as _ +import six + +from .models import CreditCards class LoginForm(forms.Form): email = forms.EmailField(label="Email address", max_length=50, - widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter email'})) + widget=forms.TextInput( + attrs={'class': 'form-control', 'placeholder': 'Enter email'})) password = forms.CharField(label='Password', max_length=50, - widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Password','type':'password'})) + widget=forms.TextInput( + attrs={'class': 'form-control', 'placeholder': 'Password', + 'type': 'password'})) class RegisterForm(LoginForm): name = forms.CharField(label='Name', max_length=50, - widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder':'Enter name'})) + widget=forms.TextInput( + attrs={'class': 'form-control', 'placeholder': 'Enter name'})) + + +class PaymentForm(forms.ModelForm): + class Meta: + model = CreditCards + fields = ('name', 'card_number', 'expiry_date', 'ccv', 'user_id') + labels = {'name': _('Name'), 'card_number': _('Card number'), 'expiry_date': _('Expiry date'), + 'ccv': _('CCV')} + exclude = ('user_id','payment_type') + widgets = { + 'name': forms.TextInput( + attrs={'class': 'form-control', "placeholder": "Enter name on card", + 'placeholder': 'Enter name on card'}), + 'card_number': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Card Number','data-stripe':'number'}), + 'expiry_date': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'MM/YYYY'}), + 'ccv': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'CCV','data-stripe':'cvc'})} + + def clean(self): + data = self.cleaned_data + + # if CreditCards.objects.filter(card_number=data.get("card_number")): + # raise forms.ValidationError({'card_number': _('Credit card is used before.')}) + return self.cleaned_data + + def save(self, user_id): + self.instance.user_id = user_id + self.instance.user_id_id = user_id.id + super(PaymentForm, self).save() diff --git a/membership/migrations/0001_initial.py b/membership/migrations/0001_initial.py new file mode 100644 index 00000000..1704515c --- /dev/null +++ b/membership/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings +import django.core.validators + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, verbose_name='ID', primary_key=True)), + ('password', models.CharField(verbose_name='password', max_length=128)), + ('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)), + ('name', models.CharField(max_length=50)), + ('email', models.EmailField(unique=True, max_length=254)), + ('validated', models.IntegerField(default=0, choices=[(0, 'Not validated'), (1, 'Validated')])), + ('validation_slug', models.CharField(unique=True, max_length=50, db_index=True)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='CreditCards', + fields=[ + ('id', models.AutoField(auto_created=True, serialize=False, verbose_name='ID', primary_key=True)), + ('name', models.CharField(max_length=50)), + ('card_number', models.CharField(max_length=50)), + ('expiry_date', models.CharField(validators=[django.core.validators.RegexValidator('\\d{2}\\/\\d{4}', 'Use this pattern(MM/YYYY).')], max_length=50)), + ('ccv', models.CharField(validators=[django.core.validators.RegexValidator('\\d{3,4}', 'Wrong CCV number.')], max_length=4)), + ('payment_type', models.CharField(max_length=5, default='N')), + ('user_id', models.ForeignKey(to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/membership/migrations/__init__.py b/membership/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/membership/models.py b/membership/models.py index 273b764b..349c56a0 100644 --- a/membership/models.py +++ b/membership/models.py @@ -1,7 +1,9 @@ from django.db import models +from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager from django.contrib.auth.hashers import make_password from django.core.mail import send_mail +from django.core.validators import RegexValidator REGISTRATION_MESSAGE = {'subject': "Validation mail", 'message': 'Please validate Your account under this link http://localhost:8000/en-us/validate/{}', @@ -110,7 +112,12 @@ class CustomUser(AbstractBaseUser): # Simplest possible answer: All admins are staff return self.is_admin -# class CreditCards(models.Model): -# id = models.IntegerField(primary_key=True) -# user_id = models.ForeignKey(User, on_delete=models.CASCADE) -# number = models.CharField(max_length=400) + +class CreditCards(models.Model): + name = models.CharField(max_length=50) + user_id = models.ForeignKey(CustomUser, on_delete=models.CASCADE) + card_number = models.CharField(max_length=50) + expiry_date = models.CharField(max_length=50, validators=[RegexValidator(r'\d{2}\/\d{4}', _( + 'Use this pattern(MM/YYYY).'))]) + ccv = models.CharField(max_length=4,validators=[RegexValidator(r'\d{3,4}',_('Wrong CCV number.'))]) + payment_type = models.CharField(max_length=5,default='N') diff --git a/membership/payment.py b/membership/payment.py new file mode 100644 index 00000000..31e2ce73 --- /dev/null +++ b/membership/payment.py @@ -0,0 +1,46 @@ +__author__ = 'tomislav' +from django.conf import settings +from .models import CreditCards +import stripe +stripe.api_key = settings.STRIPE_API_PRIVATE_KEY + + +class StripePayment(object): + + @classmethod + def make_payment(cls,user,amount,token,time): + try: + # Use Stripe's library to make requests... + charge = stripe.Charge.create( + amount=amount, + currency='chf', + source=token, + description=settings.STRIPE_DESCRIPTION_ON_PAYMENT + ) + if charge['status'] =='succeeded': + obj = CreditCards.objects.filter(user_id=user.id).first() + obj.payment_type = time + obj.save() + return charge['status'] + + except stripe.error.CardError as e: + # Since it's a decline, stripe.error.CardError will be caught + body = e.json_body + err = body['error'] + return err['message'] + except stripe.error.RateLimitError as e: + return "Too many requests made to the API too quickly" + except stripe.error.InvalidRequestError as e: + return "Invalid parameters" + except stripe.error.AuthenticationError as e: + # Authentication with Stripe's API failed + # (maybe you changed API keys recently) + pass + except stripe.error.APIConnectionError as e: + return "Currently its not possible to make payments." + except stripe.error.StripeError as e: + return "Currently its not possible to make payments." + #maybe send email + except Exception as e: + return "Currently its not possible to make payments." + #maybe send email diff --git a/membership/templates/confirm.html b/membership/templates/confirm.html index 3623d8dc..9ca82b0b 100644 --- a/membership/templates/confirm.html +++ b/membership/templates/confirm.html @@ -4,7 +4,8 @@ - + {% load static %} +
@@ -19,8 +20,15 @@

Your membership is almost ready!

If this is correct information, click CONFIRM

-

Name: Nico Schottelius

-

Email: nico.schottelius@digitalglarus.ch

+

Name: {{ name }}

+ + {% if email %} +

Email: {{ email }}

+ {% else %} + + {% endif %}

Membership requested for:

01.01.2016-31.12.2016


@@ -30,12 +38,12 @@
-

Have probelm? Contact +

Have problem? Contact help@digitalglarus.ch.

- GO BACK - CONFIRM + GO BACK + CONFIRM
diff --git a/membership/templates/creditcard.html b/membership/templates/creditcard.html index 7c704187..bb8801c3 100644 --- a/membership/templates/creditcard.html +++ b/membership/templates/creditcard.html @@ -1,66 +1,104 @@ - + + - - - - - -
-
+ + + + + + {% load static %} + + + +
+
-
-
-

Payment details

-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
- -
- Cancel -
-
-
-
-
-
-

Have probelm? Contact - help@digitalglarus.ch. -
-
-

-
-
-
-
- +
+
+

Payment details

+
+ + +
+
+ {% csrf_token %} + {% for field in form %} +
+ + {{ field }} + {% for error in field.errors %} + {{ error|striptags }} + {% endfor %} +
+ {% endfor %} + +
+ Cancel +
+
+
+
+
+
+ +

Have probelm? Contact + help@digitalglarus.ch. +
+
+

+
+
+
+ + + + + \ No newline at end of file diff --git a/membership/templates/error.html b/membership/templates/error.html index 2fe974e6..f5206a59 100644 --- a/membership/templates/error.html +++ b/membership/templates/error.html @@ -2,12 +2,16 @@ - - - + + {% load static %} +
@@ -24,6 +28,8 @@ help@digitalglarus.ch

+

{{ msg }}

+

diff --git a/membership/templates/membership.html b/membership/templates/membership.html index 41b44f0c..a0c5468c 100644 --- a/membership/templates/membership.html +++ b/membership/templates/membership.html @@ -79,7 +79,7 @@ for coworking. It is a perfect try-out package!

-
Buy Now + Buy Now @@ -98,7 +98,7 @@ membership.

- Buy Now + Buy Now
diff --git a/membership/templates/success.html b/membership/templates/success.html index 26ef30cf..d55cf1e1 100644 --- a/membership/templates/success.html +++ b/membership/templates/success.html @@ -21,6 +21,6 @@
- + \ No newline at end of file diff --git a/membership/templates/validated.html b/membership/templates/validated.html index c05d9c19..bd1a3c90 100644 --- a/membership/templates/validated.html +++ b/membership/templates/validated.html @@ -8,13 +8,27 @@ type="text/css"> + {% if request.session.next == None %} + + {% endif %}
-

You're successfully validated!

+

+ {% if msg == 'succeeded' %} + Thank You for Your payment!

redirecting...

+ {% else %} + Your payment was not processed correctly.
Reason: {{ msg }} + {% endif %} +

diff --git a/membership/urls.py b/membership/urls.py index 6df168f6..4fca7607 100644 --- a/membership/urls.py +++ b/membership/urls.py @@ -1,10 +1,13 @@ __author__ = 'tomislav' from django.conf.urls import url +from django.contrib.auth.decorators import login_required from . import views urlpatterns = ( - url(r"^/$", views.LoginRegistrationView.as_view()), + url(r"^/$", views.LoginRegistrationView.as_view(), name='login'), url(r"^/validate/(?P.*)/$", views.validate_email), - url(r"^/membership/$",views.MembershipView.as_view(),name='membership') + url(r"^/membership/$", login_required(views.MembershipView.as_view()), name='membership'), + url(r"^/buy/(?P