--- /dev/null
+from django.contrib import admin
+from modeltranslation.admin import TranslationAdmin
+from . import models
+
+
+class PlanAdmin(admin.ModelAdmin):
+ list_display = ['min_amount', 'interval']
+
+admin.site.register(models.Plan, PlanAdmin)
+
+
+class PaymentInline(admin.TabularInline):
+ model = models.Payment
+ extra = 0
+ readonly_fields = ['payed_at']
+
+
+class ScheduleAdmin(admin.ModelAdmin):
+ list_display = ['email', 'started_at', 'expires_at', 'plan', 'amount', 'is_active', 'is_cancelled']
+ list_search = ['email']
+ list_filter = ['is_active', 'is_cancelled']
+ date_hierarchy = 'started_at'
+ inlines = [PaymentInline]
+
+admin.site.register(models.Schedule, ScheduleAdmin)
+
+
+class PaymentAdmin(admin.ModelAdmin):
+ list_display = ['payed_at', 'schedule']
+
+admin.site.register(models.Payment, PaymentAdmin)
+
+
+class MembershipAdmin(admin.ModelAdmin):
+ pass
+
+admin.site.register(models.Membership, MembershipAdmin)
+
+
+admin.site.register(models.ReminderEmail, TranslationAdmin)
--- /dev/null
+from django.apps import AppConfig
+
+class ClubConfig(AppConfig):
+ name = 'club'
+ verbose_name = 'Towarzystwo'
--- /dev/null
+# -*- coding: utf-8
+from django import forms
+from . import models
+from . import widgets
+from .payment_methods import method_by_slug
+
+
+class ScheduleForm(forms.ModelForm):
+ class Meta:
+ model = models.Schedule
+ fields = ['plan', 'method', 'amount', 'email']
+ widgets = {
+ 'plan': forms.RadioSelect,
+ 'method': forms.RadioSelect,
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(ScheduleForm, self).__init__(*args, **kwargs)
+ self.fields['plan'].empty_label = None
+
+ def clean(self):
+ cleaned_data = super(ScheduleForm, self).clean()
+ if 'method' in cleaned_data:
+ method = method_by_slug[cleaned_data['method']]
+ if method not in cleaned_data['plan'].payment_methods():
+ self.add_error('method', 'Metoda płatności niedostępna dla tego planu.')
+ if cleaned_data['amount'] < cleaned_data['plan'].min_amount:
+ self.add_error('amount', 'Minimalna kwota dla tego planu to %d zł.' % cleaned_data['plan'].min_amount)
+
--- /dev/null
+from django.utils.timezone import now
+from .models import Schedule
+
+
+def get_active_schedule(user):
+ if not user.is_authenticated:
+ return None
+ return Schedule.objects.filter(membership__user=user, is_active=True).exclude(expires_at__lt=now()).first()
+
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-03-04 11:36+0100\n"
+"PO-Revision-Date: 2019-03-04 11:34+0100\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n"
+"%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
+"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
+"X-Generator: Poedit 2.0.6\n"
+
+#: models.py:25
+msgid "a month"
+msgstr "miesięcznie"
+
+#: models.py:26
+msgid "a year"
+msgstr "rocznie"
+
+#: models.py:27
+msgid "in perpetuity"
+msgstr "na zawsze"
+
+#: models.py:30
+msgid "inteval"
+msgstr "okres"
+
+#: models.py:31
+msgid "min_amount"
+msgstr "minimalna kwota"
+
+#: models.py:32
+msgid "allow recurring"
+msgstr "płatności cykliczne"
+
+#: models.py:33
+msgid "allow one time"
+msgstr "płatności jednorazowe"
+
+#: models.py:36 models.py:69
+msgid "plan"
+msgstr "plan"
+
+#: models.py:37
+msgid "plans"
+msgstr "plany"
+
+#: models.py:66
+msgid "key"
+msgstr "klucz"
+
+#: models.py:67
+msgid "email"
+msgstr "email"
+
+#: models.py:68 models.py:123
+msgid "membership"
+msgstr "członkostwo"
+
+#: models.py:70
+msgid "amount"
+msgstr "kwota"
+
+#: models.py:71
+msgid "method"
+msgstr "metoda płatności"
+
+#: models.py:72
+msgid "active"
+msgstr "aktywny"
+
+#: models.py:73
+msgid "cancelled"
+msgstr "anulowany"
+
+#: models.py:74
+msgid "started at"
+msgstr "start"
+
+#: models.py:75
+msgid "expires_at"
+msgstr "wygasa"
+
+#: models.py:79 models.py:105
+msgid "schedule"
+msgstr "harmonogram"
+
+#: models.py:80
+msgid "schedules"
+msgstr "harmonogramy"
+
+#: models.py:106 models.py:120
+msgid "created at"
+msgstr "utworzone"
+
+#: models.py:107
+msgid "payed at"
+msgstr "opłacona"
+
+#: models.py:110
+msgid "payment"
+msgstr "płatność"
+
+#: models.py:111
+msgid "payments"
+msgstr "płatności"
+
+#: models.py:119
+msgid "user"
+msgstr "użytkownik"
+
+#: models.py:124
+msgid "memberships"
+msgstr "członkostwa"
+
+#: models.py:131
+msgid "days before"
+msgstr "dni przed"
+
+#: models.py:132
+msgid "subject"
+msgstr "temat"
+
+#: models.py:133
+msgid "body"
+msgstr "treść"
+
+#: models.py:136
+msgid "reminder email"
+msgstr "email z przypomnieniem"
+
+#: models.py:137
+msgid "reminder emails"
+msgstr "emaile z przypomnieniem"
+
+#: models.py:142
+#, python-format
+msgid "a day before expiration"
+msgid_plural "%d days before expiration"
+msgstr[0] "%d dzień przed wygaśnięciem"
+msgstr[1] "%d dni przed wygaśnięciem"
+msgstr[2] "%d dni przed wygaśnięciem"
+msgstr[3] "%d dni przed wygaśnięciem"
+
+#: models.py:144
+#, python-format
+msgid "a day after expiration"
+msgid_plural "%d days after expiration"
+msgstr[0] "%d dzień po wygaśnięciu"
+msgstr[1] "%d dni po wygaśnięciu"
+msgstr[2] "%d dni po wygaśnięciu"
+msgstr[3] "%d dni przed wygaśnięciem"
--- /dev/null
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-03-04 20:50
+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 = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Membership',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')),
+ ],
+ options={
+ 'verbose_name': 'membership',
+ 'verbose_name_plural': 'memberships',
+ },
+ ),
+ migrations.CreateModel(
+ name='Payment',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
+ ('payed_at', models.DateTimeField(blank=True, null=True, verbose_name='payed at')),
+ ],
+ options={
+ 'verbose_name': 'payment',
+ 'verbose_name_plural': 'payments',
+ },
+ ),
+ migrations.CreateModel(
+ name='Plan',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('interval', models.SmallIntegerField(choices=[(30, 'a month'), (365, 'a year'), (999, 'in perpetuity')], verbose_name='inteval')),
+ ('min_amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='min_amount')),
+ ('allow_recurring', models.BooleanField(verbose_name='allow recurring')),
+ ('allow_one_time', models.BooleanField(verbose_name='allow one time')),
+ ],
+ options={
+ 'ordering': ('interval',),
+ },
+ ),
+ migrations.CreateModel(
+ name='ReminderEmail',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('days_before', models.SmallIntegerField(verbose_name='days before')),
+ ('subject', models.CharField(max_length=1024, verbose_name='subject')),
+ ('subject_de', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_en', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_es', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_fr', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_it', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_lt', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_pl', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_ru', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('subject_uk', models.CharField(max_length=1024, null=True, verbose_name='subject')),
+ ('body', models.TextField(verbose_name='body')),
+ ('body_de', models.TextField(null=True, verbose_name='body')),
+ ('body_en', models.TextField(null=True, verbose_name='body')),
+ ('body_es', models.TextField(null=True, verbose_name='body')),
+ ('body_fr', models.TextField(null=True, verbose_name='body')),
+ ('body_it', models.TextField(null=True, verbose_name='body')),
+ ('body_lt', models.TextField(null=True, verbose_name='body')),
+ ('body_pl', models.TextField(null=True, verbose_name='body')),
+ ('body_ru', models.TextField(null=True, verbose_name='body')),
+ ('body_uk', models.TextField(null=True, verbose_name='body')),
+ ],
+ options={
+ 'ordering': ['days_before'],
+ 'verbose_name': 'reminder email',
+ 'verbose_name_plural': 'reminder emails',
+ },
+ ),
+ migrations.CreateModel(
+ name='Schedule',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('key', models.CharField(max_length=255, unique=True, verbose_name='key')),
+ ('email', models.EmailField(max_length=254, verbose_name='email')),
+ ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')),
+ ('method', models.CharField(choices=[(b'payu', b'PayU'), (b'payu-re', b'PayU Recurring'), (b'paypal-re', b'PayPal Recurring')], max_length=255, verbose_name='method')),
+ ('is_active', models.BooleanField(default=False, verbose_name='active')),
+ ('is_cancelled', models.BooleanField(default=False, verbose_name='cancelled')),
+ ('started_at', models.DateTimeField(auto_now_add=True, verbose_name='started at')),
+ ('expires_at', models.DateTimeField(blank=True, null=True, verbose_name='expires_at')),
+ ('membership', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='club.Membership', verbose_name='membership')),
+ ('plan', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='club.Plan', verbose_name='plan')),
+ ],
+ options={
+ 'verbose_name': 'schedule',
+ 'verbose_name_plural': 'schedules',
+ },
+ ),
+ migrations.AddField(
+ model_name='payment',
+ name='schedule',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='club.Schedule', verbose_name='schedule'),
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8
+from __future__ import unicode_literals
+
+from datetime import timedelta
+from django.conf import settings
+from django.urls import reverse
+from django.db import models
+from django.utils.timezone import now
+from django.utils.translation import ugettext_lazy as _, ungettext
+from catalogue.utils import get_random_hash
+from .payment_methods import methods, method_by_slug
+
+
+class Plan(models.Model):
+ """ Plans are set up by administrators. """
+ MONTH = 30
+ YEAR = 365
+ PERPETUAL = 999
+ intervals = [
+ (MONTH, _('a month')),
+ (YEAR, _('a year')),
+ (PERPETUAL, _('in perpetuity')),
+ ]
+
+ interval = models.SmallIntegerField(_('inteval'), choices=intervals)
+ min_amount = models.DecimalField(_('min_amount'), max_digits=10, decimal_places=2)
+ allow_recurring = models.BooleanField(_('allow recurring'))
+ allow_one_time = models.BooleanField(_('allow one time'))
+
+ class Meta:
+ verbose_name = _('plan')
+ verbose_name_plural = _('plans')
+
+ def __unicode__(self):
+ return "%s %s" % (self.min_amount, self.get_interval_display())
+
+ class Meta:
+ ordering = ('interval',)
+
+ def payment_methods(self):
+ for method in methods:
+ if self.allow_recurring and method.is_recurring or self.allow_one_time and not method.is_recurring:
+ yield method
+
+ def get_next_installment(self, date):
+ if self.interval == self.PERPETUAL:
+ return None
+ elif self.interval == self.YEAR:
+ return date.replace(year=date.year + 1)
+ elif self.interval == self.MONTH:
+ day = date.day
+ date = (date.replace(day=1) + timedelta(31)).replace(day=1) + timedelta(day - 1)
+ if date.day != day:
+ date = date.replace(day=1)
+ return date
+
+
+
+class Schedule(models.Model):
+ """ Represents someone taking up a plan. """
+ key = models.CharField(_('key'), max_length=255, unique=True)
+ email = models.EmailField(_('email'))
+ membership = models.ForeignKey('Membership', verbose_name=_('membership'), null=True, blank=True, on_delete=models.PROTECT)
+ plan = models.ForeignKey(Plan, verbose_name=_('plan'), on_delete=models.PROTECT)
+ amount = models.DecimalField(_('amount'), max_digits=10, decimal_places=2)
+ method = models.CharField(_('method'), max_length=255, choices=[(method.slug, method.name) for method in methods])
+ is_active = models.BooleanField(_('active'), default=False)
+ is_cancelled = models.BooleanField(_('cancelled'), default=False)
+ started_at = models.DateTimeField(_('started at'), auto_now_add=True)
+ expires_at = models.DateTimeField(_('expires_at'), null=True, blank=True)
+ # extra info?
+
+ class Meta:
+ verbose_name = _('schedule')
+ verbose_name_plural = _('schedules')
+
+ def __unicode__(self):
+ return self.key
+
+ def save(self, *args, **kwargs):
+ if not self.key:
+ self.key = get_random_hash(self.email)
+ return super(Schedule, self).save(*args, **kwargs)
+
+ def get_absolute_url(self):
+ return reverse('club_schedule', args=[self.key])
+
+ def get_payment_method(self):
+ return method_by_slug[self.method]
+
+
+ def is_expired(self):
+ return self.expires_at is not None and self.expires_at < now()
+
+ def create_payment(self):
+ n = now()
+ self.expires_at = self.plan.get_next_installment(n)
+ self.is_active = True
+ self.save()
+ self.payment_set.create(payed_at=n)
+
+
+class Payment(models.Model):
+ schedule = models.ForeignKey(Schedule, verbose_name=_('schedule'), on_delete=models.PROTECT)
+ created_at = models.DateTimeField(_('created at'), auto_now_add=True)
+ payed_at = models.DateTimeField(_('payed at'), null=True, blank=True)
+
+ class Meta:
+ verbose_name = _('payment')
+ verbose_name_plural = _('payments')
+
+ def __unicode__(self):
+ return "%s %s" % (self.schedule, self.payed_at)
+
+
+class Membership(models.Model):
+ """ Represents a user being recognized as a member of the club. """
+ user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
+ created_at = models.DateTimeField(_('created at'), auto_now_add=True)
+
+ class Meta:
+ verbose_name = _('membership')
+ verbose_name_plural = _('memberships')
+
+ def __unicode__(self):
+ return u'tow. ' + unicode(self.user)
+
+
+class ReminderEmail(models.Model):
+ days_before = models.SmallIntegerField(_('days before'))
+ subject = models.CharField(_('subject'), max_length=1024)
+ body = models.TextField(_('body'))
+
+ class Meta:
+ verbose_name = _('reminder email')
+ verbose_name_plural = _('reminder emails')
+ ordering = ['days_before']
+
+ def __unicode__(self):
+ if self.days_before >= 0:
+ return ungettext('a day before expiration', '%d days before expiration', n=self.days_before)
+ else:
+ return ungettext('a day after expiration', '%d days after expiration', n=-self.days_before)
+
--- /dev/null
+from django.urls import reverse
+
+
+class PaymentMethod(object):
+ is_recurring = False
+
+ @classmethod
+ def get_payment_url(cls, schedule):
+ return reverse('club_dummy_payment', args=[schedule.key])
+
+
+class PayU(PaymentMethod):
+ slug = 'payu'
+ name = 'PayU'
+ template_name = 'club/payment/payu.html'
+
+ @classmethod
+ def get_payment_url(cls, schedule):
+ return reverse('club_dummy_payment', args=[schedule.key])
+
+
+class PayURe(PaymentMethod):
+ slug='payu-re'
+ name = 'PayU Recurring'
+ template_name = 'club/payment/payu-re.html'
+ is_recurring = True
+
+ @classmethod
+ def get_payment_url(cls, schedule):
+ return reverse('club_dummy_payment', args=[schedule.key])
+
+
+class PayPalRe(PaymentMethod):
+ slug='paypal-re'
+ name = 'PayPal Recurring'
+ template_name = 'club/payment/paypal-re.html'
+ is_recurring = True
+
+ @classmethod
+ def get_payment_url(cls, schedule):
+ return reverse('club_dummy_payment', args=[schedule.key])
+
+
+methods = [
+ PayU,
+ PayURe,
+ PayPalRe,
+]
+
+method_by_slug = {
+ m.slug: m
+ for m in methods
+}
--- /dev/null
+{% extends "base/base.html" %}
+
+
+{% block titleextra %}Towarzystwo Wolnych Lektur{% endblock %}
+
+
+{% block body %}
+<div class="white-box normal-text">
+
+ <h1>Testowa płatność</h1>
+
+ <p> {{ schedule.email }}</p>
+ <p> {{ schedule.amount }}</p>
+ <p> {{ schedule.plan.get_interval_display }}</p>
+
+<form method="POST" action="">
+ {% csrf_token %}
+ {{ form.as_p }}
+ <button type='submit'>Zapłać</button>
+</form>
+
+</div>
+
+{% endblock %}
--- /dev/null
+{% extends "base/base.html" %}
+{% load active_schedule from club %}
+
+
+{% block titleextra %}Towarzystwo Wolnych Lektur{% endblock %}
+
+
+{% block body %}
+<div class="white-box normal-text">
+
+ <h1>Towarzystwo Wolnych Lektur</h1>
+
+ <p>Towarzystwo jest fajne.</p>
+
+{% with schedule=request.user|active_schedule %}
+{% if schedule %}
+<p><a href="{{ schedule.get_absolute_url }}">Jesteś już w Towarzystwie</a>!</p>
+{% else %}
+<a href="{% url 'club_join' %}">Dołącz do Towarzystwa</a>.
+{% endif %}
+{% endwith %}
+
+
+</div>
+
+{% endblock %}
--- /dev/null
+{% extends "base/base.html" %}
+
+
+{% block titleextra %}Towarzystwo Wolnych Lektur{% endblock %}
+
+
+{% block body %}
+<div class="white-box normal-text">
+
+ <h1>{% if membership %}Odnów swoje członkostwo w Towarzystwie Wolnych Lektur{% else %}Dołącz do Towarzystwa Wolnych Lektur{% endif %}</h1>
+
+<form method="POST" action="">
+ {% csrf_token %}
+
+ {{ form.as_p }}
+ <button type='submit'>Dołącz</button>
+</form>
+
+</div>
+
+{% endblock %}
--- /dev/null
+Czekolada / karta płatnicza
--- /dev/null
+{% extends "base/base.html" %}
+
+
+{% block titleextra %}Towarzystwo Wolnych Lektur{% endblock %}
+
+
+{% block body %}
+<div class="white-box normal-text">
+
+<h1>Plan płatności</h1>
+
+<div>{{ schedule.email }}</div>
+<div>{{ schedule.amount }}</div>
+<div>{{ schedule.plan.get_interval_display }}</div>
+
+<div>{{ schedule.is_active|yesno:"Aktywne,Nieaktywne" }}</div>
+
+<div>Start: {{ schedule.started_at }}</div>
+<div>Opłacone do: {{ schedule.expires_at|default:"brak" }} {% if schedule.is_cancelled %}(anulowana){% endif %}</div>
+
+{% if schedule.expires_at and not schedule.is_cancelled %}
+<form method='post' action="{% url 'club_cancel' schedule.key %}">
+ {% csrf_token %}
+ <button type="submit">Anuluj płatność</button>
+</form>
+{% endif %}
+
+{% if schedule.is_expired %}
+ Płatność wygasła. <a href="{% url 'club_join' %}">Wykonaj nową płatność</a>.
+{% endif %}
+
+{% if schedule.membership %}
+ <p>
+ Członek/członkini Towarzystwa nr {{ schedule.membership.id }} ({{ schedule.membership.user }}).
+ </p>
+{% else %}
+<p>
+Płatność nie przypisana do członkostwa.<br>
+<a href="{% url 'club_claim' schedule.key %}">Przypisz</a>
+</p>
+{% endif %}
+
+
+
+
+
+<a href="">
+
+</div>
+
+{% endblock %}
--- /dev/null
+
+<div style="display:flex">
+{% for _1, optgroup, _2 in widget.optgroups %}
+ {% for option in optgroup %}
+ <div style="display: flex-item;">
+ {% with plan=option.label %}
+ <big>{{ plan.min_amount }} zł</big><br>
+ {{ plan.get_interval_display }}
+
+ {% for pm in plan.payment_methods %}
+ <div>
+ <input id="id_{{ option.value }}_{{ pm.slug }}" type="radio" name="payment_method" value="{{ option.value }}_{{ pm.slug }}">
+ <label for="id_{{ option.value }}_{{ pm.slug }}">
+ {% include pm.template_name %}
+ </label>
+ </div>
+ {% endfor %}
+
+ {% endwith %}
+ </div>
+ {% endfor %}
+{% endfor %}
+</div>
+
+
--- /dev/null
+from django import template
+from ..helpers import get_active_schedule
+
+
+register = template.Library()
+
+
+@register.filter
+def active_schedule(user):
+ return get_active_schedule(user)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+
+from modeltranslation.translator import translator, TranslationOptions
+from .models import ReminderEmail
+
+
+class ReminderEmailTranslationOptions(TranslationOptions):
+ fields = ('subject', 'body')
+
+translator.register(ReminderEmail, ReminderEmailTranslationOptions)
--- /dev/null
+from django.conf.urls import url
+from . import views
+
+
+urlpatterns = [
+ url(r'^$', views.ClubView.as_view()),
+ url(r'^dolacz/$', views.JoinView.as_view(), name='club_join'),
+
+ url(r'^plan/(?P<key>[-a-z0-9]+)/$', views.ScheduleView.as_view(), name='club_schedule'),
+ url(r'^przylacz/(?P<key>[-a-z0-9]+)/$', views.claim, name='club_claim'),
+ url(r'^anuluj/(?P<key>[-a-z0-9]+)/$', views.cancel, name='club_cancel'),
+
+ url(r'^testowa-platnosc/(?P<key>[-a-z0-9]+)/$', views.DummyPaymentView.as_view(), name='club_dummy_payment'),
+]
--- /dev/null
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponseRedirect
+from django.shortcuts import render
+from django.views.generic import FormView, CreateView, TemplateView
+from django.views import View
+from .forms import ScheduleForm
+from . import models
+from .helpers import get_active_schedule
+
+
+class ClubView(TemplateView):
+ template_name = 'club/index.html'
+
+
+class JoinView(CreateView):
+ template_name = 'club/membership_form.html'
+ form_class = ScheduleForm
+
+ def get(self, request):
+ schedule = get_active_schedule(request.user)
+ if schedule is not None:
+ return HttpResponseRedirect(schedule.get_absolute_url())
+ else:
+ return super(JoinView, self).get(request)
+
+ def get_context_data(self):
+ c = super(JoinView, self).get_context_data()
+ c['membership'] = getattr(self.request.user, 'membership', None)
+ return c
+
+ def get_initial(self):
+ if self.request.user.is_authenticated and self.request.user.email:
+ return {
+ 'email': self.request.user.email,
+ }
+
+ def form_valid(self, form):
+ retval = super(JoinView, self).form_valid(form)
+ if self.request.user.is_authenticated:
+ form.instance.membership, created = models.Membership.objects.get_or_create(user=self.request.user)
+ form.instance.save()
+ return retval
+
+
+class ScheduleView(View):
+ def get(self, request, key):
+ schedule = models.Schedule.objects.get(key=key)
+ if not schedule.is_active:
+ return HttpResponseRedirect(schedule.get_payment_method().get_payment_url(schedule))
+ else:
+ return render(
+ request,
+ 'club/schedule.html',
+ {
+ 'schedule': schedule,
+ }
+ )
+
+
+@login_required
+def claim(request, key):
+ schedule = models.Schedule.objects.get(key=key, membership=None)
+ schedule.membership, created = models.Membership.objects.get_or_create(user=request.user)
+ schedule.save()
+ return HttpResponseRedirect(schedule.get_absolute_url())
+
+
+def cancel(request, key):
+ schedule = models.Schedule.objects.get(key=key)
+ schedule.is_cancelled = True
+ schedule.save()
+ return HttpResponseRedirect(schedule.get_absolute_url())
+
+
+class DummyPaymentView(TemplateView):
+ template_name = 'club/dummy_payment.html'
+
+ def get_context_data(self, key):
+ return {
+ 'schedule': models.Schedule.objects.get(key=key),
+ }
+
+ def post(self, request, key):
+ schedule = models.Schedule.objects.get(key=key)
+ schedule.create_payment()
+ return HttpResponseRedirect(schedule.get_absolute_url())
'django_extensions',
'raven.contrib.django.raven_compat',
+ 'club.apps.ClubConfig',
'migdal',
'django_comments',
'django_comments_xtd',
url(r'^isbn/', include('isbn.urls')),
url(r'^paypal/', include('paypal.urls')),
url(r'^powiadomienie/', include('push.urls')),
+ url(r'^towarzystwo/', include('club.urls')),
# Admin panel
url(r'^admin/catalogue/book/import$', catalogue.views.import_book, name='import_book'),