mod: Рефакторинг страницы цен одного окна (вьюшки, шаблоны, тесты, новый canonical-роутинг)
This commit is contained in:
250
oknardia/web/test_prices.py
Normal file
250
oknardia/web/test_prices.py
Normal file
@@ -0,0 +1,250 @@
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import connection
|
||||
from django.http import HttpResponse
|
||||
from django.test import RequestFactory, TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from oknardia.models import (
|
||||
Apartment_Type,
|
||||
Glazing,
|
||||
MerchantBrand,
|
||||
MerchantOffice,
|
||||
MountDim2Apartment,
|
||||
OurUser,
|
||||
PVCprofiles,
|
||||
PriceOffer,
|
||||
Seria_Info,
|
||||
SetKit,
|
||||
)
|
||||
from web.prices import redirect_one_win_price_legacy, report_one_win_price
|
||||
|
||||
|
||||
class ReportOneWinPriceTests(TestCase):
|
||||
"""Регрессионные тесты для ORM-версии report_one_win_price."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.factory = RequestFactory()
|
||||
django_user = User.objects.create_user(username="price-tester", password="secret")
|
||||
self.our_user = OurUser.objects.create(kDjangoUser=django_user)
|
||||
|
||||
# Тестовая SQLite-схема в проекте может быть legacy-вариантом с flap_config вместо sFlapConfig.
|
||||
# Для тестов report_one_win_price явно добавляем sFlapConfig, чтобы код проверялся в целевом режиме.
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("PRAGMA table_info(oknardia_win_mountdim)")
|
||||
existing_columns = {row[1] for row in cursor.fetchall()}
|
||||
if "sFlapConfig" not in existing_columns:
|
||||
cursor.execute("ALTER TABLE oknardia_win_mountdim ADD COLUMN sFlapConfig varchar(32)")
|
||||
# if "flap_config" in existing_columns:
|
||||
# cursor.execute(
|
||||
# "UPDATE oknardia_win_mountdim SET sFlapConfig = flap_config "
|
||||
# "WHERE sFlapConfig IS NULL"
|
||||
# )
|
||||
|
||||
self.brand = MerchantBrand.objects.create(
|
||||
sMerchantName="Оконный бренд",
|
||||
sMerchantMainURL="https://example.com",
|
||||
)
|
||||
self.office = MerchantOffice.objects.create(
|
||||
sOfficeName="Оконный бренд — офис",
|
||||
kMerchantName=self.brand,
|
||||
sOfficePhones="+7(495)123-45-67",
|
||||
sOfficeAddress="Москва, Тестовая улица, 1",
|
||||
sOfficeDiscountMetaFormula="{'discount': {'10000': 5}}",
|
||||
)
|
||||
self.our_user.kMerchantOffice = self.office
|
||||
self.our_user.save(update_fields=["kMerchantOffice"])
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
insert_columns = [
|
||||
"iWinWidth",
|
||||
"iWinHight",
|
||||
"iWinDepth",
|
||||
"sFlapConfig",
|
||||
"sDescripion",
|
||||
"bIsDoor",
|
||||
"bIsNearDoor",
|
||||
"iWinLimit",
|
||||
"dMountXYZDataCreate",
|
||||
"dMountXYZModify",
|
||||
]
|
||||
insert_values = [
|
||||
Decimal("67.0"),
|
||||
Decimal("216.0"),
|
||||
Decimal("15.0"),
|
||||
"[>]",
|
||||
"Тестовый проём",
|
||||
0,
|
||||
0,
|
||||
Decimal("5.0"),
|
||||
]
|
||||
if "flap_config" in existing_columns:
|
||||
insert_columns.insert(3, "flap_config")
|
||||
insert_values.insert(3, "[>]")
|
||||
columns_sql = ", ".join(insert_columns)
|
||||
placeholders_sql = ", ".join(["?"] * len(insert_values)) + ", CURRENT_TIMESTAMP, CURRENT_TIMESTAMP"
|
||||
cursor.execute(
|
||||
f"INSERT INTO oknardia_win_mountdim ({columns_sql}) VALUES ({placeholders_sql})",
|
||||
insert_values,
|
||||
)
|
||||
self.window_id = cursor.lastrowid
|
||||
self.seria = Seria_Info.objects.create(sName="П-44")
|
||||
self.apartment = Apartment_Type.objects.create(
|
||||
sNameApartment="1-комнатная",
|
||||
kSeria=self.seria,
|
||||
)
|
||||
MountDim2Apartment.objects.create(
|
||||
kApartment=self.apartment,
|
||||
kMountDim_id=self.window_id,
|
||||
iQuantity=1,
|
||||
)
|
||||
|
||||
self.glazing = Glazing.objects.create(
|
||||
sGlazingName="Тестовый стеклопакет",
|
||||
sGlazingBriefDescription="Двухкамерный стеклопакет",
|
||||
sGlazingMark="4-10-4-10-4",
|
||||
sGlazingToning="нет",
|
||||
kGlazing2User=self.our_user,
|
||||
)
|
||||
self.profile = PVCprofiles.objects.create(
|
||||
sProfileName="Profile Test",
|
||||
sProfileBriefDescription="Профиль для теста",
|
||||
sProfileManufacturer="Test Manufacturer",
|
||||
sProfileSealDescription="чёрный",
|
||||
sProfileReinforcement="сталь",
|
||||
kProfile2User=self.our_user,
|
||||
fProfileRating=4.2,
|
||||
)
|
||||
self.set_kit = SetKit.objects.create(
|
||||
sSetName="Тестовый набор",
|
||||
kSet2User=self.our_user,
|
||||
kSet2PVCprofiles=self.profile,
|
||||
kSet2Glazing=self.glazing,
|
||||
sSetImplementAll="Фурнитура",
|
||||
sSetImplementHandles="Ручки",
|
||||
sSetImplementHinges="Петли",
|
||||
sSetImplementLatch="Запоры",
|
||||
sSetImplementLimiter="Ограничитель",
|
||||
sSetImplementCatch="Фиксатор",
|
||||
sSetSill="Подоконник",
|
||||
sSetSlope="Откос",
|
||||
sSetPanes="Отлив",
|
||||
sSetDelivery="Доставка",
|
||||
bSetDelivery=True,
|
||||
sSetUninstallInstall="Монтаж",
|
||||
bSetUninstallInstall=True,
|
||||
sSetOtherConditions="Прочие условия",
|
||||
sSetClimateControl="Климат",
|
||||
fSetRating=4.5,
|
||||
dSetCommercialUntil=timezone.now() + timedelta(days=30),
|
||||
)
|
||||
self.active_offer = PriceOffer.objects.create(
|
||||
kOffer2MountDim_id=self.window_id,
|
||||
kOfferFromUser=self.our_user,
|
||||
kOffer2SetKit=self.set_kit,
|
||||
sOfferFlapConfig="[>]",
|
||||
fOfferPrice=Decimal("12345.00"),
|
||||
sOfferActive=True,
|
||||
)
|
||||
self.archived_offer = PriceOffer.objects.create(
|
||||
kOffer2MountDim_id=self.window_id,
|
||||
kOfferFromUser=self.our_user,
|
||||
kOffer2SetKit=self.set_kit,
|
||||
sOfferFlapConfig="[<]",
|
||||
fOfferPrice=Decimal("11111.00"),
|
||||
sOfferActive=False,
|
||||
)
|
||||
|
||||
@patch("web.prices.get_last_all_user_visit_list", return_value=[])
|
||||
@patch("web.prices.get_last_user_visit_list", return_value=[])
|
||||
@patch("web.prices.get_last_user_visit_cookies", return_value=[])
|
||||
@patch("web.prices.get_flaps_for_mini_pictures", return_value="img/test-mini.png")
|
||||
@patch(
|
||||
"web.prices.get_flaps_for_big_pictures",
|
||||
return_value={
|
||||
"FLAP_DIM": [{
|
||||
"iWinWidth": Decimal("67.0"),
|
||||
"iWinHight": Decimal("216.0"),
|
||||
"iWinWidth_mm": 670,
|
||||
"iWinHight_mm": 2160,
|
||||
}],
|
||||
"WIN_DIM": [],
|
||||
},
|
||||
)
|
||||
def test_report_one_win_price_renders_expected_context(
|
||||
self,
|
||||
mocked_big_pictures,
|
||||
mocked_mini_pictures,
|
||||
mocked_cookies,
|
||||
mocked_last_visits,
|
||||
mocked_all_visits,
|
||||
):
|
||||
"""Вьюха должна собирать тот же ключевой контекст, но уже без raw SQL."""
|
||||
request = self.factory.get(
|
||||
f"/catalog/standard_opening/price-670x2160mm-tip{self.window_id}",
|
||||
)
|
||||
captured = {}
|
||||
|
||||
def fake_render(_request, template_name, context):
|
||||
captured["template_name"] = template_name
|
||||
captured["context"] = context
|
||||
return HttpResponse("ok")
|
||||
|
||||
with patch("web.prices.render", side_effect=fake_render):
|
||||
response = report_one_win_price(request, "670", "2160", str(self.window_id))
|
||||
|
||||
context = captured["context"]
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(captured["template_name"], "price/price_offers_for_one_window.html")
|
||||
self.assertEqual(context["WIN_ID"], self.window_id)
|
||||
self.assertEqual(context["MOUNT_DIM_PER_OFFER"], 1)
|
||||
self.assertEqual(context["NUM_ARCHIVE_OFFER"], 1)
|
||||
self.assertIn("2", context["NUM_TOTAL_OFFER_N_WORD"])
|
||||
self.assertEqual(len(context["LIST_FLAP_VARIATION"]), 1)
|
||||
self.assertEqual(context["LIST_FLAP_VARIATION"][0].sOfferFlapConfig, "[>]")
|
||||
self.assertTrue(context["LIST_FLAP_VARIATION"][0].STR_NUM.startswith("вариант"))
|
||||
self.assertEqual(context["LIST_FLAP_VARIATION"][0].IMG_MINI, "img/test-mini.png")
|
||||
self.assertEqual(len(context["SERIA_FOR_WIN"]), 1)
|
||||
self.assertEqual(context["SERIA_FOR_WIN"][0].sName, self.seria.sName)
|
||||
self.assertEqual(len(context["PRICE_FRAME"]), 1)
|
||||
self.assertEqual(context["PRICE_FRAME"][0]["SETS_NAME"], self.set_kit.sSetName)
|
||||
self.assertEqual(context["PRICE_FRAME"][0]["MERCHANT"], self.brand.sMerchantName)
|
||||
self.assertEqual(context["PRICE_FRAME"][0]["DIM"][0]["IMG_MINI"], "img/test-mini.png")
|
||||
self.assertIn("META_DATA_PUBLISH", context)
|
||||
self.assertTrue(mocked_big_pictures.called)
|
||||
self.assertTrue(mocked_mini_pictures.called)
|
||||
self.assertTrue(mocked_cookies.called)
|
||||
self.assertTrue(mocked_last_visits.called)
|
||||
self.assertTrue(mocked_all_visits.called)
|
||||
|
||||
def test_report_one_win_price_redirects_to_canonical_dimensions(self):
|
||||
"""Если SEO-размеры в URL неверные, вьюха должна редиректить на канонический URL."""
|
||||
request = self.factory.get(
|
||||
f"/catalog/standard_opening/price-999x999mm-tip{self.window_id}",
|
||||
)
|
||||
|
||||
response = report_one_win_price(request, "999", "999", str(self.window_id))
|
||||
|
||||
self.assertEqual(response.status_code, 301)
|
||||
self.assertEqual(
|
||||
response["Location"],
|
||||
f"/catalog/standard_opening/price-670x2160mm-tip{self.window_id}/",
|
||||
)
|
||||
|
||||
def test_legacy_one_win_url_redirects_to_canonical_url(self):
|
||||
"""Старый URL страницы одного окна должен отдавать 301 на новый канонический путь."""
|
||||
request = self.factory.get(
|
||||
f"/tsena-odnogo-okna/670x2160mm/tip{self.window_id}",
|
||||
)
|
||||
|
||||
response = redirect_one_win_price_legacy(request, "670", "2160", str(self.window_id))
|
||||
|
||||
self.assertEqual(response.status_code, 301)
|
||||
self.assertEqual(
|
||||
response["Location"],
|
||||
f"/catalog/standard_opening/price-670x2160mm-tip{self.window_id}/",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user