Вьюшка и шаблоны: Выдача предложений -- готово

This commit is contained in:
2022-12-31 02:55:09 +03:00
parent 28a680fdf1
commit 37a605ef09
6 changed files with 638 additions and 51 deletions

View File

@@ -266,4 +266,6 @@ CATALOG_RECORD_FOR_PROFILE_MANUFACTURER = 100
CATALOG_SORTER_MAGIC_NUMBER_ADV = 5 CATALOG_SORTER_MAGIC_NUMBER_ADV = 5
CATALOG_SORTER_MAGIC_NUMBER_TIZER = 1 CATALOG_SORTER_MAGIC_NUMBER_TIZER = 1
MAX_LEN_RING_LOG_BUFFER = 250 # МАКСИМАЛЬНЫЙ РАЗМЕР КОЛЬЦЕВОГО БУФЕРА
YANDEX_MAPS_API_KEY = MY_YANDEX_MAPS_API_KEY YANDEX_MAPS_API_KEY = MY_YANDEX_MAPS_API_KEY

View File

@@ -73,6 +73,7 @@ urlpatterns = [
# ЦЕНОВЫЕ ПРЕДЛОЖЕНИЯ # ЦЕНОВЫЕ ПРЕДЛОЖЕНИЯ
re_path(r'^tsena-odnogo-okna/(?P<win_width_mm>\d+)x(?P<win_height_mm>\d+)mm/tip(?P<win_id>\d+)[/*]$', re_path(r'^tsena-odnogo-okna/(?P<win_width_mm>\d+)x(?P<win_height_mm>\d+)mm/tip(?P<win_id>\d+)[/*]$',
prices.report_one_win_price), prices.report_one_win_price),
re_path(r'^(?P<build_id>\d{1,6})/(?P<apart_id>\d{1,})/(?P<slug>[\s\S]+|.*)$', prices.report_price),
] ]

View File

@@ -0,0 +1,150 @@
{% load static %}{% load filters %}
{% for CurOffer in PRICE_FRAME %}
<tr>
<td colspan="11" style="font-size:xx-small;border-top:double black;border-bottom: solid 1px white;padding: 0;"></td>
</tr>{% for CurInOffer in CurOffer.DIM %}
<tr>
{% 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>
<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">
<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>)
&nbsp;{{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
&nbsp;Тонирование:&nbsp;{{ CurOffer.GLAZING_TONING }}
{% if CurOffer.PVC_SEAL %}■&nbsp;Уплотнитель:&nbsp;{{ CurOffer.PVC_SEAL }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT %}■&nbsp;Фурнитура:&nbsp;{{ CurOffer.SETS_IMPLEMENT|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_R %}■&nbsp;Ручки:&nbsp;{{ CurOffer.SETS_IMPLEMENT_R|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_P %}■&nbsp;Петли:&nbsp;{{ CurOffer.SETS_IMPLEMENT_P|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_Z %}■&nbsp;Запоры:&nbsp;{{ CurOffer.SETS_IMPLEMENT_Z|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_O %}■&nbsp;Ограничители:&nbsp;{{ CurOffer.SETS_IMPLEMENT_O|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_F %}■&nbsp;Фиксаторы:&nbsp;{{ CurOffer.SETS_IMPLEMENT_F|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_CLIMATE_CONTROL %}<span {% if CurOffer.SETS_CLIMATE_CONTROL|capfirst != "Нет" or CurOffer.SETS_CLIMATE_CONTROL|length > 3 %}class="bullet-green"{% endif %}>■&nbsp;Климат-контроль:&nbsp;{{ CurOffer.SETS_CLIMATE_CONTROL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_SILL %}<span {% if CurOffer.SETS_SILL|capfirst == "Нет" or CurOffer.SETS_SILL|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Подоконник:&nbsp;{{ CurOffer.SETS_SILL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_SLOPE %}<span {% if CurOffer.SETS_SLOPE|capfirst == "Нет" or CurOffer.SETS_SLOPE|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Откос:&nbsp;{{ CurOffer.SETS_SLOPE|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_PANES %}<span {% if CurOffer.SETS_PANES|capfirst == "Нет" or CurOffer.SETS_PANES|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Водоотлив:&nbsp;{{ CurOffer.SETS_PANES|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_UNINSTALL_INSTALL %}<span {% if CurOffer.SETS_UNINSTALL_INSTALL_B %}class="bullet-green"{% else %}class="bullet-red"{% endif %}>&nbsp;Демонтаж/монтаж:&nbsp;{{ CurOffer.SETS_UNINSTALL_INSTALL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_DELIVERY %}<span {% if CurOffer.SETS_DELIVERY_B %}class="bullet-green"{% else %}class="bullet-red"{% endif %}>&nbsp;Доставка:&nbsp;{{ CurOffer.SETS_DELIVERY|capfirst|safe }}</span>{% endif %}{% comment %} {% if CurOffer.SETS_OTHER %}■&nbsp;Прочие условия:&nbsp;{{ CurOffer.SETS_OTHER|capfirst|safe }}
{% endif %}{% endcomment %}
</DiV>
<!-- Расстояние до офиса поставщика -->
<nobr>{% if CurOffer.DISTANCE != -1 %}<nobr class="badge badge4price" title="Удалённость офиса — {{ CurOffer.DISTANCE|stringformat:"0.1f" }} км."><b class="glyphicon glyphicon-map-marker"></b> {{ CurOffer.DISTANCE|stringformat:"0.1f"|price_format }}&thinsp;км.</nobr>{% endif %}</nobr>
<!-- Дата обновления -->
<nobr class="badge badge4price" title="Дата обновления коммерческого предложения окон — {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }}"><b class="glyphicon glyphicon-calendar"></b> {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }}</nobr>
<!-- Звездочки рейтинга -->
<nobr class="badge badge4price" title="Рейтинг «Окнардии»{% if CurOffer.SETS_RATING > -0.1 %} — {{ CurOffer.SETS_RATING|stringformat:".2f" }} баллов{% endif %}"><a
href="javascript://"
id-set="{{ CurOffer.SETS_ID }}"
data-trigger="focus" tabindex="0"
title="{% if CurOffer.SETS_RATING > 0.01 %}<b> Рейтинг {{ CurOffer.SETS_RATING|stringformat:".2f" }}</b> для оконого набора «{{ CurOffer.SETS_NAME }}» компании «{{ CurOffer.MERCHANT }}» состоит&nbsp;из:{% else %}Рейтинг не присвоен{% endif %}"
data-toggle="popover">рейтинг</a>:&nbsp;{% 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 itemprop="brand" itemscope itemtype="http://schema.org/Brand">
<meta itemprop="name" content="{{ CurOffer.MERCHANT }}" />
<meta itemprop="logo" content="https://oknardia.ru/media/{{ CurOffer.MERCHANT_LOGO }}" />
</span></td>
<!--- Конец большой ячейки со спецификацией оконного предложения --->
{% endif %}
<td class="rnw" title="{{ CurInOffer.QUANTITY }} × {{ CurInOffer.DESCRIPTION }} — {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм.">{% for BUL in CurInOffer.BULLET %}<span class="color-bullet" style="background-image:url({% static "img/svg/mark" %}{{ BUL }}.svg);"></span>{% endfor %}</td>
<td class="rnw" title="Схема открывания окна или двери {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм."><img src="{% static CurInOffer.IMG_MINI %}" alt="Схема открывания: {{ CurInOffer.DESCRIPTION }} — {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм." /></td>
<td class="rnw" title="Цена {{ CurInOffer.PRICE|stringformat:".2f" }} рублей.">{{ CurInOffer.PRICE|stringformat:".2f"|price_format }}</td>
<td title="Количество: {{ CurInOffer.QUANTITY }} шт.">×{{ CurInOffer.QUANTITY }}</td>
<td class="rnw hidden-xs hidden-sm">=</td>
<td class="rnw hidden-xs hidden-sm" title="Сумма {{ CurInOffer.SUBTOTAL|stringformat:".2f" }} рублей за {{ CurInOffer.QUANTITY }} шт.">{{ CurInOffer.SUBTOTAL|stringformat:".2f"|price_format }}</td>
{% if forloop.first %}<!-- FIRST -->
<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 %}&minus;{{ 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" }} рублей">
Итого: {{ CurOffer.FIN_PRICE|stringformat:".2f"|price_format }}&thinsp;<small class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></small>
<meta itemprop="price" content="{{ CurOffer.FIN_PRICE }}" />
<meta itemprop="priceCurrency" content="RUB" />
</th>
{% if CurOffer.DIM|length == 1 %}
</tr><tr>
<td colspan="6">&nbsp;</td>
<td colspan="3">
{% endif %}
{% elif forloop.counter0 == 1 %}
<td colspan="3" rowspan="{{ CurOffer.DIM|length|add:"-1" }}">
{% endif %}
{% if forloop.counter0 == 1 or CurOffer.DIM|length == 1 %}
<stong>{{ CurOffer.OFFICE_NAME }}</stong><br />
<div id="hid{{ CurOffer.SETS_ID }}" class="collapse in">
<a class="btn btn-info btn-xs shake-trigger" data-toggle="collapse" data-target="#tel{{ CurOffer.SETS_ID }}" onclick="show_phone_num({{ CurOffer.SETS_ID }})"><b class="glyphicon glyphicon-phone-alt shake-vertical"></b> Показать телефон</a>
</div>
<div id="tel{{ CurOffer.SETS_ID }}" class="collapse">
<small>{{ CurOffer.OFFICE_ADDRESS }}</small><br /> <b class="glyphicon glyphicon-phone-alt"></b> {{ CurOffer.OFFICE_PHONES }}<br />
<small><nobr>Пожалуйста, скажите, что нашли цены на oknardia.ru</nobr></small>
</div>
</td>
{% endif %}
</tr>{% endfor %}<!----- ПРОВЕРКА --->{% endfor %}
<Tr id="preloader_{{ N }}">
<tH colspan="11"><center><img src="{% static "img/preloader.gif" %}" alt="подгружаю цены на окна..." height="64" width="64" /></center></tH>
</Tr>
<tR id="load_and_banner_{{ N }}">
<!-- сюда подгружаем следующий фрейм прайслиста --->
<script type="application/javascript">
function get_next_pricelist_frame( ) {
try{yaCounter32997984.reachGoal("MoreOffer");}catch(e){}
// заменяем ряд с кнопочками кнопочками на рекламу
// $("#load_and_banner_{{ N }}").html("<th colspan=10>РЕКЛАМА TMP</th>");
// добавляем ячейки с дополнительными ценами и новые кнопочки
$("#load_and_banner_{{ N }}").css({"display":"none"});
$("#preloader_{{ N }}").css({"display":"table-row","transition":"1s"});// подсчитать сколько прочеканных оферов для сравнения
$("#tmp").load(
"/next_price_frame/idA{{ APPARTMENT_ID }}MDPO{{ MOUNT_DIM_PER_OFFER }}LON0LAT0N{{ N }}",
function (){
window.frame = $("#tmp").html();
$("#price-list > tbody").append(window.frame);
}
);
window.setTimeout(
function show_adv() {
$("#load_and_banner_{{ N }}").html("<td colspan='11' bgcolor='#CCCCCC' align='center'><center><a href='https://api.ozon.ru/partner-tools.affiliates/pankarta/11052421746600/link?partner=e-serg&&utm_content=banner&width=728&height=90' target='_blank'><img src='https://api.ozon.ru/partner-tools.affiliates/pankarta/11052421746600/image?partner=e-serg&utm_content=banner&width=728&height=90' width='728px' height='90px'></a><small><br/>↑ Здесь могла бы быть ваша реклама ↑</small></center></td>");
$("#load_and_banner_{{ N }}").css({"display":"table-row","transition":"all 5s"});
$("#preloader_{{ N }}").css({"display":"none","transition":"1s"});
// (adsbygoogle=window.adsbygoogle || []).push({});
window.count = 0;
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
window.count++;
$("#NumberOfSelected").html(window.count);
$('[data-toggle="popover"]').popover({ // реинициализировать подгружаемые поповеры
placement: "top",
html: true,
content: function () {
// сохранить текущий контекст
var _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id-set"),
function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
});
},
2800);
}
</script>
<td colspan="2"><a class="btn btn-info btn-block" data-toggle="collapse" onclick="Click2CompareOffers();">Сравнить выбранные (<span id="NumberOfSelected">0</span>) <small class="glyphicon-stats glyphicon"></small></a><p id="tmp"></p></td>
<td colspan="8">{% if N != "-1" %}<a href="javascript://" class="btn btn-info btn-block" onclick="get_next_pricelist_frame();">Ещё коммерческие предложения окон &nbsp;<small class="glyphicon-refresh glyphicon"></small></a>{% endif %}</td>
<td><a data-toggle="collapse" href="#collapse_it" onclick="get_more_info_about_building()" class="shake-trigger">Подробная информация по зданию <small class="glyphicon-chevron-down glyphicon shake-vertical"></small></a></td>
</tR>

View File

@@ -0,0 +1,207 @@
{% extends "base.html" %}
{% load static %}
{% load filters %}
{% block Title %}Цены на окна для {{ ADDRESS }} — дом серии {{ APART|safe }}{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% 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 %}
{% 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 %}
{% block Top_JS3%}<script type="text/javascript">
function show_phone_num( id ){ // колапсатор для отображения контатной информации постафшика окон
$('#tel'+id).collapse('show');
$('#hid'+id).collapse('hide');
try {
yaCounter32997984.reachGoal('ShowPhone')
} catch (e) {
}
try {
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "2018432", type: "reachGoal", goal: "ViewPhone"});
} catch (e) {
}
}
function show_dtl( id ){ // колапсаторы для отобращения детальной информации оконого набора
$('#dtl'+id).collapse('show');
$('#btn'+id+' a .glyphicon-chevron-down').remove();
var ContentInA = $('#btn'+id+' a').text();
$('#btn'+id).empty();
$('#btn'+id).text(ContentInA);
try {
yaCounter32997984.reachGoal('ShowDetails')
} catch (e) {
}
try {
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "2018432", type: "reachGoal", goal: "ViewDetails"});
} catch (e) {
}
}
$(window).load( // уменьшение картинок .half для ретина-дисплеев
function(){var images = $('.half');images.each(function(i){$(this).width($(this).width()/2);});}
);
var count = 0;
var ForCompare = document.getElementsByName('ForCompare');
$(window).load( // подсчитать сколько прочеканных оферов для сравнения (нужно, когда на страничку возращаются через back, ее подгрущают или она приходит из кеша
function(){
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
count++;
// alert(count);
$('#NumberOfSelected').html(count)
}
);
var ToURL = '';
function Click2CompareOffers(){ // вызывается при клике "сравнить коммерческие предложения"
try{yaCounter32997984.reachGoal('CompareOffers')}catch(e){}
//ForCompare = $('[name]=ForCompare');
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
ToURL += ForCompare[i].value +',';
if (ToURL.match(/[,]/g).length > 1 && ToURL.match(/[,]/g).length < 7 )
location.href = '/compare_offers/' + ToURL.slice(0,-1);
else {
$('#modal-exclamation').modal('show');
ToURL = '';
}
}
function ChangeCountCheckedBox(CHK_ID){ // изменение числа выбранных для сравнения оферов
if ($("#CHK"+CHK_ID).is(":checked")) count++;
else count--;
$("#NumberOfSelected").html(count)
}
function get_more_info_about_building() {
try{yaCounter32997984.reachGoal("ClickBuildingDetails");}catch(e){}
}
$(function () { // инициализация и обработка поповеров рейтинга
$('[data-toggle="popover"]').popover({
placement: "top",
html: true,
content: function () {
// сохранить текущий контекст
var _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id-set"), function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
})
})
</script>{% endblock %}
{% block Top_CSS1 %}<link rel="stylesheet" type="text/css" href="{% static "css/csshake-vertical.min.css" %}">{% endblock %}
{% block Main_Content %}
<span itemscope itemtype="http://schema.org/Product">
<div class="row col-md-12">
<div class="col-md-9">
<h1>Цены на окна для серии {{ APART|safe }} <small>({{ ADDRESS }})</small></h1>
</div>
<div class="col-md-9">
<p>Квартира имеет проёмы (окна и балконные двери) следующих размеров: {% for I_WIN_DIM in FLAP_DIM %}{% if not forloop.first %}{% if forloop.last %} и&nbsp;{% else %}, {% endif %}{% endif %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}&nbsp;см. —&nbsp;{{ I_WIN_DIM.iQuantity }}&nbsp;шт.{% endfor %} Проект (<a href="/catalog/seria/{{ BASE_SERIA_LAT }}/all{{ BASE_SERIA_ID }}">типовая серия {{ BASE_SERIA }}</a>) предполагает следующие схемы открывания окон:</p>
</div>
{# Микроразмектка: названеи продукта #}<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})" />
</div>
<div class="row col-md-12 ShowBigFlapPictures">
<div class="col-sm-9">
{% include 'report/show_big_flap_pictures.html' %}
</div>
<div class="col-sm-3 visible-md visible-lg ap_list">
<h6>Другие типовые квартиры в&nbsp;этом доме:</h6>
<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 %}
</ul>
<a href="/catalog/seria/{{ BASE_SERIA_LAT }}/all{{ BASE_SERIA_ID }}">Информация по серии {{ BASE_SERIA }}</a>
</div>
</div>
<div class="row col-md-12">
<div class="col-md-12">
<p id="tab-note">Таблица содержит цены поставщиков. Клик на&nbsp;название отобразит детальные спецификации каждого предложения: марку профиля рамы и&nbsp;створки, схему стеклопакета, тип фурнитуры, элементы отделки (отлив, подоконник, откос, клапан <nobr>климат-контроля</nobr>) и&nbsp;сопутствующие услуги. Предложения выводятся покадрово, получите следующий кадр кнопкой &laquo;Ещё коммерческие предложения окон&raquo; под таблицей. Просмотреть и&nbsp;сравнить технические характеристик стеклопакетов, профилей и&nbsp;детальное описание сопутствующих услуг возможно с&nbsp;помощью кнопки &laquo;Сравнить выбранные&raquo;.</p>
</div>
{# Микроразмектка: названеи продукта #}
<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})"/>
</div>
<form class="col-md-12" method="get" action="\" id="compare_offers">
{% csrf_token %}
<table class="table" id="price-list">
<thead>
<tr>
<th><b class="glyphicon glyphicon-th-list" title="Добавление набора окон в список сравнения" aria-label="Добавление набора окон в список сравнения"></b></th>
<th>Поставщик окон и название оконного набора<small><br />
кликните чтобы увидеть описание и характеристики предложения</small>
</th>
<th colspan="2">Схема<small><br />
открывания</small></th>
<th>Цена,<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
одно окно</small></th>
<th>N</th>
<th colspan="2" class="hidden-xs hidden-sm">Cумма,<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
однотипные окна</small></th>
<th>Стоимость, <b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
все окна квартиры</small></th>
<th>Скидка</th>
<th>Итого<small><br />
за все окна с учетом скидки</small></th>
</tr>
</thead>
<tbody id="offers">
{% include "report/report_precelist_frame.html" %}
</tbody>
</table>
</form>
</span>
{% 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">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
<p id="shadow_buffer"></p>
</div>
{# модальное окно #}
<div class="modal fade bs-example-modal-sm" id="modal-exclamation" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="mySmallModalLabel">Внимание:</h4>
</div>
<div class="modal-body">
<p>Извините, для сравнения коммерческих предложений окон нужно выбрать не менее двух и не более шести позиций.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Спасибо, все понятно.</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% comment %}
{% block Top_Nav_Bar %}
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
{% endblock %}
{% endcomment %}

View File

@@ -2,15 +2,16 @@
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
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 oknardia.models import Win_MountDim, PriceOffer from oknardia.models import Win_MountDim, PriceOffer, Apartment_Type, Seria_Info, LogVisitPriceReport
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, \
get_geo_distance get_geo_distance
import django.utils.dateformat import django.utils.dateformat
import time import time
import os import os
import re import re
import json
import pytils import pytils
@@ -33,7 +34,7 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
:return: dict -- словарь данных для отображения в фрейме (цены предложений и их характеристики) :return: dict -- словарь данных для отображения в фрейме (цены предложений и их характеристики)
""" """
# ценовая выдача # ценовая выдача
time_for_meta = 0 # время для мета-данных в HTML-кода time_for_meta = 0 # время для мета-данных в HTML-кода
apartment_id = int(apartment_id) apartment_id = int(apartment_id)
mount_dim_per_offer = int(mount_dim_per_offer) mount_dim_per_offer = int(mount_dim_per_offer)
address_longitude = float(address_longitude) address_longitude = float(address_longitude)
@@ -46,7 +47,7 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
if brand_id != 0: if brand_id != 0:
# Это вывод для выджета. Нужны цены только по определенному поставщику # Это вывод для выджета. Нужны цены только по определенному поставщику
add_to_sql_for_widget = f" AND oknardia_merchantbrand.id = {brand_id} " add_to_sql_for_widget = f" AND oknardia_merchantbrand.id = {brand_id} "
offer_per_frame = 1000 # Фреймовый вывод не нужен... фигачим сразу целую 1000 предложений. offer_per_frame = 1000 # Фреймовый вывод не нужен... фигачим сразу целую 1000 предложений.
if int(apartment_id) == 0 and int(win_id) != 0: if int(apartment_id) == 0 and int(win_id) != 0:
# если выводим цены только для одного проема # если выводим цены только для одного проема
offer_per_frame = OFFER_PER_FRAME_FOR_ONE_FLAP offer_per_frame = OFFER_PER_FRAME_FOR_ONE_FLAP
@@ -192,15 +193,15 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
total += i2.fOfferPrice * i2.iQuantity total += i2.fOfferPrice * i2.iQuantity
image_file = get_flaps_for_mini_pictures(i2.sOfferFlapConfig) image_file = get_flaps_for_mini_pictures(i2.sOfferFlapConfig)
dim_in_offer.append({ dim_in_offer.append({
'PRICE': i2.fOfferPrice, 'PRICE': i2.fOfferPrice,
'FLAP': i2.sOfferFlapConfig, 'FLAP': i2.sOfferFlapConfig,
'DESCRIPTION': i2.sDescripion, 'DESCRIPTION': i2.sDescripion,
'WIDTH': i2.iWinWidth, 'WIDTH': i2.iWinWidth,
'HIGHT': i2.iWinHight, 'HIGHT': i2.iWinHight,
'ID': i2.id, 'ID': i2.id,
'IMG_MINI': image_file, 'IMG_MINI': image_file,
'QUANTITY': i2.iQuantity, 'QUANTITY': i2.iQuantity,
'BULLET': [chr(65+cur_bullet+i) for i in range(i2.iQuantity)], 'BULLET': [chr(65 + cur_bullet + i) for i in range(i2.iQuantity)],
# 'BULLET': range(CurBullet, CurBullet+i2.iQuantity), # 'BULLET': range(CurBullet, CurBullet+i2.iQuantity),
'SUBTOTAL': i2.fOfferPrice * i2.iQuantity, 'SUBTOTAL': i2.fOfferPrice * i2.iQuantity,
}) })
@@ -236,59 +237,61 @@ def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_long
# address_latitude) # address_latitude)
else: else:
distance = -1 distance = -1
print(discount)
if discount > 99 or discount < 0.1: if discount > 99 or discount < 0.1:
discount_color1 = "" discount_color1 = ""
discount_color2 = "" discount_color2 = ""
else: else:
color_ratio = (discount + 0.) / 100 color_ratio = (discount + 0.) / 100
discount_color1 = f"#{255 - int(color_ratio * 128): 02x}ff{255 - int(color_ratio * 128) :02x}" discount_color1 = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
discount_color2 = f"#{255-int(color_ratio * 255): 02x}ff{255 - int(color_ratio * 255) :02x}" discount_color2 = f"#{255 - int(color_ratio * 255):02x}ff{255 - int(color_ratio * 255):02x}"
print(discount_color1, discount_color2)
price_frame.append({ price_frame.append({
'DISTANCE': distance, 'DISTANCE': distance,
'DIM': dim_in_offer, 'DIM': dim_in_offer,
'TOTAL': total, 'TOTAL': total,
'DISCOUNT': discount, 'DISCOUNT': discount,
'DISCOUNT_COLOR1': discount_color1, 'DISCOUNT_COLOR1': discount_color1,
'DISCOUNT_COLOR2': discount_color2, 'DISCOUNT_COLOR2': discount_color2,
'FIN_PRICE': fin_price, 'FIN_PRICE': fin_price,
'OFFICE_NAME': i2.sOfficeName, 'OFFICE_NAME': i2.sOfficeName,
'OFFICE_ADDRESS': i2.sOfficeAddress, 'OFFICE_ADDRESS': i2.sOfficeAddress,
'OFFICE_PHONES': i2.sOfficePhones, 'OFFICE_PHONES': i2.sOfficePhones,
'MERCHANT': i2.sMerchantName, 'MERCHANT': i2.sMerchantName,
'MERCHANT_LOGO': i2.pMerchantLogo, 'MERCHANT_LOGO': i2.pMerchantLogo,
'MERCHANT_URL': i2.sMerchantMainURL, 'MERCHANT_URL': i2.sMerchantMainURL,
'MERCHANT_URL_SHOT': re.sub(r"(?:^http://|^https://|/$|www\.)", "", i2.sMerchantMainURL), 'MERCHANT_URL_SHOT': re.sub(r"(?:^http://|^https://|/$|www\.)", "", i2.sMerchantMainURL),
'SETS_NAME': i2.sSetName, 'SETS_NAME': i2.sSetName,
'GLAZING_NAME_B': i2.sGlazingBriefDescription, 'GLAZING_NAME_B': i2.sGlazingBriefDescription,
'GLAZING_MARK': i2.sGlazingMark, 'GLAZING_MARK': i2.sGlazingMark,
'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': pytils.translit.slugify(i2.sProfileName).lower(),
'PVC_MANUFACTURER': i2.sProfileManufacturer, 'PVC_MANUFACTURER': i2.sProfileManufacturer,
'PVC_MANUFACTURER_T': pytils.translit.slugify(i2.sProfileManufacturer).lower(), 'PVC_MANUFACTURER_T': pytils.translit.slugify(i2.sProfileManufacturer).lower(),
'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,
'SETS_IMPLEMENT': i2.sSetImplementAll, 'SETS_IMPLEMENT': i2.sSetImplementAll,
'SETS_IMPLEMENT_R': i2.sSetImplementHandles, 'SETS_IMPLEMENT_R': i2.sSetImplementHandles,
'SETS_IMPLEMENT_P': i2.sSetImplementHinges, 'SETS_IMPLEMENT_P': i2.sSetImplementHinges,
'SETS_IMPLEMENT_Z': i2.sSetImplementLatch, 'SETS_IMPLEMENT_Z': i2.sSetImplementLatch,
'SETS_IMPLEMENT_O': i2.sSetImplementLimiter, 'SETS_IMPLEMENT_O': i2.sSetImplementLimiter,
'SETS_IMPLEMENT_F': i2.sSetImplementCatch, 'SETS_IMPLEMENT_F': i2.sSetImplementCatch,
'SETS_PANES': i2.sSetPanes, 'SETS_PANES': i2.sSetPanes,
'SETS_SLOPE': i2.sSetSlope, 'SETS_SLOPE': i2.sSetSlope,
'SETS_DELIVERY': i2.sSetDelivery, 'SETS_DELIVERY': i2.sSetDelivery,
'SETS_DELIVERY_B': i2.bSetDelivery, 'SETS_DELIVERY_B': i2.bSetDelivery,
'SETS_OTHER': i2.sSetOtherConditions, 'SETS_OTHER': i2.sSetOtherConditions,
'SETS_ID': i2.setID, 'SETS_ID': i2.setID,
'SETS_UNINSTALL_INSTALL': i2.sSetUninstallInstall, 'SETS_UNINSTALL_INSTALL': i2.sSetUninstallInstall,
'SETS_UNINSTALL_INSTALL_B': i2.bSetUninstallInstall, 'SETS_UNINSTALL_INSTALL_B': i2.bSetUninstallInstall,
'SETS_RATING': i2.fSetRating, 'SETS_RATING': i2.fSetRating,
'SETS_RATING_STARTS': get_rating_set_for_stars(i2.fSetRating), 'SETS_RATING_STARTS': get_rating_set_for_stars(i2.fSetRating),
'SETS_DATA_MODIFY': i2.dOfferModify, 'SETS_DATA_MODIFY': i2.dOfferModify,
'IS_COMMERCIAL': i2.bCommercial, 'IS_COMMERCIAL': i2.bCommercial,
}) })
if len(price_frame) == offer_per_frame: if len(price_frame) == offer_per_frame:
break break
count_mount_dim_in_offer = 0 count_mount_dim_in_offer = 0
@@ -439,3 +442,225 @@ def report_one_win_price(request: HttpRequest, win_width_mm: str = '670', win_he
'ticks': float(time.time() - time_start) 'ticks': float(time.time() - time_start)
}) })
return render(request, "report/report_price-offers_for_one_window.html", to_template) return render(request, "report/report_price-offers_for_one_window.html", to_template)
def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str = "61",
slug: str = "g-moskva-ul-novorossijskaya-d-16") -> HttpResponse:
""" Страница с расчетом стоимости окон
:param request: HttpRequest -- входящий http-запрос
:param build_id: str - id здания (адрес в таблице oknardia_building_info.id)
:param apart_id: str - id типовой планировки квартиры (в таблице oknardia_apartment_type.id)
:param slug: str - slug адреса здания
:return: response: HttpResponse
"""
time_start = time.time()
msg = ""
to_template = {}
try:
build_id = int(build_id)
apart_id = int(apart_id)
except ValueError:
return redirect("/")
try:
# получаем все типы квартир для данного адреса (а заодно и попутную информацию о площади дома и пр.)
q_apart = Apartment_Type.objects.raw(
f'SELECT'
f' oknardia_apartment_type.sNameApartment, oknardia_apartment_type.id,'
f' oknardia_apartment_type.iSort, oknardia_seria_info.kRoot_id,'
f' oknardia_building_info.kSeria_Link_id, oknardia_building_info.sAddress,'
f' oknardia_building_info.fGeoCode_Latitude, oknardia_building_info.fGeoCode_Longitude,'
f' oknardia_building_info.fTotal_Area, oknardia_building_info.sCadastre_Num_Area,'
f' oknardia_building_info.fLand_Area, oknardia_building_info.sInventory_Num,'
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 квартиры не для этого дома, то сделаем так, что он будет от этого дома!
apart_inside = False
for i in q_apart:
if i.id == apart_id:
apart_inside = True
break
if not apart_inside or slug != pytils.translit.slugify(list_apart[0].sAddress):
# Переадресация 302, если с apart_id (ID-квартиры нахимичили) или slug-ом.
# Нужно для склейки парных URL в поисковиках
# При переходе с карты apart_id выставляем в 0. Из-за этого тоже нужно 302-переадресация.
return redirect(f"/{build_id}/{list_apart[0].id}/{pytils.translit.slugify(list_apart[0].sAddress)}")
address_latitude = list_apart[0].fGeoCode_Latitude
address_longitude = list_apart[0].fGeoCode_Longitude
to_template.update({'BUILD_ID': build_id})
to_template.update({'APPARTMENT_ID': apart_id})
to_template.update({'ADDRESS_LAT': address_latitude})
to_template.update({'ADDRESS_LON': address_longitude})
to_template.update({'ADDRESS': list_apart[0].sAddress})
to_template.update({'ADDRESS_T': pytils.translit.slugify(list_apart[0].sAddress)})
to_template.update({'SERIA': list_apart[0].sSerias_Project})
# данные нужные для отображения информации о доме (метраж, число подъездов и пр.)
to_template.update({'CADASTRE_NUM': list_apart[0].sCadastre_Num_Area})
to_template.update({'INVENTORY_NUM': list_apart[0].sInventory_Num})
to_template.update({'TYPE_BUILDING': list_apart[0].sType})
to_template.update({'ENERGY_EFFICIENCY': list_apart[0].sEnergy_Efficiency})
if list_apart[0].fTotal_Area != -1.0:
to_template.update({'TOTAL_AREA': f"{list_apart[0].fTotal_Area:.1f}"})
if list_apart[0].fLand_Area != -1.0:
to_template.update({'LAND': f"{list_apart[0].fLand_Area:.1f}"})
if list_apart[0].iNum_Apartments != -1:
to_template.update({'NUM_APARTMENTS': list_apart[0].iNum_Apartments})
if list_apart[0].iStoreys != -1:
to_template.update({'STOREYS': list_apart[0].iStoreys})
if list_apart[0].fCommon_Area != -1.0:
to_template.update({'COMMON_AREA': f"{list_apart[0].fCommon_Area:.1f}"})
if list_apart[0].iEntrances_Porchs != -1:
to_template.update({'NUM_ENTERANCES': list_apart[0].iEntrances_Porchs})
if list_apart[0].fUninhabited_Area != -1.0:
to_template.update({'UNINHABITED_AREA': f"{list_apart[0].fUninhabited_Area:.1f}"})
if list_apart[0].sManagement_Co != u"N/A":
to_template.update({'MANAGEMENT_CO': list_apart[0].sManagement_Co})
if list_apart[0].iElevators != -1:
to_template.update({'NUM_ELEVATORS': list_apart[0].iElevators})
if list_apart[0].fResidential_Area != -1.0:
to_template.update({'RESIDENTIAL_AREA': f"{list_apart[0].fResidential_Area:.1f}"})
if list_apart[0].iNum_Residents != -1:
to_template.update({'NUM_RESIDENTS': list_apart[0].iNum_Residents})
if list_apart[0].fPrivate_Area != -1.0:
to_template.update({'PRIVATE_AREA': f"{list_apart[0].fPrivate_Area:.1f}"})
if list_apart[0].iNum_Accounts != -1:
to_template.update({'NUM_ACCOUNTS': list_apart[0].iNum_Accounts})
if list_apart[0].iCommissioning_year != "N/A":
to_template.update({'COMMISSIONING_YEAR': list_apart[0].iCommissioning_year})
if list_apart[0].fGovernment_Area != -1.0:
to_template.update({'GOVERNMENT_AREA': f"{list_apart[0].fGovernment_Area:.1f}"})
if list_apart[0].fCondition_House != -1.0:
to_template.update({'CONDITION_HOUSE': f"{list_apart[0].fCondition_House:.0f}%"})
if list_apart[0].fCondition_Foundation != -1.0:
to_template.update({'CONDITION_FOUNDATION': f"{list_apart[0].fCondition_Foundation:.0f}%"})
if list_apart[0].fCondition_Walls != -1.0:
to_template.update({'CONDITION_WALL': f"{list_apart[0].fCondition_Walls:.0f}%"})
if list_apart[0].fCondition_Overlap != -1.0:
to_template.update({'CONDITION_OVERLAP': f"{list_apart[0].fCondition_Overlap:.0f}%"})
if list_apart[0].fMunicipal_Area != -1.0:
to_template.update({'MUNICIPAL_AREA': f"{list_apart[0].fMunicipal_Area:.1f}"})
# заполняем массив квартир для отправки в шаблон
apart_in_building = []
for apartment_count in q_apart:
apartment_in = {}
if apartment_count.id != apart_id:
apartment_in.update({'APT_ID': apartment_count.id})
else:
apartment_in.update({'APT_ID': "!"})
apartment_in.update({'APT_NAME': apartment_count.sNameApartment})
apart_in_building.append(apartment_in)
to_template.update({'APARTMENT_IN_BUILDING': apart_in_building})
# узнаем базовую серию дома
q_base_seria = Seria_Info.objects.get(id=list_apart[0].kRoot_id)
base_seria_slug = pytils.translit.slugify(q_base_seria.sName)
to_template.update({'BASE_SERIA': q_base_seria.sName,
'BASE_SERIA_LAT': base_seria_slug,
'BASE_SERIA_ID': q_base_seria.id})
except (ValueError, IndexError, TypeError, ObjectDoesNotExist):
return redirect("/")
###############################################
# получаем массив окон для данной квартиры...
try:
q_md = Win_MountDim.objects.raw(
f'SELECT'
f' oknardia_apartment_type.sNameApartment, oknardia_win_mountdim.iWinWidth,'
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
f' oknardia_win_mountdim.id, oknardia_mountdim2apartment.iQuantity '
f'FROM oknardia_mountdim2apartment '
f'INNER JOIN oknardia_apartment_type'
f' ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id'
f' INNER JOIN oknardia_win_mountdim'
f' ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id '
f'WHERE oknardia_mountdim2apartment.kApartment_id = {apart_id} '
f'GROUP BY'
f' oknardia_apartment_type.sNameApartment, oknardia_win_mountdim.iWinWidth,'
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
f' oknardia_apartment_type.bApartmentCheck, oknardia_win_mountdim.dMountXYZModify,'
f' oknardia_apartment_type.dApartmentModify, oknardia_win_mountdim.iWinLimit,'
f' oknardia_win_mountdim.id, oknardia_mountdim2apartment.iQuantity '
f'ORDER BY'
f' oknardia_win_mountdim.bIsNearDoor DESC,'
f' oknardia_win_mountdim.bIsDoor DESC,'
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)
to_template.update({'APART': list_mount_dim_per_offer[0].sNameApartment})
# получаем данные для отрисовки больших картинок с проемами.
to_template.update(get_flaps_for_big_pictures(q_md))
# <---
except (ValueError, IndexError, TypeError, ObjectDoesNotExist):
return redirect("/")
# получаем данные для фрейма ценовых предложений
price_frame = report_price_frame(apart_id, mount_dim_per_offer, address_longitude, address_latitude)
to_template.update(price_frame)
# print u"строк в querySet:", CountMountDimInFramePage
# dimension_to_template.update({'DISCOUNT_TXT': DiscountTXT})
to_template.update({'MOUNT_DIM_PER_OFFER': mount_dim_per_offer,
'META_DESCRIPTION': "Окнардия ",
'META_KEYWORDS': "Окнардия+ ",
'MSG': msg})
# получаем последние визиты всех посетителей из базы
log_visit = get_last_all_user_visit_list()
id_last_visit_log = log_visit[0]['id'] + 1
# 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: # максимальный размер циклического буфера
id_last_visit_log = 1 # ставим в начало буфера
try:
log_entry = LogVisitPriceReport.objects.get(id=id_last_visit_log)
log_entry.sLogAddress = to_template["ADDRESS"]
log_entry.sLogNameApartment = to_template["APART"]
log_entry.sLogURL = f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}"
log_entry.dLogVisitTime = time.time()
log_entry.save() # UPDATE
except ObjectDoesNotExist:
log_entry = LogVisitPriceReport(
sLogAddress=to_template["ADDRESS"],
sLogNameApartment=to_template["APART"],
sLogURL=f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}",
dLogVisitTime=time.time()
)
log_entry.save() # INSERT
# получаем последние визиты клиента через куки
last_visit = get_last_user_visit_cookies(request)
to_template.update({'LAST_VISIT': get_last_user_visit_list(last_visit)})
# подготавливаем данные о текущем посещении для помещения в cookie
Item = {
"LastURL": f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}",
"LastAddress": to_template["ADDRESS"],
"LastApart": to_template["APART"],
"Time": time.time()}
last_visit.insert(0, Item) # Добавляем текущий Item в начало
last_visit = json.dumps(last_visit[:3]) # упаковываем json без пробелов (три записи)
# print u"сейчас запишем вот эту куку:", LastVisit
to_template.update({'ticks': float(time.time() - time_start)})
response = render(request, "report/report_pricelist.html", to_template)
response.set_cookie("LastVisit", last_visit, max_age=7862400) # ставим или перезаписываем куки (91 день)
return response

View File

@@ -6,6 +6,7 @@ from oknardia.models import LogVisitPriceReport
# from oknardia.settings import * # from oknardia.settings import *
# from web.add_func import normalize, get_rating_set_for_stars # from web.add_func import normalize, get_rating_set_for_stars
# from time import time # from time import time
import django.utils.dateformat
import json import json
import pytils import pytils
@@ -50,19 +51,20 @@ def get_last_all_user_visit_list() -> list:
:return: list -- список четырех последних посещений ценовых предложений всеми пользователями :return: list -- список четырех последних посещений ценовых предложений всеми пользователями
""" """
result_list_visit = [] result_list_visit = []
id_fourth_visit = 0 # id четвертого посещения??? Зачем??? Не помню хоть убей!!! # id_last_visit = 0 # id четвертого посещения??? Зачем??? Не помню хоть убей!!!
try: try:
q_log_visit = LogVisitPriceReport.objects.all().order_by('-dLogVisitTime')[:4] q_log_visit = LogVisitPriceReport.objects.all().order_by('-dLogVisitTime')[:4]
for i in q_log_visit: for i in q_log_visit:
if id_fourth_visit == 0: # if id_last_visit == 0:
id_fourth_visit = i.id # id_last_visit = i.id
result_list_visit.append({ result_list_visit.append({
"Time": pytils.dt.distance_of_time_in_words(int(format(i.dLogVisitTime, 'U'))), "id": i.id,
"Time": pytils.dt.distance_of_time_in_words(int(django.utils.dateformat.format(i.dLogVisitTime, 'U'))),
"LogURL": i.sLogURL, "LogURL": i.sLogURL,
"LogAddress": i.sLogAddress, "LogAddress": i.sLogAddress,
"LogApart": i.sLogNameApartment "LogApart": i.sLogNameApartment
}) })
except LogVisitPriceReport.DoesNotExist: except LogVisitPriceReport.DoesNotExist:
pass pass
# return id_fourth_visit+1, list_visit # return id_last_visit+1, list_visit
return result_list_visit return result_list_visit