mod: raw-SQL --> ORM для цен на наборы кокон в квартиру. SEO-атртибуты + добавлена schema.org
This commit is contained in:
@@ -6,15 +6,86 @@
|
|||||||
|
|
||||||
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
|
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
|
||||||
|
|
||||||
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"Y-m-d" }}{% endblock %}
|
{# SEO-описание: информативно для поисковиков и людей, но кратно. #}
|
||||||
|
{% block Description %}Лучшие цены на пластиковые окна для серии {{ APART|safe }} в доме по адресу {{ ADDRESS }}. Сравните {{ PRICE_FRAME|length }} предложений от ведущих компаний, узнайте стоимость окон для вашей квартиры и получите скидку!{% endblock %}
|
||||||
|
|
||||||
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"Y-m-d" }}{% endblock %}
|
{# SEO-ключевые слова: расширяем, добавляем вариации, город, преимущества. #}
|
||||||
|
{% block Keywords %}цены на окна, пластиковые окна, серия {{ BASE_SERIA }}, стоимость окон, окна для {{ BASE_SERIA }}, размеры окон, проемы серии {{ BASE_SERIA }}, окна в {{ APART|safe }}, скидки на окна, {{ ADDRESS }}, оконный профиль, монтаж окон, установка окон, сравнение цен, лучшие предложения, акции, рассрочка, {{ KEYWORDS_EXTRA }}{% endblock %}
|
||||||
|
|
||||||
{% block Description %}Цены на окна для серии {{ APART|safe }} по адресу {{ ADDRESS }}. Размер окон (см.): {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}{% if forloop.last %}.{% else %}; {% endif %}{% endfor %} Оконные наборы: {% for CurOffer in PRICE_FRAME %}{{ CurOffer.SETS_NAME }} – {{ CurOffer.FIN_PRICE|stringformat:".0f" }} рублей{% if forloop.last %}.{% else %}; {% endif %}{% endfor %}{% endblock %}
|
{% block ADD_TO_HEAD %}{# --- Микроразметка schema.org, Open Graph, Twitter Card, meta-даты --- #}
|
||||||
|
{# --- JSON-LD микроразметка schema.org --- #}<script type="application/ld+json">
|
||||||
{% comment %}{% block Description %}Цены на плаcтиковые окна для серии {{ BASE_SERIA }} ({{ APART }} квартира, {{ ADDRESS }}) :: {% for CurOffer in PRICE_FRAME %}Поставщик: {{ CurOffer.MERCHANT }}; Комплектация: {{ CurOffer.SETS_NAME }}; Цена: {{ CurOffer.FIN_PRICE }}₽ :: {% endfor %}{% endblock %}{% endcomment %}
|
[
|
||||||
|
{
|
||||||
{% block Keywords %}цены окон, серия {{ BASE_SERIA }}, {{ BASE_SERIA }}, стоимость окон, окна для {{ BASE_SERIA }}, размеры окон, проемы серии {{ BASE_SERIA }}, окна в {{ APART|safe }}, скидки на окна, {{ ADDRESS }}, оконный профиль, {% for CurOffer in PRICE_FRAME %}{{ CurOffer.MERCHANT }}, {{ CurOffer.PVC_NAME }}, {{ CurOffer.PVC_MANUFACTURER }}, {{ CurOffer.GLAZING_MARK }}, {% endfor %} характеристики пластиковых окон, {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см., {% endfor %}{{ META_KEYWORDS|default:"" }}{% endblock %}
|
"@context": "https://schema.org/",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{"@type": "ListItem", "position": 1, "name": "Главная", "item": "{{ request.scheme }}://{{ request.get_host }}/"},
|
||||||
|
{"@type": "ListItem", "position": 2, "name": "Каталог", "item": "{{ request.scheme }}://{{ request.get_host }}/catalog"},
|
||||||
|
{"@type": "ListItem", "position": 3, "name": "Цены на окна", "item": "{{ request.scheme }}://{{ request.get_host }}{{ request.path }}"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org/",
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "ОКНАРДИЯ — агрегатор цен на окна",
|
||||||
|
"url": "{{ request.scheme }}://{{ request.get_host }}/",
|
||||||
|
"logo": "{{ request.scheme }}://{{ request.get_host }}{% static 'img/oknardia_logo.svg' %}",
|
||||||
|
"description": "Сравнение цен на установку оконных конструкций в типовых жилых домах России",
|
||||||
|
"contactPoint": {"@type": "ContactPoint", "contactType": "Customer Service"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org/",
|
||||||
|
"@type": "Product",
|
||||||
|
"name": "Окна для {{ APART|safe }} ({{ ADDRESS }})",
|
||||||
|
"size": "{% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}мм — {{ I_WIN_DIM.iQuantity }} шт.{% if not forloop.last %}; {% endif %}{% endfor %}",
|
||||||
|
"description": "Цены на пластиковые окна для серии {{ APART|safe }} по адресу {{ ADDRESS }}. Сравните предложения, комплектации, получите скидки и выберите лучшее решение!",
|
||||||
|
"image": {"@type": "ImageObject", "url": "{{ request.scheme }}://{{ request.get_host }}{% static 'img/oknardia_logo.svg' %}"},
|
||||||
|
"brand": {"@type": "Brand", "name": "ОКНАРДИЯ"},
|
||||||
|
"url": "{{ request.scheme }}://{{ request.get_host }}{{ request.path }}",
|
||||||
|
"offers": {"@type": "AggregateOffer", "priceCurrency": "RUB", "itemCondition": "https://schema.org/NewCondition", "availability": "https://schema.org/InStock", "offerCount": "{{ PRICE_FRAME|length }}"}
|
||||||
|
},
|
||||||
|
{# --- ItemList с Offer для каждого предложения (цена, продавец, рейтинг, дата, внутренняя ссылка, профиль, стеклопакет, список окон) --- #}{
|
||||||
|
"@context": "https://schema.org/",
|
||||||
|
"@type": "ItemList",
|
||||||
|
"itemListElement": [
|
||||||
|
{% for CurOffer in PRICE_FRAME %}
|
||||||
|
{
|
||||||
|
"@type": "Offer",
|
||||||
|
"position": {{ forloop.counter }},
|
||||||
|
"name": "{{ CurOffer.SETS_NAME|escapejs }}",
|
||||||
|
"seller": {"@type": "Organization", "name": "{{ CurOffer.MERCHANT|escapejs }}"},
|
||||||
|
"windows": [
|
||||||
|
{% for CurInOffer in CurOffer.DIM %}{"size": "{{ CurInOffer.WIDTH|stringformat:'d' }}x{{ CurInOffer.HIGHT|stringformat:'d' }}", "count": {{ CurInOffer.QUANTITY }}}{% if not forloop.last %}, {% endif %}{% endfor %}
|
||||||
|
],
|
||||||
|
"profile": "{{ CurOffer.PVC_NAME|escapejs }}",
|
||||||
|
"glazing": "{{ CurOffer.GLAZING_NAME_B|escapejs }}",
|
||||||
|
"price": "{{ CurOffer.FIN_PRICE|stringformat:'d' }}",
|
||||||
|
"priceCurrency": "RUB",
|
||||||
|
{% if CurOffer.SETS_RATING %}"aggregateRating": {"@type": "AggregateRating", "ratingValue": "{{ CurOffer.SETS_RATING|stringformat:'.2f' }}"}, {% endif %}
|
||||||
|
{% if CurOffer.SETS_DATA_MODIFY %}"priceValidUntil": "{{ CurOffer.SETS_DATA_MODIFY|date:'Y-m-d' }}", {% endif %}
|
||||||
|
"availability": "https://schema.org/InStock",
|
||||||
|
"itemCondition": "https://schema.org/NewCondition",
|
||||||
|
"url": "#offer_{{ CurOffer.SETS_ID }}"
|
||||||
|
}{% if not forloop.last %},
|
||||||
|
{% endif %}{% endfor %}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
{# --- Open Graph (OG) --- #}<meta property="og:title" content="Цены на окна для {{ APART|safe }} ({{ ADDRESS }})" />
|
||||||
|
<meta property="og:description" content="Сравните цены, комплектации и получите лучшие предложения на пластиковые окна для серии {{ APART|safe }} по адресу {{ ADDRESS }}!" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="{{ request.scheme }}://{{ request.get_host }}{{ request.path }}" />
|
||||||
|
<meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/oknardia_logo.svg' %}" />
|
||||||
|
<meta property="og:site_name" content="ОКНАРДИЯ — агрегатор цен на окна" />
|
||||||
|
{# --- Twitter Card --- #}<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content="Цены на окна для {{ APART|safe }} ({{ ADDRESS }})" />
|
||||||
|
<meta name="twitter:description" content="Сравните цены, комплектации и получите лучшие предложения на пластиковые окна для серии {{ APART|safe }} по адресу {{ ADDRESS }}!" />
|
||||||
|
<meta name="twitter:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/oknardia_logo.svg' %}" />
|
||||||
|
{# --- Даты публикации и обновления --- #}<meta name="date" content="{{ META_DATA_PUBLISH|date:'Y-m-d' }}" />
|
||||||
|
<meta property="article:published_time" content="{{ META_DATA_PUBLISH|date:'Y-m-d' }}" />
|
||||||
|
<meta property="article:modified_time" content="{{ META_DATA_PUBLISH|date:'Y-m-d' }}" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block Top_JS3%}<script type="text/javascript">
|
{% block Top_JS3%}<script type="text/javascript">
|
||||||
function show_phone_num( id ){ // колапсатор для отображения контатной информации постафшика окон
|
function show_phone_num( id ){ // колапсатор для отображения контатной информации постафшика окон
|
||||||
@@ -107,23 +178,20 @@ $(function () { // инициализация и обработка попове
|
|||||||
|
|
||||||
{% block Top_CSS1 %}<link rel="stylesheet" type="text/css" href="{% static "css/csshake-vertical.min.css" %}">{% endblock %}
|
{% block Top_CSS1 %}<link rel="stylesheet" type="text/css" href="{% static "css/csshake-vertical.min.css" %}">{% endblock %}
|
||||||
|
|
||||||
{% block Main_Content %}
|
{% block Main_Content %}<div class="container-fluid">
|
||||||
<span itemscope itemtype="http://schema.org/Product">
|
<div class="row">
|
||||||
<div class="row col-md-12">
|
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<h1>Цены на окна для серии {{ APART|safe }} <small>({{ ADDRESS }})</small></h1>
|
<h1>Цены на окна для серии {{ APART|safe }} <small><nobr>({{ ADDRESS }})</nobr></small></h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<p>Квартира имеет проёмы (окна и балконные двери) следующих размеров: {% for I_WIN_DIM in FLAP_DIM %}{% if not forloop.first %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см. — {{ I_WIN_DIM.iQuantity }} шт.{% endfor %} Проект (<a href="/catalog/seria/{{ BASE_SERIA_LAT }}/all{{ BASE_SERIA_ID }}">типовая серия {{ BASE_SERIA }}</a>) предполагает следующие схемы открывания окон:</p>
|
<p>Квартира имеет проёмы (окна и балконные двери) следующих размеров: {% for I_WIN_DIM in FLAP_DIM %}{% if not forloop.first %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см. — {{ I_WIN_DIM.iQuantity }} шт.{% endfor %} Проект (<a href="/catalog/seria/{{ BASE_SERIA_LAT }}/all{{ BASE_SERIA_ID }}">типовая серия {{ BASE_SERIA }}</a>) предполагает следующие схемы открывания окон:</p>
|
||||||
</div>
|
</div>
|
||||||
{# Микроразмектка: названеи продукта #}<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})" />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-md-12 ShowBigFlapPictures">
|
<div class="row ShowBigFlapPictures">
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">{% include 'report/show_big_flap_pictures.html' %}</div>
|
||||||
{% include 'report/show_big_flap_pictures.html' %}
|
<div class="col-sm-3 visible-md visible-lg ap_list">
|
||||||
</div>
|
|
||||||
<div class="col-sm-3 visible-md visible-lg ap_list">
|
|
||||||
<h6>Другие типовые квартиры в этом доме:</h6>
|
<h6>Другие типовые квартиры в этом доме:</h6>
|
||||||
<ul>{% for I_APART in APARTMENT_IN_BUILDING %}
|
<ul>{% for I_APART in APARTMENT_IN_BUILDING %}
|
||||||
{% if I_APART.APT_ID == '!' %}<li>{{ I_APART.APT_NAME|safe }}</li>{% else %}<li><a href="/{{ BUILD_ID }}/{{ I_APART.APT_ID }}/{{ ADDRESS_T }}">{{ I_APART.APT_NAME|safe }}</a></li>{% endif %}{% endfor %}
|
{% if I_APART.APT_ID == '!' %}<li>{{ I_APART.APT_NAME|safe }}</li>{% else %}<li><a href="/{{ BUILD_ID }}/{{ I_APART.APT_ID }}/{{ ADDRESS_T }}">{{ I_APART.APT_NAME|safe }}</a></li>{% endif %}{% endfor %}
|
||||||
@@ -136,8 +204,6 @@ $(function () { // инициализация и обработка попове
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<p id="tab-note">Таблица содержит цены поставщиков. Клик на название отобразит детальные спецификации каждого предложения: марку профиля рамы и створки, схему стеклопакета, тип фурнитуры, элементы отделки (отлив, подоконник, откос, клапан <nobr>климат-контроля</nobr>) и сопутствующие услуги. Предложения выводятся покадрово, получите следующий кадр кнопкой «Ещё коммерческие предложения окон» под таблицей. Просмотреть и сравнить технические характеристик стеклопакетов, профилей и детальное описание сопутствующих услуг возможно с помощью кнопки «Сравнить выбранные».</p>
|
<p id="tab-note">Таблица содержит цены поставщиков. Клик на название отобразит детальные спецификации каждого предложения: марку профиля рамы и створки, схему стеклопакета, тип фурнитуры, элементы отделки (отлив, подоконник, откос, клапан <nobr>климат-контроля</nobr>) и сопутствующие услуги. Предложения выводятся покадрово, получите следующий кадр кнопкой «Ещё коммерческие предложения окон» под таблицей. Просмотреть и сравнить технические характеристик стеклопакетов, профилей и детальное описание сопутствующих услуг возможно с помощью кнопки «Сравнить выбранные».</p>
|
||||||
</div>
|
</div>
|
||||||
{# Микроразмектка: названеи продукта #}
|
|
||||||
<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -168,8 +234,7 @@ $(function () { // инициализация и обработка попове
|
|||||||
{% include "price/price_list_frame.html" %}
|
{% include "price/price_list_frame.html" %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</span>
|
|
||||||
{% with SERIA_BASE=BASE_SERIA %}{% include "report/build_info_in_table.html" %}{% endwith %}
|
{% with SERIA_BASE=BASE_SERIA %}{% include "report/build_info_in_table.html" %}{% endwith %}
|
||||||
{# --- Баннер: НАЧАЛО --- #}
|
{# --- Баннер: НАЧАЛО --- #}
|
||||||
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
|
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
{% if forloop.first %}
|
{% if forloop.first %}
|
||||||
<th rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}" title="Добавить коммерческое предложение окон к сравнению">{# красивые чекбоксы BEGIN #}<div class="checkbox"><label><input id="CHK{{ CurOffer.SETS_ID }}" type="checkbox" name="ForCompare" value="{{ CurOffer.SETS_ID }}" onChange="ChangeCountCheckedBox({{ CurOffer.SETS_ID }});" /><span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span></label></div>{# красивые чекбоксы END #}</th>
|
<th rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}" title="Добавить коммерческое предложение окон к сравнению">{# красивые чекбоксы BEGIN #}<div class="checkbox"><label><input id="CHK{{ CurOffer.SETS_ID }}" type="checkbox" name="ForCompare" value="{{ CurOffer.SETS_ID }}" onChange="ChangeCountCheckedBox({{ CurOffer.SETS_ID }});" /><span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span></label></div>{# красивые чекбоксы END #}</th>
|
||||||
<td rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}"{% if CurOffer.IS_COMMERCIAL %} style="background-image: url(/media/{{ CurOffer.MERCHANT_LOGO }})"{% endif %} title="Краткая спецификация коммерческого предложения">
|
<td rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}"{% if CurOffer.IS_COMMERCIAL %} style="background-image: url(/media/{{ CurOffer.MERCHANT_LOGO }})"{% endif %} title="Краткая спецификация коммерческого предложения">
|
||||||
<span itemprop="description">
|
<span>
|
||||||
<h3 class="set-name shake-trigger" id="btn{{ CurOffer.SETS_ID }}"><a href="javascript://" onclick="show_dtl({{ CurOffer.SETS_ID }})">{{ CurOffer.MERCHANT }} – {{ CurOffer.SETS_NAME }}<i class="glyphicon glyphicon-chevron-down shake-vertical"></i></a></h3>
|
<h3 class="set-name shake-trigger" id="btn{{ CurOffer.SETS_ID }}"><a href="javascript://" onclick="show_dtl({{ CurOffer.SETS_ID }})">{{ CurOffer.MERCHANT }} – {{ CurOffer.SETS_NAME }}<i class="glyphicon glyphicon-chevron-down shake-vertical"></i></a></h3>
|
||||||
|
|
||||||
<DiV id="dtl{{ CurOffer.SETS_ID }}" class="collapse">■ Профиль: <a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_NAME_T }}">{{ CurOffer.PVC_NAME|safe }}</a> (<a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}">{{ CurOffer.PVC_MANUFACTURER }}</a>)
|
<DiV id="dtl{{ CurOffer.SETS_ID }}" class="collapse">■ Профиль: <a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_NAME_T }}">{{ CurOffer.PVC_NAME|safe }}</a> (<a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}">{{ CurOffer.PVC_MANUFACTURER }}</a>)
|
||||||
■ {{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
|
■ {{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
|
||||||
@@ -40,10 +40,8 @@
|
|||||||
title="{% if CurOffer.SETS_RATING > 0.01 %}<b> Рейтинг {{ CurOffer.SETS_RATING|stringformat:".2f" }}</b> для оконого набора «{{ CurOffer.SETS_NAME }}» компании «{{ CurOffer.MERCHANT }}» состоит из:{% else %}Рейтинг не присвоен{% endif %}"
|
title="{% if CurOffer.SETS_RATING > 0.01 %}<b> Рейтинг {{ CurOffer.SETS_RATING|stringformat:".2f" }}</b> для оконого набора «{{ CurOffer.SETS_NAME }}» компании «{{ CurOffer.MERCHANT }}» состоит из:{% else %}Рейтинг не присвоен{% endif %}"
|
||||||
data-toggle="popover">рейтинг</a>: {% for Star in CurOffer.SETS_RATING_STARTS %}{% if Star == 0 %}<b class="glyphicon glyphicon-star-empty"></b>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if CurOffer.SETS_RATING > -0.1 %} {{ CurOffer.SETS_RATING|stringformat:".2f" }}{% endif %}</nobr>
|
data-toggle="popover">рейтинг</a>: {% for Star in CurOffer.SETS_RATING_STARTS %}{% if Star == 0 %}<b class="glyphicon glyphicon-star-empty"></b>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if CurOffer.SETS_RATING > -0.1 %} {{ CurOffer.SETS_RATING|stringformat:".2f" }}{% endif %}</nobr>
|
||||||
</span>
|
</span>
|
||||||
<span itemprop="brand" itemscope itemtype="http://schema.org/Brand">
|
{# Удалить: старая микроразметка schema.org (brand, meta) #}
|
||||||
<meta itemprop="name" content="{{ CurOffer.MERCHANT }}" />
|
</td>
|
||||||
<meta itemprop="logo" content="{{ request.scheme }}://{{ request.get_host }}/media/{{ CurOffer.MERCHANT_LOGO }}" />
|
|
||||||
</span></td>
|
|
||||||
<!--- Конец большой ячейки со спецификацией оконного предложения --->
|
<!--- Конец большой ячейки со спецификацией оконного предложения --->
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -58,10 +56,9 @@
|
|||||||
|
|
||||||
<td class="rnw" title="Стоимость {{ CurOffer.TOTAL|stringformat:".2f" }} рублей за все окна квартиры {{ APART|safe }}.">{{ CurOffer.TOTAL|stringformat:".2f"|price_format }}</td>
|
<td class="rnw" title="Стоимость {{ CurOffer.TOTAL|stringformat:".2f" }} рублей за все окна квартиры {{ APART|safe }}.">{{ CurOffer.TOTAL|stringformat:".2f"|price_format }}</td>
|
||||||
<th{% if CurOffer.DISCOUNT_COLOR2 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR2 }};"{% endif %} title="{% if CurOffer.DISCOUNT < 0.1 %}Нет скидки{% else %}Скидка — {{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}">{% if CurOffer.DISCOUNT < 0.1 %}—{% else %}−{{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}</th>
|
<th{% if CurOffer.DISCOUNT_COLOR2 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR2 }};"{% endif %} title="{% if CurOffer.DISCOUNT < 0.1 %}Нет скидки{% else %}Скидка — {{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}">{% if CurOffer.DISCOUNT < 0.1 %}—{% else %}−{{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}</th>
|
||||||
<th{% if CurOffer.DISCOUNT_COLOR1 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR1 }};"{% endif %} itemprop="offers" itemscope itemtype="http://schema.org/Offer" title="Итого за все окна с учетом скидки: {{ CurOffer.FIN_PRICE|stringformat:".2f" }} рублей">
|
<th{% if CurOffer.DISCOUNT_COLOR1 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR1 }};"{% endif %} title="Итого за все окна с учетом скидки: {{ CurOffer.FIN_PRICE|stringformat:".2f" }} рублей">
|
||||||
Итого: {{ CurOffer.FIN_PRICE|stringformat:".2f"|price_format }} <small class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></small>
|
Итого: {{ CurOffer.FIN_PRICE|stringformat:".2f"|price_format }} <small class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></small>
|
||||||
<meta itemprop="price" content="{{ CurOffer.FIN_PRICE }}" />
|
{# Удалить: старая микроразметка schema.org (meta price, priceCurrency) #}
|
||||||
<meta itemprop="priceCurrency" content="RUB" />
|
|
||||||
</th>
|
</th>
|
||||||
{% if CurOffer.DIM|length == 1 %}
|
{% if CurOffer.DIM|length == 1 %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
{# Отрисовка больших картинок с проемами и схамаи открывания #}{% load static %}{% if WIN_DIM %}
|
{# Отрисовка больших картинок с проемами и схемами открывания #}{% load static %}{% if WIN_DIM %}
|
||||||
{% for I_WIN_DIM in FLAP_DIM %}
|
{% for I_WIN_DIM in FLAP_DIM %}
|
||||||
<div class="win_discr pull-left" id="flap{{ forloop.counter0 }}">
|
<div class="win_discr pull-left" id="flap{{ forloop.counter0 }}">
|
||||||
<div><img src="{% static I_WIN_DIM.url2img %}" alt="{{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 (Ш х В, мм.). Типовая схема открывания." title="{{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
|
<div><img src="{% static I_WIN_DIM.url2img %}" alt="{{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 (Ш х В, мм.). Типовая схема открывания." title="{{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
|
||||||
<div class="caption" style="width:{{ I_WIN_DIM.W }}px;min-width:13ex;">
|
<div class="caption" style="width:{{ I_WIN_DIM.W }}px;min-width:13ex;">
|
||||||
<nobr>{{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0×{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 мм.</nobr><br />{% if not I_WIN_DIM.iQuantity == 0 %}
|
<nobr>{{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0×{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 мм.</nobr><br />{% if not I_WIN_DIM.iQuantity == 0 %}
|
||||||
<nobr><b>{{ I_WIN_DIM.iQuantity }} шт.</b>{% for I_II in I_WIN_DIM.qStr %}<span class="color-bullet" style="background-image:url('{% static 'img/svg/mark' %}{{ I_II }}.svg');"></span>{% endfor %}</nobr><br />{% endif %}
|
<nobr><b>{{ I_WIN_DIM.iQuantity }} шт.</b>{% for I_II in I_WIN_DIM.qStr %}<span class="color-bullet" style="background-image:url('{% static 'img/svg/mark' %}{{ I_II }}.svg');"></span>{% endfor %}</nobr><br />{% endif %}
|
||||||
{{ I_WIN_DIM.sDescription }}{% if not I_WIN_DIM.iQuantity == 0 %}<br />
|
{{ I_WIN_DIM.sDescription }}{% if not I_WIN_DIM.iQuantity == 0 %}<br />
|
||||||
<a href="/catalog/standard_opening/price-{{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0mm-tip{{ I_WIN_DIM.id }}">цены только этого типового окна</a>{% endif %}
|
<a href="/catalog/standard_opening/price-{{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0x{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0mm-tip{{ I_WIN_DIM.id }}">цены только этого типового окна</a>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>{% endfor %}{% comment %}
|
</div>{% endfor %}{% comment %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
|||||||
@@ -4,7 +4,15 @@ from django.db.models import Count
|
|||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from oknardia.models import Win_MountDim, PriceOffer, Apartment_Type, Seria_Info, LogVisitPriceReport, MountDim2Apartment
|
from oknardia.models import (
|
||||||
|
Win_MountDim,
|
||||||
|
PriceOffer,
|
||||||
|
Apartment_Type,
|
||||||
|
Seria_Info,
|
||||||
|
Building_Info,
|
||||||
|
LogVisitPriceReport,
|
||||||
|
MountDim2Apartment,
|
||||||
|
)
|
||||||
from oknardia.settings import *
|
from oknardia.settings import *
|
||||||
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
|
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
|
||||||
from web.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures, get_flaps_for_mini_pictures, \
|
from web.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures, get_flaps_for_mini_pictures, \
|
||||||
@@ -18,6 +26,11 @@ from types import SimpleNamespace
|
|||||||
import pytils
|
import pytils
|
||||||
|
|
||||||
|
|
||||||
|
def _slugify_lower(value: str | None) -> str:
|
||||||
|
"""Транслитерирует строку в slug и всегда приводит к нижнему регистру."""
|
||||||
|
return pytils.translit.slugify((value or "").strip()).lower()
|
||||||
|
|
||||||
|
|
||||||
def _one_win_price_canonical_path(win_width_mm: int | str, win_height_mm: int | str, win_id: int | str) -> str:
|
def _one_win_price_canonical_path(win_width_mm: int | str, win_height_mm: int | str, win_id: int | str) -> str:
|
||||||
"""Возвращает канонический путь страницы цен для одного типового окна."""
|
"""Возвращает канонический путь страницы цен для одного типового окна."""
|
||||||
return f"/catalog/standard_opening/price-{int(win_width_mm)}x{int(win_height_mm)}mm-tip{int(win_id)}/"
|
return f"/catalog/standard_opening/price-{int(win_width_mm)}x{int(win_height_mm)}mm-tip{int(win_id)}/"
|
||||||
@@ -34,6 +47,26 @@ def redirect_one_win_price_legacy(request: HttpRequest,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _append_visit_context(
|
||||||
|
to_template: dict,
|
||||||
|
request: HttpRequest,
|
||||||
|
time_start: float,
|
||||||
|
log_visit: list | None = None,
|
||||||
|
last_visit_cookie: list | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
|
||||||
|
if log_visit is None:
|
||||||
|
log_visit = get_last_all_user_visit_list()
|
||||||
|
if last_visit_cookie is None:
|
||||||
|
last_visit_cookie = get_last_user_visit_cookies(request)
|
||||||
|
|
||||||
|
to_template.update({
|
||||||
|
'LAST_VISIT': get_last_user_visit_list(last_visit_cookie[:3]),
|
||||||
|
'LOG_VISIT': log_visit,
|
||||||
|
'ticks': float(time.perf_counter() - time_start),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_longitude: float, address_latitude: float,
|
def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_longitude: float, address_latitude: float,
|
||||||
frame_begin_n: int = 0, brand_id: int = 0, win_id: int = 0) -> dict:
|
frame_begin_n: int = 0, brand_id: int = 0, win_id: int = 0) -> dict:
|
||||||
""" Формируем выдачу цен для фрейма
|
""" Формируем выдачу цен для фрейма
|
||||||
@@ -241,9 +274,9 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
|
|||||||
'GLAZING_TONING': offer.sGlazingToning,
|
'GLAZING_TONING': offer.sGlazingToning,
|
||||||
'PVC_ID': offer.pwc_id,
|
'PVC_ID': offer.pwc_id,
|
||||||
'PVC_NAME': offer.sProfileName,
|
'PVC_NAME': offer.sProfileName,
|
||||||
'PVC_NAME_T': pytils.translit.slugify(offer.sProfileName).lower(),
|
'PVC_NAME_T': _slugify_lower(offer.sProfileName),
|
||||||
'PVC_MANUFACTURER': offer.sProfileManufacturer,
|
'PVC_MANUFACTURER': offer.sProfileManufacturer,
|
||||||
'PVC_MANUFACTURER_T': pytils.translit.slugify(offer.sProfileManufacturer).lower(),
|
'PVC_MANUFACTURER_T': _slugify_lower(offer.sProfileManufacturer),
|
||||||
'PVC_SEAL': offer.sProfileSealDescription,
|
'PVC_SEAL': offer.sProfileSealDescription,
|
||||||
'SETS_CLIMATE_CONTROL': offer.sSetClimateControl,
|
'SETS_CLIMATE_CONTROL': offer.sSetClimateControl,
|
||||||
'SETS_SILL': offer.sSetSill,
|
'SETS_SILL': offer.sSetSill,
|
||||||
@@ -283,50 +316,110 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
|
|||||||
return {'META_DATA_PUBLISH': time_for_meta, 'PRICE_FRAME': price_frame, 'N': n_begin}
|
return {'META_DATA_PUBLISH': time_for_meta, 'PRICE_FRAME': price_frame, 'N': n_begin}
|
||||||
else:
|
else:
|
||||||
# если выводим цены для типовой квартиры
|
# если выводим цены для типовой квартиры
|
||||||
# print("Нужно несколько окон для квартиры")
|
# ORM-ветка сохраняет контракт полей для шаблонов price_list.html и price_list_frame.html.
|
||||||
q_price_offer = PriceOffer.objects.raw(
|
quantities_by_mount_dim = {
|
||||||
f"SELECT"
|
row['kMountDim_id']: row['iQuantity']
|
||||||
f" oknardia_priceoffer.*,"
|
for row in MountDim2Apartment.objects.filter(kApartment_id=apartment_id).values('kMountDim_id', 'iQuantity')
|
||||||
f" oknardia_win_mountdim.*,"
|
}
|
||||||
f" oknardia_setkit.*,"
|
if not quantities_by_mount_dim:
|
||||||
f" oknardia_merchantoffice.*,"
|
return {'META_DATA_PUBLISH': 0, 'PRICE_FRAME': [], 'N': '-1'}
|
||||||
f" oknardia_glazing.*,"
|
|
||||||
f" oknardia_pvcprofiles.*,"
|
q_price_offer = (
|
||||||
f" oknardia_merchantbrand.*,"
|
PriceOffer.objects.filter(
|
||||||
f" oknardia_mountdim2apartment.iQuantity,"
|
sOfferActive=True,
|
||||||
f" oknardia_win_mountdim.id AS mID, "
|
kOffer2MountDim_id__in=quantities_by_mount_dim.keys(),
|
||||||
f" oknardia_setkit.id AS setID,"
|
kOffer2SetKit__sSetActive=True,
|
||||||
f" (oknardia_setkit.dSetCommercialUntil > CURRENT_TIMESTAMP) AS bCommercial,"
|
kOffer2SetKit__kSet2User__kMerchantOffice__isnull=False,
|
||||||
f" oknardia_pvcprofiles.id AS pwc_id,"
|
kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__isnull=False,
|
||||||
f" oknardia_merchantbrand.id AS brand_id "
|
kOffer2SetKit__kSet2Glazing__isnull=False,
|
||||||
f"FROM oknardia_priceoffer"
|
kOffer2SetKit__kSet2PVCprofiles__isnull=False,
|
||||||
f" INNER JOIN oknardia_win_mountdim"
|
)
|
||||||
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
|
.select_related(
|
||||||
f" INNER JOIN oknardia_setkit"
|
'kOffer2MountDim',
|
||||||
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
|
'kOffer2SetKit',
|
||||||
f" INNER JOIN oknardia_ouruser"
|
'kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName',
|
||||||
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
|
'kOffer2SetKit__kSet2Glazing',
|
||||||
f" INNER JOIN oknardia_merchantoffice"
|
'kOffer2SetKit__kSet2PVCprofiles',
|
||||||
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
|
)
|
||||||
f" INNER JOIN oknardia_glazing"
|
.order_by(
|
||||||
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
|
'-kOffer2SetKit__dSetCreate',
|
||||||
f" INNER JOIN oknardia_pvcprofiles"
|
'-kOffer2MountDim__bIsNearDoor',
|
||||||
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
|
'-kOffer2MountDim__bIsDoor',
|
||||||
f" INNER JOIN oknardia_mountdim2apartment"
|
'kOffer2MountDim__iWinWidth',
|
||||||
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
|
'-kOffer2MountDim__iWinHight',
|
||||||
f" INNER JOIN oknardia_merchantbrand"
|
'id',
|
||||||
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
|
)
|
||||||
f"WHERE oknardia_priceoffer.sOfferActive IS TRUE"
|
)
|
||||||
f" AND oknardia_mountdim2apartment.kApartment_id = {int(apartment_id)}"
|
if brand_id != 0:
|
||||||
f" AND oknardia_setkit.sSetActive IS TRUE {add_to_sql_for_widget} "
|
q_price_offer = q_price_offer.filter(
|
||||||
f"ORDER BY"
|
kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName_id=brand_id,
|
||||||
f" oknardia_setkit.dSetCreate DESC, " # Сейчас окна в наборе собираются через это
|
)
|
||||||
f" oknardia_win_mountdim.bIsNearDoor DESC,"
|
|
||||||
f" oknardia_win_mountdim.bIsDoor DESC,"
|
q_price_offer = [
|
||||||
f" oknardia_win_mountdim.iWinWidth,"
|
SimpleNamespace(
|
||||||
f" oknardia_win_mountdim.iWinHight DESC "
|
id=offer.id,
|
||||||
f"LIMIT {int(frame_begin_n)} , 10000;")
|
fOfferPrice=offer.fOfferPrice,
|
||||||
# print list(qPO)
|
dOfferModify=offer.dOfferModify,
|
||||||
|
sOfferFlapConfig=offer.sOfferFlapConfig,
|
||||||
|
sDescripion=offer.kOffer2MountDim.sDescripion,
|
||||||
|
iWinWidth=offer.kOffer2MountDim.iWinWidth,
|
||||||
|
iWinHight=offer.kOffer2MountDim.iWinHight,
|
||||||
|
iQuantity=quantities_by_mount_dim.get(offer.kOffer2MountDim_id, 0),
|
||||||
|
setID=offer.kOffer2SetKit.id,
|
||||||
|
dSetModify=offer.kOffer2SetKit.dSetModify,
|
||||||
|
dSetCommercialUntil=offer.kOffer2SetKit.dSetCommercialUntil,
|
||||||
|
bCommercial=bool(
|
||||||
|
offer.kOffer2SetKit.dSetCommercialUntil
|
||||||
|
and offer.kOffer2SetKit.dSetCommercialUntil > timezone.now()
|
||||||
|
),
|
||||||
|
sSetName=offer.kOffer2SetKit.sSetName,
|
||||||
|
sSetClimateControl=offer.kOffer2SetKit.sSetClimateControl,
|
||||||
|
sSetSill=offer.kOffer2SetKit.sSetSill,
|
||||||
|
sSetImplementAll=offer.kOffer2SetKit.sSetImplementAll,
|
||||||
|
sSetImplementHandles=offer.kOffer2SetKit.sSetImplementHandles,
|
||||||
|
sSetImplementHinges=offer.kOffer2SetKit.sSetImplementHinges,
|
||||||
|
sSetImplementLatch=offer.kOffer2SetKit.sSetImplementLatch,
|
||||||
|
sSetImplementLimiter=offer.kOffer2SetKit.sSetImplementLimiter,
|
||||||
|
sSetImplementCatch=offer.kOffer2SetKit.sSetImplementCatch,
|
||||||
|
sSetPanes=offer.kOffer2SetKit.sSetPanes,
|
||||||
|
sSetSlope=offer.kOffer2SetKit.sSetSlope,
|
||||||
|
sSetOtherConditions=offer.kOffer2SetKit.sSetOtherConditions,
|
||||||
|
sSetDelivery=offer.kOffer2SetKit.sSetDelivery,
|
||||||
|
bSetDelivery=offer.kOffer2SetKit.bSetDelivery,
|
||||||
|
sSetUninstallInstall=offer.kOffer2SetKit.sSetUninstallInstall,
|
||||||
|
bSetUninstallInstall=offer.kOffer2SetKit.bSetUninstallInstall,
|
||||||
|
fSetRating=offer.kOffer2SetKit.fSetRating,
|
||||||
|
sOfficePhones=offer.kOffer2SetKit.kSet2User.kMerchantOffice.sOfficePhones,
|
||||||
|
sOfficeDiscountMetaFormula=(
|
||||||
|
offer.kOffer2SetKit.kSet2User.kMerchantOffice.sOfficeDiscountMetaFormula or ""
|
||||||
|
),
|
||||||
|
sOfficeName=offer.kOffer2SetKit.kSet2User.kMerchantOffice.sOfficeName,
|
||||||
|
sOfficeAddress=offer.kOffer2SetKit.kSet2User.kMerchantOffice.sOfficeAddress,
|
||||||
|
fOfficeGeoCode_Longitude=(
|
||||||
|
offer.kOffer2SetKit.kSet2User.kMerchantOffice.fOfficeGeoCode_Longitude or 0
|
||||||
|
),
|
||||||
|
fOfficeGeoCode_Latitude=(
|
||||||
|
offer.kOffer2SetKit.kSet2User.kMerchantOffice.fOfficeGeoCode_Latitude or 0
|
||||||
|
),
|
||||||
|
sGlazingBriefDescription=offer.kOffer2SetKit.kSet2Glazing.sGlazingBriefDescription,
|
||||||
|
sGlazingMark=offer.kOffer2SetKit.kSet2Glazing.sGlazingMark,
|
||||||
|
sGlazingToning=offer.kOffer2SetKit.kSet2Glazing.sGlazingToning,
|
||||||
|
pwc_id=offer.kOffer2SetKit.kSet2PVCprofiles.id,
|
||||||
|
sProfileName=offer.kOffer2SetKit.kSet2PVCprofiles.sProfileName,
|
||||||
|
sProfileManufacturer=offer.kOffer2SetKit.kSet2PVCprofiles.sProfileManufacturer or "",
|
||||||
|
sProfileSealDescription=offer.kOffer2SetKit.kSet2PVCprofiles.sProfileSealDescription,
|
||||||
|
sMerchantName=offer.kOffer2SetKit.kSet2User.kMerchantOffice.kMerchantName.sMerchantName,
|
||||||
|
pMerchantLogo=(
|
||||||
|
str(offer.kOffer2SetKit.kSet2User.kMerchantOffice.kMerchantName.pMerchantLogo)
|
||||||
|
if offer.kOffer2SetKit.kSet2User.kMerchantOffice.kMerchantName.pMerchantLogo
|
||||||
|
else ""
|
||||||
|
),
|
||||||
|
sMerchantMainURL=(
|
||||||
|
offer.kOffer2SetKit.kSet2User.kMerchantOffice.kMerchantName.sMerchantMainURL or ""
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for offer in q_price_offer[frame_begin_n:frame_begin_n + 10000]
|
||||||
|
]
|
||||||
price_frame = []
|
price_frame = []
|
||||||
count_mount_dim_in_offer = 0
|
count_mount_dim_in_offer = 0
|
||||||
dim_in_offer = []
|
dim_in_offer = []
|
||||||
@@ -440,9 +533,9 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
|
|||||||
'GLAZING_TONING': i2.sGlazingToning,
|
'GLAZING_TONING': i2.sGlazingToning,
|
||||||
'PVC_ID': i2.pwc_id,
|
'PVC_ID': i2.pwc_id,
|
||||||
'PVC_NAME': i2.sProfileName,
|
'PVC_NAME': i2.sProfileName,
|
||||||
'PVC_NAME_T': pytils.translit.slugify(i2.sProfileName).lower(),
|
'PVC_NAME_T': _slugify_lower(i2.sProfileName),
|
||||||
'PVC_MANUFACTURER': i2.sProfileManufacturer,
|
'PVC_MANUFACTURER': i2.sProfileManufacturer,
|
||||||
'PVC_MANUFACTURER_T': pytils.translit.slugify(i2.sProfileManufacturer).lower(),
|
'PVC_MANUFACTURER_T': _slugify_lower(i2.sProfileManufacturer),
|
||||||
'PVC_SEAL': i2.sProfileSealDescription,
|
'PVC_SEAL': i2.sProfileSealDescription,
|
||||||
'SETS_CLIMATE_CONTROL': i2.sSetClimateControl,
|
'SETS_CLIMATE_CONTROL': i2.sSetClimateControl,
|
||||||
'SETS_SILL': i2.sSetSill,
|
'SETS_SILL': i2.sSetSill,
|
||||||
@@ -620,7 +713,7 @@ def report_one_win_price(request: HttpRequest,
|
|||||||
list_seria_for_win.append(SimpleNamespace(
|
list_seria_for_win.append(SimpleNamespace(
|
||||||
id=seria_item['kApartment__kSeria__id'],
|
id=seria_item['kApartment__kSeria__id'],
|
||||||
sName=seria_name,
|
sName=seria_name,
|
||||||
sNameLat=pytils.translit.slugify(seria_name),
|
sNameLat=_slugify_lower(seria_name),
|
||||||
num_variation_of_apartment=pytils.numeral.sum_string(
|
num_variation_of_apartment=pytils.numeral.sum_string(
|
||||||
seria_item['num_variation_of_apartment'],
|
seria_item['num_variation_of_apartment'],
|
||||||
pytils.numeral.MALE,
|
pytils.numeral.MALE,
|
||||||
@@ -642,13 +735,8 @@ def report_one_win_price(request: HttpRequest,
|
|||||||
'SERIA_FOR_WIN': list_seria_for_win,
|
'SERIA_FOR_WIN': list_seria_for_win,
|
||||||
'WIN_ID': int(win_id),
|
'WIN_ID': int(win_id),
|
||||||
'MOUNT_DIM_PER_OFFER': 1,
|
'MOUNT_DIM_PER_OFFER': 1,
|
||||||
# получаем последние визиты клиента через куки
|
|
||||||
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
|
|
||||||
# получаем последние визиты всех посетителей из базы
|
|
||||||
# id2log, log_visit = get_last_all_user_visit_list()
|
|
||||||
'LOG_VISIT': get_last_all_user_visit_list(),
|
|
||||||
'ticks': float(time.perf_counter() - time_start)
|
|
||||||
})
|
})
|
||||||
|
_append_visit_context(to_template=to_template, request=request, time_start=time_start)
|
||||||
return render(request, "price/price_offers_for_one_window.html", to_template)
|
return render(request, "price/price_offers_for_one_window.html", to_template)
|
||||||
|
|
||||||
|
|
||||||
@@ -696,102 +784,81 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
try:
|
try:
|
||||||
# получаем все типы квартир для данного адреса (а заодно и попутную информацию о площади дома и пр.)
|
building = Building_Info.objects.select_related('kSeria_Link__kRoot').get(id=build_id)
|
||||||
q_apart = Apartment_Type.objects.raw(
|
if not building.kSeria_Link_id or not getattr(building.kSeria_Link, 'kRoot_id', None):
|
||||||
f'SELECT'
|
return redirect("/")
|
||||||
f' oknardia_apartment_type.sNameApartment, oknardia_apartment_type.id,'
|
|
||||||
f' oknardia_apartment_type.iSort, oknardia_seria_info.kRoot_id,'
|
list_apart = list(
|
||||||
f' oknardia_building_info.kSeria_Link_id, oknardia_building_info.sAddress,'
|
Apartment_Type.objects.filter(kSeria_id=building.kSeria_Link.kRoot_id).order_by('iSort')
|
||||||
f' oknardia_building_info.fGeoCode_Latitude, oknardia_building_info.fGeoCode_Longitude,'
|
)
|
||||||
f' oknardia_building_info.fTotal_Area, oknardia_building_info.sCadastre_Num_Area,'
|
if not list_apart:
|
||||||
f' oknardia_building_info.fLand_Area, oknardia_building_info.sInventory_Num,'
|
return redirect("/")
|
||||||
f' oknardia_building_info.iNum_Apartments, oknardia_building_info.sType,'
|
|
||||||
f' oknardia_building_info.iStoreys, oknardia_building_info.fCommon_Area,'
|
|
||||||
f' oknardia_building_info.sEnergy_Efficiency, oknardia_building_info.iEntrances_Porchs,'
|
|
||||||
f' oknardia_building_info.fUninhabited_Area, oknardia_building_info.sManagement_Co,'
|
|
||||||
f' oknardia_building_info.iElevators, oknardia_building_info.fResidential_Area,'
|
|
||||||
f' oknardia_building_info.iNum_Residents, oknardia_building_info.fPrivate_Area,'
|
|
||||||
f' oknardia_building_info.iNum_Accounts, oknardia_building_info.iCommissioning_year,'
|
|
||||||
f' oknardia_building_info.fGovernment_Area, oknardia_building_info.fCondition_House,'
|
|
||||||
f' oknardia_building_info.fCondition_Foundation, oknardia_building_info.fCondition_Walls,'
|
|
||||||
f' oknardia_building_info.fCondition_Overlap, oknardia_building_info.fMunicipal_Area,'
|
|
||||||
f' oknardia_building_info.sSerias_Project '
|
|
||||||
f'FROM oknardia_seria_info '
|
|
||||||
f'INNER JOIN oknardia_apartment_type'
|
|
||||||
f' ON oknardia_seria_info.kRoot_id = oknardia_apartment_type.kSeria_id '
|
|
||||||
f' INNER JOIN oknardia_building_info'
|
|
||||||
f' ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id '
|
|
||||||
f'WHERE oknardia_building_info.id = {build_id} '
|
|
||||||
f'ORDER BY oknardia_apartment_type.iSort;')
|
|
||||||
list_apart = list(q_apart)
|
|
||||||
# если кто-то нахимичит ID квартиры не для этого дома, то сделаем так, что он будет от этого дома!
|
# если кто-то нахимичит ID квартиры не для этого дома, то сделаем так, что он будет от этого дома!
|
||||||
apart_inside = False
|
apart_inside = any(ap.id == apart_id for ap in list_apart)
|
||||||
for i in q_apart:
|
address_slug = _slugify_lower(building.sAddress)
|
||||||
if i.id == apart_id:
|
if not apart_inside or slug != address_slug:
|
||||||
apart_inside = True
|
|
||||||
break
|
|
||||||
if not apart_inside or slug != pytils.translit.slugify(list_apart[0].sAddress):
|
|
||||||
# Переадресация 302, если с apart_id (ID-квартиры нахимичили) или slug-ом.
|
# Переадресация 302, если с apart_id (ID-квартиры нахимичили) или slug-ом.
|
||||||
# Нужно для склейки парных URL в поисковиках
|
# Нужно для склейки парных URL в поисковиках
|
||||||
# При переходе с карты apart_id выставляем в 0. Из-за этого тоже нужно 302-переадресация.
|
# При переходе с карты apart_id выставляем в 0. Из-за этого тоже нужно 302-переадресация.
|
||||||
return redirect(f"/{build_id}/{list_apart[0].id}/{pytils.translit.slugify(list_apart[0].sAddress)}")
|
return redirect(f"/{build_id}/{list_apart[0].id}/{address_slug}")
|
||||||
address_latitude = list_apart[0].fGeoCode_Latitude
|
address_latitude = building.fGeoCode_Latitude
|
||||||
address_longitude = list_apart[0].fGeoCode_Longitude
|
address_longitude = building.fGeoCode_Longitude
|
||||||
to_template.update({'BUILD_ID': build_id})
|
to_template.update({'BUILD_ID': build_id})
|
||||||
to_template.update({'APPARTMENT_ID': apart_id})
|
to_template.update({'APPARTMENT_ID': apart_id})
|
||||||
to_template.update({'ADDRESS_LAT': address_latitude})
|
to_template.update({'ADDRESS_LAT': address_latitude})
|
||||||
to_template.update({'ADDRESS_LON': address_longitude})
|
to_template.update({'ADDRESS_LON': address_longitude})
|
||||||
to_template.update({'ADDRESS': list_apart[0].sAddress})
|
to_template.update({'ADDRESS': building.sAddress})
|
||||||
to_template.update({'ADDRESS_T': pytils.translit.slugify(list_apart[0].sAddress)})
|
to_template.update({'ADDRESS_T': address_slug})
|
||||||
to_template.update({'SERIA': list_apart[0].sSerias_Project})
|
to_template.update({'SERIA': building.sSerias_Project})
|
||||||
# данные нужные для отображения информации о доме (метраж, число подъездов и пр.)
|
# данные нужные для отображения информации о доме (метраж, число подъездов и пр.)
|
||||||
to_template.update({'CADASTRE_NUM': list_apart[0].sCadastre_Num_Area})
|
to_template.update({'CADASTRE_NUM': building.sCadastre_Num_Area})
|
||||||
to_template.update({'INVENTORY_NUM': list_apart[0].sInventory_Num})
|
to_template.update({'INVENTORY_NUM': building.sInventory_Num})
|
||||||
to_template.update({'TYPE_BUILDING': list_apart[0].sType})
|
to_template.update({'TYPE_BUILDING': building.sType})
|
||||||
to_template.update({'ENERGY_EFFICIENCY': list_apart[0].sEnergy_Efficiency})
|
to_template.update({'ENERGY_EFFICIENCY': building.sEnergy_Efficiency})
|
||||||
if list_apart[0].fTotal_Area != -1.0:
|
if building.fTotal_Area != -1.0:
|
||||||
to_template.update({'TOTAL_AREA': f"{list_apart[0].fTotal_Area:.1f}"})
|
to_template.update({'TOTAL_AREA': f"{building.fTotal_Area:.1f}"})
|
||||||
if list_apart[0].fLand_Area != -1.0:
|
if building.fLand_Area != -1.0:
|
||||||
to_template.update({'LAND': f"{list_apart[0].fLand_Area:.1f}"})
|
to_template.update({'LAND': f"{building.fLand_Area:.1f}"})
|
||||||
if list_apart[0].iNum_Apartments != -1:
|
if building.iNum_Apartments != -1:
|
||||||
to_template.update({'NUM_APARTMENTS': list_apart[0].iNum_Apartments})
|
to_template.update({'NUM_APARTMENTS': building.iNum_Apartments})
|
||||||
if list_apart[0].iStoreys != -1:
|
if building.iStoreys != -1:
|
||||||
to_template.update({'STOREYS': list_apart[0].iStoreys})
|
to_template.update({'STOREYS': building.iStoreys})
|
||||||
if list_apart[0].fCommon_Area != -1.0:
|
if building.fCommon_Area != -1.0:
|
||||||
to_template.update({'COMMON_AREA': f"{list_apart[0].fCommon_Area:.1f}"})
|
to_template.update({'COMMON_AREA': f"{building.fCommon_Area:.1f}"})
|
||||||
if list_apart[0].iEntrances_Porchs != -1:
|
if building.iEntrances_Porchs != -1:
|
||||||
to_template.update({'NUM_ENTERANCES': list_apart[0].iEntrances_Porchs})
|
to_template.update({'NUM_ENTERANCES': building.iEntrances_Porchs})
|
||||||
if list_apart[0].fUninhabited_Area != -1.0:
|
if building.fUninhabited_Area != -1.0:
|
||||||
to_template.update({'UNINHABITED_AREA': f"{list_apart[0].fUninhabited_Area:.1f}"})
|
to_template.update({'UNINHABITED_AREA': f"{building.fUninhabited_Area:.1f}"})
|
||||||
if list_apart[0].sManagement_Co != u"N/A":
|
if building.sManagement_Co != u"N/A":
|
||||||
to_template.update({'MANAGEMENT_CO': list_apart[0].sManagement_Co})
|
to_template.update({'MANAGEMENT_CO': building.sManagement_Co})
|
||||||
if list_apart[0].iElevators != -1:
|
if building.iElevators != -1:
|
||||||
to_template.update({'NUM_ELEVATORS': list_apart[0].iElevators})
|
to_template.update({'NUM_ELEVATORS': building.iElevators})
|
||||||
if list_apart[0].fResidential_Area != -1.0:
|
if building.fResidential_Area != -1.0:
|
||||||
to_template.update({'RESIDENTIAL_AREA': f"{list_apart[0].fResidential_Area:.1f}"})
|
to_template.update({'RESIDENTIAL_AREA': f"{building.fResidential_Area:.1f}"})
|
||||||
if list_apart[0].iNum_Residents != -1:
|
if building.iNum_Residents != -1:
|
||||||
to_template.update({'NUM_RESIDENTS': list_apart[0].iNum_Residents})
|
to_template.update({'NUM_RESIDENTS': building.iNum_Residents})
|
||||||
if list_apart[0].fPrivate_Area != -1.0:
|
if building.fPrivate_Area != -1.0:
|
||||||
to_template.update({'PRIVATE_AREA': f"{list_apart[0].fPrivate_Area:.1f}"})
|
to_template.update({'PRIVATE_AREA': f"{building.fPrivate_Area:.1f}"})
|
||||||
if list_apart[0].iNum_Accounts != -1:
|
if building.iNum_Accounts != -1:
|
||||||
to_template.update({'NUM_ACCOUNTS': list_apart[0].iNum_Accounts})
|
to_template.update({'NUM_ACCOUNTS': building.iNum_Accounts})
|
||||||
if list_apart[0].iCommissioning_year != "N/A":
|
if building.iCommissioning_year != "N/A":
|
||||||
to_template.update({'COMMISSIONING_YEAR': list_apart[0].iCommissioning_year})
|
to_template.update({'COMMISSIONING_YEAR': building.iCommissioning_year})
|
||||||
if list_apart[0].fGovernment_Area != -1.0:
|
if building.fGovernment_Area != -1.0:
|
||||||
to_template.update({'GOVERNMENT_AREA': f"{list_apart[0].fGovernment_Area:.1f}"})
|
to_template.update({'GOVERNMENT_AREA': f"{building.fGovernment_Area:.1f}"})
|
||||||
if list_apart[0].fCondition_House != -1.0:
|
if building.fCondition_House != -1.0:
|
||||||
to_template.update({'CONDITION_HOUSE': f"{list_apart[0].fCondition_House:.0f}%"})
|
to_template.update({'CONDITION_HOUSE': f"{building.fCondition_House:.0f}%"})
|
||||||
if list_apart[0].fCondition_Foundation != -1.0:
|
if building.fCondition_Foundation != -1.0:
|
||||||
to_template.update({'CONDITION_FOUNDATION': f"{list_apart[0].fCondition_Foundation:.0f}%"})
|
to_template.update({'CONDITION_FOUNDATION': f"{building.fCondition_Foundation:.0f}%"})
|
||||||
if list_apart[0].fCondition_Walls != -1.0:
|
if building.fCondition_Walls != -1.0:
|
||||||
to_template.update({'CONDITION_WALL': f"{list_apart[0].fCondition_Walls:.0f}%"})
|
to_template.update({'CONDITION_WALL': f"{building.fCondition_Walls:.0f}%"})
|
||||||
if list_apart[0].fCondition_Overlap != -1.0:
|
if building.fCondition_Overlap != -1.0:
|
||||||
to_template.update({'CONDITION_OVERLAP': f"{list_apart[0].fCondition_Overlap:.0f}%"})
|
to_template.update({'CONDITION_OVERLAP': f"{building.fCondition_Overlap:.0f}%"})
|
||||||
if list_apart[0].fMunicipal_Area != -1.0:
|
if building.fMunicipal_Area != -1.0:
|
||||||
to_template.update({'MUNICIPAL_AREA': f"{list_apart[0].fMunicipal_Area:.1f}"})
|
to_template.update({'MUNICIPAL_AREA': f"{building.fMunicipal_Area:.1f}"})
|
||||||
# заполняем массив квартир для отправки в шаблон
|
# заполняем массив квартир для отправки в шаблон
|
||||||
apart_in_building = []
|
apart_in_building = []
|
||||||
for apartment_count in q_apart:
|
for apartment_count in list_apart:
|
||||||
apartment_in = {}
|
apartment_in = {}
|
||||||
if apartment_count.id != apart_id:
|
if apartment_count.id != apart_id:
|
||||||
apartment_in.update({'APT_ID': apartment_count.id})
|
apartment_in.update({'APT_ID': apartment_count.id})
|
||||||
@@ -802,8 +869,8 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
|
|||||||
to_template.update({'APARTMENT_IN_BUILDING': apart_in_building})
|
to_template.update({'APARTMENT_IN_BUILDING': apart_in_building})
|
||||||
|
|
||||||
# узнаем базовую серию дома
|
# узнаем базовую серию дома
|
||||||
q_base_seria = Seria_Info.objects.get(id=list_apart[0].kRoot_id)
|
q_base_seria = building.kSeria_Link.kRoot
|
||||||
base_seria_slug = pytils.translit.slugify(q_base_seria.sName)
|
base_seria_slug = _slugify_lower(q_base_seria.sName)
|
||||||
to_template.update({'BASE_SERIA': q_base_seria.sName,
|
to_template.update({'BASE_SERIA': q_base_seria.sName,
|
||||||
'BASE_SERIA_LAT': base_seria_slug,
|
'BASE_SERIA_LAT': base_seria_slug,
|
||||||
'BASE_SERIA_ID': q_base_seria.id})
|
'BASE_SERIA_ID': q_base_seria.id})
|
||||||
@@ -813,38 +880,36 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
|
|||||||
###############################################
|
###############################################
|
||||||
# получаем массив окон для данной квартиры...
|
# получаем массив окон для данной квартиры...
|
||||||
try:
|
try:
|
||||||
q_md = Win_MountDim.objects.raw(
|
list_mount_dim_per_offer = [
|
||||||
f'SELECT'
|
SimpleNamespace(
|
||||||
f' oknardia_apartment_type.sNameApartment, oknardia_win_mountdim.iWinWidth,'
|
sNameApartment=row.kApartment.sNameApartment,
|
||||||
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
|
iWinWidth=row.kMountDim.iWinWidth,
|
||||||
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
|
iWinHight=row.kMountDim.iWinHight,
|
||||||
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
|
iWinDepth=row.kMountDim.iWinDepth,
|
||||||
f' oknardia_win_mountdim.id, oknardia_mountdim2apartment.iQuantity '
|
sFlapConfig=row.kMountDim.sFlapConfig,
|
||||||
f'FROM oknardia_mountdim2apartment '
|
bIsNearDoor=row.kMountDim.bIsNearDoor,
|
||||||
f'INNER JOIN oknardia_apartment_type'
|
bIsDoor=row.kMountDim.bIsDoor,
|
||||||
f' ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id'
|
sDescripion=row.kMountDim.sDescripion,
|
||||||
f' INNER JOIN oknardia_win_mountdim'
|
id=row.kMountDim.id,
|
||||||
f' ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id '
|
iQuantity=row.iQuantity,
|
||||||
f'WHERE oknardia_mountdim2apartment.kApartment_id = {apart_id} '
|
)
|
||||||
f'GROUP BY'
|
for row in MountDim2Apartment.objects.filter(kApartment_id=apart_id)
|
||||||
f' oknardia_apartment_type.sNameApartment, oknardia_win_mountdim.iWinWidth,'
|
.select_related('kApartment', 'kMountDim')
|
||||||
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
|
.order_by(
|
||||||
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
|
'-kMountDim__bIsNearDoor',
|
||||||
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
|
'-kMountDim__bIsDoor',
|
||||||
f' oknardia_apartment_type.bApartmentCheck, oknardia_win_mountdim.dMountXYZModify,'
|
'kMountDim__iWinWidth',
|
||||||
f' oknardia_apartment_type.dApartmentModify, oknardia_win_mountdim.iWinLimit,'
|
'-kMountDim__iWinHight',
|
||||||
f' oknardia_win_mountdim.id, oknardia_mountdim2apartment.iQuantity '
|
)
|
||||||
f'ORDER BY'
|
]
|
||||||
f' oknardia_win_mountdim.bIsNearDoor DESC,'
|
if not list_mount_dim_per_offer:
|
||||||
f' oknardia_win_mountdim.bIsDoor DESC,'
|
return redirect("/")
|
||||||
f' oknardia_win_mountdim.iWinWidth,'
|
|
||||||
f' oknardia_win_mountdim.iWinHight DESC;')
|
|
||||||
list_mount_dim_per_offer = list(q_md)
|
|
||||||
mount_dim_per_offer = len(list_mount_dim_per_offer)
|
mount_dim_per_offer = len(list_mount_dim_per_offer)
|
||||||
to_template.update({'APART': list_mount_dim_per_offer[0].sNameApartment})
|
to_template.update({'APART': list_mount_dim_per_offer[0].sNameApartment})
|
||||||
|
|
||||||
# получаем данные для отрисовки больших картинок с проемами.
|
# получаем данные для отрисовки больших картинок с проемами.
|
||||||
to_template.update(get_flaps_for_big_pictures(q_md))
|
to_template.update(get_flaps_for_big_pictures(list_mount_dim_per_offer))
|
||||||
# <---
|
# <---
|
||||||
except (ValueError, IndexError, TypeError, ObjectDoesNotExist):
|
except (ValueError, IndexError, TypeError, ObjectDoesNotExist):
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
@@ -865,12 +930,11 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
|
|||||||
|
|
||||||
# получаем последние визиты всех посетителей из базы
|
# получаем последние визиты всех посетителей из базы
|
||||||
log_visit = get_last_all_user_visit_list()
|
log_visit = get_last_all_user_visit_list()
|
||||||
if log_visit[0]['id'] is not None:
|
if log_visit and log_visit[0].get('id') is not None:
|
||||||
id_last_visit_log = log_visit[0]['id'] + 1
|
id_last_visit_log = log_visit[0]['id'] + 1
|
||||||
else:
|
else:
|
||||||
id_last_visit_log = 1
|
id_last_visit_log = 1
|
||||||
# print("id_last_visit_log:", id_last_visit_log)
|
# print("id_last_visit_log:", id_last_visit_log)
|
||||||
to_template.update({'LOG_VISIT': log_visit})
|
|
||||||
if id_last_visit_log > MAX_LEN_RING_LOG_BUFFER: # максимальный размер циклического буфера
|
if id_last_visit_log > MAX_LEN_RING_LOG_BUFFER: # максимальный размер циклического буфера
|
||||||
id_last_visit_log = 1 # ставим в начало буфера
|
id_last_visit_log = 1 # ставим в начало буфера
|
||||||
try:
|
try:
|
||||||
@@ -891,7 +955,8 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
|
|||||||
|
|
||||||
# получаем последние визиты клиента через куки
|
# получаем последние визиты клиента через куки
|
||||||
last_visit = get_last_user_visit_cookies(request)
|
last_visit = get_last_user_visit_cookies(request)
|
||||||
to_template.update({'LAST_VISIT': get_last_user_visit_list(last_visit)})
|
# Для блока LAST_VISIT показываем историю до текущего захода.
|
||||||
|
last_visit_for_context = list(last_visit)
|
||||||
# подготавливаем данные о текущем посещении для помещения в cookie
|
# подготавливаем данные о текущем посещении для помещения в cookie
|
||||||
Item = {
|
Item = {
|
||||||
"LastURL": f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}",
|
"LastURL": f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}",
|
||||||
@@ -901,7 +966,13 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
|
|||||||
last_visit.insert(0, Item) # Добавляем текущий Item в начало
|
last_visit.insert(0, Item) # Добавляем текущий Item в начало
|
||||||
last_visit = json.dumps(last_visit[:3]) # упаковываем json без пробелов (три записи)
|
last_visit = json.dumps(last_visit[:3]) # упаковываем json без пробелов (три записи)
|
||||||
# print u"сейчас запишем вот эту куку:", LastVisit
|
# print u"сейчас запишем вот эту куку:", LastVisit
|
||||||
to_template.update({'ticks': float(time.perf_counter() - time_start)})
|
_append_visit_context(
|
||||||
|
to_template=to_template,
|
||||||
|
request=request,
|
||||||
|
time_start=time_start,
|
||||||
|
log_visit=log_visit,
|
||||||
|
last_visit_cookie=last_visit_for_context,
|
||||||
|
)
|
||||||
response = render(request, "price/price_list.html", to_template)
|
response = render(request, "price/price_list.html", to_template)
|
||||||
response.set_cookie("LastVisit", last_visit, max_age=7862400) # ставим или перезаписываем куки (91 день)
|
response.set_cookie("LastVisit", last_visit, max_age=7862400) # ставим или перезаписываем куки (91 день)
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from oknardia.models import (
|
|||||||
Seria_Info,
|
Seria_Info,
|
||||||
SetKit,
|
SetKit,
|
||||||
)
|
)
|
||||||
from web.prices import redirect_one_win_price_legacy, report_one_win_price
|
from web.prices import redirect_one_win_price_legacy, report_one_win_price, report_price_frame
|
||||||
|
|
||||||
|
|
||||||
class ReportOneWinPriceTests(TestCase):
|
class ReportOneWinPriceTests(TestCase):
|
||||||
@@ -248,3 +248,26 @@ class ReportOneWinPriceTests(TestCase):
|
|||||||
f"/catalog/standard_opening/price-670x2160mm-tip{self.window_id}/",
|
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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user