remove FK from ShopTicket to Order and replace with an FK to OrderProductRelation

This commit is contained in:
Thomas Steen Rasmussen 2021-07-29 09:03:52 +02:00
parent 4c6eca2a6d
commit 517f29940a
14 changed files with 125 additions and 38 deletions

View file

@ -95,6 +95,9 @@ Enjoy!
## Notes ## Notes
### Running tests
If your database user in your dev setup is not a postgres superuser you will encounter permission errors when the migrations try to create extensions "btree_gist" and "postgis". You can solve this by connecting to the "template1" database as the postgres superuser and creating the extensions there, which means they will be automatically loaded for all newly created databases.
### Add a camp ### Add a camp
Add a new camp by running: Add a new camp by running:

View file

@ -65,7 +65,7 @@ Scan | {{ block.super }}
<td> <td>
<strong>Quantity:</strong> <strong>Quantity:</strong>
<td> <td>
{{ ticket.orp.quantity }} {{ ticket.opr.quantity }}
{% endif %} {% endif %}
<tr> <tr>
<td> <td>

View file

@ -44,7 +44,7 @@ Your Tickets | {{ block.super }}
<td> <td>
{{ ticket.product.name }} {{ ticket.product.name }}
<td> <td>
{% if ticket.ticket_type.single_ticket_per_product %}{{ ticket.orp.quantity }} &times; {% endif %} {% if ticket.ticket_type.single_ticket_per_product %}{{ ticket.opr.quantity }} &times; {% endif %}
{{ ticket.product.price|currency }} {{ ticket.product.price|currency }}
<td> <td>
{% if ticket.used %} {% if ticket.used %}

View file

@ -1,7 +1,5 @@
from django.contrib import admin from django.contrib import admin
from tickets.admin import ShopTicketInline
from .models import ( from .models import (
CoinifyAPICallback, CoinifyAPICallback,
CoinifyAPIInvoice, CoinifyAPIInvoice,
@ -138,7 +136,7 @@ class OrderAdmin(admin.ModelAdmin):
exclude = ["products"] exclude = ["products"]
inlines = [ProductInline, ShopTicketInline] inlines = [ProductInline]
actions = [ actions = [
"mark_order_as_paid", "mark_order_as_paid",

View file

@ -222,7 +222,9 @@ class Order(CreatedUpdatedModel):
if order_product.product.ticket_type.single_ticket_per_product: if order_product.product.ticket_type.single_ticket_per_product:
# This ticket type is one where we only create one ticket # This ticket type is one where we only create one ticket
ticket, created = self.shoptickets.get_or_create(**query_kwargs) ticket, created = order_product.shoptickets.get_or_create(
**query_kwargs
)
if created: if created:
msg = ( msg = (
@ -244,7 +246,7 @@ class Order(CreatedUpdatedModel):
messages.success(request, msg) messages.success(request, msg)
else: else:
# We should create a number of tickets equal to OrderProductRelation quantity # We should create a number of tickets equal to OrderProductRelation quantity
already_created_tickets = self.shoptickets.filter( already_created_tickets = order_product.shoptickets.filter(
**query_kwargs **query_kwargs
).count() ).count()
tickets_to_create = max( tickets_to_create = max(
@ -256,7 +258,7 @@ class Order(CreatedUpdatedModel):
for i in range( for i in range(
0, (order_product.quantity - already_created_tickets) 0, (order_product.quantity - already_created_tickets)
): ):
ticket = self.shoptickets.create(**query_kwargs) ticket = order_product.shoptickets.create(**query_kwargs)
tickets.append(ticket) tickets.append(ticket)
msg = "Created %s tickets of type: %s" % ( msg = "Created %s tickets of type: %s" % (

View file

@ -43,16 +43,16 @@ Details for Order #{{ order.id }} | {{ block.super }}
Total Total
<tbody> <tbody>
{% for orp in order.orderproductrelation_set.all %} {% for opr in order.orderproductrelation_set.all %}
<tr> <tr>
<td> <td>
{{ orp.product.name }} {{ opr.product.name }}
<td> <td>
{{ orp.quantity }} {{ opr.quantity }}
<td> <td>
{{ orp.product.price|currency }} {{ opr.product.price|currency }}
<td> <td>
{{ orp.total|currency }} {{ opr.total|currency }}
{% endfor %} {% endfor %}

View file

@ -383,7 +383,7 @@ class TestTicketCreation(TestCase):
OrderProductRelationFactory(order=order, product=product, quantity=5) OrderProductRelationFactory(order=order, product=product, quantity=5)
order.mark_as_paid() order.mark_as_paid()
self.assertEquals( self.assertEquals(
ShopTicket.objects.filter(product=product, order=order).count(), 5 ShopTicket.objects.filter(product=product, opr__order=order).count(), 5
) )
def test_single_ticket_created(self): def test_single_ticket_created(self):
@ -394,5 +394,5 @@ class TestTicketCreation(TestCase):
OrderProductRelationFactory(order=order, product=product, quantity=5) OrderProductRelationFactory(order=order, product=product, quantity=5)
order.mark_as_paid() order.mark_as_paid()
self.assertEquals( self.assertEquals(
ShopTicket.objects.filter(product=product, order=order).count(), 1 ShopTicket.objects.filter(product=product, opr__order=order).count(), 1
) )

View file

@ -1,7 +1,5 @@
from django.contrib import admin from django.contrib import admin
from shop.models import OrderProductRelation
from .models import DiscountTicket, ShopTicket, SponsorTicket, TicketType from .models import DiscountTicket, ShopTicket, SponsorTicket, TicketType
@ -57,18 +55,18 @@ class ShopTicketAdmin(BaseTicketAdmin):
"product_quantity", "product_quantity",
] ]
list_filter = ["ticket_type__camp", "used", "ticket_type", "order", "product"] list_filter = ["ticket_type__camp", "used", "ticket_type", "opr__order", "product"]
search_fields = ["uuid", "order__id", "order__user__email", "name", "email"] search_fields = [
"uuid",
"opr__order__id",
"opr__order__user__email",
"name",
"email",
]
def product_quantity(self, ticket): def product_quantity(self, ticket):
orp = OrderProductRelation.objects.get( return str(ticket.opr.quantity)
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" product_quantity.short_description = "Quantity"

View file

@ -0,0 +1,25 @@
# Generated by Django 3.2.5 on 2021-07-26 19:37
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("shop", "0064_add_product_comment_and_cost"),
("tickets", "0014_auto_20190803_2241"),
]
operations = [
migrations.AddField(
model_name="shopticket",
name="opr",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="shoptickets",
to="shop.orderproductrelation",
),
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 3.2.5 on 2021-07-26 19:38
from django.db import migrations
def populate_opr(apps, schema_editor):
OrderProductRelation = apps.get_model("shop", "OrderProductRelation")
ShopTicket = apps.get_model("tickets", "ShopTicket")
for st in ShopTicket.objects.all():
st.opr = OrderProductRelation.objects.get(product=st.product, order=st.order)
st.save()
class Migration(migrations.Migration):
dependencies = [
("tickets", "0015_shopticket_opr"),
]
operations = [migrations.RunPython(populate_opr)]

View file

@ -0,0 +1,24 @@
# Generated by Django 3.2.5 on 2021-07-26 19:52
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("shop", "0064_add_product_comment_and_cost"),
("tickets", "0016_populate_opr"),
]
operations = [
migrations.AlterField(
model_name="shopticket",
name="opr",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="shoptickets",
to="shop.orderproductrelation",
),
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 3.2.5 on 2021-07-26 20:00
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("tickets", "0017_shopticket_opr_not_null"),
]
operations = [
migrations.RemoveField(
model_name="shopticket",
name="order",
),
]

View file

@ -9,7 +9,6 @@ from django.db import models
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from shop.models import OrderProductRelation
from utils.models import CampRelatedModel, UUIDModel from utils.models import CampRelatedModel, UUIDModel
from utils.pdf import generate_pdf_letter from utils.pdf import generate_pdf_letter
@ -104,7 +103,7 @@ class BaseTicket(CampRelatedModel, UUIDModel):
formatdict = {"ticket": self} formatdict = {"ticket": self}
if self.ticket_type.single_ticket_per_product and self.shortname == "shop": if self.ticket_type.single_ticket_per_product and self.shortname == "shop":
formatdict["quantity"] = self.orp.quantity formatdict["quantity"] = self.opr.quantity
return generate_pdf_letter( return generate_pdf_letter(
filename="{}_ticket_{}.pdf".format(self.shortname, self.pk), filename="{}_ticket_{}.pdf".format(self.shortname, self.pk),
@ -138,11 +137,12 @@ class DiscountTicket(BaseTicket):
class ShopTicket(BaseTicket): class ShopTicket(BaseTicket):
"""Why doesn't this have an FK to OrderProductRelation instead of the fk to Order?""" opr = models.ForeignKey(
"shop.OrderProductRelation",
order = models.ForeignKey( related_name="shoptickets",
"shop.Order", related_name="shoptickets", on_delete=models.PROTECT on_delete=models.PROTECT,
) )
product = models.ForeignKey("shop.Product", on_delete=models.PROTECT) product = models.ForeignKey("shop.Product", on_delete=models.PROTECT)
name = models.CharField( name = models.CharField(
@ -178,5 +178,5 @@ class ShopTicket(BaseTicket):
return "shop" return "shop"
@property @property
def orp(self): def order(self):
return OrderProductRelation.objects.get(product=self.product, order=self.order) return self.opr.order

View file

@ -10,12 +10,11 @@ class TicketTests(TestCase):
def test_correct_token_and_badge_token_are_different(self): def test_correct_token_and_badge_token_are_different(self):
ticket_type = TicketTypeFactory() ticket_type = TicketTypeFactory()
opr = OrderProductRelationFactory()
orp = OrderProductRelationFactory()
shop_ticket = ShopTicket.objects.create( shop_ticket = ShopTicket.objects.create(
ticket_type=ticket_type, ticket_type=ticket_type,
product=orp.product, product=opr.product,
order=orp.order, opr=opr,
) )
self.assertNotEqual(shop_ticket.token, shop_ticket.badge_token) self.assertNotEqual(shop_ticket.token, shop_ticket.badge_token)