Files
2022_oknardia/oknardia/web/prices.py

696 lines
44 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from oknardia.models import Win_MountDim, PriceOffer, Apartment_Type, Seria_Info, LogVisitPriceReport
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.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures, get_flaps_for_mini_pictures, \
get_geo_distance
import django.utils.dateformat
import time
import os
import re
import json
import pytils
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:
""" Формируем выдачу цен для фрейма
:param apartment_id: int -- ID типа квартиры, для которой получаем ценовые предложения
:param mount_dim_per_offer: int -- число различных оконых проемов в этой квартире (чтобы отсеять предложения,
в которых не представлены все проемы)
:param address_longitude: float -- долгота адреса (геокоордината), чтобы рассчитать удаленность компании
предоставившей коммерческие предложения
:param address_latitude: float -- широта адреса (геокоордината), чтобы рассчитать удаленность компании
предоставившей коммерческие предложения
:param frame_begin_n: int -- Номер записи с которой начинается фрейм с ценами (с какого предложения начинать)
:param brand_id: int -- ID бренда, если выбран бренд, то отображаем только предложения этого бренда
(нужно для виджета, где отображаются предложения только от одной компании)
если 0, то отображаем все предложения
:param win_id: int -- ID окна, если выбрано окно, то отображаем только предложения этого окна
:return: dict -- словарь данных для отображения в фрейме (цены предложений и их характеристики)
"""
# ценовая выдача
time_for_meta = 0 # время для мета-данных в HTML-кода
apartment_id = int(apartment_id)
mount_dim_per_offer = int(mount_dim_per_offer)
address_longitude = float(address_longitude)
address_latitude = float(address_latitude)
frame_begin_n = int(frame_begin_n)
brand_id = int(brand_id)
win_id = int(win_id)
add_to_sql_for_widget = ""
offer_per_frame = OFFER_PER_FRAME
if brand_id != 0:
# Это вывод для выджета. Нужны цены только по определенному поставщику
add_to_sql_for_widget = f" AND oknardia_merchantbrand.id = {brand_id} "
offer_per_frame = 1000 # Фреймовый вывод не нужен... фигачим сразу целую 1000 предложений.
if int(apartment_id) == 0 and int(win_id) != 0:
# если выводим цены только для одного проема
offer_per_frame = OFFER_PER_FRAME_FOR_ONE_FLAP
q_price_offer = PriceOffer.objects.raw(
f"SELECT"
f" oknardia_priceoffer.id, oknardia_priceoffer.iOfferImpressions,"
f" oknardia_priceoffer.fOfferPrice, oknardia_priceoffer.dOfferModify,"
f" oknardia_priceoffer.fOfferRating, oknardia_priceoffer.sOfferFlapConfig,"
f" oknardia_priceoffer.iOfferViews, oknardia_priceoffer.sOfferActive,"
f" oknardia_win_mountdim.sDescripion, oknardia_win_mountdim.id AS mID, "
f" oknardia_win_mountdim.bIsNearDoor, oknardia_win_mountdim.bIsDoor,"
f" oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight,"
f" oknardia_setkit.id AS setID,"
f" oknardia_setkit.sSetName, oknardia_setkit.dSetModify,"
f" oknardia_setkit.sSetClimateControl, oknardia_setkit.sSetSill,"
f" oknardia_setkit.sSetImplementAll, oknardia_setkit.sSetImplementHandles,"
f" oknardia_setkit.sSetImplementHinges, oknardia_setkit.sSetImplementLatch,"
f" oknardia_setkit.sSetImplementLimiter, oknardia_setkit.sSetImplementCatch,"
f" oknardia_setkit.sSetPanes, oknardia_setkit.sSetSlope,"
f" oknardia_setkit.sSetOtherConditions, oknardia_setkit.sSetActive,"
f" oknardia_setkit.bSetDelivery, oknardia_setkit.sSetDelivery,"
f" oknardia_setkit.sSetUninstallInstall, oknardia_setkit.bSetUninstallInstall,"
f" oknardia_setkit.fSetRating, oknardia_setkit.iSetNumEval,"
f" oknardia_setkit.iSetImpressions, oknardia_setkit.iSetViews,"
f" (oknardia_setkit.dSetCommercialUntil > NOW()) AS bCommercial,"
f" oknardia_merchantoffice.sOfficePhones, "
f" oknardia_merchantoffice.sOfficeDiscountMetaFormula,"
f" oknardia_merchantoffice.sOfficeName, oknardia_merchantoffice.sOfficeAddress,"
f" oknardia_glazing.fGlazingRating,"
f" oknardia_glazing.sGlazingName, oknardia_glazing.sGlazingBriefDescription,"
f" oknardia_glazing.sGlazingMark, oknardia_glazing.sGlazingToning,"
f" oknardia_pvcprofiles.sProfileBriefDescription, oknardia_pvcprofiles.id AS pwc_id,"
f" oknardia_pvcprofiles.sProfileReinforcement, oknardia_pvcprofiles.sProfileSealDescription,"
f" oknardia_pvcprofiles.sProfileName, oknardia_pvcprofiles.sProfileColor,"
f" oknardia_pvcprofiles.fProfileRating, oknardia_pvcprofiles.sProfileManufacturer,"
f" oknardia_merchantbrand.sMerchantName, oknardia_merchantbrand.pMerchantLogo,"
f" oknardia_merchantbrand.sMerchantMainURL, oknardia_merchantbrand.id AS brand_id,"
f" 1 AS iQuantity, 0 AS fOfficeGeoCode_Longitude, 0 AS fOfficeGeoCode_Latitude "
f"FROM oknardia_priceoffer"
f" INNER JOIN oknardia_win_mountdim"
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
f"WHERE oknardia_priceoffer.sOfferActive IS TRUE"
f" AND oknardia_setkit.sSetActive IS TRUE "
f" AND oknardia_win_mountdim.id = {int(win_id)}"
f" {add_to_sql_for_widget} "
f"ORDER BY"
f" oknardia_priceoffer.dOfferModify DESC "
f"LIMIT {int(frame_begin_n)}, 10000;")
else:
# если выводим цены для типовой квартиры
# print("Нужно несколько окон для квартиры")
q_price_offer = PriceOffer.objects.raw(
f"SELECT"
f" oknardia_priceoffer.*,"
f" oknardia_win_mountdim.*,"
f" oknardia_setkit.*,"
f" oknardia_merchantoffice.*,"
f" oknardia_glazing.*,"
f" oknardia_pvcprofiles.*,"
f" oknardia_merchantbrand.*,"
f" oknardia_mountdim2apartment.iQuantity,"
f" oknardia_win_mountdim.id AS mID, "
f" oknardia_setkit.id AS setID,"
f" (oknardia_setkit.dSetCommercialUntil > NOW()) AS bCommercial,"
f" oknardia_pvcprofiles.id AS pwc_id,"
f" oknardia_merchantbrand.id AS brand_id "
f"FROM oknardia_priceoffer"
f" INNER JOIN oknardia_win_mountdim"
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_mountdim2apartment"
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_merchantbrand"
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)}"
f" AND oknardia_setkit.sSetActive IS TRUE {add_to_sql_for_widget} "
f"ORDER BY"
f" oknardia_setkit.dSetCreate DESC, " # Сейчас окна в наборе собираются через это
f" oknardia_win_mountdim.bIsNearDoor DESC,"
f" oknardia_win_mountdim.bIsDoor DESC,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight DESC "
f"LIMIT {int(frame_begin_n)} , 10000;")
# print list(qPO)
price_frame = []
count_mount_dim_in_offer = 0
dim_in_offer = []
total = 0
cur_bullet = 0
previous_set_id = 0
count_mount_dim_in_frame_page = 0
# Так как получен QuerySet начиная с frame_begin_n, то для того чтобы получить frame_begin_n следующего фрйма
# считаем не от нуля, а от старого frame_begin_n
n_begin = int(frame_begin_n)
# Проверяем есть ли папка для хранения мини-картинки конфигурации схемы открывания.
if not os.path.exists(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_IMGFLAPCONFIG}"):
# создаем такую папку если её нет
os.makedirs(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_IMGFLAPCONFIG}")
# print(">>>>>>>>>>>>>", apartment_id)
for i2 in q_price_offer:
n_begin += 1
count_mount_dim_in_frame_page += 1
# Случается, что в том или ином наборе поставщиком просчитаны не все проёмы.
# Чтобы не происходило формирование предложения (офера) из окон разных наборов делаем проверку
# является ли текущий проём в предложении из того же набора, что и предыдущий.
# Если он из другого набора, то удаляем предыдущий проём из предложения и начинаем
# формирование предложения сначала.
if count_mount_dim_in_offer == 0:
previous_set_id = i2.setID
else:
if previous_set_id != i2.setID:
# print("Сбой в наборе. Обнуляем набор")
previous_set_id = i2.setID
count_mount_dim_in_offer = 0
total = 0
cur_bullet = 0
dim_in_offer.pop()
dim_in_offer = []
# print("mID:", i2.mID, " || pID:", i2.id, " || price:", i2.fOfferPrice, " || N:", i2.iQuantity,
# " || set:", i2.sSetName, " || merchant:", i2.sOfficeName)
total += i2.fOfferPrice * i2.iQuantity
image_file = get_flaps_for_mini_pictures(i2.sOfferFlapConfig)
dim_in_offer.append({
'PRICE': i2.fOfferPrice,
'FLAP': i2.sOfferFlapConfig,
'DESCRIPTION': i2.sDescripion,
'WIDTH': i2.iWinWidth,
'HIGHT': i2.iWinHight,
'ID': i2.id,
'IMG_MINI': image_file,
'QUANTITY': i2.iQuantity,
'BULLET': [chr(65 + cur_bullet + i) for i in range(i2.iQuantity)],
# 'BULLET': range(CurBullet, CurBullet+i2.iQuantity),
'SUBTOTAL': i2.fOfferPrice * i2.iQuantity,
})
cur_bullet += i2.iQuantity
count_mount_dim_in_offer += 1
if count_mount_dim_in_offer == mount_dim_per_offer:
# print("-----------------")
# узнаем скидку через разбор формулы на метаязыке
discount = 0
try:
meta_keys = eval(i2.sOfficeDiscountMetaFormula)
if KEY_DICSOUNT in meta_keys:
# скидки рассчитываются исходя из общей суммы
for CountVal in sorted(meta_keys[KEY_DICSOUNT]):
# print(CountVal, "::", meta_keys[KEY_DICSOUNT][CountVal])
if float(total) > float(CountVal):
discount = meta_keys[KEY_DICSOUNT][CountVal]
# # DiscountTXT += u"!!%d!!" % Discount
# print("Значит DISCOUNT: ", Discount)
except (ValueError, TypeError):
pass
fin_price = total * (100 - discount) / 100
# уточняем, есть ли в принципе геокоординаты?
if int(i2.fOfficeGeoCode_Longitude) != 0 and int(i2.fOfficeGeoCode_Latitude) != 0 and \
int(address_longitude) != 0 and int(address_latitude) != 0:
# рассчитываем дистанцию между адресом дома и офиса.
distance = get_geo_distance(i2.fOfficeGeoCode_Longitude, i2.fOfficeGeoCode_Latitude, address_longitude,
address_latitude)
# т.к. из-за изменений в api яндекс карт поменялась местами широта-долгота и вообще, то
# порядок переменных строчной выше... На самом деле должно быть как в закоментированной
# строке ниже
# distance = get_geo_distance(i2.fOfficeGeoCode_Longitude, i2.fOfficeGeoCode_Latitude,
# address_longitude, address_latitude)
else:
distance = -1
# print(discount)
if discount > 99 or discount < 0.1:
discount_color1 = ""
discount_color2 = ""
else:
color_ratio = (discount + 0.) / 100
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}"
# print(discount_color1, discount_color2)
price_frame.append({
'DISTANCE': distance,
'DIM': dim_in_offer,
'TOTAL': total,
'DISCOUNT': discount,
'DISCOUNT_COLOR1': discount_color1,
'DISCOUNT_COLOR2': discount_color2,
'FIN_PRICE': fin_price,
'OFFICE_NAME': i2.sOfficeName,
'OFFICE_ADDRESS': i2.sOfficeAddress,
'OFFICE_PHONES': i2.sOfficePhones,
'MERCHANT': i2.sMerchantName,
'MERCHANT_LOGO': i2.pMerchantLogo,
'MERCHANT_URL': i2.sMerchantMainURL,
'MERCHANT_URL_SHOT': re.sub(r"(?:^http://|^https://|/$|www\.)", "", i2.sMerchantMainURL),
'SETS_NAME': i2.sSetName,
'GLAZING_NAME_B': i2.sGlazingBriefDescription,
'GLAZING_MARK': i2.sGlazingMark,
'GLAZING_TONING': i2.sGlazingToning,
'PVC_ID': i2.pwc_id,
'PVC_NAME': i2.sProfileName,
'PVC_NAME_T': pytils.translit.slugify(i2.sProfileName).lower(),
'PVC_MANUFACTURER': i2.sProfileManufacturer,
'PVC_MANUFACTURER_T': pytils.translit.slugify(i2.sProfileManufacturer).lower(),
'PVC_SEAL': i2.sProfileSealDescription,
'SETS_CLIMATE_CONTROL': i2.sSetClimateControl,
'SETS_SILL': i2.sSetSill,
'SETS_IMPLEMENT': i2.sSetImplementAll,
'SETS_IMPLEMENT_R': i2.sSetImplementHandles,
'SETS_IMPLEMENT_P': i2.sSetImplementHinges,
'SETS_IMPLEMENT_Z': i2.sSetImplementLatch,
'SETS_IMPLEMENT_O': i2.sSetImplementLimiter,
'SETS_IMPLEMENT_F': i2.sSetImplementCatch,
'SETS_PANES': i2.sSetPanes,
'SETS_SLOPE': i2.sSetSlope,
'SETS_DELIVERY': i2.sSetDelivery,
'SETS_DELIVERY_B': i2.bSetDelivery,
'SETS_OTHER': i2.sSetOtherConditions,
'SETS_ID': i2.setID,
'SETS_UNINSTALL_INSTALL': i2.sSetUninstallInstall,
'SETS_UNINSTALL_INSTALL_B': i2.bSetUninstallInstall,
'SETS_RATING': i2.fSetRating,
'SETS_RATING_STARTS': get_rating_set_for_stars(i2.fSetRating),
'SETS_DATA_MODIFY': i2.dOfferModify,
'IS_COMMERCIAL': i2.bCommercial,
})
if len(price_frame) == offer_per_frame:
break
count_mount_dim_in_offer = 0
dim_in_offer = []
total = 0
cur_bullet = 0
# узнаем дату-время самого свежего ценового предложения для размещения в META-тега
if time_for_meta == 0 or django.utils.dateformat.format(time_for_meta, 'U') < \
django.utils.dateformat.format(i2.dOfferModify, 'U'):
time_for_meta = i2.dOfferModify
if time_for_meta == 0 or django.utils.dateformat.format(time_for_meta, 'U') < \
django.utils.dateformat.format(i2.dSetModify, 'U'):
time_for_meta = i2.dSetModify
# массив ценовых предложений (что бы предложения на одной дистанции были в случайном порядке)
# random.shuffle(PriceFrame)
# сортируем по удаленности
price_frame = sorted(price_frame, key=lambda item: item['DISTANCE'])
if len(price_frame) < offer_per_frame:
n_begin = '-1'
return {'META_DATA_PUBLISH': time_for_meta, 'PRICE_FRAME': price_frame, 'N': n_begin}
def report_one_win_price(request: HttpRequest, win_width_mm: str = '670', win_height_mm: str = '2160',
win_id: str = '16') -> HttpResponse:
""" Формируем выдачу цен для единичного ТИПОВОГО окна (т.е. проема из серийного дома).
:param request: HttpRequest -- входящий http-запрос
:param win_width_mm: str -- Ширина проема в миллиметрах (это SEO-параметр, в реальности он будет получен из базы)
:param win_height_mm: str -- Высота проема в миллиметрах (это SEO-параметр, в реальности он будет получен из базы)
:param win_id: str -- ID проема (см. таблицу oknardia_win_mountdim)
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
to_template = {}
try:
# т.к. для вызова GetFlapDim4BigPictures нужно иметь внутри queryset поле iQuantity нельзя использовать
# простой запрос (см. следующую строку).
# qWinInfo = Win_MountDim.objects.filter(id=int(win_id))
# Придется сделать запрос немного сложнее:
q_win_info = Win_MountDim.objects.raw(
f'SELECT 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, 0 as iQuantity '
f'FROM oknardia_win_mountdim '
f'WHERE oknardia_win_mountdim.id = {int(win_id)};'
)
list_win_info = list(q_win_info)
# Если размеры типового проема не совпадают с размерами из базы, то подменяем
# на правильные и перевызываем страницу
if (list_win_info[0].iWinWidth * 10 != int(win_width_mm)) or \
(list_win_info[0].iWinHight * 10 != int(win_height_mm)):
return redirect(f"/tsena-odnogo-okna/{list_win_info[0].iWinWidth * 10}x{list_win_info[0].iWinHight * 10}"
f"mm/tip{win_id}")
except (ObjectDoesNotExist, ValueError, IndexError, TypeError):
return redirect("/tsena-odnogo-okna/670x2160mm/tip16")
# все хорошо, засылаем картинку в шаблон
to_template.update(get_flaps_for_big_pictures(list_win_info))
# получаем варианты схемы открывания (для графиков)
q_offer_flap_variation = PriceOffer.objects.raw(
f'SELECT'
f' COUNT(oknardia_priceoffer.sOfferFlapConfig) AS id,'
f' "" AS IMG_MINI,'
f' "" AS STR_NUM,'
f' oknardia_priceoffer.sOfferFlapConfig '
f'FROM oknardia_priceoffer '
f'WHERE oknardia_priceoffer.sOfferActive <> 0'
f' AND oknardia_priceoffer.kOffer2MountDim_id = {int(win_id)} '
f'GROUP BY oknardia_priceoffer.sOfferFlapConfig,'
f' oknardia_priceoffer.sOfferActive,'
f' oknardia_priceoffer.kOffer2MountDim_id '
f'ORDER BY id DESC;'
)
list_offer_flap_variation = list(q_offer_flap_variation)
for i in range(0, len(list_offer_flap_variation)):
if i < 3:
list_offer_flap_variation[i].STR_NUM = "вариант " + pytils.numeral.in_words(i + 1)
elif i == 3:
list_offer_flap_variation[i].STR_NUM = "остальные варианты"
continue
else:
list_offer_flap_variation[3].id += list_offer_flap_variation[i].id
continue
list_offer_flap_variation[i].IMG_MINI = get_flaps_for_mini_pictures(
list_offer_flap_variation[i].sOfferFlapConfig
)
to_template.update({'LIST_FLAP_VARIATION': list_offer_flap_variation[:4]})
to_template.update({'NUM_FLAP_VARIATION_IN_WORD': pytils.numeral.sum_string(len(list_offer_flap_variation),
pytils.numeral.MALE,
("вариант схемы",
"варианта схем",
"вариантов схем"))})
#
q = PriceOffer.objects.raw(f'SELECT'
f' COUNT(oknardia_priceoffer.kOfferFromUser_id) AS id,'
f' oknardia_priceoffer.kOfferFromUser_id,'
f' oknardia_priceoffer.kOffer2MountDim_id '
f'FROM oknardia_priceoffer '
f'WHERE oknardia_priceoffer.kOffer2MountDim_id = {int(win_id)} '
f'GROUP BY oknardia_priceoffer.kOffer2MountDim_id,'
f' oknardia_priceoffer.kOfferFromUser_id;')
to_template.update({'NUM_TOTAL_FIRM_N_WORD': pytils.numeral.get_plural(len(list(q)),
("компании", "компаний", "компаний"))})
q = PriceOffer.objects.filter(kOffer2MountDim_id=int(win_id))
to_template.update({'NUM_TOTAL_OFFER_N_WORD': pytils.numeral.get_plural(q.count(),
("готовый расчёт", "готовых расчёта",
"готовых расчётов"))})
to_template.update({'NUM_ARCHIVE_OFFER': q.filter(sOfferActive=0).count()})
#
q_seria_for_win = PriceOffer.objects.raw(
f'SELECT'
f' oknardia_seria_info.sName, oknardia_seria_info.id AS id,'
f' "" AS sNameLat,'
f' COUNT(oknardia_mountdim2apartment.id) AS num_variation_of_apartment '
f'FROM oknardia_apartment_type'
f' INNER JOIN oknardia_mountdim2apartment'
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' INNER JOIN oknardia_seria_info'
f' ON oknardia_apartment_type.kSeria_id = oknardia_seria_info.id '
f'WHERE oknardia_win_mountdim.id = {int(win_id)} '
f'GROUP BY oknardia_win_mountdim.id,'
f' oknardia_seria_info.sName,'
f' oknardia_seria_info.id '
f'ORDER BY oknardia_seria_info.sName;'
)
list_seria_for_win = list(q_seria_for_win)
for i in list_seria_for_win:
i.sNameLat = pytils.translit.slugify(i.sName)
i.num_variation_of_apartment = pytils.numeral.sum_string(i.num_variation_of_apartment,
pytils.numeral.MALE,
("типовую планировку квартиры",
"типовые планировки квартир",
"типовых планировок квартир"))
to_template.update(report_price_frame(0, 1, 0, 0, 0, 0, int(win_id)))
to_template.update({
'SERIA_FOR_WIN': list_seria_for_win,
'WIN_ID': int(win_id),
'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.time() - time_start)
})
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
def next_price_frame(request: HttpRequest, apart_id: str = "1", mount_dim_per_offer: str = "1",
address_longitude: str = "0.", address_latitude: str = "0.",
frame_begin_n: str = "0") -> HttpResponse:
""" Возвращает очередным фреймом ценовых предложений.
:param request: HttpRequest -- входящий HTTP-запрос
:param apart_id: str -- ID типовой квартиры, для которой получаем ценовые предложения
:param mount_dim_per_offer: str -- число различных оконных проемов в этой квартире (чтобы отсеять предложения,
в которых не представлены все проемы)
:param address_longitude: str -- долгота адреса (геокоордината), для которого получаем ценовые предложения, чтобы
рассчитать удаленность компании предоставившей коммерческие предложения
:param address_latitude: str -- широта адреса (геокоордината), для которого получаем ценовые предложения, чтобы
рассчитать удаленность компании предоставившей коммерческие предложения
:param frame_begin_n: str -- Номер записи с которой начинается фрейм с ценами
:return: HttpResponse -- HTTP-ответ
"""
time_start = time.time()
# получаем данные для фрейма ценовых предложений
price_frame = report_price_frame(int(apart_id), int(mount_dim_per_offer), float(address_longitude),
float(address_latitude), int(frame_begin_n))
to_template = price_frame
to_template.update({'APPARTMENT_ID': apart_id,
'MOUNT_DIM_PER_OFFER': mount_dim_per_offer,
'ADDRESS_LAT': address_latitude,
'ADDRESS_LON': address_longitude,
'ticks': float(time.time() - time_start)})
return render(request, "report/report_precelist_frame.html", to_template)