feat: implement shopping cart feature with user authentication support
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
This commit is contained in:
2026-05-15 23:18:16 +02:00
parent d2126e0fba
commit 52cbc1c2b3
22 changed files with 1317 additions and 18 deletions

View File

@@ -54,3 +54,35 @@ class MediaUrlTests(SimpleTestCase):
self.assertEqual(match.func.__module__, "django.views.static")
self.assertEqual(match.func.__name__, "serve")
class ContactsPageTests(TestCase):
def test_contacts_page_renders_contact_details(self):
response = self.client.get(reverse("contacts"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "КОНТАКТЫ")
self.assertContains(response, "Беларусь, г. Минск, ул. Тимирязева, д. 123, к.1, пав. 59")
self.assertContains(response, "info@santehray.by")
self.assertContains(response, "+375 (29) 688-18-19")
self.assertContains(response, "+375 (33) 337-67-81")
def test_contacts_page_includes_leaflet_map_assets(self):
response = self.client.get(reverse("contacts"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css")
self.assertContains(response, "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js")
self.assertContains(response, 'id="contacts-map"', html=False)
self.assertContains(response, "L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'")
self.assertContains(response, "OpenStreetMap")
def test_contacts_page_does_not_include_yandex_api(self):
response = self.client.get(reverse("contacts"))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, "api-maps.yandex.ru")
self.assertNotContains(response, "YANDEX_MAPS_API_KEY")
self.assertContains(response, 'data-lat="53.9334960"', html=False)
self.assertContains(response, 'data-lon="27.4551021"', html=False)
self.assertContains(response, "Открыть адрес в OpenStreetMap")

View File

@@ -11,6 +11,19 @@ from home.forms import FaqQuestionForm
logger = logging.getLogger(__name__)
CONTACT_ADDRESS = "Беларусь, г. Минск, ул. Тимирязева, д. 123, к.1, пав. 59"
CONTACT_EMAIL = "info@santehray.by"
CONTACT_PHONE_PRIMARY = "+375 (29) 688-18-19"
CONTACT_PHONE_PRIMARY_URL = "+375296881819"
CONTACT_PHONE_SECONDARY = "+375 (33) 337-67-81"
CONTACT_PHONE_SECONDARY_URL = "+375333376781"
CONTACT_HOURS_WEEKDAYS = "Пн-Пт: 9.00 - 21.00"
CONTACT_HOURS_WEEKENDS = "Сб-Вс: 10.00 - 18.00"
CONTACT_MAP_CENTER = {"lat": "53.9334960", "lon": "27.4551021", "zoom": 15}
CONTACT_MAP_EXTERNAL_URL = (
"https://www.openstreetmap.org/?mlat=53.9334960&mlon=27.4551021#map=15/53.9334960/27.4551021"
)
def index(request):
form = FaqQuestionForm(request.POST or None)
@@ -58,4 +71,18 @@ def warranty(request):
def contacts(request):
return render(request=request, template_name='home/contacts.html', context={})
context = {
"contact_address": CONTACT_ADDRESS,
"contact_email": CONTACT_EMAIL,
"contact_phone_primary": CONTACT_PHONE_PRIMARY,
"contact_phone_primary_url": CONTACT_PHONE_PRIMARY_URL,
"contact_phone_secondary": CONTACT_PHONE_SECONDARY,
"contact_phone_secondary_url": CONTACT_PHONE_SECONDARY_URL,
"contact_hours_weekdays": CONTACT_HOURS_WEEKDAYS,
"contact_hours_weekends": CONTACT_HOURS_WEEKENDS,
"map_lat": CONTACT_MAP_CENTER["lat"],
"map_lon": CONTACT_MAP_CENTER["lon"],
"map_zoom": CONTACT_MAP_CENTER["zoom"],
"map_external_url": CONTACT_MAP_EXTERNAL_URL,
}
return render(request=request, template_name='home/contacts.html', context=context)