All checks were successful
Build and Push Docker Image / build (push) Successful in 42s
- 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
107 lines
3.6 KiB
Python
107 lines
3.6 KiB
Python
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")))
|