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 @@ Listing Image {% endif %} - {{ listing.condition }} + {{ listing.get_condition_display }}
Condition
{% if listing.is_foil %} diff --git a/templates/store/card_list.html b/templates/store/card_list.html index de538f2..70d6401 100644 --- a/templates/store/card_list.html +++ b/templates/store/card_list.html @@ -146,7 +146,11 @@ Out of Stock {% endif %} {% endwith %} - ... + {% if card.total_quantity > 0 %} + {{ card.total_quantity }} in stock + {% else %} + Out of Stock + {% endif %}
@@ -178,26 +182,5 @@ - + {% endblock %} \ No newline at end of file