Last bit of major changes
Closes #1 Closes #5 Closes #6 Closes #8 Closes #9 Closes #10
This commit is contained in:
276
store/views.py
276
store/views.py
@@ -1,4 +1,5 @@
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.contrib import messages
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.core.paginator import Paginator
|
||||
@@ -6,7 +7,7 @@ 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, Length
|
||||
from .forms import SellerRegistrationForm, CardListingForm, PackListingForm, AddCardListingForm, SellerEditForm, BountyForm, BountyOfferForm, BulkListingForm
|
||||
from .forms import SellerRegistrationForm, CardListingForm, PackListingForm, AddCardListingForm, SellerEditForm, BountyForm, BountyOfferForm, BulkListingForm, CheckoutForm
|
||||
from django.utils.text import slugify
|
||||
import random
|
||||
import csv
|
||||
@@ -367,6 +368,11 @@ def bounty_create(request):
|
||||
return redirect('store:seller_register')
|
||||
|
||||
seller = request.user.seller_profile
|
||||
|
||||
# Check for profile completion
|
||||
if not seller.tax_id or not seller.payout_details:
|
||||
messages.error(request, "You must complete your seller profile (Tax ID and Payout Details) before posting a bounty.")
|
||||
return redirect('store:edit_seller_profile')
|
||||
|
||||
if request.method == 'POST':
|
||||
form = BountyForm(request.POST)
|
||||
@@ -512,109 +518,116 @@ def checkout(request):
|
||||
if not cart.items.exists():
|
||||
return redirect('store:cart')
|
||||
|
||||
# Group items by seller and check for virtual packs
|
||||
items_by_seller = {}
|
||||
has_virtual_packs = False
|
||||
for item in cart.items.all():
|
||||
if item.pack_listing and item.pack_listing.listing_type == 'virtual':
|
||||
has_virtual_packs = True
|
||||
seller = None
|
||||
if item.listing and item.listing.seller:
|
||||
seller = item.listing.seller
|
||||
elif item.pack_listing and item.pack_listing.seller:
|
||||
seller = item.pack_listing.seller
|
||||
if request.method == 'POST':
|
||||
form = CheckoutForm(request.POST, user=request.user)
|
||||
if form.is_valid():
|
||||
shipping_address = form.cleaned_data['shipping_address']
|
||||
|
||||
if seller not in items_by_seller:
|
||||
items_by_seller[seller] = []
|
||||
items_by_seller[seller].append(item)
|
||||
# Group items by seller and check for virtual packs
|
||||
items_by_seller = {}
|
||||
has_virtual_packs = False
|
||||
for item in cart.items.all():
|
||||
if item.pack_listing and item.pack_listing.listing_type == 'virtual':
|
||||
has_virtual_packs = True
|
||||
seller = None
|
||||
if item.listing and item.listing.seller:
|
||||
seller = item.listing.seller
|
||||
elif item.pack_listing and item.pack_listing.seller:
|
||||
seller = item.pack_listing.seller
|
||||
|
||||
if seller not in items_by_seller:
|
||||
items_by_seller[seller] = []
|
||||
items_by_seller[seller].append(item)
|
||||
|
||||
# Process orders per seller
|
||||
for seller, items in items_by_seller.items():
|
||||
sub_total = sum(item.total_price for item in items)
|
||||
shipping_cost = 0
|
||||
|
||||
if seller:
|
||||
if sub_total < seller.minimum_order_amount:
|
||||
shipping_cost = seller.shipping_cost
|
||||
|
||||
total_price = sub_total + shipping_cost
|
||||
|
||||
# Format Address Snapshot
|
||||
addr_str = f"{shipping_address.name}\n{shipping_address.street}\n{shipping_address.city}, {shipping_address.state} {shipping_address.zip_code}"
|
||||
|
||||
# Create Order (status paid for MVP)
|
||||
order = Order.objects.create(
|
||||
buyer=request.user.buyer_profile,
|
||||
status='paid',
|
||||
total_price=total_price,
|
||||
seller=seller,
|
||||
shipping_address=addr_str
|
||||
)
|
||||
|
||||
for item in items:
|
||||
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
|
||||
)
|
||||
|
||||
# 1. Handle Card Listings
|
||||
if item.listing:
|
||||
add_to_vault(request.user.buyer_profile, item.listing.card, item.quantity)
|
||||
# Decrement Stock
|
||||
if item.listing.quantity >= item.quantity:
|
||||
item.listing.quantity -= item.quantity
|
||||
item.listing.save()
|
||||
else:
|
||||
item.listing.quantity = 0
|
||||
item.listing.save()
|
||||
|
||||
# 2. Handle Pack Listings
|
||||
if item.pack_listing:
|
||||
# Decrement Stock
|
||||
if item.pack_listing.quantity >= item.quantity:
|
||||
item.pack_listing.quantity -= item.quantity
|
||||
item.pack_listing.save()
|
||||
else:
|
||||
item.pack_listing.quantity = 0
|
||||
item.pack_listing.save()
|
||||
|
||||
# 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 ONLY if it's a system pack (no seller)
|
||||
if len(available_packs) < item.quantity:
|
||||
if item.pack_listing.seller:
|
||||
pass
|
||||
else:
|
||||
needed = item.quantity - len(available_packs)
|
||||
game = item.pack_listing.game
|
||||
all_game_cards = list(Card.objects.filter(set__game=game))
|
||||
|
||||
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.buyer_profile
|
||||
pack.save()
|
||||
|
||||
# Clear cart
|
||||
cart.items.all().delete()
|
||||
|
||||
if has_virtual_packs:
|
||||
return redirect('store:my_packs')
|
||||
return redirect('users:vault')
|
||||
else:
|
||||
form = CheckoutForm(user=request.user)
|
||||
|
||||
# Process orders per seller
|
||||
for seller, items in items_by_seller.items():
|
||||
sub_total = sum(item.total_price for item in items)
|
||||
shipping_cost = 0
|
||||
|
||||
if seller:
|
||||
if sub_total < seller.minimum_order_amount:
|
||||
shipping_cost = seller.shipping_cost
|
||||
|
||||
total_price = sub_total + shipping_cost
|
||||
|
||||
# Create Order (status paid for MVP)
|
||||
order = Order.objects.create(
|
||||
buyer=request.user.buyer_profile,
|
||||
status='paid',
|
||||
total_price=total_price,
|
||||
seller=seller # Populate seller
|
||||
)
|
||||
|
||||
for item in items:
|
||||
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
|
||||
)
|
||||
|
||||
# 1. Handle Card Listings
|
||||
if item.listing:
|
||||
add_to_vault(request.user.buyer_profile, item.listing.card, item.quantity)
|
||||
# Decrement Stock
|
||||
if item.listing.quantity >= item.quantity:
|
||||
item.listing.quantity -= item.quantity
|
||||
item.listing.save()
|
||||
else:
|
||||
# Stock issue handling (for now just take what's left or allow negative?
|
||||
# Ideally check before checkout. Assuming check happened at add-to-cart or cart-view)
|
||||
item.listing.quantity = 0
|
||||
item.listing.save()
|
||||
|
||||
# 2. Handle Pack Listings
|
||||
if item.pack_listing:
|
||||
# Decrement Stock
|
||||
if item.pack_listing.quantity >= item.quantity:
|
||||
item.pack_listing.quantity -= item.quantity
|
||||
item.pack_listing.save()
|
||||
else:
|
||||
item.pack_listing.quantity = 0
|
||||
item.pack_listing.save()
|
||||
|
||||
# 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 ONLY if it's a system pack (no seller) or configured to do so
|
||||
if len(available_packs) < item.quantity:
|
||||
# Seller packs must be pre-filled
|
||||
if item.pack_listing.seller:
|
||||
# We only fulfill what we have.
|
||||
# Ideally we should have caught this at cart validation.
|
||||
pass
|
||||
else:
|
||||
needed = item.quantity - len(available_packs)
|
||||
game = item.pack_listing.game
|
||||
all_game_cards = list(Card.objects.filter(set__game=game))
|
||||
|
||||
for _ in range(needed):
|
||||
pack = VirtualPack.objects.create(listing=item.pack_listing)
|
||||
if all_game_cards:
|
||||
# Sample logic (mock)
|
||||
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.buyer_profile
|
||||
pack.save()
|
||||
|
||||
# Clear cart
|
||||
cart.items.all().delete()
|
||||
|
||||
if has_virtual_packs:
|
||||
return redirect('store:my_packs')
|
||||
return redirect('users:vault')
|
||||
return render(request, 'store/checkout.html', {'form': form, 'cart': cart})
|
||||
|
||||
@login_required
|
||||
def my_packs(request):
|
||||
@@ -699,6 +712,27 @@ def seller_register(request):
|
||||
seller.user = request.user
|
||||
seller.slug = slugify(seller.store_name)
|
||||
seller.save()
|
||||
|
||||
# Create Address and link to seller
|
||||
from users.models import Address
|
||||
street = seller_form.cleaned_data.get('street')
|
||||
city = seller_form.cleaned_data.get('city')
|
||||
state = seller_form.cleaned_data.get('state')
|
||||
zip_code = seller_form.cleaned_data.get('zip_code')
|
||||
|
||||
if street and city:
|
||||
address = Address.objects.create(
|
||||
user=request.user,
|
||||
name=seller.store_name,
|
||||
street=street,
|
||||
city=city,
|
||||
state=state,
|
||||
zip_code=zip_code,
|
||||
address_type='shipping'
|
||||
)
|
||||
seller.store_address = address
|
||||
seller.save()
|
||||
|
||||
return redirect('store:seller_dashboard')
|
||||
else:
|
||||
user_form = CustomUserCreationForm(request.POST)
|
||||
@@ -712,6 +746,27 @@ def seller_register(request):
|
||||
seller.user = user
|
||||
seller.slug = slugify(seller.store_name)
|
||||
seller.save()
|
||||
|
||||
# Create Address and link to seller
|
||||
from users.models import Address
|
||||
street = seller_form.cleaned_data.get('street')
|
||||
city = seller_form.cleaned_data.get('city')
|
||||
state = seller_form.cleaned_data.get('state')
|
||||
zip_code = seller_form.cleaned_data.get('zip_code')
|
||||
|
||||
if street and city:
|
||||
address = Address.objects.create(
|
||||
user=user,
|
||||
name=seller.store_name,
|
||||
street=street,
|
||||
city=city,
|
||||
state=state,
|
||||
zip_code=zip_code,
|
||||
address_type='shipping'
|
||||
)
|
||||
seller.store_address = address
|
||||
seller.save()
|
||||
|
||||
return redirect('store:seller_dashboard')
|
||||
else:
|
||||
if request.user.is_authenticated:
|
||||
@@ -735,10 +790,9 @@ def edit_seller_profile(request):
|
||||
if request.method == 'POST':
|
||||
form = SellerEditForm(request.POST, request.FILES, instance=seller)
|
||||
if form.is_valid():
|
||||
seller = form.save(commit=False)
|
||||
if 'store_name' in form.changed_data:
|
||||
seller.slug = slugify(seller.store_name)
|
||||
seller.save()
|
||||
form.instance.slug = slugify(form.cleaned_data['store_name'])
|
||||
form.save()
|
||||
return redirect('store:seller_profile', slug=seller.slug)
|
||||
else:
|
||||
form = SellerEditForm(instance=seller)
|
||||
@@ -1057,7 +1111,7 @@ import csv # Added import
|
||||
import io # Added import
|
||||
|
||||
# ... existing imports ...
|
||||
from .forms import SellerRegistrationForm, CardListingForm, PackListingForm, AddCardListingForm, SellerEditForm, BountyForm, BountyOfferForm, BulkListingForm
|
||||
from .forms import SellerRegistrationForm, CardListingForm, PackListingForm, AddCardListingForm, SellerEditForm, BountyForm, BountyOfferForm, BulkListingForm, CheckoutForm
|
||||
|
||||
# ... [Keep existing code until add_card_listing] ...
|
||||
|
||||
@@ -1093,6 +1147,11 @@ def add_card_listing(request):
|
||||
except Seller.DoesNotExist:
|
||||
return redirect('store:seller_register')
|
||||
|
||||
# Check for profile completion
|
||||
if not seller.tax_id or not seller.payout_details:
|
||||
messages.error(request, "You must complete your seller profile (Tax ID and Payout Details) before listing items.")
|
||||
return redirect('store:edit_seller_profile')
|
||||
|
||||
bulk_form = BulkListingForm() # Initialize bulk form
|
||||
|
||||
if request.method == 'POST':
|
||||
@@ -1244,6 +1303,11 @@ def add_pack_listing(request):
|
||||
if not settings.FEATURE_VIRTUAL_PACKS:
|
||||
return redirect('store:manage_listings')
|
||||
seller = request.user.seller_profile
|
||||
|
||||
# Check for profile completion
|
||||
if not seller.tax_id or not seller.payout_details:
|
||||
messages.error(request, "You must complete your seller profile (Tax ID and Payout Details) before listing items.")
|
||||
return redirect('store:edit_seller_profile')
|
||||
|
||||
bulk_form = BulkListingForm()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user