Пример #1
0
    def handle(self, *args, **options):
        """Загрузка cdr_csv информации о звонках в базу"""
        is_running = search_process(q=('load_cdr_csv', 'manage.py'))
        if is_running:
            logger.error('Already running %s' % (is_running, ))
            exit()

        # Разовая операция, нужна, чтобы привязать
        # звонки на наши номера, например, 73952546133,
        # а в белом списке этот телефон стоит как 83952546133
        if options.get('link_redirects2clients'):
            # Достаем и подготавливаем редиректы
            redirects = Redirects.objects.all().values_list('phone', flat=True)
            redirects = [
                kill_quotes(redirect, 'int') for redirect in redirects
            ]
            redirects = ['7%s' % redirect[1:] for redirect in redirects]
            rows = CdrCsv.objects.filter(dest__in=redirects,
                                         client_id__isnull=True).values(
                                             'id', 'dest')
            for row in rows:
                dest = '8%s' % row['dest'][1:]
                client = PhonesWhiteList.objects.filter(phone=dest).first()
                if client:
                    CdrCsv.objects.filter(pk=row['id']).update(
                        client_id=client.tag, client_name=client.name)
                    print(row['id'], row['dest'], client.name, client.tag)
            return

        # Разовая операция, нужна, чтобы задать правильный путь
        # для звонков через переадресацию, т/к они встают как uuid
        # без пути к файлу и расширения
        if options.get('fix_redirects2clients'):
            # Достаем и подготавливаем редиректы
            redirects = Redirects.objects.all().values_list('phone', flat=True)
            redirects = [
                kill_quotes(redirect, 'int') for redirect in redirects
            ]
            print(redirects)
            rows = CdrCsv.objects.filter(dest__in=redirects,
                                         context='redirects_context')
            for row in rows:
                new_dest = '7%s' % row.dest[1:]
                CdrCsv.objects.filter(pk=row.id).update(dest=new_dest)
                print(row.id, new_dest)
            return

        analyze_logs()
Пример #2
0
def prepare_session(request, phone: str = None):
    """Подготовить сессию для регистрации/обновления
       профиля с подтверждением по обратному звонку
       :param request: HttpRequest
       :param phone: Телефон (если нет пользователя)
    """
    result = {}
    shopper = get_shopper(request)
    if request.method == 'GET' and (shopper or phone):
        if shopper:
            phone = shopper.phone
        phone = kill_quotes(phone, 'int')
        request.session['confirm_phone'] = GenPasswd(4, '1234567890')
        request.session['phone'] = phone
        request.session.save()
        # Скрипт отправляет на свич телефон
        # и код и свич звонит и диктует
        params = {
            'phone': phone,
            'digit': request.session['confirm_phone'],
        }
        r = requests.get('%s/freeswitch/sms_service/say_code/' %
                         settings.FREESWITCH_DOMAIN,
                         params=params)

        result = r.json()
    return result
Пример #3
0
 def save(self, *args, **kwargs):
     if self.phone:
         phone = kill_quotes(self.phone, 'int')
         if phone.startswith('7'):
             phone = '8%s' % (phone[1:], )
         self.phone = phone
     super(PhonesWhiteList, self).save(*args, **kwargs)
Пример #4
0
def set_color(request):
    """Аякс запрос по сохранению цвета на товар
    """
    result = {}
    product_id = request.GET.get('product_id')
    if not product_id.isdigit():
        return JsonResponse(result, safe=False)
    color = request.GET.get('color')
    if color:
        color = kill_quotes(color, 'int')
    if not color:
        color = 0
    product = Products.objects.filter(pk=product_id).first()
    if product:
        if request.user.has_perm('products.change_products'):
            product_color = ProductColor.objects.filter(product=product).first()
            if product_color:
                product_color.color = color
            else:
                product_color = ProductColor(product=product)
            product_color.save()
            result['success'] = 'Основной цвет сохранен'
        else:
            result['error'] = 'Недостаточно прав'
    else:
        result['error'] = 'Товар не найден'
    return JsonResponse(result, safe=False)
 def update_product(self, attributes):
     """Обновление товара
        :param attributes: атрибуты товара
     """
     articul = '_%s' % attributes.get(self.Articul)
     code = attributes.get(self.Kod)
     count = ''.join(attributes.get(self.Count, '').split())
     manufacturer = attributes.get(self.Manufacturer)
     price = attributes.get(self.Cost)
     price = kill_quotes(price, 'int')
     price = price.replace(',', '.')
     name = attributes.get(self.Name)
     analog = Products.objects.filter(code=code).first()
     if not analog:
         #logger.info('[ERROR]: product not exists: %s' % articul)
         return
     params = {
         'name': name,
         'count': count,
         'price': price,
         'manufacturer': manufacturer,
     }
     try:
         Products.objects.filter(pk=analog.id).update(**params)
     except Exception as e:
         print(params, e)
         return
     self.updated.append(analog.code)
Пример #6
0
def defiz_phone(phone):
    """Дефизы в телефоне
       :param phone: телефон 83952123321
    """
    if not phone:
        return phone

    if type(phone) == int:
        phone = str(phone)
    phone = kill_quotes(phone, 'int')
    phone_len = len(phone)

    if phone_len == 5:
        phone = '%s-%s' % (phone[:3], phone[3:])
    elif phone_len == 6:
        phone = '%s-%s' % (phone[:3], phone[3:])
    elif phone_len == 7:
        phone = '%s-%s-%s' % (phone[:1], phone[1:4], phone[4:])
    elif phone_len == 10:
        if phone.startswith('9'):  # сотовые
            phone = '(%s) %s-%s-%s' % (phone[:3], phone[3], phone[4:7],
                                       phone[7:])
        else:  # городские
            phone = '(%s) %s-%s' % (phone[:4], phone[4:7], phone[7:])
    elif phone_len == 11:
        if phone[1] == '9':  # сотовые
            phone = '%s (%s) %s-%s-%s' % (phone[0], phone[1:4], phone[4],
                                          phone[5:8], phone[8:])
        else:  # городские
            phone = '%s (%s) %s-%s' % (phone[0], phone[1:5], phone[5:8],
                                       phone[8:])
    return phone
Пример #7
0
def check_phone(phone):
    """Проверка телефона на валидность
       :param phone: телефон
    """
    if not phone:
        return
    phone = kill_quotes(phone, 'int')
    if len(phone) == 11 and phone[0] in ('7', '8'):
        phone = '8%s' % phone[1:]
        return phone
Пример #8
0
def textize(text: str):
    """Убираем из текста все кавычки и спец символы
       Нужно для вставки в атрибуты тегов,
       например alt="" или title=""
       :param text: текст
    """
    if not text:
        return ''
    if not isinstance(text, str):
        return text
    text = kill_quotes(text, 'strict_text', ' ')
    return text
Пример #9
0
def imagine(img: str, size: str, source: str, alt: str = ''):
    """Создание миниатюры изображения
       :param img: имя файла, например 1.jpg
       :param size: размер, например 150х150, x разделитель
       :param source: папка с исходным изображением, например, logos
       :param alt: текст alt для изображения,
                   если тип bool вернем просто путь до изображения
       USAGE:
       <img src="{% imagine 'help.png' '150x150' 'img' %}"/>
       {% imagine 'help.png' '150x150' 'img' True %} - просто путь
    """
    ups_path = UPS_PATH
    ups_image = '<img loading="lazy" src="%s" />' % ups_path
    if not img:
        if isinstance(alt, bool):
            return ups_path
        return ups_image
    # -----------------------------------
    # Изображение на удаленном хостинге
    # Весь удаленно расположенный контент
    # следует грузить через lazy load js
    # Нужно передать размеры XXXxYYY
    # -----------------------------------
    if img.startswith('http'):
        if isinstance(alt, bool):
            return img
        return '<img data-original="%s?size=%s" alt="%s" class="lazy" src="/static/img/misc/loading.gif" loading="lazy" />' % (
            img, size, kill_quotes(alt, 'strict_text', ' '))

    path_resized_img = imagine_image(img, size, source)
    if not path_resized_img:
        if isinstance(alt, bool):
            return ups_path
        return ups_image

    if isinstance(alt, bool):
        return path_resized_img

    return '<img src="%s" alt="%s" loading="lazy" />' % (
        path_resized_img, kill_quotes(alt, 'strict_text', ' '))
Пример #10
0
    def save(self, *args, **kwargs):
        super(Redirects, self).save(*args, **kwargs)
        if not self.is_active:
            self.drop_extension()
            return
        extension = """
<extension name="redirect_{}">
  <condition field="destination_number" expression="^([78]{})$">
    <action application="set" data="effective_caller_id_number={}"/>
    <action application="set" data="effective_caller_id_name={}"/>
    <action application="set" data="ringback={}"/>
    <action application="export" data="hold_music={}"/>
    <action application="set" data="ignore_early_media=true" />
    <action application="set" data="record_file_name={}"/>
    <action application="set" data="media_bug_answer_req=true"/>
    <action application="export" data="execute_on_answer=record_session {}"/>
    <action application="set" data="sip_h_Diversion=&quot;{}&quot; <sip: {}@{}>;reason=unconditional;"/>
    <action application="bridge" data="sofia/gateway/{}/{}"/>
  </condition>
</extension>""".format(self.phone,
                       kill_quotes(self.phone[1:], 'int'),
                       '${caller_id_number}',
                       '${caller_id_number}',
                       '${us-ring}',
                       '$${hold_music}',
                       '$${base_dir}/${context}/${strftime(%Y-%m-%d)}/${destination_number}_${uuid}.wav',
                       '${record_file_name}',
                       '${diversion_phone}',
                       '${diversion_phone}',
                       '${diversion_domain}',
                       self.gw,
                       kill_quotes(self.dest, 'int'))
        fname = full_path('%s/redirect_%s.xml' % (self.FOLDER, self.id))
        if check_path(fname):
            make_folder(self.FOLDER)
        with open(fname, 'w+') as f:
            f.write(extension)
        FreeswitchBackend(settings.FREESWITCH_URI).reloadxml()
Пример #11
0
def hershin(string, result):
    """1) Заменить в строке запятые на пробелы
       2) Разбить по пробелам строку
       3) Проверить не входит ли уже это слово в результат
       4) Добавить в кортеж в нижнем регистре
    """
    if not string:
        return result
    string = kill_quotes(string, 'strict_text', ' ')
    string = string.split()
    for item in string:
        if item:
            if item == '-':
                continue
            item = item.lower()
            if not item in result:
                result.append(item)
    return result
Пример #12
0
    def save(self, *args, **kwargs):
        cid = kill_quotes(self.cid, 'int')
        if cid.startswith('7'):
            cid = '8%s' % (cid[1:], )
        self.cid = cid
        super(FSUser, self).save(*args, **kwargs)
        if not self.is_active or not self.user or not self.passwd or not self.context or not self.cid:
            self.drop_extension()
            return
        extension = """
<include>
  <user id="{}">
    <params>
      <param name="password" value="{}"/>
    </params>
    <variables>
      <variable name="toll_allow" value="domestic,international,local"/>
      <variable name="accountcode" value="{}"/>
      <variable name="user_context" value="{}"/>
      <variable name="effective_caller_id_name" value="{}"/>
      <variable name="effective_caller_id_number" value="{}"/>
      <variable name="outbound_caller_id_name" value="{}"/>
      <variable name="outbound_caller_id_number" value="{}"/>
      <variable name="callgroup" value="{}"/>
    </variables>
  </user>
</include>""".format(self.user.username,
                     self.passwd,
                     self.user.username,
                     self.context,
                     self.user.username,
                     self.user.username,
                     self.cid,
                     self.cid,
                     self.callgroup)
        fname = full_path('%s/fs_user_%s.xml' % (self.FOLDER, self.id))
        if check_path(fname):
            make_folder(self.FOLDER)
        with open(fname, 'w+') as f:
            f.write(extension)
        FreeswitchBackend(settings.FREESWITCH_URI).reloadxml()
def analyze_vik(sheet, titul: str, path: str):
    """Разбираем заибучее ВИК заключение,
       это первый лист в экселевском файле
       :param sheet: лист эксельки
       :param titul: экземпляр Titul
       :param path: путь до файла (для отладки)
    """
    # Не всегда в титуле есть код титула,
    # может быть просто название, например,
    # Эстакада трубопроводов
    # Может вообще не быть названия титула
    titul_description = sheet['F6'].value or sheet['G6'].value
    titul_name = None
    if titul_description:
        if not 'У' in titul_description:
            titul_name = sheet['I6'].value
        else:
            titul_name = 'У%s' % titul_description.split('У')[1]
            titul_description = titul_description.split('У')[0]
    # --------------------------------------
    # Захерачиваем описание титулу,
    # если не совпало имя титула, то алертим
    # --------------------------------------
    if titul_name:
        titul_name = titul_name.strip()
    if titul_name != titul.name:
        pass
        #logger.info('TITUL HAS INCORRECT NAME %s vs %s' % (titul.name, titul_name))
        #return
    # ---------------------------------------
    # Определяем описание титула накопительно
    # ---------------------------------------
    analyze_titul_description(titul, titul_description)
    # -----------------------------------
    # Определяем шифр титула накопительно
    # -----------------------------------
    titul_code = sheet['H7'].value or sheet['I7'].value
    analyze_titul_code(titul, titul_code)
    # ----------------
    # Определяем линию
    # ----------------
    line_str = sheet['A8'].value or sheet['B8'].value or sheet['A7'].value
    if not line_str:
        logger.info('--- LINE ABSENT %s---' % path)
        return
    line_str = line_str.replace('Линия', '').strip()
    line_str = line_str.replace('0 H', '0H')
    line_str = line_str.replace('  ', ' ')
    try:
        line_str = replace_rus2eng(line_str)
    except Exception as e:
        logger.info(e)
        return
    line = Line.objects.filter(name=line_str, titul=titul).first()
    if not line:
        logger.info('--- LINE NOT FOUND %s ---' % line_str)
        # Создаем линию, если название адекватное
        if len(line_str) < 5:
            return
        line = Line.objects.create(name=line_str, titul=titul)
    # -------------------
    # Находим дату сварки
    # -------------------
    request_control_date = get_welding_date(sheet['G11'].value)
    if not request_control_date:
        request_control_date = get_welding_date(sheet['H11'].value)
    if not request_control_date:
        request_control_date = get_welding_date(sheet['G10'].value)
    if not request_control_date:
        logger.info('--- DATE INCORRENT %s ---' % path)
    # --------------------------------
    # Находим толщину стенки и диаметр
    # --------------------------------
    side_thickness = diameter = None
    size_row_letter = 'I'
    is_completed_row = (sheet['I16'].value and sheet['I16'].value.strip() == 'выполнен') or (sheet['I14'].value and sheet['I14'].value.strip() == 'выполнен')
    if not sheet['A1'].value or is_completed_row:
        size_row_letter = 'J'

    size = None
    for i in (16, 17, 18):
        size_row_number = i
        size_row_value = sheet['%s%s' % (size_row_letter, size_row_number)].value
        if not size_row_value:
            continue
        #print('=', size_row_value)
        size = get_size(size_row_value)
        if size:
            break
    if not size:
        logger.info('--- SIDE_THICKNESS or DIAMETER NOT FOUND %s, %s ---' % (size_row_number, path))
    else:
        diameter, side_thickness = size
    # ------------------------
    # Находим номера стыков
    # У пидорасов на ВИК стыки
    # разделены точкой,
    # а на РК слешем
    # ------------------------
    joint_row_letter = 'B'
    if not sheet['A1'].value:
        joint_row_letter = 'C'
    joints_str = sheet['%s%s' % (joint_row_letter, size_row_number)].value
    if not joints_str:
        logger.info('--- JOINTS NOT FOUND %s, %s ---' % (size, path))
        return
    # Если есть говносмещение - мы найдем ячейку с №
    # вместо номеров стыков
    if joints_str == '№':
        if joint_row_letter == 'B':
            joint_row_letter = 'C'
        joints_str = sheet['%s%s' % (joint_row_letter, size_row_number)].value
    joints_str = '%s' % joints_str
    joints_arr = joints_str.split(',')

    # ----------------------------
    # Находим строчку с материалом
    # и типом сварных соединений
    # ----------------------------
    material = welding_conn_view = None
    material_str = None
    material_row_letter = 'A'
    if not sheet['A1'].value or (sheet['A18'].value is None and sheet['A19'].value is None and sheet['A20'].value is None and sheet['A21'].value is None):
        material_row_letter = 'B'
    material_q = ('Тип сварных соединений', 'материал')
    for i in (18, 19, 20, 21):
        material_row_number = i
        value = sheet['%s%s' % (material_row_letter, material_row_number)].value
        if not value:
            continue
        if material_q[0] in value and material_q[1] in value:
            material_str = value
            break
    if not material_str:
        logger.info('--- MATERIAL NOT FOUND %s ---' % path)
    else:
        material, welding_conn_view = get_material(material_str)
    if not material or not welding_conn_view:
        logger.info('--- MATERIAL NOT FOUND %s ---' % path)
    # -----------------
    # Поиск типа сварки
    # -----------------
    welding_type = None
    welding_type_row_letter = material_row_letter
    welding_type_row_number = material_row_number + 1
    welding_type_str = sheet['%s%s' % (
        welding_type_row_letter,
        welding_type_row_number
    )].value
    if not welding_type_str:
        logger.info('--- WELDING_TYPE NOT FOUND %s ---' % path)
    else:
        welding_type = get_welding_type(welding_type_str)
    if not welding_type:
        logger.info('--- WELDING_TYPE NOT FOUND %s ---' % path)
    # -------------
    # Ищем сварщика
    # -------------
    welders = []
    welder_row_number = welding_type_row_number + 1
    for letter in ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'):
        welders_str = sheet['%s%s' % (
            letter,
            welder_row_number,
        )].value
        if not welders_str:
            continue
        welders += get_welders(welders_str)
    # Следующую строчку ищем тоже
    welder_row_number += 1
    if not welders:
        for letter in ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'):
            welders_str = sheet['%s%s' % (
                letter,
                welder_row_number,
            )].value
            if not welders_str:
                continue
            welders += get_welders(welders_str)

    if not welders:
        logger.info('--- WELDERS NOT FOUND %s ---' % path)

    # ---------------------
    # Ищем дефектоскопистов
    # Контроль выполнил:
    # ---------------------
    defectoscopists = []
    letters = ('G', 'H', 'I', 'J')
    for letter in letters:
        for number in range(36, 46):
            adr = '%s%s' % (letter, number)
            value = sheet[adr].value
            if not value:
                continue
            defectoscopists += get_defectoscopists(value)
    if not defectoscopists:
        logger.info('--- DEFECTOSCOPISTS NOT FOUND %s ---' % path)

    for joint_str in joints_arr:
        joint_str = joint_str.replace('.', '/').replace('\\', '/').strip()
        if not joint_str:
            continue

        # Если нет цифр в номере стыка, тогда не создаем
        digits = kill_quotes(joint_str, 'int')
        if not digits:
            logger.info('--- BAD JOINT %s, %s ---' % (joint_str, path))
            continue

        joint = Joint.objects.filter(line=line, name=joint_str).first()
        if not joint:
            logger.info('--- JOINT NOT FOUND %s, %s ---' % (joint_str, line.name))
            # Ну создаем, блеать, раз линия найдена
            joint = Joint.objects.create(line=line, name=joint_str)
        # Стык найден - надо найти заключение,
        # если нету - создать или обновить
        welding_joints = WeldingJoint.objects.filter(joint=joint)
        if len(welding_joints) > 1:
            logger.info('--- MORE THAN 1 WeldingJoint %s' % joint)
            return
        if welding_joints:
            welding_joint = welding_joints[0]
        else:
            welding_joint = WeldingJoint(joint=joint)
        welding_joint.state = 3
        welding_joint.diameter = diameter
        welding_joint.side_thickness = side_thickness
        welding_joint.request_control_date = request_control_date
        welding_joint.material = material
        welding_joint.welding_conn_view = welding_conn_view
        welding_joint.welding_type = welding_type
        welding_joint.save()
        for i, welder in enumerate(welders):
            if i > 3:
                break
            analog = JointWelder.objects.filter(
                welder=welder,
                welding_joint=welding_joint,
            )
            if not analog:
                JointWelder.objects.create(
                    welder=welder,
                    welding_joint=welding_joint,
                    position=i + 1,
                )
        joint_conclusion = JointConclusion.objects.filter(welding_joint=welding_joint).first()
        if not joint_conclusion:
            joint_conclusion = JointConclusion(welding_joint=welding_joint)
        joint_conclusion.date = welding_joint.request_control_date
        joint_conclusion.vik_active = True
        joint_conclusion.vik_state = 1
        if defectoscopists:
            joint_conclusion.vik_controller = defectoscopists[0]
        if len(defectoscopists) > 1:
            joint_conclusion.vik_director = defectoscopists[1]
        joint_conclusion.save()
Пример #14
0
 def save(self, *args, **kwargs):
     if self.phone:
         phone = kill_quotes(self.phone, 'int')
         self.phone = phone
     super(Shopper, self).save(*args, **kwargs)
Пример #15
0
 def save(self, *args, **kwargs):
     if self.phone:
         self.phone = kill_quotes(self.phone, 'int')
     super(customUser, self).save(*args, **kwargs)
Пример #16
0
 def save(self, *args, **kwargs):
     """Сохранение"""
     if self.phone:
         self.phone = kill_quotes(self.phone, 'int')
     super(SMSPhone, self).save(*args, **kwargs)
Пример #17
0
    def parse_css_line(self, css: str, line: str):
        """Парсинг css строчки в файле css
           :param css: путь к css файлу
           :param line: строка в css файле"""
        # -----------------------------------
        # SUPPORT for @import "css/main.css";
        # -----------------------------------
        matches_import = rega_import.search(line)
        if matches_import:
            old_path = matches_import.group(1)
            if old_path.endswith('.css'):
                # -------------------------------------------------------------
                # Тут ремарка скажем @import url("../medica-parent/style.css");
                # тогда надо брать путь относительно пути текущего css файла,
                # а не базового => смотрим в функцию findpath
                # css => http://demo.themefuse.com/medica-child/style.css?v=1
                # Видно, что надо отбросить финальный элемент пути
                # -------------------------------------------------------------
                if css.endswith('.css') and '/' in css:
                    css = os.path.split(css)[0]

                temp_css_file = self.findpath(css,
                                              kill_quotes(old_path, 'quotes'))
                self.css_files.append(temp_css_file)
                temp_css_name = os.path.split(temp_css_file)[1]
                line = line.replace(old_path, '../css/%s' % temp_css_name)

        matches_img = rega_img.findall(line)
        for match_img in matches_img:
            old_path = match_img
            if old_path.endswith('.css"'):
                # SUPPORT FOR @import url(../css/xxx.css);
                temp_css_file = self.findpath(css,
                                              kill_quotes(old_path, 'quotes'))
                css_files.append(temp_css_file)
                temp_css_name = os.path.split(temp_css_file)[1]
                line = line.replace(old_path, '../css/%s' % temp_css_name)
                continue
            # -----------------------
            # Бывает, что svg попался
            # -----------------------
            if 'data:' in match_img:
                continue
            # ----------------------------------
            # Какие-то долбаебы в картинку якорь
            # и бывает, что это все что там есть
            # ----------------------------------
            if '#' in old_path:
                old_path = old_path.split('#')[0].strip()
            if not old_path:
                continue

            img = self.findpath(css, kill_quotes(old_path, 'quotes'))
            img_name = os.path.split(img)[1]
            # Меняем путь в css
            img_folder = os.path.split(img)[0]
            line = line.replace(old_path, '../img/%s' % img_name)
            # Тащим картинку
            contents = self.grab_file(img, False)
            if not contents:
                continue
            img_file_path = os.path.join(self.img_path, img_name)
            # ---------------------------
            # Фикс на имя с ? параметрами
            # ---------------------------
            img_file_path = self.clean_path(img_file_path)

            # ПРОВЕРКА НА ДУБЛИ
            if not check_path(img_file_path):
                if not img in self.img_repeated:
                    self.z += 1
                    img_file_path = img_file_path + str(self.z)
            if not img in self.img_repeated:
                self.img_repeated.append(img)

            with open_file(img_file_path, 'wb+') as f:
                f.write(contents)

        return line
Пример #18
0
def send_sms_helper(request):
    """Вспомогательная функция,
       чтобы отправить sms
       1) достаем из spamcha телефоны для рассылки,
          смотрим по лимитам кто может отправить смс,
          следим за балансировкой - кто сколько отправил
       2) у нас должен работать sms_hub.py на порту (5009)
          подключаемся в него и отправляем смс на телефон
    """
    result = {}
    method = request.GET if request.method == 'GET' else request.POST
    text = method.get('text')
    phone = method.get('phone')
    token = method.get('token')
    if not token == settings.SMS_HUB_TOKEN:
        result['error'] = 'Неправильный токен'
        return result
    if not phone or not text:
        result['error'] = 'Телефон или сообщение отсутствует'
        return result
    phone = kill_quotes(phone, 'int')
    if len(phone) != 11:
        result['error'] = 'Телефон должен быть из 11 цифр'
        return result
    receiver_number = '8%s' % phone[1:]
    if not receiver_number.startswith('89'):
        result['error'] = 'Телефон не должен быть городским (начинаться с 89)'
        return result

    # Вариант узнать какие телефоны на связи, только через
    phones_from_cache = get_phones_from_cache()

    # --------------------------------------------
    # Телефоны на связи, если дата меньше сегодня,
    # нужно просто пересохранять,
    # чтобы обновился счетчик отправленных смсин
    # --------------------------------------------
    now = datetime.datetime.today()
    today = datetime.datetime(now.year, now.month, now.day, 0, 30, 0)
    refresh_query = SMSPhone.objects.filter(updated__lt=today)
    for_refresh = refresh_query.aggregate(Count('id'))['id__count']
    if for_refresh:
        for item in refresh_query:
            item.sent = 0
            item.save()

    # Находим телефоны через которые можно отправить смс
    cond_list = [{'code__in': phones_from_cache}]
    phones = get_phones(cond_list=cond_list)
    if not phones:
        result['error'] = 'Нет телефонов для отправки смс'
        return result

    candidate = phones[0]
    if not candidate['sent']:
        candidate['sent'] = 0
    for phone in phones:
        if not phone['sent']:
            phone['sent'] = 0
        if phone['sent'] < candidate['sent']:
            candidate = phone

    # Отправка в кэш-очередь смсины
    rediska = redis.Redis()
    cache_key = '%s_%s' % (settings.SMS_HUB_TOKEN, candidate['code'])
    queue = rediska.get(cache_key)
    if queue:
        queue = json.loads(queue)
    else:
        queue = []
    queue.append({'phone': receiver_number, 'text': text})
    rediska.set(cache_key, json.dumps(queue))

    # Накидываем кол-во отправленных смсин
    candidate['sent'] += get_sms_volume(text)
    SMSPhone.objects.filter(pk=candidate['id']).update(sent=candidate['sent'])

    result['success'] = 1
    return result