Files
santeh-ray/orders/views.py
Azimkin 52cbc1c2b3
All checks were successful
Build and Push Docker Image / build (push) Successful in 42s
feat: implement shopping cart feature with user authentication support
- Added `Cart` and `CartItem` models with migrations for managing user-specific carts and items
- Developed services for cart-related operations: adding, removing, and updating cart items
- Built specialized templates (`cart.html`) and styled them with new CSS assets (`cart.css`)
- Enabled real-time UI updates via AJAX in shopping cart interactions (`cart.js`)
- Modified header to dynamically display cart link with user authentication awareness
- Added Leaflet-based interactive map to the contacts page and integrated CSS/JS dependencies
- Expanded tests for cart functionality, item detail page cart integration, and contacts page maps
2026-05-15 23:18:16 +02:00

107 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from decimal import Decimal
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from django.http import Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.http import url_has_allowed_host_and_scheme
from django.views.decorators.http import require_POST
from items.models import Item
from orders.models import CartItem
from orders.services import (
add_item_to_cart,
format_currency,
get_user_cart,
remove_item_from_cart,
update_cart_item_quantity,
)
def resolve_next_url(request: HttpRequest, fallback: str) -> str:
next_url = request.POST.get("next") or fallback
if not url_has_allowed_host_and_scheme(
next_url,
allowed_hosts={request.get_host()},
require_https=request.is_secure(),
):
return fallback
return next_url
@login_required
def cart(request: HttpRequest) -> HttpResponse:
cart_items: list[CartItem] = []
total_quantity = 0
total_amount = "0,00 руб."
cart_obj = get_user_cart(request.user)
if cart_obj:
cart_items = list(
cart_obj.items.select_related("item__category", "item__subcategory").prefetch_related("item__images")
)
total_quantity = sum(cart_item.quantity for cart_item in cart_items)
total_amount_value = sum(
(cart_item.item.price * cart_item.quantity for cart_item in cart_items),
start=Decimal("0.00"),
)
total_amount = format_currency(total_amount_value)
return render(request, "orders/cart.html", {
"cart_items": cart_items,
"total_quantity": total_quantity,
"total_amount": total_amount,
})
@login_required
@require_POST
def add(request: HttpRequest) -> HttpResponse:
item = get_object_or_404(Item, pk=request.POST.get("item_id"))
try:
_, created = add_item_to_cart(request.user, item)
if created:
messages.success(request, f"Товар «{item.name}» добавлен в корзину.")
else:
messages.info(request, f"Товар «{item.name}» уже есть в корзине.")
except ValidationError as error:
messages.error(request, error.message)
return redirect(resolve_next_url(request, reverse("orders:cart")))
@login_required
@require_POST
def remove(request: HttpRequest) -> HttpResponse:
item = get_object_or_404(Item, pk=request.POST.get("item_id"))
removed = remove_item_from_cart(request.user, item.id)
if removed:
messages.success(request, f"Товар «{item.name}» удалён из корзины.")
else:
messages.info(request, f"Товар «{item.name}» уже отсутствует в корзине.")
return redirect(resolve_next_url(request, reverse("orders:cart")))
@login_required
@require_POST
def update_quantity(request: HttpRequest) -> HttpResponse:
item = get_object_or_404(Item, pk=request.POST.get("item_id"))
try:
quantity = int(request.POST.get("quantity"))
update_cart_item_quantity(request.user, item.id, quantity)
messages.success(request, f"Количество товара «{item.name}» обновлено.")
except (TypeError, ValueError):
messages.error(request, "Некорректное количество товара.")
except CartItem.DoesNotExist as error:
raise Http404() from error
except ValidationError as error:
messages.error(request, error.message)
return redirect(resolve_next_url(request, reverse("orders:cart")))