265 lines
11 KiB
Python
265 lines
11 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, report_price_frame
|
|
|
|
|
|
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_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,
|
|
):
|
|
"""Вьюха должна собирать тот же ключевой контекст, но уже без 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)
|
|
|
|
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}/",
|
|
)
|
|
|
|
def test_report_price_frame_for_apartment_keeps_template_contract(self):
|
|
"""ORM-ветка для квартир должна сохранять ключи контекста для price_list*."""
|
|
frame = report_price_frame(
|
|
apartment_id=self.apartment.id,
|
|
mount_dim_per_offer=1,
|
|
address_longitude=0,
|
|
address_latitude=0,
|
|
frame_begin_n=0,
|
|
brand_id=0,
|
|
win_id=0,
|
|
)
|
|
|
|
self.assertIn("META_DATA_PUBLISH", frame)
|
|
self.assertIn("PRICE_FRAME", frame)
|
|
self.assertIn("N", frame)
|
|
self.assertEqual(len(frame["PRICE_FRAME"]), 1)
|
|
offer = frame["PRICE_FRAME"][0]
|
|
self.assertEqual(offer["SETS_ID"], self.set_kit.id)
|
|
self.assertEqual(offer["MERCHANT"], self.brand.sMerchantName)
|
|
self.assertEqual(offer["FIN_PRICE"], self.active_offer.fOfferPrice)
|
|
self.assertEqual(len(offer["DIM"]), 1)
|
|
self.assertEqual(offer["DIM"][0]["QUANTITY"], 1)
|
|
|