Merge payments branch with the default mainline branch.
--- a/.hgignore Thu Nov 18 16:10:38 2010 +0530
+++ b/.hgignore Thu Nov 18 16:16:28 2010 +0530
@@ -39,4 +39,5 @@
project/static/media
project/scipycon/user/*.pyc
apache/*
+*.db
--- a/project/development.py Thu Nov 18 16:10:38 2010 +0530
+++ b/project/development.py Thu Nov 18 16:16:28 2010 +0530
@@ -28,7 +28,7 @@
)
DATABASE_ENGINE = 'sqlite3'
-DATABASE_NAME = 'scipycon.db'
+DATABASE_NAME = 'scipyconpayment.db'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
--- a/project/scipycon/registration/forms.py Thu Nov 18 16:10:38 2010 +0530
+++ b/project/scipycon/registration/forms.py Thu Nov 18 16:16:28 2010 +0530
@@ -4,6 +4,7 @@
from project.scipycon.registration.models import SIZE_CHOICES
from project.scipycon.registration.models import OCCUPATION_CHOICES
from project.scipycon.registration.models import Accommodation
+from project.scipycon.registration.models import Payment
from project.scipycon.registration.models import Wifi
@@ -61,7 +62,7 @@
id = forms.CharField(widget=forms.HiddenInput)
class WifiForm(forms.ModelForm):
- """PyCon wifi form
+ """SciPyCon wifi form
"""
def save(self, user, scope):
@@ -82,7 +83,7 @@
class AccommodationForm(forms.ModelForm):
- """PyCon Accommodation form
+ """SciPyCon Accommodation form
"""
def save(self, user, scope):
@@ -128,6 +129,52 @@
fields = ('accommodation_required', 'sex', 'accommodation_days')
+class PaymentForm(forms.ModelForm):
+ """SciPyCon Payment form
+ """
+
+ paid = forms.BooleanField(
+ required=False, label="Amount paid",
+ help_text="Check this box if you have already paid the fees.")
+
+ def save(self, user, scope):
+ try:
+ payment = Payment.objects.get(user=user, scope=scope)
+ except ObjectDoesNotExist:
+ payment = Payment(user=user, scope=scope)
+
+ paid = self.cleaned_data['paid']
+ type = self.cleaned_data['type']
+ details = self.cleaned_data['details']
+
+ payment.type = type
+ payment.details = details
+
+ payment.save()
+
+ return payment
+
+ def clean(self):
+ """Makes sure that payment form is correct, i.e. type and details
+ are filled in when the required fees is paid.
+ """
+
+ paid = self.cleaned_data['paid']
+ type = self.cleaned_data['type']
+ details = self.cleaned_data['details']
+
+ if paid and (not type or not details):
+ raise forms.ValidationError(
+ u"If you have already paid the fee it is mandatory to "
+ "fill in the type and mandatory fields.")
+
+ return super(PaymentForm, self).clean()
+
+ class Meta:
+ model = Payment
+ fields = ('paid', 'type', 'details')
+
+
PC = (
('all', 'all'),
('paid', 'paid'),
--- a/project/scipycon/registration/models.py Thu Nov 18 16:10:38 2010 +0530
+++ b/project/scipycon/registration/models.py Thu Nov 18 16:16:28 2010 +0530
@@ -30,6 +30,12 @@
('Female', 'Female'),
)
+PAYMENT_MODE_CHOICES = (
+ ('Cheque', 'Cheque'),
+ ('Demand Draft(DD)', 'Demand Draft(DD)'),
+ ('Net Banking', 'Net Banking')
+ )
+
class Wifi(base_models.ScopedBase):
"""Defines wifi options at SciPy.in
@@ -117,4 +123,25 @@
self.registrant.last_name, self.registrant.email)
+class Payment(base_models.ScopedBase):
+ """Defines payment information for SciPy.in registrants
+ """
+ user = models.ForeignKey(User)
+
+ confirmed = models.BooleanField(
+ default=False, blank=True)
+
+ type = models.CharField(max_length=25, choices=PAYMENT_MODE_CHOICES,
+ verbose_name="Type", blank=True, null=True)
+
+ details = models.CharField(
+ max_length=255, verbose_name="Details",
+ help_text="If the payment mode was cheque or DD please provide "
+ "the <font color='red'>cheque or DD number and the name of the bank "
+ "and branch</font>. Example: 4536234, SBI, IIT Powai, Mumbai.<br/> "
+ "If the payment mode was Net Banking please provide the <font "
+ "color='red'>last four digits of the account number and the name "
+ "of the account holder and the bank name</font> from which the "
+ "transfer was made. Example: 8804, Harish Chandra",
+ blank=True, null=True)
--- a/project/scipycon/registration/views.py Thu Nov 18 16:10:38 2010 +0530
+++ b/project/scipycon/registration/views.py Thu Nov 18 16:16:28 2010 +0530
@@ -12,8 +12,10 @@
from project.scipycon.registration.forms import RegistrationEditForm
from project.scipycon.registration.forms import RegistrationSubmitForm
from project.scipycon.registration.forms import AccommodationForm
+from project.scipycon.registration.forms import PaymentForm
from project.scipycon.registration.forms import WifiForm
from project.scipycon.registration.models import Accommodation
+from project.scipycon.registration.models import Payment
from project.scipycon.registration.models import Registration
from project.scipycon.registration.models import Wifi
from project.scipycon.registration.utils import send_confirmation
@@ -59,11 +61,13 @@
reg = Registration.objects.get(pk=int(id))
wifi = Wifi.objects.get(user=reg.registrant)
- # TODO: This is an ugly hack to add accommodation form
- # details at later stage for SciPy.in 2010. This must be
- # removed for SciPy.in 2011
- acco, created = Accommodation.objects.get_or_create(user=reg.registrant,
- scope=scope_entity)
+ # TODO: This is an ugly hack to add accommodation and payment forms
+ # details at later stage for SciPy.in 2010. This must be removed for
+ # SciPy.in 2011
+ acco, acco_created = Accommodation.objects.get_or_create(
+ user=reg.registrant, scope=scope_entity)
+ payment, payment_created = Payment.objects.get_or_create(
+ user=reg.registrant, scope=scope_entity)
if reg.registrant != request.user:
redirect_to = reverse('scipycon_account', kwargs={'scope': scope})
@@ -77,9 +81,10 @@
registration_form = RegistrationEditForm(data=request.POST)
wifi_form = WifiForm(data=request.POST)
acco_form = AccommodationForm(data=request.POST)
+ payment_form = PaymentForm(data=request.POST)
if (registration_form.is_valid() and wifi_form.is_valid() and
- acco_form.is_valid()):
+ acco_form.is_valid() and payment_form.is_valid()):
reg.organisation = registration_form.data.get('organisation')
reg.occupation = registration_form.data.get('occupation')
reg.city = registration_form.data.get('city')
@@ -98,6 +103,7 @@
wifi = wifi_form.save(reg.registrant, reg.scope)
acco = acco_form.save(reg.registrant, reg.scope)
+ payment = payment_form.save(reg.registrant, reg.scope)
# Saved.. redirect
redirect_to = reverse('scipycon_account', kwargs={'scope': scope})
@@ -131,6 +137,13 @@
'accommodation_required': acco.accommodation_required,
'accommodation_days': acco.accommodation_days,
})
+ payment_form = PaymentForm(initial={
+ 'user': payment.user,
+ 'scope': payment.scope,
+ 'paid': payment.type or payment.details,
+ 'type': payment.type,
+ 'details': payment.details,
+ })
return render_to_response(
template_name, RequestContext(request, {
@@ -138,7 +151,8 @@
'registration': {'id': id},
'registration_form': registration_form,
'wifi_form': wifi_form,
- 'acco_form': acco_form}))
+ 'acco_form': acco_form,
+ 'payment_form': payment_form}))
def submit_registration(request, scope,
template_name='registration/submit-registration.html'):
@@ -176,6 +190,7 @@
registrant_form = RegistrantForm(data=request.POST)
wifi_form = WifiForm(data=request.POST)
acco_form = AccommodationForm(data=request.POST)
+ payment_form = PaymentForm(data=request.POST)
if request.POST.get('action', None) == 'login':
login_form = AuthenticationForm(data=request.POST)
@@ -211,7 +226,7 @@
newuser = user
if (registration_form.is_valid() and newuser and wifi_form.is_valid()
- and acco_form.is_valid()):
+ and acco_form.is_valid() and payment_form.is_valid()):
allow_contact = registration_form.cleaned_data.get(
'allow_contact') and True or False
conference = registration_form.cleaned_data.get(
@@ -247,7 +262,10 @@
wifi = wifi_form.save(registrant, scope_entity)
acco = acco_form.save(registrant, scope_entity)
+ payment = payment_form.save(registrant, scope_entity)
+
send_confirmation(registrant, scope_entity, password=passwd)
+
redirect_to = reverse('scipycon_registrations',
kwargs={'scope': scope})
return set_message_cookie(redirect_to,
@@ -259,6 +277,7 @@
registrant_form = RegistrantForm()
wifi_form = WifiForm()
acco_form = AccommodationForm()
+ payment_form = PaymentForm()
login_form = AuthenticationForm()
@@ -269,6 +288,7 @@
'registrant_form' : registrant_form,
'over_reg' : reg_count >= REG_TOTAL and True or False,
'acco_form': acco_form,
+ 'payment_form': payment_form,
'wifi_form' : wifi_form,
'message' : message,
'login_form' : login_form
@@ -283,7 +303,9 @@
if not request.user.is_staff:
redirect_to = reverse('scipycon_login', kwargs={'scope': scope})
-
+ return set_message_cookie(
+ redirect_to, msg = u'You must be a staff on this website to '
+ 'access this page.')
q = Registration.objects.all()
conf_num = q.filter(conference=True).count()
@@ -296,3 +318,56 @@
'tut_num': tut_num,
'sprint_num': sprint_num,
}))
+
+
+@login_required
+def manage_payments(request, scope,
+ template_name='registration/manage_payments.html'):
+ """View that gives a form to manage payments.
+ """
+
+ if not request.user.is_superuser:
+ redirect_to = reverse('scipycon_login', kwargs={'scope': scope})
+ return set_message_cookie(
+ redirect_to, msg = u'You must be an admin on this website to '
+ 'access this page.')
+
+ message = None
+
+ scope_entity = Event.objects.get(scope=scope)
+
+ if request.method == 'POST':
+ post_data = request.POST
+ list_user_ids = []
+ for user_id_string in post_data:
+ id_str_list = user_id_string.split('_')
+ if (len(id_str_list) == 3 and id_str_list[0] == 'registrant' and
+ id_str_list[1] == 'id'):
+ id = int(id_str_list[2])
+ reg_user = User.objects.get(pk=id)
+
+ payment, created = reg_user.payment_set.get_or_create(
+ user=reg_user, scope=scope_entity)
+
+ payment.confirmed = True
+ payment.save()
+
+ list_user_ids.append(id)
+
+ # This is done to unset for the confirmation for users for whom
+ # mistakenly confirmation was set.
+ # (TODO) This is a very expensive operation, any better solution
+ # will be appreciated.
+ unpaid_users = User.objects.exclude(pk__in=list_user_ids)
+ for user in unpaid_users:
+ payment, created = user.payment_set.get_or_create(
+ user=user, scope=scope_entity)
+ payment.confirmed = False
+ payment.save()
+
+ registrants = Registration.objects.all()
+
+ return render_to_response(template_name, RequestContext(request,
+ {'params': {'scope': scope},
+ 'registrants': registrants,
+ }))
--- a/project/static/css/styles.css Thu Nov 18 16:10:38 2010 +0530
+++ b/project/static/css/styles.css Thu Nov 18 16:16:28 2010 +0530
@@ -583,4 +583,9 @@
color: #58585a;
margin-left: 5em;
text-align: justify;
+}
+
+label.alert {
+ font-size: 1.2em;
+ color: #ff0000;
}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project/templates/registration/manage_payments.html Thu Nov 18 16:16:28 2010 +0530
@@ -0,0 +1,47 @@
+{% extends "base.html" %}
+
+{% block title %}Manage Payments - {% endblock %}
+
+{% block content %}
+<h1>Manage Payments</h1>
+
+<form action="" method="post">
+
+ <fieldset>
+ <legend>Payment Details</legend>
+ <table class="scipycon-default">
+ {% for registrant in registrants %}
+ <tr class="{% cycle odd,even %}">
+ <th>
+ <label
+ {% if registrant.registrant.payment_set.get.type or registrant.registrant.payment_set.get.details %}
+ {% if not registrant.registrant.payment_set.get.confirmed %}
+ class="alert"
+ {% endif %}
+ {% endif %}
+ for="id_{{ registrant.registrant.id }}_label">
+ {{ registrant.registrant.get_full_name }}
+ </label>
+ </th>
+ <td>
+ {{ field.errors }}
+ <input id="user_id_{{ registrant.registrant.id }}"
+ name="registrant_id_{{ registrant.registrant.id }}"
+ type="checkbox" name="paid"
+ {% if registrant.registrant.payment_set.get.confirmed %}
+ checked=checked
+ {% endif %}
+ /><br />
+ </td>
+ </tr>
+ {% endfor %}
+ <tr>
+ <th>
+ <button class="button left" type="submit">Submit Payment Status</button>
+ </th>
+ </tr>
+ </table>
+ </fieldset>
+
+</form>
+{% endblock content %}
--- a/project/templates/registration/regstats.html Thu Nov 18 16:10:38 2010 +0530
+++ b/project/templates/registration/regstats.html Thu Nov 18 16:16:28 2010 +0530
@@ -1,6 +1,6 @@
{% extends "base.html" %}
-{% block title %}Registration Statistics{% endblock %}
+{% block title %}Registration Statistics - {% endblock %}
{% block content %}
<h1>Registration Statistics</h1>
--- a/project/templates/registration/submit-registration.html Thu Nov 18 16:10:38 2010 +0530
+++ b/project/templates/registration/submit-registration.html Thu Nov 18 16:16:28 2010 +0530
@@ -19,6 +19,20 @@
$('#id_sex').removeAttr('disabled');
}
});
+
+ if (!$('#id_paid').is(':checked')) {
+ $('#id_type').attr('disabled', 'disabled');
+ $('#id_details').attr('disabled', 'disabled');
+ }
+ $('#id_paid').change(function() {
+ if (!$('#id_paid').is(':checked')) {
+ $('#id_type').attr('disabled', 'disabled');
+ $('#id_details').attr('disabled', 'disabled');
+ } else {
+ $('#id_type').removeAttr('disabled');
+ $('#id_details').removeAttr('disabled');
+ }
+ });
});
@@ -147,6 +161,13 @@
</fieldset>
<fieldset>
+ <legend>Payment</legend>
+ <table class="scipycon-default">
+ {{ payment_form }}
+ </table>
+ </fieldset>
+
+ <fieldset>
<legend>Others</legend>
<table class="scipycon-default">
{{ wifi_form }}
--- a/project/urls.py Thu Nov 18 16:10:38 2010 +0530
+++ b/project/urls.py Thu Nov 18 16:16:28 2010 +0530
@@ -51,8 +51,10 @@
'submit_registration', name='scipycon_submit_registration'),
url(r'^%s/edit-registration/(?P<id>\d+)/$' % (SCOPE_ARG_PATTERN),
'edit_registration', name='scipycon_edit_registration'),
- url(r'^%s/regstats/'% (SCOPE_ARG_PATTERN),
+ url(r'^%s/regstats/$'% (SCOPE_ARG_PATTERN),
'regstats', name="scipycon_regstats"),
+ url(r'^%s/manage_payments/$'% (SCOPE_ARG_PATTERN),
+ 'manage_payments', name="scipycon_manage_payments"),
)
# Authentication and Profile