Last bit of major changes
Closes #1 Closes #5 Closes #6 Closes #8 Closes #9 Closes #10
This commit is contained in:
316
store/tests/test_existing.py
Normal file
316
store/tests/test_existing.py
Normal file
@@ -0,0 +1,316 @@
|
||||
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'))
|
||||
|
||||
class CardListStockTests(TestCase):
|
||||
def setUp(self):
|
||||
# Create Data
|
||||
self.user = User.objects.create_user(username='stock_seller', password='password')
|
||||
self.seller = Seller.objects.create(
|
||||
user=self.user,
|
||||
store_name='Stock Store',
|
||||
slug='stock-store'
|
||||
)
|
||||
self.game = Game.objects.create(name='Stock Game', slug='stock-game')
|
||||
self.set = Set.objects.create(game=self.game, name='Stock Set')
|
||||
self.card = Card.objects.create(set=self.set, name='Stock Card')
|
||||
|
||||
def test_stock_aggregation(self):
|
||||
# 1. No listings
|
||||
url = reverse('store:card_list')
|
||||
response = self.client.get(url, {'hide_out_of_stock': 'off'})
|
||||
# Expect card in context
|
||||
self.assertEqual(len(response.context['page_obj']), 1)
|
||||
self.assertEqual(response.context['page_obj'][0].total_quantity, 0)
|
||||
|
||||
# 2. Add listings
|
||||
CardListing.objects.create(card=self.card, seller=self.seller, price=10, quantity=5, status='listed')
|
||||
CardListing.objects.create(card=self.card, seller=self.seller, price=10, quantity=3, status='listed')
|
||||
|
||||
# Add a sold listing (should be ignored)
|
||||
CardListing.objects.create(card=self.card, seller=self.seller, price=10, quantity=2, status='sold')
|
||||
|
||||
response = self.client.get(url, {'hide_out_of_stock': 'off'})
|
||||
# Should be 5 + 3 = 8
|
||||
self.assertEqual(response.context['page_obj'][0].total_quantity, 8)
|
||||
|
||||
class SellerProfileRestrictionTests(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(username='restricted_seller', password='password')
|
||||
self.seller = Seller.objects.create(
|
||||
user=self.user,
|
||||
store_name='Restricted Store',
|
||||
slug='restricted-store'
|
||||
# tax_id and payout_details are initially empty
|
||||
)
|
||||
self.client = Client()
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_add_listing_incomplete_profile(self):
|
||||
url = reverse('store:add_card_listing')
|
||||
response = self.client.get(url)
|
||||
# Should redirect to edit profile
|
||||
self.assertRedirects(response, reverse('store:edit_seller_profile'))
|
||||
|
||||
# Verify message (this requires session support in test client which is default)
|
||||
messages = list(response.wsgi_request._messages)
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertIn("must complete your seller profile", str(messages[0]))
|
||||
|
||||
def test_add_bounty_incomplete_profile(self):
|
||||
# Ensure feature flag is on if needed, or assume True based on settings
|
||||
# The view checks FEATURE_BOUNTY_BOARD, so we might need override_settings if it defaults to False
|
||||
# But settings.DEBUG is True in current env, so it should be on.
|
||||
url = reverse('store:bounty_create')
|
||||
response = self.client.get(url)
|
||||
self.assertRedirects(response, reverse('store:edit_seller_profile'))
|
||||
|
||||
def test_complete_profile_allows_access(self):
|
||||
# Update profile
|
||||
self.seller.tax_id = '123'
|
||||
self.seller.payout_details = 'Bank'
|
||||
self.seller.save()
|
||||
|
||||
url = reverse('store:add_card_listing')
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
url = reverse('store:bounty_create')
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
Reference in New Issue
Block a user