283 lines
9.7 KiB
Python
283 lines
9.7 KiB
Python
from django.shortcuts import render, get_object_or_404, redirect
|
|
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
|
|
import random
|
|
|
|
def card_list(request):
|
|
cards = Card.objects.all().select_related('set', 'set__game').prefetch_related('listings')
|
|
|
|
# Filtering
|
|
game_slug = request.GET.get('game')
|
|
if game_slug:
|
|
cards = cards.filter(set__game__slug=game_slug)
|
|
|
|
search_query = request.GET.get('q')
|
|
if search_query:
|
|
cards = cards.filter(name__icontains=search_query)
|
|
|
|
set_id = request.GET.get('set')
|
|
if set_id:
|
|
cards = cards.filter(set__id=set_id)
|
|
|
|
# Simple logic: only show cards that have listings or show all?
|
|
# Let's show all for browsing, but indicate stock.
|
|
|
|
paginator = Paginator(cards.order_by('name'), 24) # 24 cards per page
|
|
page_number = request.GET.get('page')
|
|
page_obj = paginator.get_page(page_number)
|
|
|
|
games = Game.objects.all()
|
|
# If a game is selected, getting its sets for the filter dropdown
|
|
sets = Set.objects.filter(game__slug=game_slug) if game_slug else Set.objects.all()[:50] # Limit default sets
|
|
|
|
return render(request, 'store/card_list.html', {
|
|
'page_obj': page_obj,
|
|
'games': games,
|
|
'sets': sets,
|
|
'current_game': game_slug,
|
|
'search_query': search_query,
|
|
})
|
|
|
|
def card_detail(request, card_id):
|
|
card = get_object_or_404(Card, id=card_id)
|
|
listings = card.listings.filter(quantity__gt=0).order_by('price')
|
|
return render(request, 'store/card_detail.html', {'card': card, 'listings': listings})
|
|
|
|
@login_required
|
|
def add_to_cart(request, listing_id):
|
|
listing = get_object_or_404(CardListing, id=listing_id)
|
|
cart, _ = Cart.objects.get_or_create(user=request.user)
|
|
|
|
cart_item, created = CartItem.objects.get_or_create(cart=cart, listing=listing)
|
|
if not created:
|
|
cart_item.quantity += 1
|
|
cart_item.save()
|
|
|
|
return redirect('store:cart')
|
|
|
|
@login_required
|
|
def cart_view(request):
|
|
try:
|
|
cart = request.user.cart
|
|
except Cart.DoesNotExist:
|
|
cart = None
|
|
return render(request, 'store/cart.html', {'cart': cart})
|
|
|
|
@login_required
|
|
def remove_from_cart(request, item_id):
|
|
if hasattr(request.user, 'cart'):
|
|
item = get_object_or_404(CartItem, id=item_id, cart=request.user.cart)
|
|
item.delete()
|
|
return redirect('store:cart')
|
|
|
|
@login_required
|
|
def toggle_insurance(request):
|
|
if hasattr(request.user, 'cart'):
|
|
cart = request.user.cart
|
|
cart.insurance = not cart.insurance
|
|
cart.save()
|
|
return redirect('store:cart')
|
|
|
|
from django.http import JsonResponse
|
|
|
|
def get_card_stock(request, card_id):
|
|
card = get_object_or_404(Card, id=card_id)
|
|
listings = card.listings.all()
|
|
stock_breakdown = {}
|
|
total_stock = 0
|
|
for listing in listings:
|
|
stock_breakdown[listing.get_condition_display()] = listing.quantity
|
|
total_stock += listing.quantity
|
|
|
|
return JsonResponse({
|
|
'card_id': card.id,
|
|
'total_stock': total_stock,
|
|
'breakdown': stock_breakdown
|
|
})
|
|
|
|
from .utils import parse_deck_list, find_best_listings_for_deck, get_user_collection, filter_deck_by_collection, add_to_vault
|
|
|
|
@login_required
|
|
def deck_buyer(request):
|
|
if request.method == 'POST':
|
|
action = request.POST.get('action')
|
|
|
|
if action == 'preview':
|
|
deck_text = request.POST.get('deck_text')
|
|
ignore_owned = request.POST.get('ignore_owned') == 'on'
|
|
|
|
parsed = parse_deck_list(deck_text)
|
|
|
|
if ignore_owned and request.user.is_authenticated:
|
|
owned = get_user_collection(request.user)
|
|
parsed = filter_deck_by_collection(parsed, owned)
|
|
|
|
found, missing = find_best_listings_for_deck(parsed)
|
|
|
|
total_cost = sum(item['total'] for item in found)
|
|
|
|
return render(request, 'store/deck_buyer.html', {
|
|
'found_items': found,
|
|
'missing_items': missing,
|
|
'deck_text': deck_text,
|
|
'total_cost': total_cost,
|
|
'preview': True,
|
|
'ignore_owned': ignore_owned
|
|
})
|
|
|
|
elif action == 'add_to_cart':
|
|
# Re-parse or rely on hidden fields?
|
|
# Re-parsing is safer/easier for now than passing complex data
|
|
deck_text = request.POST.get('deck_text')
|
|
parsed = parse_deck_list(deck_text)
|
|
found, _ = find_best_listings_for_deck(parsed)
|
|
|
|
cart, _ = Cart.objects.get_or_create(user=request.user)
|
|
|
|
count = 0
|
|
for item in found:
|
|
listing = item['listing']
|
|
qty = item['quantity']
|
|
# Check stock again? "Live stock"
|
|
if listing.quantity >= qty:
|
|
cart_item, created = CartItem.objects.get_or_create(cart=cart, listing=listing)
|
|
if not created:
|
|
cart_item.quantity += qty
|
|
else:
|
|
cart_item.quantity = qty
|
|
cart_item.save()
|
|
count += 1
|
|
|
|
return redirect('store:cart')
|
|
|
|
return render(request, 'store/deck_buyer.html')
|
|
|
|
from .models import Bounty
|
|
|
|
def bounty_board(request):
|
|
bounties = Bounty.objects.filter(is_active=True).select_related('card', 'card__set').order_by('-created_at')
|
|
return render(request, 'store/bounty_board.html', {'bounties': bounties})
|
|
|
|
def pack_list(request):
|
|
packs = PackListing.objects.all()
|
|
return render(request, 'store/pack_list.html', {'packs': packs})
|
|
|
|
@login_required
|
|
def add_pack_to_cart(request, pack_listing_id):
|
|
listing = get_object_or_404(PackListing, id=pack_listing_id)
|
|
cart, _ = Cart.objects.get_or_create(user=request.user)
|
|
|
|
cart_item, created = CartItem.objects.get_or_create(cart=cart, pack_listing=listing)
|
|
if not created:
|
|
cart_item.quantity += 1
|
|
cart_item.save()
|
|
|
|
return redirect('store:cart')
|
|
|
|
@login_required
|
|
def checkout(request):
|
|
try:
|
|
cart = request.user.cart
|
|
except Cart.DoesNotExist:
|
|
return redirect('store:cart')
|
|
|
|
if not cart.items.exists():
|
|
return redirect('store:cart')
|
|
|
|
# Create Order
|
|
order = Order.objects.create(
|
|
user=request.user,
|
|
status='paid',
|
|
total_price=cart.total_price
|
|
)
|
|
|
|
# Move items
|
|
for item in cart.items.all():
|
|
OrderItem.objects.create(
|
|
order=order,
|
|
listing=item.listing,
|
|
pack_listing=item.pack_listing,
|
|
price_at_purchase=item.listing.price if item.listing else item.pack_listing.price,
|
|
quantity=item.quantity
|
|
)
|
|
|
|
# Add single cards to vault
|
|
if item.listing:
|
|
add_to_vault(request.user, item.listing.card, item.quantity)
|
|
|
|
# If it's a pack, assign VirtualPacks to user
|
|
if item.pack_listing:
|
|
# Find available sealed packs
|
|
available_packs = list(VirtualPack.objects.filter(
|
|
listing=item.pack_listing,
|
|
owner__isnull=True,
|
|
status='sealed'
|
|
)[:item.quantity])
|
|
|
|
# If not enough, create more
|
|
if len(available_packs) < item.quantity:
|
|
needed = item.quantity - len(available_packs)
|
|
game = item.pack_listing.game
|
|
all_game_cards = list(Card.objects.filter(set__game=game))
|
|
if not all_game_cards:
|
|
# Fallback if no cards? Should not happen due to management command or basic setup
|
|
pass
|
|
|
|
for _ in range(needed):
|
|
pack = VirtualPack.objects.create(listing=item.pack_listing)
|
|
if all_game_cards:
|
|
pack.cards.set(random.sample(all_game_cards, min(len(all_game_cards), 5)))
|
|
available_packs.append(pack)
|
|
|
|
for pack in available_packs:
|
|
pack.owner = request.user
|
|
pack.save()
|
|
|
|
# Clear cart
|
|
cart.items.all().delete()
|
|
|
|
return redirect('store:my_packs')
|
|
|
|
@login_required
|
|
def my_packs(request):
|
|
packs = VirtualPack.objects.filter(owner=request.user, status='sealed').select_related('listing')
|
|
return render(request, 'store/my_packs.html', {'packs': packs})
|
|
|
|
@login_required
|
|
def open_pack(request, pack_id):
|
|
pack = get_object_or_404(VirtualPack, id=pack_id, owner=request.user)
|
|
|
|
if request.method == 'POST':
|
|
if pack.status == 'sealed':
|
|
pack.status = 'opened'
|
|
pack.save()
|
|
|
|
# Add cards to vault
|
|
for card in pack.cards.all():
|
|
add_to_vault(request.user, card)
|
|
|
|
data = {
|
|
'cards': [{
|
|
'name': c.name,
|
|
'image_url': c.image_url,
|
|
'rarity': c.rarity,
|
|
'set': c.set.name
|
|
} for c in pack.cards.all()]
|
|
}
|
|
return JsonResponse(data)
|
|
|
|
|
|
return render(request, 'store/open_pack.html', {'pack': pack})
|
|
|
|
@login_required
|
|
def order_detail(request, order_id):
|
|
order = get_object_or_404(Order, id=order_id)
|
|
# Security check: only allow viewing own orders (unless superuser)
|
|
if order.user != request.user and not request.user.is_superuser:
|
|
return redirect('users:profile')
|
|
|
|
return render(request, 'store/order_detail.html', {'order': order})
|
|
|