251 lines
10 KiB
Python
251 lines
10 KiB
Python
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}/",
|
||
)
|
||
|