815 lines
28 KiB
Python
815 lines
28 KiB
Python
from collections import namedtuple
|
|
from datetime import timedelta
|
|
from decimal import Decimal
|
|
from django.conf import settings
|
|
from django.contrib.auth.models import Group
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.core.management.base import BaseCommand
|
|
|
|
from registrasion.models import inventory as inv
|
|
from registrasion.models import conditions as cond
|
|
from symposion import proposals
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Populates the tickets and product inventory models'
|
|
count = 0
|
|
|
|
def add_arguments(self, parser):
|
|
pass
|
|
|
|
def handle(self, *args, **options):
|
|
|
|
kinds = []
|
|
for i in ("Talk", "Tutorial", "Miniconf"):
|
|
kinds.append(proposals.models.ProposalKind.objects.get(name=i))
|
|
self.main_conference_proposals = kinds
|
|
|
|
self.populate_groups()
|
|
self.populate_inventory()
|
|
self.populate_restrictions()
|
|
self.populate_discounts()
|
|
|
|
def populate_groups(self):
|
|
self.group_team = self.find_or_make(
|
|
Group,
|
|
("name", ),
|
|
name="Conference organisers",
|
|
)
|
|
self.group_volunteers = self.find_or_make(
|
|
Group,
|
|
("name", ),
|
|
name="Conference volunteers",
|
|
)
|
|
self.group_unpublish = self.find_or_make(
|
|
Group,
|
|
("name", ),
|
|
name="Can see unpublished products",
|
|
)
|
|
self.group_prepurchase = self.find_or_make(
|
|
Group,
|
|
("name", ),
|
|
name="Pre-purchase",
|
|
)
|
|
|
|
def populate_inventory(self):
|
|
# Categories
|
|
|
|
self.ticket = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Ticket",
|
|
description="Each type of ticket has different included products. "
|
|
"For details of what products are included, see our "
|
|
"<a href='https://linux.conf.au/attend/tickets/'>registration page</a>",
|
|
required=True,
|
|
render_type=inv.Category.RENDER_TYPE_RADIO,
|
|
limit_per_user=1,
|
|
order=1,
|
|
)
|
|
self.terms = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Terms, Conditions, and Code of Conduct Acceptance",
|
|
description="I agree to the "
|
|
"<a href=\"https://linux.conf.au/attend/terms-and-conditions\"> "
|
|
"terms and conditions of attendance</a>, and I have read, "
|
|
"understood, and agree to act according to the standards set "
|
|
"forth in our <a href=\"https://linux.conf.au/attend/code-of-conduct\">"
|
|
"Code of Conduct</a>.",
|
|
required=True,
|
|
render_type=inv.Category.RENDER_TYPE_CHECKBOX,
|
|
order=10,
|
|
)
|
|
self.penguin_dinner = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Penguin Dinner Ticket",
|
|
description="Tickets to our conference dinner on the evening of "
|
|
f"{settings.PENGUIN_DINNER_TICKET_DATE: %A %d %B}. "
|
|
"All attendees may purchase "
|
|
"seats at the dinner, even if a dinner ticket is not "
|
|
"included in your conference ticket price.",
|
|
required=False,
|
|
render_type=inv.Category.RENDER_TYPE_QUANTITY,
|
|
limit_per_user=10,
|
|
order=20,
|
|
)
|
|
self.speakers_dinner_ticket = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Speakers' Dinner Ticket",
|
|
description="Tickets to our exclusive Speakers' Dinner on the "
|
|
"evening of "
|
|
f"{settings.SPEAKER_DINNER_TICKET_DATE: %A %d %B}. "
|
|
"You may purchase up "
|
|
"to 5 tickets in total, for significant others and "
|
|
"family members.",
|
|
required=False,
|
|
render_type=inv.Category.RENDER_TYPE_QUANTITY,
|
|
limit_per_user=5,
|
|
order=30,
|
|
)
|
|
self.pdns_category = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Professional Delegates Networking Session Ticket",
|
|
description="Tickets to our Professional Delegates Networking session. "
|
|
"This event will be held on the evening of "
|
|
f"{settings.PDNS_TICKET_DATE: %A %d %B} "
|
|
"and is restricted to Professional Ticket "
|
|
"holders, speakers, miniconf organisers, and invited "
|
|
"guests.",
|
|
required=False,
|
|
render_type=inv.Category.RENDER_TYPE_RADIO,
|
|
limit_per_user=1,
|
|
order=40,
|
|
)
|
|
self.t_shirt = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Shirt",
|
|
description="Commemorative conference polo shirts, featuring the "
|
|
f"linux.conf.au {settings.LCA_START.year} artwork.",
|
|
required=False,
|
|
render_type=inv.Category.RENDER_TYPE_ITEM_QUANTITY,
|
|
order=50,
|
|
)
|
|
# self.accommodation = self.find_or_make(
|
|
# inv.Category,
|
|
# ("name",),
|
|
# name="Accommodation at University of Tasmania",
|
|
# description="Accommodation at the University of Tasmania colleges "
|
|
# "and apartments. You can come back and book your "
|
|
# "accommodation at a later date, provided rooms remain "
|
|
# "available. Rooms may only be booked from Sunday 15 "
|
|
# "January--Saturday 21 January. If you wish to stay "
|
|
# "for only a part of the 6-day period, you must book "
|
|
# "accommodation for the full 6-day period. Rooms at "
|
|
# "other hotels, including Wrest Point can be booked "
|
|
# "elsewhere. For full details, see [LINK]our "
|
|
# "accommodation page.[/LINK]",
|
|
# required=False,
|
|
# render_type=inv.Category.RENDER_TYPE_RADIO,
|
|
# limit_per_user=1,
|
|
# order=50,
|
|
# )
|
|
self.extras = self.find_or_make(
|
|
inv.Category,
|
|
("name",),
|
|
name="Extras",
|
|
description="Other items that can improve your conference "
|
|
"experience.",
|
|
required=False,
|
|
render_type=inv.Category.RENDER_TYPE_QUANTITY,
|
|
order=60,
|
|
)
|
|
|
|
# Tickets
|
|
|
|
self.ticket_contributor = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.CONTRIBUTOR.name,
|
|
price=settings.CONTRIBUTOR.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=1,
|
|
)
|
|
self.ticket_professional = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.PROFESSIONAL.name,
|
|
price=settings.PROFESSIONAL.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=10,
|
|
)
|
|
self.ticket_hobbyist = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.HOBBYIST.name,
|
|
price=settings.HOBBYIST.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=20,
|
|
)
|
|
self.ticket_student = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.STUDENT.name,
|
|
price=settings.STUDENT.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=30,
|
|
)
|
|
self.ticket_miniconfs_mt = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.MINICONF_MT.name,
|
|
price=settings.MINICONF_MT.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=40,
|
|
)
|
|
self.ticket_miniconfs_mon = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.MINICONF_M.name,
|
|
price=settings.MINICONF_M.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=42,
|
|
)
|
|
self.ticket_miniconfs_tue = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.MINICONF_MT.name,
|
|
price=settings.MINICONF_MT.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=44,
|
|
)
|
|
self.ticket_speaker = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.SPEAKER.name,
|
|
price=settings.SPEAKER.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=50,
|
|
)
|
|
self.ticket_media = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.MEDIA.name,
|
|
price=settings.MEDIA.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=60,
|
|
)
|
|
self.ticket_sponsor = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.SPONSOR.name,
|
|
price=settings.SPONSOR.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=70,
|
|
)
|
|
self.ticket_team = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.CONFERENCE_ORG.name,
|
|
price=settings.CONFERENCE_ORG.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=80,
|
|
)
|
|
self.ticket_volunteer = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.ticket,
|
|
name=settings.CONFERENCE_VOL.name,
|
|
price=settings.CONFERENCE_VOL.regular_price,
|
|
reservation_duration=hours(24),
|
|
order=90,
|
|
)
|
|
|
|
# Agreements
|
|
self.accept_terms = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.terms,
|
|
name="I Accept",
|
|
price=Decimal("00.00"),
|
|
reservation_duration=hours(24),
|
|
order=10,
|
|
limit_per_user=1,
|
|
)
|
|
|
|
for t in settings.PENGUIN_DINNER.tickets:
|
|
self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.penguin_dinner,
|
|
name=t.name,
|
|
description=t.description,
|
|
price=t.price,
|
|
reservation_duration=t.reservation,
|
|
order=t.order()
|
|
)
|
|
|
|
for t in settings.SPEAKERS_DINNER.tickets:
|
|
self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.speakers_dinner_ticket,
|
|
name=t.name,
|
|
description=t.description,
|
|
price=t.price,
|
|
reservation_duration=t.reservation,
|
|
order=t.order()
|
|
)
|
|
|
|
# PDNS
|
|
|
|
self.pdns = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.pdns_category,
|
|
name="Conference Attendee",
|
|
price=Decimal("00.00"),
|
|
reservation_duration=hours(1),
|
|
limit_per_user=1,
|
|
order=10,
|
|
)
|
|
|
|
# # Accommodation
|
|
|
|
# self.accommodation_week = self.find_or_make(
|
|
# inv.Product,
|
|
# ("name", "category",),
|
|
# category=self.accommodation,
|
|
# name="Single Bedroom with Shared Bathrooms, includes full "
|
|
# "breakfast, Sunday 15 January 2017--Saturday 21 January 2017",
|
|
# price=Decimal("396.00"),
|
|
# reservation_duration=hours(24),
|
|
# limit_per_user=1,
|
|
# order=10,
|
|
# )
|
|
|
|
# Extras
|
|
|
|
self.carbon_offset = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
category=self.extras,
|
|
name="Offset the carbon pollution generated by your attendance, "
|
|
"thanks to fifteen trees.",
|
|
price=Decimal("5.00"),
|
|
reservation_duration=hours(1),
|
|
order=10,
|
|
)
|
|
|
|
# Shirts
|
|
ShirtGroup = namedtuple("ShirtGroup", ("prefix", "sizes"))
|
|
shirt_names = {
|
|
"mens": ShirtGroup(
|
|
"Men's/Straight Cut",
|
|
("S", "M", "L", "XL", "2XL", "3XL", "4XL"),
|
|
),
|
|
"womens": ShirtGroup(
|
|
"Women's Classic Fit",
|
|
("8", "10", "12", "14", "16", "18"),
|
|
),
|
|
}
|
|
|
|
self.shirts = {}
|
|
order = 0
|
|
for name, group in shirt_names.items():
|
|
self.shirts[name] = {}
|
|
prefix = group.prefix
|
|
for size in group.sizes:
|
|
product_name = "%s %s" % (prefix, size)
|
|
order += 10
|
|
self.shirts[name][size] = self.find_or_make(
|
|
inv.Product,
|
|
("name", "category",),
|
|
name=product_name,
|
|
category=self.t_shirt,
|
|
price=settings.TSHIRT_PRICE,
|
|
reservation_duration=hours(1),
|
|
order=order,
|
|
)
|
|
|
|
def populate_restrictions(self):
|
|
|
|
# Hide the products that will eventually need a voucher
|
|
hide_voucher_products = self.find_or_make(
|
|
cond.GroupMemberFlag,
|
|
("description", ),
|
|
description="Can see hidden products",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
)
|
|
hide_voucher_products.group.set([self.group_unpublish])
|
|
hide_voucher_products.products.set([
|
|
self.ticket_media,
|
|
self.ticket_sponsor,
|
|
self.ticket_miniconfs_mt,
|
|
self.ticket_miniconfs_mon,
|
|
self.ticket_miniconfs_tue,
|
|
])
|
|
|
|
hide_all_tickets = self.find_or_make(
|
|
cond.GroupMemberFlag,
|
|
("description", ),
|
|
description="Can pre-purchase tickets",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
)
|
|
hide_all_tickets.group.set([self.group_prepurchase])
|
|
hide_all_tickets.products.set([
|
|
self.ticket_contributor,
|
|
self.ticket_professional,
|
|
self.ticket_hobbyist,
|
|
self.ticket_student,
|
|
])
|
|
|
|
# Set limits.
|
|
public_ticket_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Public ticket cap",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=600,
|
|
)
|
|
public_ticket_cap.products.set([
|
|
self.ticket_contributor,
|
|
self.ticket_professional,
|
|
self.ticket_hobbyist,
|
|
self.ticket_student,
|
|
])
|
|
|
|
student_ticket_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Student ticket cap",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=100,
|
|
)
|
|
|
|
student_ticket_cap.products.set([
|
|
self.ticket_student,
|
|
])
|
|
|
|
public_ticket_cap.products.set([
|
|
self.ticket_contributor,
|
|
self.ticket_professional,
|
|
self.ticket_hobbyist,
|
|
self.ticket_student,
|
|
])
|
|
|
|
sponsor_ticket_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Reserved for sponsors",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=70,
|
|
)
|
|
sponsor_ticket_cap.products.set([
|
|
self.ticket_sponsor,
|
|
])
|
|
|
|
volunteer_ticket_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Reserrved for volunteers and organizers",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=62,
|
|
)
|
|
volunteer_ticket_cap.products.set([
|
|
self.ticket_team,
|
|
self.ticket_volunteer,
|
|
])
|
|
|
|
media_ticket_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Reserved for media",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=10,
|
|
)
|
|
media_ticket_cap.products.set([
|
|
self.ticket_media,
|
|
])
|
|
|
|
speaker_ticket_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Reserved for speakers (and miniconf organisers)",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=104,
|
|
)
|
|
speaker_ticket_cap.products.set([
|
|
self.ticket_speaker,
|
|
])
|
|
|
|
penguin_dinner_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Penguin dinner ticket cap",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=900,
|
|
)
|
|
penguin_dinner_cap.categories.set([
|
|
self.penguin_dinner,
|
|
])
|
|
|
|
speakers_dinner_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="Speakers dinner ticket cap",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=135,
|
|
)
|
|
speakers_dinner_cap.categories.set([
|
|
self.speakers_dinner_ticket,
|
|
])
|
|
|
|
pdns_cap = self.find_or_make(
|
|
cond.TimeOrStockLimitFlag,
|
|
("description", ),
|
|
description="PDNS ticket cap",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
limit=400,
|
|
)
|
|
pdns_cap.categories.set([
|
|
self.pdns_category,
|
|
])
|
|
|
|
# Volunteer tickets are for volunteers only
|
|
volunteers = self.find_or_make(
|
|
cond.GroupMemberFlag,
|
|
("description", ),
|
|
description="Volunteer tickets",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
)
|
|
volunteers.group.set([self.group_volunteers])
|
|
volunteers.products.set([
|
|
self.ticket_volunteer,
|
|
])
|
|
|
|
# Team tickets are for team members only
|
|
team = self.find_or_make(
|
|
cond.GroupMemberFlag,
|
|
("description", ),
|
|
description="Team tickets",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
)
|
|
team.group.set([self.group_team])
|
|
team.products.set([
|
|
self.ticket_team,
|
|
])
|
|
|
|
# Speaker tickets are for primary speakers only
|
|
speaker_tickets = self.find_or_make(
|
|
cond.SpeakerFlag,
|
|
("description", ),
|
|
description="Speaker tickets",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
is_presenter=True,
|
|
is_copresenter=False,
|
|
)
|
|
speaker_tickets.proposal_kind.set(self.main_conference_proposals)
|
|
speaker_tickets.products.set([self.ticket_speaker, ])
|
|
|
|
# Speaker dinner tickets are for primary and secondary speakers
|
|
speaker_dinner_tickets = self.find_or_make(
|
|
cond.SpeakerFlag,
|
|
("description", ),
|
|
description="Speaker dinner tickets",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
is_presenter=True,
|
|
is_copresenter=True,
|
|
)
|
|
speaker_dinner_tickets.proposal_kind.set(self.main_conference_proposals)
|
|
speaker_dinner_tickets.categories.set([self.speakers_dinner_ticket, ])
|
|
|
|
# PDNS tickets are complicated.
|
|
# They can be enabled by tickets
|
|
pdns_by_ticket = self.find_or_make(
|
|
cond.ProductFlag,
|
|
("description", ),
|
|
description="PDNS available by ticket",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
)
|
|
pdns_by_ticket.enabling_products.set([
|
|
self.ticket_professional,
|
|
self.ticket_contributor,
|
|
self.ticket_media,
|
|
self.ticket_sponsor,
|
|
])
|
|
pdns_by_ticket.categories.set([self.pdns_category, ])
|
|
|
|
# They are available to speakers
|
|
pdns_by_speaker = self.find_or_make(
|
|
cond.SpeakerFlag,
|
|
("description", ),
|
|
description="PDNS available to speakers",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
is_presenter=True,
|
|
is_copresenter=True,
|
|
|
|
)
|
|
pdns_by_speaker.proposal_kind.set(self.main_conference_proposals)
|
|
pdns_by_speaker.categories.set([self.pdns_category, ])
|
|
|
|
# They are available to staff
|
|
pdns_by_staff = self.find_or_make(
|
|
cond.GroupMemberFlag,
|
|
("description", ),
|
|
description="PDNS available to staff",
|
|
condition=cond.FlagBase.ENABLE_IF_TRUE,
|
|
)
|
|
pdns_by_staff.group.set([
|
|
self.group_team,
|
|
])
|
|
pdns_by_staff.categories.set([self.pdns_category, ])
|
|
|
|
# Don't allow people to get anything if they don't have a ticket first
|
|
needs_a_ticket = self.find_or_make(
|
|
cond.CategoryFlag,
|
|
("description", ),
|
|
description="GottaGettaTicketFirst",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
enabling_category=self.ticket
|
|
)
|
|
needs_a_ticket.categories.set([
|
|
self.extras,
|
|
self.t_shirt,
|
|
self.penguin_dinner,
|
|
self.pdns_category,
|
|
])
|
|
# Require attendees to accept the T&Cs and Code of Conduct
|
|
needs_agreement = self.find_or_make(
|
|
cond.CategoryFlag,
|
|
("description", ),
|
|
description="Must Accept Terms",
|
|
condition=cond.FlagBase.DISABLE_IF_FALSE,
|
|
enabling_category=self.terms,
|
|
)
|
|
needs_agreement.categories.set([
|
|
self.extras,
|
|
self.t_shirt,
|
|
self.penguin_dinner,
|
|
self.pdns_category,
|
|
self.speakers_dinner_ticket,
|
|
])
|
|
|
|
def populate_discounts(self):
|
|
def add_early_birds(discount):
|
|
self.find_or_make(
|
|
cond.DiscountForProduct,
|
|
("discount", "product"),
|
|
discount=discount,
|
|
product=self.ticket_contributor,
|
|
price=settings.CONTRIBUTOR.earlybird_discount(),
|
|
quantity=1, # Per user
|
|
)
|
|
self.find_or_make(
|
|
cond.DiscountForProduct,
|
|
("discount", "product"),
|
|
discount=discount,
|
|
product=self.ticket_professional,
|
|
price=settings.PROFESSIONAL.earlybird_discount(),
|
|
quantity=1, # Per user
|
|
)
|
|
|
|
def free_category(parent_discount, category, quantity=1):
|
|
self.find_or_make(
|
|
cond.DiscountForCategory,
|
|
("discount", "category",),
|
|
discount=parent_discount,
|
|
category=category,
|
|
percentage=Decimal("100.00"),
|
|
quantity=quantity,
|
|
)
|
|
|
|
# Early Bird Discount (general public)
|
|
early_bird_hobbyist_discount = self.find_or_make(
|
|
cond.TimeOrStockLimitDiscount,
|
|
("description", ),
|
|
description="Early Bird Discount - Hobbyist",
|
|
end_time=settings.EARLY_BIRD_DEADLINE,
|
|
limit=150, # Across all users
|
|
)
|
|
self.find_or_make(
|
|
cond.DiscountForProduct,
|
|
("discount", "product"),
|
|
discount=early_bird_hobbyist_discount,
|
|
product=self.ticket_hobbyist,
|
|
price=settings.HOBBYIST.earlybird_discount(),
|
|
quantity=1, # Per user
|
|
)
|
|
|
|
early_bird = self.find_or_make(
|
|
cond.TimeOrStockLimitDiscount,
|
|
("description", ),
|
|
description="Early Bird Discount - Professional",
|
|
end_time=settings.EARLY_BIRD_DEADLINE,
|
|
limit=200, # Across professionals and fairy sponsors
|
|
)
|
|
add_early_birds(early_bird)
|
|
|
|
# Early bird rates for speakers
|
|
speaker_ticket_discounts = self.find_or_make(
|
|
cond.SpeakerDiscount,
|
|
("description", ),
|
|
description="Speaker Ticket Discount",
|
|
is_presenter=True,
|
|
is_copresenter=True,
|
|
)
|
|
speaker_ticket_discounts.proposal_kind.set(
|
|
self.main_conference_proposals,
|
|
)
|
|
add_early_birds(speaker_ticket_discounts)
|
|
|
|
# Primary speaker gets a free speaker dinner ticket
|
|
primary_speaker = self.find_or_make(
|
|
cond.SpeakerDiscount,
|
|
("description", ),
|
|
description="Complimentary for primary proposer",
|
|
is_presenter=True,
|
|
is_copresenter=False,
|
|
)
|
|
primary_speaker.proposal_kind.set(self.main_conference_proposals)
|
|
free_category(primary_speaker, self.speakers_dinner_ticket)
|
|
|
|
# Professional-Like ticket inclusions
|
|
ticket_prolike_inclusions = self.find_or_make(
|
|
cond.IncludedProductDiscount,
|
|
("description", ),
|
|
description="Complimentary for ticket holder (Professional-level)",
|
|
)
|
|
ticket_prolike_inclusions.enabling_products.set([
|
|
self.ticket_contributor,
|
|
self.ticket_professional,
|
|
self.ticket_media,
|
|
self.ticket_sponsor,
|
|
self.ticket_speaker,
|
|
])
|
|
free_category(ticket_prolike_inclusions, self.penguin_dinner)
|
|
free_category(ticket_prolike_inclusions, self.t_shirt)
|
|
|
|
# Hobbyist ticket inclusions
|
|
ticket_hobbyist_inclusions = self.find_or_make(
|
|
cond.IncludedProductDiscount,
|
|
("description", ),
|
|
description="Complimentary for ticket holder (Hobbyist-level)",
|
|
)
|
|
ticket_hobbyist_inclusions.enabling_products.set([
|
|
self.ticket_hobbyist,
|
|
])
|
|
free_category(ticket_hobbyist_inclusions, self.t_shirt)
|
|
|
|
# Student ticket inclusions
|
|
ticket_student_inclusions = self.find_or_make(
|
|
cond.IncludedProductDiscount,
|
|
("description", ),
|
|
description="Complimentary for ticket holder (Student-level)",
|
|
)
|
|
ticket_student_inclusions.enabling_products.set([
|
|
self.ticket_student,
|
|
])
|
|
free_category(ticket_student_inclusions, self.t_shirt)
|
|
|
|
# Team ticket inclusions
|
|
ticket_staff_inclusions = self.find_or_make(
|
|
cond.IncludedProductDiscount,
|
|
("description", ),
|
|
description="Complimentary for ticket holder staff)",
|
|
)
|
|
ticket_staff_inclusions.enabling_products.set([
|
|
self.ticket_team,
|
|
])
|
|
free_category(ticket_staff_inclusions, self.penguin_dinner)
|
|
|
|
# Team & volunteer shirts, regardless of ticket type
|
|
staff_t_shirts = self.find_or_make(
|
|
cond.GroupMemberDiscount,
|
|
("description", ),
|
|
description="Shirts complimentary for staff and volunteers",
|
|
)
|
|
staff_t_shirts.group.set([
|
|
self.group_team,
|
|
self.group_volunteers,
|
|
])
|
|
free_category(staff_t_shirts, self.t_shirt, quantity=5)
|
|
|
|
print(f"{self.count} categories found/made")
|
|
|
|
def find_or_make(self, model, search_keys, **k):
|
|
''' Either makes or finds an object of type _model_, with the given
|
|
kwargs.
|
|
|
|
Arguments:
|
|
search_keys ([str, ...]): A sequence of keys that are used to search
|
|
for an existing version in the database. The remaining arguments are
|
|
only used when creating a new object.
|
|
'''
|
|
self.count += 1
|
|
try:
|
|
keys = dict((key, k[key]) for key in search_keys)
|
|
a = model.objects.get(**keys)
|
|
self.stdout.write("FOUND : " + str(keys))
|
|
model.objects.filter(id=a.id).update(**k)
|
|
a.refresh_from_db()
|
|
return a
|
|
except ObjectDoesNotExist:
|
|
a = model.objects.create(**k)
|
|
self.stdout.write("CREATED: " + str(k))
|
|
return a
|
|
|
|
|
|
def hours(n):
|
|
return timedelta(hours=n)
|