+from decimal import Decimal
from django import forms
from . import models
-from .payment_methods import method_by_slug
+from .payment_methods import method_by_slug, methods
from .payu.forms import CardTokenForm
def __init__(self, *args, request=None, **kwargs):
super(ScheduleForm, self).__init__(*args, **kwargs)
self.request = request
- self.fields['plan'].empty_label = None
+ self.plans = models.Plan.objects.all()
+ self.payment_methods = methods
+ self.fields['amount'].required = False
def clean(self):
cleaned_data = super(ScheduleForm, self).clean()
+
+ if 'plan' in cleaned_data:
+ cleaned_data['amount'] = self.fields['amount'].clean(
+ self.request.POST['amount-{}'.format(cleaned_data['plan'].id)]
+ )
+
+ 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
+ )
+
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)
+ self.add_error('method', 'Wybrana metoda płatności nie jest dostępna dla tego planu.')
+
class PayUCardTokenForm(CardTokenForm):
--- /dev/null
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-05-10 13:10
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('club', '0008_membership_name'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='plan',
+ name='default_amount',
+ field=models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='default amount'),
+ preserve_default=False,
+ ),
+ migrations.AlterField(
+ model_name='plan',
+ name='min_amount',
+ field=models.DecimalField(decimal_places=2, max_digits=10, verbose_name='min amount'),
+ ),
+ migrations.AlterField(
+ model_name='schedule',
+ name='method',
+ field=models.CharField(choices=[('payu', 'PayU'), ('payu-re', 'PayU Recurring'), ('paypal', 'PayPal')], max_length=255, verbose_name='method'),
+ ),
+ ]
]
interval = models.SmallIntegerField(_('inteval'), choices=intervals)
- min_amount = models.DecimalField(_('min_amount'), max_digits=10, decimal_places=2)
+ min_amount = models.DecimalField(_('min amount'), max_digits=10, decimal_places=2)
+ default_amount = models.DecimalField(_('default amount'), max_digits=10, decimal_places=2)
allow_recurring = models.BooleanField(_('allow recurring'))
allow_one_time = models.BooleanField(_('allow one time'))
active = models.BooleanField(_('active'), default=True)
class PaymentMethod(object):
+ is_onetime = False
is_recurring = False
def initiate(self, request, schedule):
class PayU(PaymentMethod):
+ is_onetime = True
slug = 'payu'
name = 'PayU'
template_name = 'club/payment/payu.html'
return order.put()
-class PayPalRe(PaymentMethod):
- slug='paypal-re'
- name = 'PayPal Recurring'
- template_name = 'club/payment/paypal-re.html'
+class PayPal(PaymentMethod):
+ slug='paypal'
+ name = 'PayPal'
+ template_name = 'club/payment/paypal.html'
is_recurring = True
+ is_onetime = True
def initiate(self, request, schedule):
return reverse('club_dummy_payment', args=[schedule.key])
payure_method = None
-methods.append(PayPalRe())
+methods.append(PayPal())
method_by_slug = {
--- /dev/null
+$(function() {
+
+ function update_methods() {
+ $("#payment-form .payment-method").addClass("disabled");
+ $("#payment-form .payment-method input").prop("disabled", true);
+ var plan = $("#payment-form .plan:checked");
+ if (plan.length) {
+ $.each(
+ $("#payment-form .plan:checked").attr('data-methods').trim().split(" "),
+ function(i, slug) {
+ $("#payment-method-" + slug).removeClass("disabled");
+ $("#payment-method-" + slug + " input").prop("disabled", false);
+ }
+ );
+ }
+ }
+ update_methods();
+ $("#payment-form .plan").change(update_methods);
+
+});
{% block body %}
+
+<style>
+ .payment-method.disabled {
+ opacity: .5;
+ filter: grayscale(100%);
+ }
+
+ </style>
+
+
<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="">
+<form method="POST" action="" id="payment-form" class="wlform">
{% csrf_token %}
- {{ form.as_p }}
- <button type='submit'>Dołącz</button>
+ <h2>Składka</h2>
+
+ <ul class="errorlist">
+ {% for e in form.non_field_errors %}
+ <li>{{ e }}</li>
+ {% endfor %}
+ {% for e in form.plan.errors %}
+ <li>{{ e }}</li>
+ {% endfor %}
+ {% for e in form.amount.errors %}
+ <li>{{ e }}</li>
+ {% endfor %}
+ </ul>
+
+ {% for plan in form.plans %}
+
+ <div>
+ <input class="plan" type="radio" name="plan" value="{{ plan.id }}" id="plan{{ plan.id }}" data-methods="{% for m in plan.payment_methods %}{{ m.slug }} {% endfor %}">
+ <label for="plan{{ plan.id }}">
+ <input
+ name="amount-{{ plan.id }}"
+ type="number"
+ placeholder="min. {{ plan.min_amount|floatformat:0 }}"
+ value="{{ plan.default_amount|floatformat:0 }}"
+ min="{{ plan.min_amount|floatformat:0 }}"
+ step="1"
+ style="width: 5em;"
+ > zł
+ {{ plan.get_interval_display }}
+ </label>
+ </div>
+
+ {% endfor %}
+
+ <h2>Metoda płatności</h2>
+
+ <ul class="errorlist">
+ {% for e in form.method.errors %}
+ <li>{{ e }}</li>
+ {% endfor %}
+ </ul>
+
+ {% for payment_method in form.payment_methods %}
+ <div class="payment-method" id="payment-method-{{ payment_method.slug }}">
+ <input type="radio" id="method{{ payment_method.slug }}" name="method" value="{{ payment_method.slug }}">
+ <label for="method{{ payment_method.slug }}" style="display:inline-block">
+ {% include payment_method.template_name %}
+ </label>
+ </div>
+ {% endfor %}
+
+ <p style="margin-top: 2em;">
+ {{ form.email.label }}:
+ {{ form.email }}</p>
+ <button class="submit" type='submit'>Dołącz</button>
</form>
</div>
--- /dev/null
+{% load staticfiles %}
+<img src="{% static 'club/paypal.png' %}">
+
-Kartą
+{% load staticfiles %}
+<img src="{% static 'club/payu/payu.png' %}" height="50">
+<span class="method">karta</span>
+<span class="method">⟳ płatność cykliczna</span>
+
-Czekolada / karta płatnicza
+{% load staticfiles %}
+<img src="{% static 'club/payu/payu.png' %}" height="50">
+<img src="{% static 'club/payu/blik.png' %}" height="50">
+<span class="method">karta</span>
+<span class="method">przelew</span>
kwargs['request'] = self.request
return kwargs
- def get_context_data(self, form=None):
- c = super(JoinView, self).get_context_data()
+ def get_context_data(self, **kwargs):
+ c = super(JoinView, self).get_context_data(**kwargs)
c['membership'] = getattr(self.request.user, 'membership', None)
+ #if hasattr(form, 'errors'):
+ # print(form.errors)
return c
def get_initial(self):
'player/openplayer.js',
'js/search.js',
'funding/funding.js',
+ 'club/form.js',
'js/annoy.js',
),
padding-left: 0;
}
}
+
+.wlform {
+ .errorlist {
+ color: red;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ h2 {
+ margin-top: 1.5em;
+ }
+
+ input[type=number] {
+ height: 1.3em;
+ }
+ input[type=radio] {
+ margin-right: 1em;
+ }
+
+ .submit {
+ background: #018189;
+ color: white;
+ border: 0;
+ border-radius: 10px;
+ padding: 1em 2em;
+ font-size: 1.2em;
+ }
+}
+
+.wlform {
+ .payment-method {
+ input {
+ height: 50px;
+ vertical-align: middle;
+ }
+
+ img {
+ vertical-align: middle;
+ margin-right: 1em;
+ }
+ label {
+ margin: .5em 0;
+ vertical-align: middle;
+ }
+
+
+ .method {
+ // border: 1px solid black;
+ border-radius: 10px;
+ line-height: 48px;
+ display: inline-block;
+ vertical-align: middle;
+ padding: 0 1em;
+ margin-right: 1em;
+ font-size: 1.25em;
+ background: #01818980;
+ color: white;
+ }
+ }
+}