diff options
author | Madhusudan.C.S | 2010-11-18 19:27:11 +0530 |
---|---|---|
committer | Madhusudan.C.S | 2010-11-18 19:27:11 +0530 |
commit | 0e962f94a1c714f91b18dd3273859c1074bdcb87 (patch) | |
tree | 35b4b3f5ac2359ee1440f95549df26ecba949442 | |
parent | 1e2a6b85b2f7bd9e391c4b700fbf5b62cb93e13f (diff) | |
parent | d13f1fcfbab51eda8840bc9435308f7cdf49e7e7 (diff) | |
download | scipycon-0e962f94a1c714f91b18dd3273859c1074bdcb87.tar.gz scipycon-0e962f94a1c714f91b18dd3273859c1074bdcb87.tar.bz2 scipycon-0e962f94a1c714f91b18dd3273859c1074bdcb87.zip |
Make default the active branch.
-rw-r--r-- | .hgignore | 1 | ||||
-rw-r--r-- | buildout.cfg | 7 | ||||
-rw-r--r-- | project/development.py | 2 | ||||
-rw-r--r-- | project/production.py | 1 | ||||
-rw-r--r-- | project/scipycon/registration/forms.py | 54 | ||||
-rw-r--r-- | project/scipycon/registration/migrations/0001_initial.py | 153 | ||||
-rw-r--r-- | project/scipycon/registration/migrations/0002_auto__add_field_wifi_registration_id.py | 107 | ||||
-rw-r--r-- | project/scipycon/registration/migrations/__init__.py | 0 | ||||
-rw-r--r-- | project/scipycon/registration/models.py | 39 | ||||
-rw-r--r-- | project/scipycon/registration/views.py | 96 | ||||
-rw-r--r-- | project/static/css/styles.css | 5 | ||||
-rw-r--r-- | project/templates/notifications/regpaymentaccolaptop2010.html | 71 | ||||
-rw-r--r-- | project/templates/registration/manage_payments.html | 47 | ||||
-rw-r--r-- | project/templates/registration/regstats.html | 2 | ||||
-rw-r--r-- | project/templates/registration/submit-registration.html | 21 | ||||
-rw-r--r-- | project/urls.py | 4 | ||||
-rw-r--r-- | scripts/mails.py | 17 |
17 files changed, 600 insertions, 27 deletions
@@ -39,4 +39,5 @@ project/media/user/* project/static/media project/scipycon/user/*.pyc apache/* +*.db diff --git a/buildout.cfg b/buildout.cfg index cc20536..056215a 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -1,5 +1,5 @@ [buildout] -parts = django tagging django-robots +parts = django tagging django-robots south eggs = Werkzeug PIL @@ -13,6 +13,7 @@ eggs = ${buildout:eggs} pythonpath = ${tagging:location} ${django-robots:location} + ${south:location} [tagging] recipe = infrae.subversion @@ -21,3 +22,7 @@ urls = http://django-tagging.googlecode.com/svn/trunk/ . [django-robots] recipe = mercurialrecipe repository = http://bitbucket.org/jezdez/django-robots/ + +[south] +recipe = mercurialrecipe +repository = http://bitbucket.org/andrewgodwin/south/ diff --git a/project/development.py b/project/development.py index df95ac1..eb8a205 100644 --- a/project/development.py +++ b/project/development.py @@ -24,6 +24,7 @@ INSTALLED_APPS = ( 'project.scipycon.talk', 'tagging', 'robots', + 'south', ) DATABASE_ENGINE = 'sqlite3' @@ -35,4 +36,3 @@ EMAIL_HOST = 'localhost' EMAIL_PORT = '1025' # print to standard output: # python -m smtpd -n -c DebuggingServer localhost:1025 - diff --git a/project/production.py b/project/production.py index c7b55c7..83a1cec 100644 --- a/project/production.py +++ b/project/production.py @@ -23,6 +23,7 @@ INSTALLED_APPS = ( 'project.scipycon.user', 'tagging', 'robots', + 'south', ) DATABASE_ENGINE = 'mysql' diff --git a/project/scipycon/registration/forms.py b/project/scipycon/registration/forms.py index a646399..e3cc464 100644 --- a/project/scipycon/registration/forms.py +++ b/project/scipycon/registration/forms.py @@ -4,6 +4,7 @@ from django.core.exceptions import ObjectDoesNotExist 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 @@ class RegistrationEditForm(RegistrationSubmitForm): id = forms.CharField(widget=forms.HiddenInput) class WifiForm(forms.ModelForm): - """PyCon wifi form + """SciPyCon wifi form """ def save(self, user, scope): @@ -71,17 +72,18 @@ class WifiForm(forms.ModelForm): wifi = Wifi(user=user, scope=scope) wifi.wifi = self.cleaned_data['wifi'] + wifi.registration_id = self.cleaned_data['registration_id'] wifi.save() return wifi class Meta: model = Wifi - fields = ('wifi',) + fields = ('wifi', 'registration_id') class AccommodationForm(forms.ModelForm): - """PyCon Accommodation form + """SciPyCon Accommodation form """ def save(self, user, scope): @@ -127,6 +129,52 @@ class AccommodationForm(forms.ModelForm): 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'), diff --git a/project/scipycon/registration/migrations/0001_initial.py b/project/scipycon/registration/migrations/0001_initial.py new file mode 100644 index 0000000..7cbd77e --- /dev/null +++ b/project/scipycon/registration/migrations/0001_initial.py @@ -0,0 +1,153 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Wifi' + db.create_table('registration_wifi', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('scope', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['base.Event'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('wifi', self.gf('django.db.models.fields.CharField')(max_length=50)), + )) + db.send_create_signal('registration', ['Wifi']) + + # Adding model 'Accommodation' + db.create_table('registration_accommodation', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('scope', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['base.Event'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('sex', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True)), + ('accommodation_required', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('accommodation_days', self.gf('django.db.models.fields.IntegerField')(default=0, blank=True)), + )) + db.send_create_signal('registration', ['Accommodation']) + + # Adding model 'Registration' + db.create_table('registration_registration', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('scope', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['base.Event'])), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)), + ('registrant', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('organisation', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('occupation', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('city', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('postcode', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('phone_num', self.gf('django.db.models.fields.CharField')(max_length=14, blank=True)), + ('tshirt', self.gf('django.db.models.fields.CharField')(max_length=3)), + ('conference', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('tutorial', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('sprint', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('final_conference', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('final_tutorial', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('final_sprint', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('allow_contact', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('submitted', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('last_mod', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + )) + db.send_create_signal('registration', ['Registration']) + + + def backwards(self, orm): + + # Deleting model 'Wifi' + db.delete_table('registration_wifi') + + # Deleting model 'Accommodation' + db.delete_table('registration_accommodation') + + # Deleting model 'Registration' + db.delete_table('registration_registration') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'base.event': { + 'Meta': {'object_name': 'Event'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'scope': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'turn': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'registration.accommodation': { + 'Meta': {'object_name': 'Accommodation'}, + 'accommodation_days': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'accommodation_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'scope': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['base.Event']"}), + 'sex': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'registration.registration': { + 'Meta': {'object_name': 'Registration'}, + 'allow_contact': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'conference': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'final_conference': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'final_sprint': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'final_tutorial': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_mod': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'organisation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'phone_num': ('django.db.models.fields.CharField', [], {'max_length': '14', 'blank': 'True'}), + 'postcode': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'registrant': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'scope': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['base.Event']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'sprint': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'tshirt': ('django.db.models.fields.CharField', [], {'max_length': '3'}), + 'tutorial': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'registration.wifi': { + 'Meta': {'object_name': 'Wifi'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'scope': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['base.Event']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'wifi': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + } + } + + complete_apps = ['registration'] diff --git a/project/scipycon/registration/migrations/0002_auto__add_field_wifi_registration_id.py b/project/scipycon/registration/migrations/0002_auto__add_field_wifi_registration_id.py new file mode 100644 index 0000000..b172c40 --- /dev/null +++ b/project/scipycon/registration/migrations/0002_auto__add_field_wifi_registration_id.py @@ -0,0 +1,107 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'Wifi.registration_id' + db.add_column('registration_wifi', 'registration_id', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'Wifi.registration_id' + db.delete_column('registration_wifi', 'registration_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'base.event': { + 'Meta': {'object_name': 'Event'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'scope': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'turn': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'registration.accommodation': { + 'Meta': {'object_name': 'Accommodation'}, + 'accommodation_days': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}), + 'accommodation_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'scope': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['base.Event']"}), + 'sex': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'registration.registration': { + 'Meta': {'object_name': 'Registration'}, + 'allow_contact': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'conference': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'final_conference': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'final_sprint': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'final_tutorial': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_mod': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'organisation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'phone_num': ('django.db.models.fields.CharField', [], {'max_length': '14', 'blank': 'True'}), + 'postcode': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'registrant': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'scope': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['base.Event']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'sprint': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'tshirt': ('django.db.models.fields.CharField', [], {'max_length': '3'}), + 'tutorial': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'registration.wifi': { + 'Meta': {'object_name': 'Wifi'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'registration_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'scope': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['base.Event']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'wifi': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + } + } + + complete_apps = ['registration'] diff --git a/project/scipycon/registration/migrations/__init__.py b/project/scipycon/registration/migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/project/scipycon/registration/migrations/__init__.py diff --git a/project/scipycon/registration/models.py b/project/scipycon/registration/models.py index b1e216d..d0f104c 100644 --- a/project/scipycon/registration/models.py +++ b/project/scipycon/registration/models.py @@ -30,6 +30,13 @@ SEX_CHOICES = ( ('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 """ @@ -39,6 +46,17 @@ class Wifi(base_models.ScopedBase): wifi = models.CharField(max_length=50, choices=WIFI_CHOICES, help_text=WIFI_HELP, verbose_name="Laptop") + registration_id = models.CharField( + max_length=255, verbose_name="Identification Number", + help_text="- Provide the serial or identification number at the " + "back of your laptop using which your laptop can be uniquely " + "identified. Ex: 8BDB8FB (Service Tag on Dell Laptops).<br /> - " + "This is for security reasons and will be used while you enter and " + "leave the venue.<br /> - Please don't provide the model number " + "like Dell Inspiron 1545. There may be many laptops of that model " + "and hence your laptop cannot be uniquely identified.", + blank=True, null=True) + class Accommodation(base_models.ScopedBase): """Defines accommodation information for SciPy.in @@ -105,4 +123,25 @@ class Registration(base_models.ScopedBase): 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) diff --git a/project/scipycon/registration/views.py b/project/scipycon/registration/views.py index ee7b5ff..43d19ff 100644 --- a/project/scipycon/registration/views.py +++ b/project/scipycon/registration/views.py @@ -12,8 +12,10 @@ from project.scipycon.base.models import Event 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 @@ def edit_registration(request, scope, id, 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 @@ def edit_registration(request, scope, id, 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 @@ def edit_registration(request, scope, id, 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}) @@ -121,7 +127,8 @@ def edit_registration(request, scope, id, wifi_form = WifiForm(initial={ 'user': wifi.user, 'scope': wifi.scope, - 'wifi': wifi.wifi + 'wifi': wifi.wifi, + 'registration_id': wifi.registration_id }) acco_form = AccommodationForm(initial={ 'user': acco.user, @@ -130,6 +137,13 @@ def edit_registration(request, scope, id, '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, { @@ -137,7 +151,8 @@ def edit_registration(request, scope, id, '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'): @@ -175,6 +190,7 @@ def submit_registration(request, scope, 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) @@ -210,7 +226,7 @@ def submit_registration(request, scope, 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( @@ -246,7 +262,10 @@ def submit_registration(request, scope, 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, @@ -258,6 +277,7 @@ def submit_registration(request, scope, registrant_form = RegistrantForm() wifi_form = WifiForm() acco_form = AccommodationForm() + payment_form = PaymentForm() login_form = AuthenticationForm() @@ -268,6 +288,7 @@ def submit_registration(request, scope, '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 @@ -282,7 +303,9 @@ def regstats(request, scope, 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() @@ -295,3 +318,56 @@ def regstats(request, scope, '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, + })) diff --git a/project/static/css/styles.css b/project/static/css/styles.css index 4127bd0..aef48ba 100644 --- a/project/static/css/styles.css +++ b/project/static/css/styles.css @@ -583,4 +583,9 @@ ol li { color: #58585a; margin-left: 5em; text-align: justify; +} + +label.alert { + font-size: 1.2em; + color: #ff0000; }
\ No newline at end of file diff --git a/project/templates/notifications/regpaymentaccolaptop2010.html b/project/templates/notifications/regpaymentaccolaptop2010.html new file mode 100644 index 0000000..b2dde17 --- /dev/null +++ b/project/templates/notifications/regpaymentaccolaptop2010.html @@ -0,0 +1,71 @@ +Hello {{ name }}, + +The SciPy.in team is glad that you have registered for SciPy.in 2010, +to be held at International Institute of Information Technology, +Hyderabad. + +We would like to inform you that we have updated the information about +registration and accommodation fees and payment methods for the same, +on the website. Please find these details at +http://scipy.in/scipyin/2010/about/fees/ + +Due to some requests, we have decided to provide accommodation to a +limited number of out-station participants on a first-come-first-serve +basis. So, if you are an out-station participant and require +accommodation, please fill in your details and send us your fees as +early as possible. + +Your registration for the conference is not confirmed until you pay the +registration fees. If you requested for accommodation, your +accommodation can be confirmed only after we receive your accommodation +fees, based on the availability. It is not confirmed, until you receive +a confirmation mail from our side. + +Also, if you are bringing your own laptop for the conference, please +update the details of the same, in the registration form. + +To update all or any of the information indicated above, follow the +steps below: + +1. Login to your account on http://scipy.in. If you are unable to login + to your account through which you previously registered please + contact admin@scipy.in. We request you not to duplicate the + registrations. + +2. Click on "Registration" link on the left sidebar which takes you to + your registration summary page. + +3. Click on the "Edit Registration" link on that page which takes you + to your original registration form you submitted. + +4. Now you can see two new sections titled "Accommodation" and + "Payment" below the "Demographics" section. + +5. Please check the box if you need accommodation and select your + gender and number of days for which you need the accommodation. + +6. If you have already made the payment as instructed in the Fees page, + please check the "Paid" field and provide additional information + about your payment as mentioned on the registration page. Once + the payment is received you will receive a confirmation email from + the organizers. + +7. In the laptop section you will see a new field called + "Identification Number". If you are getting your own laptop select + "Yes" in the laptop dropdown field and provide us with the Serial + Number/Service Tag Number/Express Service Code of your laptop + using which your laptop can be uniquely identified. This is usually + present at the back of the laptop. Please DONOT give us the Laptop + make and model number such as "Dell Inspiron 1545". + + For example, the unique number for Dell laptops may be service tag + number like "8FRT7RDE" + +8. Submit the registration form to update the details. + +The registration and accommodation fees have to be paid as soon as +possible for us to confirm your registration for the conference. Please +note that there is a limit for the number of registrations. So Hurry! + +Thanks and regards, +Scipy Team diff --git a/project/templates/registration/manage_payments.html b/project/templates/registration/manage_payments.html new file mode 100644 index 0000000..472b53b --- /dev/null +++ b/project/templates/registration/manage_payments.html @@ -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 %} diff --git a/project/templates/registration/regstats.html b/project/templates/registration/regstats.html index e1a0736..f73a36f 100644 --- a/project/templates/registration/regstats.html +++ b/project/templates/registration/regstats.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block title %}Registration Statistics{% endblock %} +{% block title %}Registration Statistics - {% endblock %} {% block content %} <h1>Registration Statistics</h1> diff --git a/project/templates/registration/submit-registration.html b/project/templates/registration/submit-registration.html index 1124cd3..7c238b0 100644 --- a/project/templates/registration/submit-registration.html +++ b/project/templates/registration/submit-registration.html @@ -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 }} diff --git a/project/urls.py b/project/urls.py index d955f87..9d1530e 100644 --- a/project/urls.py +++ b/project/urls.py @@ -51,8 +51,10 @@ urlpatterns += patterns('project.scipycon.registration.views', '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 diff --git a/scripts/mails.py b/scripts/mails.py index 84e2f04..448ed26 100644 --- a/scripts/mails.py +++ b/scripts/mails.py @@ -53,22 +53,19 @@ def speaker_sponsorship(): from_email='admin@scipy.in') -def delegate_remainder(): - """Sends a mail to each speaker whose talk has been accepted - informing them about the their sponsorship. +def delegate_remainder(template=None): + """Sends a mail to each delegate about the template content specified. """ - regs = User.objects.all() - - template = 'notifications/reminder_mail.html' + regs = Registration.objects.all() for reg in regs: - subject = 'SciPy.in 2009: Remainder and details' + subject = 'SciPy.in 2010: Registration updates required for confirmation' message = loader.render_to_string( - template, dictionary={'name': reg.username}) + template, dictionary={'name': reg.registrant.get_full_name()}) - reg.email_user(subject=subject, message=message, - from_email='madhusudancs@gmail.com') + reg.registrant.email_user(subject=subject, message=message, + from_email='info@scipy.in') def delegate_about_event(): |