Files
Example-TCG-Site/store/tests.py
Ryan Westfall 9040021d1b MASSIVE UPDATE:
bounty board feature

buyers to see bounty boards

seller profile page (like have theme chooser)

Have the game and set name be filters.

Add cards to vault manually

update card inventory add to have the autocomplete for the card  -

store analytics, clicks, views, link to store (url/QR code)

bulk item inventory creation --

Make the banner feature flag driven so I can have a beta site setup like the primary site

don't use primary key values in urls - update to use uuid4 values

site analytics. tianji is being sent

item potent on the mtg and lorcana populate scripts

Card item images for specific listings

check that when you buy a card it is in the vault

Buys should be able to search on store inventories

More pie charts for the seller!

post bounty board is slow to load

seller reviews/ratings - show a historgram - need a way for someone to rate

Report a seller feature for buyer to report

Make sure the stlying is consistent based on the theme choosen

smart minimum order quantity and shipping amounts (defined by the store itself)

put virtual packs behind a feature flag like bounty board

proxy service feature flag

Terms of Service

new description for TCGKof

store SSN, ITIN, and EIN

optomize for SEO
2026-01-23 12:28:20 -06:00

240 lines
9.5 KiB
Python

from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.files.uploadedfile import SimpleUploadedFile
from .models import Seller, Game, Set, Card, CardListing, Order
from decimal import Decimal
User = get_user_model()
class CardListingTests(TestCase):
def setUp(self):
# Create User and Seller
self.user = User.objects.create_user(username='seller', password='password')
self.seller = Seller.objects.create(
user=self.user,
store_name='Test Store',
slug='test-store'
)
# Create Game, Set, Card
self.game = Game.objects.create(name='Test Game', slug='test-game')
self.set = Set.objects.create(game=self.game, name='Test Set')
self.card = Card.objects.create(set=self.set, name='Test Card')
# Create Listing
self.listing = CardListing.objects.create(
card=self.card,
seller=self.seller,
price=10.00,
quantity=1,
condition='NM'
)
self.client = Client()
self.client.force_login(self.user)
def test_edit_card_listing_image_upload(self):
url = reverse('store:edit_card_listing', args=[self.listing.uuid])
# Create a small image file
image_content = b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x01\x44\x00\x3b'
image = SimpleUploadedFile("test_image.gif", image_content, content_type="image/gif")
data = {
'condition': 'LP',
'price': '15.00',
'quantity': 2,
'status': 'listed',
'image': image
}
response = self.client.post(url, data, format='multipart')
# Check redirect
self.assertRedirects(response, reverse('store:manage_listings'))
# Reload listing
self.listing.refresh_from_db()
# Check updates
self.assertEqual(self.listing.condition, 'LP')
self.assertEqual(self.listing.price, 15.00)
self.assertEqual(self.listing.quantity, 2)
# Check image
self.assertTrue(self.listing.image)
self.assertTrue(self.listing.image.name.endswith('test_image.gif'))
class SellerDashboardTests(TestCase):
def setUp(self):
# Create User and Seller
self.user = User.objects.create_user(username='dashboard_seller', password='password')
self.seller = Seller.objects.create(
user=self.user,
store_name='Dashboard Store',
slug='dashboard-store'
)
self.buyer_user = User.objects.create_user(username='buyer', password='password')
from users.models import Buyer
self.buyer = Buyer.objects.create(user=self.buyer_user)
# Create Game, Set, Card
self.game = Game.objects.create(name='Dashboard Game', slug='dashboard-game')
self.set = Set.objects.create(game=self.game, name='Dashboard Set')
self.card = Card.objects.create(set=self.set, name='Dashboard Card')
# Create Listing
self.listing = CardListing.objects.create(
card=self.card,
seller=self.seller,
price=10.00,
quantity=10,
condition='NM'
)
# Create Order & OrderItem
from .models import Order, OrderItem
self.order = Order.objects.create(
buyer=self.buyer,
status='paid',
total_price=20.00
)
OrderItem.objects.create(
order=self.order,
listing=self.listing,
price_at_purchase=10.00,
quantity=2
)
self.client = Client()
self.client.force_login(self.user)
def test_dashboard_context_data(self):
url = reverse('store:seller_dashboard')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
# Check for new context keys
self.assertIn('condition_labels', response.context)
self.assertIn('condition_data', response.context)
self.assertIn('set_labels', response.context)
self.assertIn('set_data', response.context)
self.assertIn('game_labels', response.context)
self.assertIn('game_data', response.context)
self.assertIn('all_games', response.context)
# Check data correctness (we sold 2 NM items)
import json
cond_data = json.loads(response.context['condition_data'])
cond_labels = json.loads(response.context['condition_labels'])
self.assertIn('Near Mint', cond_labels)
idx = cond_labels.index('Near Mint')
self.assertEqual(cond_data[idx], 2)
def test_dashboard_game_filter(self):
from .models import OrderItem
url = reverse('store:seller_dashboard')
# Create another game/sale
game2 = Game.objects.create(name='Other Game', slug='other-game')
set2 = Set.objects.create(game=game2, name='Other Set')
card2 = Card.objects.create(set=set2, name='Other Card')
listing2 = CardListing.objects.create(card=card2, seller=self.seller, price=5, quantity=5, condition='LP')
OrderItem.objects.create(
order=self.order,
listing=listing2,
price_at_purchase=5.00,
quantity=1
)
# 1. No Filter - Should see both
response = self.client.get(url)
import json
game_labels = json.loads(response.context['game_labels'])
self.assertIn('Dashboard Game', game_labels)
self.assertIn('Other Game', game_labels)
# 2. Filter by Dashboard Game
response = self.client.get(url, {'game': 'Dashboard Game'})
game_labels = json.loads(response.context['game_labels'])
self.assertIn('Dashboard Game', game_labels)
self.assertNotIn('Other Game', game_labels)
# Check condition data also filtered
cond_labels = json.loads(response.context['condition_labels'])
# Dashboard Game items were NM. Other Game items were LP.
self.assertIn('Near Mint', cond_labels)
self.assertNotIn('Lightly Played', cond_labels)
class AdminRevenueTests(TestCase):
def setUp(self):
self.client = Client()
self.staff_user = User.objects.create_user(username='staff', password='password', is_staff=True)
self.seller_user = User.objects.create_user(username='seller2', password='password')
self.seller = Seller.objects.create(
user=self.seller_user,
store_name='Revenue Store',
slug='revenue-store',
tax_id='123-45-6789',
payout_details='Bank Acct 123'
)
# Create Orders
from users.models import Buyer
buyer_user = User.objects.create_user(username='buyer2', password='password')
buyer = Buyer.objects.create(user=buyer_user)
# Order 1: $100 -> Fee: 5 + 0.70 = 5.70
order1 = Order.objects.create(buyer=buyer, status='paid', total_price=Decimal('100.00'), seller=self.seller)
# Order 2: $1000 -> Fee: 50 + 0.70 = 50.70 -> Capped at 25.00
order2 = Order.objects.create(buyer=buyer, status='shipped', total_price=Decimal('1000.00'), seller=self.seller)
# Order 3: Pending (should be ignored)
order3 = Order.objects.create(buyer=buyer, status='pending', total_price=Decimal('50.00'), seller=self.seller)
def test_encryption(self):
# Refresh from db
seller = Seller.objects.get(pk=self.seller.pk)
# Verify decrypted values match
self.assertEqual(seller.tax_id, '123-45-6789')
self.assertEqual(seller.payout_details, 'Bank Acct 123')
# Verify db values are encrypted (not plaintext and are bytes)
self.assertIsInstance(seller.tax_id_encrypted, bytes)
self.assertNotEqual(seller.tax_id_encrypted, b'123-45-6789')
# Ensure it's not just the string encoded
self.assertNotEqual(seller.tax_id_encrypted, '123-45-6789'.encode('utf-8'))
def test_fee_calculation(self):
from .utils import calculate_platform_fee
# 5% + 0.70
self.assertEqual(calculate_platform_fee(Decimal('10.00')), Decimal('1.20')) # 0.50 + 0.70
self.assertEqual(calculate_platform_fee(Decimal('100.00')), Decimal('5.70')) # 5.00 + 0.70
# Cap at 25
# Threshold: (25 - 0.70) / 0.05 = 486.00
self.assertEqual(calculate_platform_fee(Decimal('486.00')), Decimal('25.00'))
self.assertEqual(calculate_platform_fee(Decimal('1000.00')), Decimal('25.00'))
def test_dashboard_view(self):
self.client.force_login(self.staff_user)
response = self.client.get(reverse('store:admin_revenue_dashboard'))
self.assertEqual(response.status_code, 200)
# Check context
total_rev = response.context['total_platform_revenue']
# Order 1 (5.70) + Order 2 (25.00) = 30.70
self.assertEqual(total_rev, Decimal('30.70'))
seller_data = response.context['seller_data']
self.assertEqual(len(seller_data), 1)
self.assertEqual(seller_data[0]['total_revenue'], Decimal('1100.00'))
self.assertEqual(seller_data[0]['platform_fees'], Decimal('30.70'))