Files
Example-TCG-Site/store/utils.py
2026-01-20 05:22:38 -06:00

134 lines
4.0 KiB
Python

import re
from .models import Card, CardListing, Order, OrderItem, VaultItem
from django.db.models import Min
def add_to_vault(user, card, quantity=1):
"""
Adds a card to the user's vault.
"""
vault_item, created = VaultItem.objects.get_or_create(user=user, card=card)
if not created:
vault_item.quantity += quantity
else:
vault_item.quantity = quantity
vault_item.save()
def parse_deck_list(deck_text):
"""
Parses a deck list string and returns a list of dictionaries with 'quantity' and 'name'.
Format expected: "4 Lightning Bolt" or "1x Lightning Bolt"
"""
lines = deck_text.strip().split('\n')
parsed_cards = []
for line in lines:
line = line.strip()
if not line:
continue
match = re.match(r'^(\d+)[xX]?\s+(.+)$', line)
if match:
quantity = int(match.group(1))
name = match.group(2).strip()
parsed_cards.append({'quantity': quantity, 'name': name})
else:
# Maybe just name? assume 1
parsed_cards.append({'quantity': 1, 'name': line})
return parsed_cards
def find_best_listings_for_deck(parsed_cards):
"""
Finds cheapest listings for the parsed cards.
Returns:
- found_items: list of {listing, quantity_needed, total_cost, card_name}
- missing_items: list of {name, quantity}
"""
found_items = []
missing_items = []
for item in parsed_cards:
name = item['name']
qty_needed = item['quantity']
# Find card (simple name match)
cards = Card.objects.filter(name__iexact=name)
if not cards.exists():
# Try contains
cards = Card.objects.filter(name__icontains=name)
if not cards.exists():
missing_items.append(item)
continue
# Find cheapest listing with stock
# We try to fill the quantity from multiple listings if needed
listings = CardListing.objects.filter(
card__in=cards,
quantity__gt=0
).order_by('price')
qty_remaining = qty_needed
for listing in listings:
if qty_remaining <= 0:
break
qty_to_take = min(listing.quantity, qty_remaining)
found_items.append({
'listing': listing,
'quantity': qty_to_take,
'card_name': listing.card.name,
'price': listing.price,
'total': listing.price * qty_to_take
})
qty_remaining -= qty_to_take
if qty_remaining > 0:
missing_items.append({'name': name, 'quantity': qty_remaining})
return found_items, missing_items
def get_user_collection(user):
"""
Returns a dict {card_name: quantity} of cards in user's vault.
"""
owned = {}
if not user.is_authenticated:
return owned
vault_items = VaultItem.objects.filter(user=user).select_related('card')
for item in vault_items:
owned[item.card.name] = item.quantity
return owned
def filter_deck_by_collection(parsed_cards, owned_cards):
"""
Subtracts owned quantities from parsed_cards.
Returns new list of parsed_cards.
"""
filtered = []
for item in parsed_cards:
name = item['name']
needed = item['quantity']
# Simple name match
owned_qty = 0
# Try exact match first
if name in owned_cards:
owned_qty = owned_cards[name]
else:
# Try case insensitive fallback
for key in owned_cards:
if key.lower() == name.lower():
owned_qty = owned_cards[key]
break
remaining = needed - owned_qty
if remaining > 0:
filtered.append({'name': name, 'quantity': remaining})
return filtered