diff --git a/store/tests.py b/store/tests.py
index 0907815..1997ece 100644
--- a/store/tests.py
+++ b/store/tests.py
@@ -237,3 +237,35 @@ class AdminRevenueTests(TestCase):
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)
diff --git a/store/views.py b/store/views.py
index d0cc60d..8004f86 100644
--- a/store/views.py
+++ b/store/views.py
@@ -4,6 +4,8 @@ from django.db.models import Q
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from .models import Card, Game, Set, Cart, CartItem, CardListing, PackListing, VirtualPack, Order, OrderItem, Seller, Bounty, BountyOffer, SellerReport
+from django.db.models import Sum, Value
+from django.db.models.functions import Coalesce
from .forms import SellerRegistrationForm, CardListingForm, PackListingForm, AddCardListingForm, SellerEditForm, BountyForm, BountyOfferForm, BulkListingForm
from django.utils.text import slugify
import random
@@ -19,6 +21,14 @@ def index(request):
def card_list(request):
cards = Card.objects.all().select_related('set', 'set__game').prefetch_related('listings')
+ # Annotate with total quantity of listed items
+ cards = cards.annotate(
+ total_quantity=Coalesce(
+ Sum('listings__quantity', filter=Q(listings__status='listed')),
+ Value(0)
+ )
+ )
+
# Filtering
game_slug = request.GET.get('game')
if game_slug:
@@ -43,7 +53,7 @@ def card_list(request):
hide_oos = 'on'
if hide_oos == 'on':
- cards = cards.filter(listings__quantity__gt=0, listings__status='listed').distinct()
+ cards = cards.filter(total_quantity__gt=0)
# Simple logic: only show cards that have listings or show all?
# Let's show all for browsing, but indicate stock.
diff --git a/templates/store/card_detail.html b/templates/store/card_detail.html
index 69bf6d3..1dd0274 100644
--- a/templates/store/card_detail.html
+++ b/templates/store/card_detail.html
@@ -101,7 +101,7 @@
{% endif %}
- {{ listing.condition }}
+ {{ listing.get_condition_display }}