Files
timetracker/tests/test_purchase_separate_orders.py
T
lukas 1c0c067377 fix(game): show game name in dropdown labels (#43)
search_label built its label from sort_name, an optional sort key that
is blank for most games, so the Game and Related-game dropdowns in the
add-purchase form (and the session form and search API, which share the
property) showed a blank/"None" label. Use name, which is required.

Also route search_label and Purchase.full_name through label_with_details
so a missing year_released drops out of the parenthetical instead of
rendering a literal "None". (platform is never None at display time -
Game.save() substitutes the "Unspecified" sentinel.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:48:42 +02:00

124 lines
4.8 KiB
Python

from datetime import date
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from games.models import Game, Platform, Purchase
class AddPurchasePricingTest(TestCase):
def setUp(self):
self.user = User.objects.create_superuser("u", "u@e.com", "pw")
self.client.force_login(self.user)
self.platform = Platform.objects.create(name="PC", icon="pc", group="PC")
self.game_a = Game.objects.create(name="Game A", platform=self.platform)
self.game_b = Game.objects.create(name="Game B", platform=self.platform)
def _base_data(self, **overrides):
data = {
"games": [self.game_a.id, self.game_b.id],
"platform": self.platform.id,
"date_purchased": "2025-01-01",
"price_currency": "USD",
"ownership_type": Purchase.DIGITAL,
"type": Purchase.GAME,
"name": "",
}
data.update(overrides)
return data
def test_combined_creates_single_bundle(self):
data = self._base_data(pricing_mode="combined", price="30")
response = self.client.post(reverse("games:add_purchase"), data)
self.assertEqual(response.status_code, 302)
self.assertEqual(Purchase.objects.count(), 1)
bundle = Purchase.objects.get()
self.assertEqual(bundle.num_purchases, 2)
self.assertEqual(bundle.price, 30)
def test_per_game_creates_separate_single_game_purchases(self):
data = self._base_data(
pricing_mode="per_game",
**{
f"price_for_game_{self.game_a.id}": "10",
f"price_for_game_{self.game_b.id}": "20",
},
)
response = self.client.post(reverse("games:add_purchase"), data)
self.assertEqual(response.status_code, 302)
self.assertEqual(Purchase.objects.count(), 2)
for purchase in Purchase.objects.all():
self.assertEqual(purchase.num_purchases, 1)
self.assertEqual(sorted(p.price for p in Purchase.objects.all()), [10.0, 20.0])
linked_games = [
list(p.games.values_list("id", flat=True)) for p in Purchase.objects.all()
]
self.assertTrue(all(len(games) == 1 for games in linked_games))
self.assertEqual(
{games[0] for games in linked_games},
{self.game_a.id, self.game_b.id},
)
def test_full_name_keeps_parenthesized_detail_shape(self):
bundle = Purchase.objects.create(
name="Humble Bundle",
date_purchased=date(2025, 1, 1),
price=30,
price_currency="USD",
ownership_type=Purchase.DIGITAL,
)
bundle.games.set([self.game_a, self.game_b])
bundle.refresh_from_db()
full_name = bundle.full_name
self.assertTrue(full_name.startswith("Humble Bundle (2 games, "))
self.assertTrue(full_name.endswith(")"))
class SplitPurchaseTest(TestCase):
def setUp(self):
self.user = User.objects.create_superuser("u", "u@e.com", "pw")
self.client.force_login(self.user)
self.platform = Platform.objects.create(name="PC", icon="pc", group="PC")
self.game_a = Game.objects.create(name="Game A", platform=self.platform)
self.game_b = Game.objects.create(name="Game B", platform=self.platform)
def _bundle(self, games, price=30.0):
bundle = Purchase.objects.create(
price=price,
price_currency="USD",
date_purchased=date(2025, 1, 1),
platform=self.platform,
ownership_type=Purchase.DIGITAL,
type=Purchase.GAME,
)
bundle.games.set(games)
return bundle
def test_split_creates_per_game_purchases_and_deletes_original(self):
bundle = self._bundle([self.game_a, self.game_b], price=30.0)
response = self.client.post(reverse("games:split_purchase", args=[bundle.id]))
self.assertEqual(response.status_code, 204)
self.assertEqual(response["HX-Redirect"], reverse("games:list_purchases"))
self.assertFalse(Purchase.objects.filter(id=bundle.id).exists())
self.assertEqual(Purchase.objects.count(), 2)
for purchase in Purchase.objects.all():
self.assertEqual(purchase.num_purchases, 1)
self.assertEqual(purchase.price, 15.0) # 30 / 2, split evenly
self.assertTrue(purchase.needs_price_update)
def test_split_is_noop_for_single_game_purchase(self):
single = self._bundle([self.game_a], price=10.0)
response = self.client.post(reverse("games:split_purchase", args=[single.id]))
self.assertEqual(response.status_code, 204)
self.assertTrue(Purchase.objects.filter(id=single.id).exists())
self.assertEqual(Purchase.objects.count(), 1)