From 4580a75f89e99d5e1374a27dd601bd4840618fd8 Mon Sep 17 00:00:00 2001 From: Levi Date: Wed, 27 Jul 2016 00:08:45 -0500 Subject: [PATCH] Added DonatorStatus model in order to know if an donator has canceled or not his monthly donation, Now we create a DonatorStatus for the user after receiving his first donation. Added DonatorStatus view. Added donator_status.html in order to allow an user view his donation status , Added action to allow user to cancel his monthly donations. Now the user can logout using navbar. added Donation model to admin.Added command make_donations_charges in order to create stripe current monthly donations from all donators --- dynamicweb/settings/local.py | 21 -- hosting/admin.py | 1 - hosting/static/hosting/js/payment.js | 2 +- nosystemd/admin.py | 19 ++ nosystemd/forms.py | 41 +++- nosystemd/management/__init__.py | 0 nosystemd/management/commands/__init__.py | 0 .../commands/make_donation_charges.py | 51 +++++ nosystemd/migrations/0001_initial.py | 33 ++++ .../migrations/0002_auto_20160723_1848.py | 21 ++ nosystemd/migrations/0003_donatorstatus.py | 26 +++ nosystemd/models.py | 25 ++- nosystemd/static/nosystemd/js/donation.js | 124 ++++++++++++ nosystemd/templates/nosystemd/base.html | 21 +- nosystemd/templates/nosystemd/donation.html | 47 +++-- .../templates/nosystemd/donation_detail.html | 74 +++++++ .../templates/nosystemd/donator_status.html | 40 ++++ nosystemd/templates/nosystemd/landing.html | 99 +--------- nosystemd/urls.py | 11 +- nosystemd/views.py | 181 ++++++++++-------- utils/models.py | 3 + utils/stripe_utils.py | 3 - 22 files changed, 611 insertions(+), 232 deletions(-) delete mode 100644 dynamicweb/settings/local.py create mode 100644 nosystemd/management/__init__.py create mode 100644 nosystemd/management/commands/__init__.py create mode 100644 nosystemd/management/commands/make_donation_charges.py create mode 100644 nosystemd/migrations/0001_initial.py create mode 100644 nosystemd/migrations/0002_auto_20160723_1848.py create mode 100644 nosystemd/migrations/0003_donatorstatus.py create mode 100644 nosystemd/static/nosystemd/js/donation.js create mode 100644 nosystemd/templates/nosystemd/donation_detail.html create mode 100644 nosystemd/templates/nosystemd/donator_status.html diff --git a/dynamicweb/settings/local.py b/dynamicweb/settings/local.py deleted file mode 100644 index 799df594..00000000 --- a/dynamicweb/settings/local.py +++ /dev/null @@ -1,21 +0,0 @@ -from .base import * -REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='dynamicweb-development.ungleich.ch',slug='{slug}') -ALLOWED_HOSTS = [ - "*" - ] - -EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' - -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - 'LOCATION': 'unique-snowflake' - } -} - -MIDDLEWARE_CLASSES+=("debug_toolbar.middleware.DebugToolbarMiddleware",) - -INSTALLED_APPS+=( - 'django_extensions', - 'debug_toolbar' - ) diff --git a/hosting/admin.py b/hosting/admin.py index 4d1489ce..c4bff6e0 100644 --- a/hosting/admin.py +++ b/hosting/admin.py @@ -3,7 +3,6 @@ from django.utils.html import format_html from django.core.urlresolvers import reverse from utils.mailer import BaseEmail -from utils.stripe_utils import StripeUtils from .forms import HostingOrderAdminForm from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder diff --git a/hosting/static/hosting/js/payment.js b/hosting/static/hosting/js/payment.js index dd6c64d4..c431f7ce 100644 --- a/hosting/static/hosting/js/payment.js +++ b/hosting/static/hosting/js/payment.js @@ -56,7 +56,7 @@ $( document ).ready(function() { //set token on a hidden input $('#id_token').val(token); - $('#billing-form').submit(); + $('#donation-form').submit(); } }); } diff --git a/nosystemd/admin.py b/nosystemd/admin.py index 8c38f3f3..b07cea8c 100644 --- a/nosystemd/admin.py +++ b/nosystemd/admin.py @@ -1,3 +1,22 @@ from django.contrib import admin +from django.utils.html import format_html +from django.core.urlresolvers import reverse + +from .models import Donation + # Register your models here. + + +class DonationAdmin(admin.ModelAdmin): + + list_display = ('id', 'donation', 'donator') + search_fields = ['id', 'donator__user__email'] + + def user(self, obj): + email = obj.customer.user.email + user_url = reverse("admin:membership_customuser_change", args=[obj.customer.user.id]) + return format_html("{email}", url=user_url, email=email) + + +admin.site.register(Donation, DonationAdmin) diff --git a/nosystemd/forms.py b/nosystemd/forms.py index 464c1424..8aa3eb35 100644 --- a/nosystemd/forms.py +++ b/nosystemd/forms.py @@ -1,7 +1,11 @@ from django import forms +from django.utils.translation import ugettext_lazy as _ -from utils.forms import LoginFormMixin, SignupFormMixin +from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm +from utils.models import BillingAddress + +from .models import Donation, DonatorStatus class LoginForm(LoginFormMixin): @@ -10,5 +14,38 @@ class LoginForm(LoginFormMixin): class SignupForm(SignupFormMixin): - confirm_password = forms.CharField(widget=forms.EmailInput()) + confirm_password = forms.CharField(widget=forms.PasswordInput()) password = forms.CharField(widget=forms.PasswordInput()) + + +class DonationForm(forms.ModelForm): + + class Meta: + model = Donation + fields = ['donation', 'donator', 'billing_address', + 'last4', 'cc_brand', 'stripe_charge_id'] + + def save(self, commit=True): + instance = super(DonationForm, self).save(commit=False) + + if commit: + DonatorStatus.create(self.cleaned_data['donator'].user) + instance.save() + + return instance + + +class DonationBillingForm(BillingAddressForm): + token = forms.CharField(widget=forms.HiddenInput()) + donation_amount = forms.FloatField(widget=forms.TextInput(attrs={'placeholder': 'Amount'})) + + class Meta: + model = BillingAddress + fields = ['donation_amount', 'street_address', 'city', 'postal_code', 'country'] + labels = { + 'amount': _('Amount'), + 'street_address': _('Street Address'), + 'city': _('City'), + 'postal_code': _('Postal Code'), + 'Country': _('Country'), + } diff --git a/nosystemd/management/__init__.py b/nosystemd/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nosystemd/management/commands/__init__.py b/nosystemd/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nosystemd/management/commands/make_donation_charges.py b/nosystemd/management/commands/make_donation_charges.py new file mode 100644 index 00000000..210b04be --- /dev/null +++ b/nosystemd/management/commands/make_donation_charges.py @@ -0,0 +1,51 @@ +from django.core.management.base import BaseCommand + +from nosystem.models import DonatorStatus, Donation +from datetime import datetime + +from utils.stripe_utils import StripeUtils +from .forms import DonationForm + + +class Command(BaseCommand): + help = 'Make the monthly stripe charge to all donators' + + def handle(self, *args, **options): + donators = DonatorStatus.objects.filter(status=DonatorStatus.ACTIVE) + current_month = datetime.now().month + current_year = datetime.now().year + for donator in donators: + current_month_donation = Donation.objects.get(created_at__month=current_month, + created_at__year=current_year) + if not current_month_donation: + last_donation = Donation.objects.filter(donator=donator).last() + + donation_amount = last_donation.donation + # Make stripe charge to a customer + stripe_utils = StripeUtils() + stripe_utils.CURRENCY = 'usd' + charge_response = stripe_utils.make_charge(amount=donation_amount, + customer=donator.stripe_id) + charge = charge_response.get('response_object') + + # Check if the payment was approved + if not charge: + # TODO save error + context = { + 'paymentError': charge_response.get('error'), + } + print(context) + # Create a donation + charge = charge_response.get('response_object') + donation_data = { + 'cc_brand': charge.source.brand, + 'stripe_charge_id': charge.id, + 'last4': charge.source.last4, + 'billing_address': last_donation.billing_address.id, + 'donator': donator.id, + 'donation': donation_amount + } + donation_form = DonationForm(donation_data) + if donation_form.is_valid(): + donation = donation_form.save() + print(donation) diff --git a/nosystemd/migrations/0001_initial.py b/nosystemd/migrations/0001_initial.py new file mode 100644 index 00000000..8fa8bb71 --- /dev/null +++ b/nosystemd/migrations/0001_initial.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2016-07-22 06:51 +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): + + initial = True + + dependencies = [ + ('utils', '0002_billingaddress'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Donation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('donation', models.FloatField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('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')), + ('donator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/nosystemd/migrations/0002_auto_20160723_1848.py b/nosystemd/migrations/0002_auto_20160723_1848.py new file mode 100644 index 00000000..b4585533 --- /dev/null +++ b/nosystemd/migrations/0002_auto_20160723_1848.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2016-07-23 18:48 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('nosystemd', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='donation', + name='donator', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='membership.StripeCustomer'), + ), + ] diff --git a/nosystemd/migrations/0003_donatorstatus.py b/nosystemd/migrations/0003_donatorstatus.py new file mode 100644 index 00000000..6054c5da --- /dev/null +++ b/nosystemd/migrations/0003_donatorstatus.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2016-07-26 01: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 = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('nosystemd', '0002_auto_20160723_1848'), + ] + + operations = [ + migrations.CreateModel( + name='DonatorStatus', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(choices=[('active', 'Active'), ('canceled', 'Canceled')], max_length=10)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/nosystemd/models.py b/nosystemd/models.py index 8400b34f..45c3948a 100644 --- a/nosystemd/models.py +++ b/nosystemd/models.py @@ -1,15 +1,28 @@ from django.db import models -from membership.models import CustomUser +from membership.models import StripeCustomer, CustomUser from utils.models import BillingAddress -# Create your models here. +class DonatorStatus(models.Model): + ACTIVE = 'active' + CANCELED = 'canceled' + + STATUS_CHOICES = ( + (ACTIVE, 'Active'), + (CANCELED, 'Canceled') + ) + user = models.OneToOneField(CustomUser) + status = models.CharField(choices=STATUS_CHOICES, max_length=10, default=ACTIVE) + + @classmethod + def create(cls, user): + cls.objects.get_or_create(user=user) class Donation(models.Model): donation = models.FloatField() - donator = models.ForeignKey(CustomUser) + donator = models.ForeignKey(StripeCustomer) created_at = models.DateTimeField(auto_now_add=True) billing_address = models.ForeignKey(BillingAddress) last4 = models.CharField(max_length=4) @@ -20,3 +33,9 @@ class Donation(models.Model): def create(cls, data): obj = cls.objects.create(**data) return obj + + def set_stripe_charge(self, stripe_charge): + self.stripe_charge_id = stripe_charge.id + self.last4 = stripe_charge.source.last4 + self.cc_brand = stripe_charge.source.brand + self.save diff --git a/nosystemd/static/nosystemd/js/donation.js b/nosystemd/static/nosystemd/js/donation.js new file mode 100644 index 00000000..c431f7ce --- /dev/null +++ b/nosystemd/static/nosystemd/js/donation.js @@ -0,0 +1,124 @@ +$( 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 $form = $('#payment-form'); + $form.submit(payWithStripe); + + /* If you're using Stripe for payments */ + function payWithStripe(e) { + e.preventDefault(); + + /* Visual feedback */ + $form.find('[type=submit]').html('Validating '); + + 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 '); + /* 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); + $('#donation-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); + +}); + diff --git a/nosystemd/templates/nosystemd/base.html b/nosystemd/templates/nosystemd/base.html index a2041fee..b9691186 100644 --- a/nosystemd/templates/nosystemd/base.html +++ b/nosystemd/templates/nosystemd/base.html @@ -1,4 +1,4 @@ -{% load static bootstrap3 %} +{% load static bootstrap3 i18n %} @@ -59,9 +59,20 @@
  • Contact
  • -
  • - Login -
  • + {% if request.user.is_authenticated %} + + {% else %} +
  • + Login +
  • + {% endif %} @@ -90,7 +101,7 @@ - + diff --git a/nosystemd/templates/nosystemd/donation.html b/nosystemd/templates/nosystemd/donation.html index 5d866768..f78eb39e 100644 --- a/nosystemd/templates/nosystemd/donation.html +++ b/nosystemd/templates/nosystemd/donation.html @@ -8,36 +8,41 @@
    -
    -
    -

    Monthly Donation

    -
    -
    -
    -
    -
    -
    - + +
    +
    +

    Monthly Donation

    +
    + +
    +
    +
    +
    + {% bootstrap_field form.donation_amount show_label=False type='fields'%} + +
    -
    - + +
    -
    -
    -
    -

    Billing Address

    -
    -
    +
    +
    +

    Billing Address

    +
    {% for field in form %} {% csrf_token %} - {% bootstrap_field field show_label=False type='fields'%} + + {% if not field.name == 'donation_amount' %} + {% bootstrap_field field show_label=False type='fields'%} + {% endif %} {% endfor %} {% bootstrap_form_errors form type='non_fields'%} - + +
    -
    +

    Payment Details

    diff --git a/nosystemd/templates/nosystemd/donation_detail.html b/nosystemd/templates/nosystemd/donation_detail.html new file mode 100644 index 00000000..f103b461 --- /dev/null +++ b/nosystemd/templates/nosystemd/donation_detail.html @@ -0,0 +1,74 @@ +{% extends "nosystemd/base.html" %} +{% load staticfiles bootstrap3 %} +{% load i18n %} +{% block content %} + +
    +
    +
    +
    +

    {% trans "Invoice"%}

    {% trans "Donation #"%} {{donation.id}}

    +
    +
    +
    +
    +

    {% trans "Billing Address:"%}

    + {{user.name}}
    + {{donation.billing_address.street_address}},{{donation.billing_address.postal_code}}
    + {{donation.billing_address.city}}, {{donation.billing_address.country}}. +
    +
    +
    +
    + {% trans "Date:"%}
    + {{donation.created_at}}

    +

    +
    + +
    +
    +
    +
    +
    + {% trans "Payment Method:"%}
    + {{donation.cc_brand}} ending **** {{donation.last4}}
    + {{user.email}} +
    +
    +
    +
    +
    + +
    +
    +

    {% trans "Donation summary"%}

    +
    +
    +

    {% trans "Donation"%}-{{donation.created_at|date:"M Y"}} {{donation.donation}} USD

    +
    +

    {% trans "Total"%}

    {{donation.donation}} USD

    +
    +
    + {% url 'hosting:payment' as payment_url %} + {% if payment_url in request.META.HTTP_REFERER %} + + {% endif %} +
    +
    +
    +
    +
    + {% trans "Thanks for you donation, you can cancel your monthly donation at any time going to profile > cancel danation"%} +
    +
    + +
    +{%endblock%} diff --git a/nosystemd/templates/nosystemd/donator_status.html b/nosystemd/templates/nosystemd/donator_status.html new file mode 100644 index 00000000..6d80f82b --- /dev/null +++ b/nosystemd/templates/nosystemd/donator_status.html @@ -0,0 +1,40 @@ +{% extends "nosystemd/base.html" %} +{% load staticfiles bootstrap3 i18n %} +{% block content %} + +
    +
    +
    +
    + + + {% if messages %} +
      + {% for message in messages %} +
    • {{ message }}
    • + {% endfor %} +
    + {% endif %} + +

    Thanks you

    +
    +

    Your monthly donation status is {{donator_status.status}}

    +
    + {% csrf_token %} + +
    +
    + +
    +
    +
    +
    + +{% endblock %} \ No newline at end of file diff --git a/nosystemd/templates/nosystemd/landing.html b/nosystemd/templates/nosystemd/landing.html index 08fcd46b..d9093b4f 100755 --- a/nosystemd/templates/nosystemd/landing.html +++ b/nosystemd/templates/nosystemd/landing.html @@ -1,79 +1,6 @@ -{% load static bootstrap3 %} - - - - - - - - - - - - Creative - Start Bootstrap Theme - - - - - - - - - - - - - - - - - - - - - - - - +{% extends "nosystemd/base.html" %} +{% load staticfiles bootstrap3 i18n %} +{% block content %}
    @@ -81,7 +8,7 @@

    No more SYSTEMD


    We want to remove systemd from the famous linux distros and create a good replacement

    - DONATE NOW + DONATE NOW
    @@ -170,21 +97,5 @@
    +{% endblock %} - - - - - - - - - - - - - - - - - diff --git a/nosystemd/urls.py b/nosystemd/urls.py index 7bf9273d..0b4b8d53 100644 --- a/nosystemd/urls.py +++ b/nosystemd/urls.py @@ -1,7 +1,8 @@ from django.conf.urls import url from .views import LandingView, LoginView, SignupView, PasswordResetView,\ - PasswordResetConfirmView, DonationView + PasswordResetConfirmView, DonationView, DonationDetailView, ChangeDonatorStatusDetailView,\ + DonatorStatusDetailView urlpatterns = [ url(r'^$', LandingView.as_view(), name='landing'), @@ -13,6 +14,12 @@ urlpatterns = [ url(r'reset-password-confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', PasswordResetConfirmView.as_view(), name='reset_password_confirm'), - url(r'^donation/?$', DonationView.as_view(), name='donation'), + url(r'^donations/?$', DonationView.as_view(), name='donations'), + url(r'donations/(?P\d+)/?$', DonationDetailView.as_view(), name='donations'), + url(r'donations/status/?$', DonatorStatusDetailView.as_view(), + name='donator_status'), + url(r'donations/status/(?P\d+)/?$', ChangeDonatorStatusDetailView.as_view(), + name='change_donator_status'), + # url(r'^donation/invoice?$', DonationView.as_view(), name='donation_detail'), ] diff --git a/nosystemd/views.py b/nosystemd/views.py index 24ef1d4d..ee5a91e8 100644 --- a/nosystemd/views.py +++ b/nosystemd/views.py @@ -1,15 +1,20 @@ -from django.views.generic import TemplateView, CreateView, FormView +from django.views.generic import TemplateView, CreateView, FormView, DetailView, UpdateView from django.http import HttpResponseRedirect +from django.shortcuts import render from django.core.urlresolvers import reverse_lazy, reverse from django.contrib.auth import authenticate, login from django.contrib.auth.mixins import LoginRequiredMixin from django.conf import settings +from django.contrib import messages -from membership.models import CustomUser + +from membership.models import CustomUser, StripeCustomer +from utils.stripe_utils import StripeUtils from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin -from utils.forms import PasswordResetRequestForm, BillingAddressForm +from utils.forms import PasswordResetRequestForm -from .forms import LoginForm, SignupForm +from .forms import LoginForm, SignupForm, DonationForm, DonationBillingForm +from .models import Donation, DonatorStatus class LandingView(TemplateView): @@ -74,7 +79,8 @@ class PasswordResetConfirmView(PasswordResetConfirmViewMixin): class DonationView(LoginRequiredMixin, FormView): template_name = 'nosystemd/donation.html' login_url = reverse_lazy('nosystemd:login') - form_class = BillingAddressForm + form_class = DonationBillingForm + success_url = reverse_lazy('nosystemd:donations') def get_context_data(self, **kwargs): context = super(DonationView, self).get_context_data(**kwargs) @@ -84,86 +90,103 @@ class DonationView(LoginRequiredMixin, FormView): return context - # def post(self, request, *args, **kwargs): - # form = self.get_form() + def post(self, request, *args, **kwargs): + form = self.get_form() - # if form.is_valid(): - # context = self.get_context_data() - # specifications = request.session.get('vm_specs') - # vm_type = specifications.get('hosting_company') - # vm = VirtualMachineType.objects.get(hosting_company=vm_type) - # final_price = vm.calculate_price(specifications) + if form.is_valid(): + context = self.get_context_data() + token = form.cleaned_data.get('token') + donation_amount = form.cleaned_data.get('donation_amount') - # plan_data = { - # 'vm_type': vm, - # 'cores': specifications.get('cores'), - # 'memory': specifications.get('memory'), - # 'disk_size': specifications.get('disk_size'), - # 'configuration': specifications.get('configuration'), - # 'price': final_price - # } - # token = form.cleaned_data.get('token') + # 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)) - # # 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)) + # Create Billing Address + billing_address = form.save() - # # Create Virtual Machine Plan - # plan = VirtualMachinePlan.create(plan_data, request.user) + # Make stripe charge to a customer + stripe_utils = StripeUtils() + stripe_utils.CURRENCY = 'usd' + charge_response = stripe_utils.make_charge(amount=donation_amount, + customer=customer.stripe_id) + charge = charge_response.get('response_object') - # # Create Billing Address - # billing_address = form.save() + # 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) - # # Create a Hosting Order - # order = HostingOrder.create(vm_plan=plan, customer=customer, - # billing_address=billing_address) + # Create a donation + charge = charge_response.get('response_object') + donation_data = request.POST.copy() + donation_data.update({ + 'cc_brand': charge.source.brand, + 'stripe_charge_id': charge.id, + 'last4': charge.source.last4, + 'billing_address': billing_address.id, + 'donator': customer.id, + 'donation': donation_amount + }) + donation_form = DonationForm(donation_data) + if donation_form.is_valid(): + donation = donation_form.save() + return HttpResponseRedirect(reverse('nosystemd:donations', + kwargs={'pk': donation.id})) + else: + self.form_invalid(donation_form) - # # Make stripe charge to a customer - # stripe_utils = StripeUtils() - # charge_response = stripe_utils.make_charge(amount=final_price, - # customer=customer.stripe_id) - # charge = charge_response.get('response_object') - - # # Check if the payment was approved - # if not charge: - # context.update({ - # 'paymentError': charge_response.get('error'), - # 'form': form - # }) - # return render(request, self.template_name, context) - - # charge = charge_response.get('response_object') - - # # Associate an order with a stripe payment - # order.set_stripe_charge(charge) - - # # If the Stripe payment was successed, set order status approved - # order.set_approved() - - # # Send notification to ungleich as soon as VM has been booked - # # TODO send email using celery - - # context = { - # 'vm': plan, - # 'order': order, - # 'base_url': "{0}://{1}".format(request.scheme, request.get_host()) - - # } - # email_data = { - # 'subject': 'New VM request', - # 'to': request.user.email, - # 'context': context, - # 'template_name': 'new_booked_vm', - # 'template_path': 'hosting/emails/' - # } - # email = BaseEmail(**email_data) - # email.send() - - # return HttpResponseRedirect(reverse('hosting:orders', kwargs={'pk': order.id})) - # else: - # return self.form_invalid(form) + else: + return self.form_invalid(form) +class DonationDetailView(LoginRequiredMixin, DetailView): + template_name = "nosystemd/donation_detail.html" + context_object_name = "donation" + login_url = reverse_lazy('nosystemd:login') + model = Donation + + +class DonatorStatusDetailView(LoginRequiredMixin, TemplateView): + template_name = "nosystemd/donator_status.html" + login_url = reverse_lazy('nosystemd:login') + model = DonatorStatus + + def get_context_data(self, **kwargs): + context = super(DonatorStatusDetailView, self).get_context_data(**kwargs) + context.update({ + 'donator_status': self.request.user.donatorstatus + if self.request.user.donatorstatus else None + }) + return context + + def get(self, request, *args, **kwargs): + if not request.user.donatorstatus: + HttpResponseRedirect('nosystemd:landing') + return super(DonatorStatusDetailView, self).get(request, *args, **kwargs) + + +class ChangeDonatorStatusDetailView(LoginRequiredMixin, UpdateView): + template_name = "nosystemd/donator_status.html" + context_object_name = "donator_status" + login_url = reverse_lazy('nosystemd:login') + model = DonatorStatus + + def get_object(self, queryset=None): + return self.request.user.donatorstatus + + def post(self, *args, **kwargs): + donator_status = self.get_object() + + donator_status.status = DonatorStatus.ACTIVE \ + if donator_status.status == DonatorStatus.CANCELED else DonatorStatus.CANCELED + + donator_status.save() + messages.success(self.request, 'Your monthly donation status has been changed.') + return HttpResponseRedirect(reverse_lazy('nosystemd:donator_status')) diff --git a/utils/models.py b/utils/models.py index d0cab897..1720e1b6 100644 --- a/utils/models.py +++ b/utils/models.py @@ -11,6 +11,9 @@ class BillingAddress(models.Model): postal_code = models.CharField(max_length=50) country = CountryField() + def __str__(self): + return self.street_address + class ContactMessage(models.Model): name = models.CharField(max_length=200) diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index eb17ea09..693c57fc 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -11,7 +11,6 @@ def handleStripeError(f): 'error': None } common_message = "Currently its not possible to make payments." - try: response_object = f(*args, **kwargs) response = { @@ -85,7 +84,6 @@ class StripeUtils(object): @handleStripeError def make_charge(self, amount=None, customer=None): amount = int(amount * 100) # stripe amount unit, in cents - charge = self.stripe.Charge.create( amount=amount, # in cents currency=self.CURRENCY, @@ -93,7 +91,6 @@ class StripeUtils(object): ) return charge - @handleStripeError def create_plan(self, amount, name, id): self.stripe.Plan.create(