378 lines
13 KiB
Python
378 lines
13 KiB
Python
from django.shortcuts import render, get_object_or_404, redirect
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth import login
|
|
from .models import Category, Product, Vendor, Order, OrderItem, Profile, ProductReview, ProductImage, Article
|
|
from .forms import ProductForm, SignUpForm # Added SignUpForm
|
|
from django.contrib import messages
|
|
from django.db.models import Q, Avg
|
|
|
|
def home(request):
|
|
categories = Category.objects.all()[:6]
|
|
featured_products = Product.objects.filter(is_available=True)[:8]
|
|
new_arrivals = Product.objects.filter(is_available=True).order_by('-created_at')[:8]
|
|
|
|
selected_kebele = request.GET.get('kebele')
|
|
local_vendors = Vendor.objects.filter(is_verified=True)
|
|
if selected_kebele:
|
|
local_vendors = local_vendors.filter(kebele=selected_kebele)
|
|
local_vendors = local_vendors[:4]
|
|
|
|
latest_articles = Article.objects.filter(is_published=True).order_by('-created_at')[:3]
|
|
kebeles = [k[0] for k in Vendor.JIMMA_KEBELES]
|
|
|
|
return render(request, 'core/index.html', {
|
|
'categories': categories,
|
|
'featured_products': featured_products,
|
|
'new_arrivals': new_arrivals,
|
|
'local_vendors': local_vendors,
|
|
'latest_articles': latest_articles,
|
|
'kebeles': kebeles,
|
|
'selected_kebele': selected_kebele,
|
|
})
|
|
|
|
def signup(request):
|
|
if request.method == 'POST':
|
|
form = SignUpForm(request.POST)
|
|
if form.is_valid():
|
|
user = form.save()
|
|
login(request, user)
|
|
messages.success(request, "Registration successful. Welcome to Jimma Market!")
|
|
return redirect('index')
|
|
else:
|
|
form = SignUpForm()
|
|
return render(request, 'registration/signup.html', {'form': form})
|
|
|
|
def product_list(request):
|
|
query = request.GET.get('q')
|
|
category_slug = request.GET.get('category')
|
|
sort = request.GET.get('sort')
|
|
kebele = request.GET.get('kebele')
|
|
|
|
products = Product.objects.filter(is_available=True)
|
|
|
|
if query:
|
|
products = products.filter(
|
|
Q(name__icontains=query) |
|
|
Q(description__icontains=query)
|
|
)
|
|
|
|
if category_slug:
|
|
products = products.filter(category__slug=category_slug)
|
|
|
|
if kebele:
|
|
products = products.filter(vendor__kebele=kebele)
|
|
|
|
if sort == 'price_low':
|
|
products = products.order_by('price')
|
|
elif sort == 'price_high':
|
|
products = products.order_by('-price')
|
|
elif sort == 'newest':
|
|
products = products.order_by('-created_at')
|
|
|
|
categories = Category.objects.all()
|
|
kebeles = [k[0] for k in Vendor.JIMMA_KEBELES]
|
|
|
|
return render(request, 'core/product_list.html', {
|
|
'products': products,
|
|
'categories': categories,
|
|
'kebeles': kebeles,
|
|
'current_category': category_slug,
|
|
'current_sort': sort,
|
|
'current_kebele': kebele,
|
|
})
|
|
|
|
def product_detail(request, slug):
|
|
product = get_object_or_404(Product, slug=slug, is_available=True)
|
|
related_products = Product.objects.filter(category=product.category).exclude(id=product.id)[:4]
|
|
reviews = product.reviews.all().order_by('-created_at')
|
|
|
|
return render(request, 'core/product_detail.html', {
|
|
'product': product,
|
|
'related_products': related_products,
|
|
'reviews': reviews,
|
|
})
|
|
|
|
def product_review_submit(request, product_id):
|
|
if request.method == 'POST':
|
|
product = get_object_or_404(Product, id=product_id)
|
|
rating = request.POST.get('rating')
|
|
comment = request.POST.get('comment')
|
|
full_name = request.POST.get('full_name', 'Anonymous')
|
|
|
|
if request.user.is_authenticated:
|
|
full_name = f"{request.user.first_name} {request.user.last_name}".strip() or request.user.username
|
|
|
|
ProductReview.objects.create(
|
|
product=product,
|
|
user=request.user if request.user.is_authenticated else None,
|
|
full_name=full_name,
|
|
rating=rating,
|
|
comment=comment
|
|
)
|
|
messages.success(request, "Thank you for your review!")
|
|
return redirect('product_detail', slug=product.slug)
|
|
|
|
def category_products(request, slug):
|
|
category = get_object_or_404(Category, slug=slug)
|
|
products = category.products.filter(is_available=True)
|
|
|
|
kebele = request.GET.get('kebele')
|
|
if kebele:
|
|
products = products.filter(vendor__kebele=kebele)
|
|
|
|
kebeles = [k[0] for k in Vendor.JIMMA_KEBELES]
|
|
|
|
return render(request, 'core/category_products.html', {
|
|
'category': category,
|
|
'products': products,
|
|
'kebeles': kebeles,
|
|
'current_kebele': kebele
|
|
})
|
|
|
|
# Basic Cart System using Session
|
|
def get_cart(request):
|
|
cart = request.session.get('cart', {})
|
|
return cart
|
|
|
|
def cart_add(request, product_id):
|
|
cart = get_cart(request)
|
|
product_id_str = str(product_id)
|
|
quantity = int(request.POST.get('quantity', 1))
|
|
|
|
if product_id_str in cart:
|
|
cart[product_id_str] += quantity
|
|
else:
|
|
cart[product_id_str] = quantity
|
|
|
|
request.session['cart'] = cart
|
|
messages.success(request, "Product added to cart")
|
|
return redirect('cart_detail')
|
|
|
|
def cart_remove(request, product_id):
|
|
cart = get_cart(request)
|
|
product_id_str = str(product_id)
|
|
if product_id_str in cart:
|
|
del cart[product_id_str]
|
|
request.session['cart'] = cart
|
|
return redirect('cart_detail')
|
|
|
|
def cart_detail(request):
|
|
cart = get_cart(request)
|
|
cart_items = []
|
|
total = 0
|
|
for product_id, quantity in cart.items():
|
|
try:
|
|
product = Product.objects.get(id=product_id)
|
|
subtotal = product.price * quantity
|
|
total += subtotal
|
|
cart_items.append({'product': product, 'quantity': quantity, 'subtotal': subtotal})
|
|
except Product.DoesNotExist:
|
|
continue
|
|
return render(request, 'core/cart_detail.html', {'cart_items': cart_items, 'total': total})
|
|
|
|
def checkout(request):
|
|
cart = get_cart(request)
|
|
if not cart:
|
|
return redirect('product_list')
|
|
|
|
if request.method == 'POST':
|
|
full_name = request.POST.get('full_name')
|
|
email = request.POST.get('email')
|
|
phone = request.POST.get('phone')
|
|
address = request.POST.get('address')
|
|
kebele = request.POST.get('kebele')
|
|
delivery_time_slot = request.POST.get('delivery_time_slot')
|
|
payment_method = request.POST.get('payment_method')
|
|
|
|
total = 0
|
|
order_items_data = []
|
|
for product_id, quantity in cart.items():
|
|
product = get_object_or_404(Product, id=product_id)
|
|
total += product.price * quantity
|
|
order_items_data.append((product, quantity, product.price))
|
|
|
|
order = Order.objects.create(
|
|
user=request.user if request.user.is_authenticated else None,
|
|
full_name=full_name,
|
|
email=email,
|
|
phone=phone,
|
|
address=address,
|
|
kebele=kebele,
|
|
delivery_time_slot=delivery_time_slot,
|
|
total_price=total,
|
|
payment_method=payment_method
|
|
)
|
|
|
|
for product, quantity, price in order_items_data:
|
|
OrderItem.objects.create(order=order, product=product, quantity=quantity, price=price)
|
|
|
|
request.session['cart'] = {}
|
|
messages.success(request, "Order placed successfully!")
|
|
return redirect('order_success', order_id=order.id)
|
|
|
|
kebeles = Order.JIMMA_KEBELES
|
|
time_slots = Order.TIME_SLOTS
|
|
|
|
total = 0
|
|
for product_id, quantity in cart.items():
|
|
product = get_object_or_404(Product, id=product_id)
|
|
total += product.price * quantity
|
|
|
|
return render(request, 'core/checkout.html', {
|
|
'kebeles': kebeles,
|
|
'time_slots': time_slots,
|
|
'total': total,
|
|
})
|
|
|
|
def order_success(request, order_id):
|
|
order = get_object_or_404(Order, id=order_id)
|
|
return render(request, 'core/order_success.html', {'order': order})
|
|
|
|
@login_required
|
|
def vendor_register(request):
|
|
if hasattr(request.user, 'vendor'):
|
|
return redirect('vendor_dashboard')
|
|
|
|
if request.method == 'POST':
|
|
business_name = request.POST.get('business_name')
|
|
description = request.POST.get('description')
|
|
address = request.POST.get('address')
|
|
kebele = request.POST.get('kebele')
|
|
phone = request.POST.get('phone')
|
|
|
|
Vendor.objects.create(
|
|
user=request.user,
|
|
business_name=business_name,
|
|
description=description,
|
|
address=address,
|
|
kebele=kebele,
|
|
phone=phone
|
|
)
|
|
# Update user role
|
|
profile, created = Profile.objects.get_or_create(user=request.user)
|
|
profile.role = 'seller'
|
|
profile.save()
|
|
|
|
messages.success(request, "Vendor registration successful. Wait for admin verification.")
|
|
return redirect('vendor_dashboard')
|
|
|
|
return render(request, 'core/vendor_register.html', {'kebeles': Vendor.JIMMA_KEBELES})
|
|
|
|
@login_required
|
|
def vendor_dashboard(request):
|
|
vendor = get_object_or_404(Vendor, user=request.user)
|
|
products = vendor.products.all().order_by('-created_at')
|
|
|
|
# Get all orders that contain products from this vendor
|
|
# We use a set of order IDs to avoid duplicates if multiple products from same vendor in one order
|
|
vendor_order_items = OrderItem.objects.filter(product__vendor=vendor).select_related('order', 'product').order_by('-order__created_at')
|
|
|
|
return render(request, 'core/vendor_dashboard.html', {
|
|
'vendor': vendor,
|
|
'products': products,
|
|
'order_items': vendor_order_items
|
|
})
|
|
|
|
@login_required
|
|
def vendor_product_add(request):
|
|
vendor = get_object_or_404(Vendor, user=request.user)
|
|
if request.method == 'POST':
|
|
form = ProductForm(request.POST, request.FILES)
|
|
if form.is_valid():
|
|
product = form.save(commit=False)
|
|
product.vendor = vendor
|
|
product.save()
|
|
messages.success(request, "Product added successfully!")
|
|
return redirect('vendor_dashboard')
|
|
else:
|
|
form = ProductForm()
|
|
|
|
return render(request, 'core/vendor_product_form.html', {'form': form, 'title': 'Add New Product'})
|
|
|
|
@login_required
|
|
def vendor_product_edit(request, pk):
|
|
vendor = get_object_or_404(Vendor, user=request.user)
|
|
product = get_object_or_404(Product, pk=pk, vendor=vendor)
|
|
|
|
if request.method == 'POST':
|
|
form = ProductForm(request.POST, request.FILES, instance=product)
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, "Product updated successfully!")
|
|
return redirect('vendor_dashboard')
|
|
else:
|
|
form = ProductForm(instance=product)
|
|
|
|
return render(request, 'core/vendor_product_form.html', {'form': form, 'title': f'Edit {product.name}'})
|
|
|
|
@login_required
|
|
def vendor_product_delete(request, pk):
|
|
vendor = get_object_or_404(Vendor, user=request.user)
|
|
product = get_object_or_404(Product, pk=pk, vendor=vendor)
|
|
|
|
if request.method == 'POST':
|
|
product.delete()
|
|
messages.success(request, "Product deleted successfully!")
|
|
return redirect('vendor_dashboard')
|
|
|
|
return render(request, 'core/vendor_product_confirm_delete.html', {'product': product})
|
|
|
|
@login_required
|
|
def vendor_order_status_update(request, order_id):
|
|
vendor = get_object_or_404(Vendor, user=request.user)
|
|
order = get_object_or_404(Order, id=order_id)
|
|
|
|
# Check if this vendor has products in this order
|
|
if not OrderItem.objects.filter(order=order, product__vendor=vendor).exists():
|
|
messages.error(request, "You don't have permission to update this order.")
|
|
return redirect('vendor_dashboard')
|
|
|
|
if request.method == 'POST':
|
|
new_status = request.POST.get('status')
|
|
if new_status in dict(Order.STATUS_CHOICES):
|
|
order.status = new_status
|
|
order.save()
|
|
messages.success(request, f"Order status updated to {new_status}")
|
|
|
|
return redirect('vendor_dashboard')
|
|
|
|
# Essential Pages
|
|
def about_us(request):
|
|
return render(request, 'core/about_us.html')
|
|
|
|
def how_it_works(request):
|
|
return render(request, 'core/how_it_works.html')
|
|
|
|
def seller_info(request):
|
|
return render(request, 'core/seller_info.html')
|
|
|
|
def delivery_info(request):
|
|
return render(request, 'core/delivery_info.html')
|
|
|
|
def contact_us(request):
|
|
if request.method == 'POST':
|
|
messages.success(request, "Thank you for your message. We will get back to you soon!")
|
|
return redirect('contact_us')
|
|
return render(request, 'core/contact_us.html')
|
|
|
|
def track_order(request):
|
|
order = None
|
|
if request.method == 'POST':
|
|
order_id = request.POST.get('order_id')
|
|
phone = request.POST.get('phone')
|
|
try:
|
|
order = Order.objects.get(id=order_id, phone=phone)
|
|
except (Order.DoesNotExist, ValueError):
|
|
messages.error(request, "Order not found. Please check your order ID and phone number.")
|
|
|
|
return render(request, 'core/track_order.html', {'order': order})
|
|
|
|
# Blog/Article Views
|
|
def article_list(request):
|
|
articles = Article.objects.filter(is_published=True).order_by('-created_at')
|
|
return render(request, 'core/article_list.html', {'articles': articles})
|
|
|
|
def article_detail(request, slug):
|
|
article = get_object_or_404(Article, slug=slug, is_published=True)
|
|
return render(request, 'core/article_detail.html', {'article': article})
|