Skip to content
This repository has been archived by the owner on Jan 17, 2020. It is now read-only.

Commit

Permalink
Merge pull request #175 from EuroPython/feature/no-invoice
Browse files Browse the repository at this point in the history
Allow ticket types to conditionally prevent sending the invoice PDF to the buyer
  • Loading branch information
MarkusH committed Jun 11, 2014
2 parents 4475d88 + 880ba64 commit 61773b4
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# -*- coding: 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 'TicketType.prevent_invoice'
db.add_column(u'attendees_tickettype', 'prevent_invoice',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)


def backwards(self, orm):
# Deleting field 'TicketType.prevent_invoice'
db.delete_column(u'attendees_tickettype', 'prevent_invoice')


models = {
u'attendees.purchase': {
'Meta': {'object_name': 'Purchase'},
'city': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'company_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['conference.Conference']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
'country': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'date_added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
'exported': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'invoice_filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'invoice_number': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
'payment_method': ('django.db.models.fields.CharField', [], {'default': "u'invoice'", 'max_length': '20'}),
'payment_total': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'payment_transaction': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'state': ('django.db.models.fields.CharField', [], {'default': "u'incomplete'", 'max_length': '25'}),
'street': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True'}),
'vat_id': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'zip_code': ('django.db.models.fields.CharField', [], {'max_length': '20'})
},
u'attendees.simcardticket': {
'Meta': {'ordering': "(u'ticket_type__tutorial_ticket', u'ticket_type__product_number')", 'object_name': 'SIMCardTicket', '_ormbases': [u'attendees.Ticket']},
'city': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'country': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'date_of_birth': ('django.db.models.fields.DateField', [], {}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
'gender': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
'hotel_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
'phone': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'sim_id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'street': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'ticket_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['attendees.Ticket']", 'unique': 'True', 'primary_key': 'True'}),
'zip_code': ('django.db.models.fields.CharField', [], {'max_length': '20'})
},
u'attendees.supportticket': {
'Meta': {'ordering': "(u'ticket_type__tutorial_ticket', u'ticket_type__product_number')", 'object_name': 'SupportTicket', '_ormbases': [u'attendees.Ticket']},
u'ticket_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['attendees.Ticket']", 'unique': 'True', 'primary_key': 'True'})
},
u'attendees.ticket': {
'Meta': {'ordering': "(u'ticket_type__tutorial_ticket', u'ticket_type__product_number')", 'object_name': 'Ticket'},
'date_added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'purchase': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['attendees.Purchase']"}),
'ticket_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['attendees.TicketType']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'attendees_ticket_tickets'", 'null': 'True', 'to': u"orm['auth.User']"})
},
u'attendees.tickettype': {
'Meta': {'ordering': "(u'tutorial_ticket', u'product_number', u'vouchertype_needed')", 'unique_together': "[(u'product_number', u'conference')]", 'object_name': 'TicketType'},
'allow_editing': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['conference.Conference']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
'date_valid_from': ('django.db.models.fields.DateTimeField', [], {}),
'date_valid_to': ('django.db.models.fields.DateTimeField', [], {}),
'editable_fields': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'editable_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'fee': ('django.db.models.fields.FloatField', [], {'default': '0'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'max_purchases': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'prevent_invoice': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'product_number': ('django.db.models.fields.IntegerField', [], {'blank': 'True'}),
'remarks': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'tutorial_ticket': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'vouchertype_needed': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['attendees.VoucherType']", 'null': 'True', 'blank': 'True'})
},
u'attendees.tshirtsize': {
'Meta': {'ordering': "(u'sort',)", 'object_name': 'TShirtSize'},
'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['conference.Conference']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'size': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'sort': ('django.db.models.fields.IntegerField', [], {'default': '999'})
},
u'attendees.venueticket': {
'Meta': {'ordering': "(u'ticket_type__tutorial_ticket', u'ticket_type__product_number')", 'object_name': 'VenueTicket', '_ormbases': [u'attendees.Ticket']},
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
'organisation': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'shirtsize': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['attendees.TShirtSize']", 'null': 'True', 'blank': 'True'}),
u'ticket_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['attendees.Ticket']", 'unique': 'True', 'primary_key': 'True'}),
'voucher': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['attendees.Voucher']", 'null': 'True', 'blank': 'True'})
},
u'attendees.voucher': {
'Meta': {'object_name': 'Voucher'},
'code': ('django.db.models.fields.CharField', [], {'max_length': '12', 'blank': 'True'}),
'date_valid': ('django.db.models.fields.DateTimeField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_used': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'remarks': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['attendees.VoucherType']", 'null': 'True'})
},
u'attendees.vouchertype': {
'Meta': {'object_name': 'VoucherType'},
'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['conference.Conference']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'conference.conference': {
'Meta': {'object_name': 'Conference'},
'anonymize_proposal_author': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'reviews_active': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'reviews_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'reviews_start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'tickets_editable': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'tickets_editable_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'timezone': ('timezones.fields.TimeZoneField', [], {'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'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'}),
u'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'})
}
}

complete_apps = ['attendees']
19 changes: 18 additions & 1 deletion pyconde/attendees/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ class TicketType(models.Model):
date_valid_from = models.DateTimeField(_('Date (valid from)'), blank=False)
date_valid_to = models.DateTimeField(_('Date (valid to)'), blank=False)

vouchertype_needed = models.ForeignKey('VoucherType', null=True, blank=True, verbose_name=_('voucher type needed'))
vouchertype_needed = models.ForeignKey('VoucherType', null=True, blank=True,
verbose_name=_('voucher type needed'))
tutorial_ticket = models.BooleanField(_('Tutorial ticket'), default=False)

remarks = models.TextField(_('Remarks'), blank=True)
Expand All @@ -148,6 +149,12 @@ class TicketType(models.Model):
editable_fields = models.TextField(_('Editable fields'), blank=True)
editable_until = models.DateTimeField(_('Editable until'), blank=True, null=True)

prevent_invoice = models.BooleanField(_("Conditionally prevent invoice to user"),
default=False, blank=True,
help_text=_('If checked, a purchase, that contains only tickets of '
'ticket types where this is checked, will not be send to '
'the user. This can be useful for e.g. sponsor tickets'))

content_type = models.ForeignKey(
content_models.ContentType, blank=False,
limit_choices_to=limit_ticket_types(),
Expand Down Expand Up @@ -309,6 +316,16 @@ def email_receiver(self):
name = "%s %s" % (self.first_name, self.last_name)
return formataddr((name, self.email))

@property
def send_invoice_to_user(self):
if (
self.payment_total == 0.0 and
self.payment_method == 'invoice' and
self.ticket_set.exclude(ticket_type__prevent_invoice=True).count() == 0
):
return False
return True

def __unicode__(self):
return '%s - %s' % (self.pk, self.get_state_display())

Expand Down
3 changes: 2 additions & 1 deletion pyconde/attendees/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ def render_invoice(purchase_id):
purchase.save(update_fields=['exported', 'state'])

# Send invoice to buyer
send_invoice.delay(purchase_id, (purchase.email_receiver,))
if purchase.send_invoice_to_user:
send_invoice.delay(purchase_id, (purchase.email_receiver,))
# Send invoice to orga
send_invoice.delay(purchase_id, app_settings.INVOICE_EXPORT_RECIPIENTS)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
{% if terms_of_use_url %}{% trans "Purchasing a ticket requires agreeing to the terms of service. These can be found here:" %}
{{ terms_of_use_url }}{% endif %}

{% if purchase.payment_method == 'invoice' %}
{% if purchase.payment_method == 'invoice' and purchase.send_invoice_to_user %}
{% trans "During the next couple of days you will receive an invoice via e-mail." %}
{% trans "You can check your payment status in your profile. The incoming payments are checked at least twice a week." %}
{% trans "If you have any problems with the payment, please contact us ASAP!" %}
Expand Down
Loading

0 comments on commit 61773b4

Please sign in to comment.