Merge pull request #370 from bornhack/ticket_type_create_single_ticket_option

Add "single_ticket_per_product" boolean to ticket types
This commit is contained in:
Víðir Valberg Guðmundsson 2019-07-30 22:58:36 +02:00 committed by GitHub
commit 7dc82ee4ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 166 additions and 21 deletions

36
src/camps/factories.py Normal file
View file

@ -0,0 +1,36 @@
import factory
from django.utils import timezone
from factory.django import DjangoModelFactory
from psycopg2._range import DateTimeTZRange
class CampFactory(DjangoModelFactory):
class Meta:
model = "camps.Camp"
read_only = False
title = factory.Faker("word")
tagline = factory.Faker("sentence")
slug = factory.Faker("slug")
shortslug = factory.Faker("slug")
buildup = factory.LazyFunction(
lambda: DateTimeTZRange(
lower=timezone.now() - timezone.timedelta(3), upper=timezone.now()
)
)
camp = factory.LazyFunction(
lambda: DateTimeTZRange(lower=timezone.now(), upper=timezone.now())
)
teardown = factory.LazyFunction(
lambda: DateTimeTZRange(
lower=timezone.now() + timezone.timedelta(8),
upper=timezone.now() + timezone.timedelta(11),
)
)
colour = factory.Faker("hex_color")

View file

@ -30,6 +30,7 @@ class ProductFactory(DjangoModelFactory):
lower=timezone.now(), upper=timezone.now() + timezone.timedelta(31)
)
)
ticket_type = factory.SubFactory("tickets.factories.TicketTypeFactory")
class OrderFactory(DjangoModelFactory):

View file

@ -208,6 +208,7 @@ class Order(CreatedUpdatedModel):
return str(reverse_lazy("shop:order_detail", kwargs={"pk": self.pk}))
def create_tickets(self, request=None):
tickets = []
for order_product in self.orderproductrelation_set.all():
# if this is a Ticket product?
if order_product.product.ticket_type:
@ -216,32 +217,57 @@ class Order(CreatedUpdatedModel):
ticket_type=order_product.product.ticket_type,
)
already_created_tickets = self.shoptickets.filter(
**query_kwargs
).count()
tickets_to_create = max(
0, order_product.quantity - already_created_tickets
)
if order_product.product.ticket_type.single_ticket_per_product:
# This ticket type is one where we only create one ticket
ticket, created = self.shoptickets.get_or_create(**query_kwargs)
# create the number of tickets required
if tickets_to_create > 0:
for _ in range(
0, (order_product.quantity - already_created_tickets)
):
self.shoptickets.create(**query_kwargs)
if created:
msg = (
"Created ticket for product %s on order %s (quantity: %s)"
% (
order_product.product,
order_product.order.pk,
order_product.quantity,
)
)
tickets.append(ticket)
else:
msg = "Ticket already created for product %s on order %s" % (
order_product.product,
order_product.order.pk,
)
msg = "Created %s tickets of type: %s" % (
order_product.quantity,
order_product.product.ticket_type.name,
)
if request:
messages.success(request, msg)
else:
print(msg)
else:
# We should create a number of tickets equal to OrderProductRelation quantity
already_created_tickets = self.shoptickets.filter(
**query_kwargs
).count()
tickets_to_create = max(
0, order_product.quantity - already_created_tickets
)
# and mark the OPR as ticket_generated=True
order_product.ticket_generated = True
order_product.save()
# create the number of tickets required
if tickets_to_create > 0:
for _ in range(
0, (order_product.quantity - already_created_tickets)
):
ticket = self.shoptickets.create(**query_kwargs)
tickets.append(ticket)
msg = "Created %s tickets of type: %s" % (
order_product.quantity,
order_product.product.ticket_type.name,
)
if request:
messages.success(request, msg)
# and mark the OPR as ticket_generated=True
order_product.ticket_generated = True
order_product.save()
return tickets
def mark_as_paid(self, request=None):
self.paid = True

View file

@ -4,6 +4,8 @@ from django.utils import timezone
from psycopg2.extras import DateTimeTZRange
from shop.forms import OrderProductRelationForm
from tickets.factories import TicketTypeFactory
from tickets.models import ShopTicket
from utils.factories import UserFactory
from .factories import ProductFactory, OrderProductRelationFactory, OrderFactory
@ -371,3 +373,27 @@ class TestOrderListView(TestCase):
path = reverse("shop:order_list")
response = self.client.get(path)
self.assertEquals(response.status_code, 200)
class TestTicketCreation(TestCase):
def test_multiple_tickets_created(self):
user = UserFactory()
ticket_type = TicketTypeFactory(single_ticket_per_product=False)
product = ProductFactory(ticket_type=ticket_type)
order = OrderFactory(user=user)
OrderProductRelationFactory(order=order, product=product, quantity=5)
order.mark_as_paid()
self.assertEquals(
ShopTicket.objects.filter(product=product, order=order).count(), 5
)
def test_single_ticket_created(self):
user = UserFactory()
ticket_type = TicketTypeFactory(single_ticket_per_product=True)
product = ProductFactory(ticket_type=ticket_type)
order = OrderFactory(user=user)
OrderProductRelationFactory(order=order, product=product, quantity=5)
order.mark_as_paid()
self.assertEquals(
ShopTicket.objects.filter(product=product, order=order).count(), 1
)

View file

@ -1,5 +1,6 @@
from django.contrib import admin
from shop.models import OrderProductRelation
from .models import TicketType, SponsorTicket, DiscountTicket, ShopTicket
@ -51,12 +52,24 @@ class ShopTicketAdmin(BaseTicketAdmin):
"order",
"product",
"used",
"product_quantity",
]
list_filter = ["ticket_type__camp", "used", "ticket_type", "order", "product"]
search_fields = ["uuid", "order__id", "order__user__email", "name", "email"]
def product_quantity(self, ticket):
orp = OrderProductRelation.objects.get(
product=ticket.product, order=ticket.order
)
return (
str(orp.quantity) if ticket.ticket_type.single_ticket_per_product else "1"
)
product_quantity.short_description = "Quantity"
class ShopTicketInline(admin.TabularInline):
model = ShopTicket

18
src/tickets/factories.py Normal file
View file

@ -0,0 +1,18 @@
import factory
from factory.django import DjangoModelFactory
class TicketTypeFactory(DjangoModelFactory):
class Meta:
model = "tickets.TicketType"
name = factory.Faker("sentence")
camp = factory.SubFactory("camps.factories.CampFactory")
class ShopTicketFactory(DjangoModelFactory):
class Meta:
model = "tickets.ShopTicket"
ticket_type = factory.SubFactory(TicketTypeFactory)

View file

@ -0,0 +1,18 @@
# Generated by Django 2.2.3 on 2019-07-30 20:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tickets', '0012_auto_20190724_2037'),
]
operations = [
migrations.AddField(
model_name='tickettype',
name='single_ticket_per_product',
field=models.BooleanField(default=False, help_text='Only create one ticket for a product/order pair no matter the quantity. Useful for products which are bought in larger quantity (ie. village chairs)'),
),
]

View file

@ -18,6 +18,13 @@ class TicketType(CampRelatedModel, UUIDModel):
name = models.TextField()
camp = models.ForeignKey("camps.Camp", on_delete=models.PROTECT)
includes_badge = models.BooleanField(default=False)
single_ticket_per_product = models.BooleanField(
default=False,
help_text=(
"Only create one ticket for a product/order pair no matter the quantity. "
"Useful for products which are bought in larger quantity (ie. village chairs)"
),
)
def __str__(self):
return "{} ({})".format(self.name, self.camp.title)