# -*- 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 #p rint(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}" #p rint(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 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-ответ с JSON-данными: """ time_start = time.time() # получаем данные для фрейма ценовых предложений PriceFrame = report_price_frame(int(apart_id), int(mount_dim_per_offer), float(address_longitude), float(address_latitude), int(frame_begin_n)) to_template = PriceFrame 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) 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