def info(msg: types.Message): if not is_admin(msg.from_user): bot.send_message(msg.from_user.id, 'Вы не являетесь админом.') return def format_executor(ex: Executor) -> str: return f" [{ex.intraservice_user.name}](tg://user?id={ex.telegram_user.user_id}) \n" def format_task(tsk: IntraserviceTask) -> str: task_url = api.new_api.get_task_url(tsk.id) return f" [#{tsk.id}]({task_url})" def format_executor_with_task(ex: Executor) -> str: tsk = ex.intraservice_task_active if not tsk: return f" [{ex.intraservice_user.name}](tg://user?id={ex.telegram_user.user_id})\n" else: task_url = api.new_api.get_task_url(tsk) return f" [{ex.intraservice_user.name}](tg://user?id={ex.telegram_user.user_id}) " \ f"([#{tsk.id}]({task_url})\n" ready_executors = get_ready_executors() ready_executors_list = '' for executor in ready_executors: ready_executors_list += format_executor(executor) working_executors = get_working_executors() working_executors_list = '' for executor in working_executors: working_executors_list += format_executor_with_task(executor) opened_tasks = get_opened_tasks() opened_tasks_list = '' for task in opened_tasks: opened_tasks_list += format_task(task) if opened_tasks: opened_tasks_list += '\n' mass_tasks = get_mass_tasks() mass_tasks_list = '' for task in mass_tasks: mass_tasks += format_task(task) if mass_tasks: mass_tasks_list += '\n' bot.send_message( msg.from_user.id, r.INFO_MESSAGE.format( ready_executors=f"{len(ready_executors)}:" if ready_executors else "нет", ready_executors_list=ready_executors_list, working_executors=f"{len(working_executors)}:" if working_executors else "нет", working_executors_list=working_executors_list, opened_tasks=f"{len(opened_tasks)}:" if opened_tasks else "нет", opened_tasks_list=opened_tasks_list, blockage_exist="Завал есть" if len(opened_tasks) >= 5 else "Завала нет", mass_tasks=f"len(mass_tasks):" if mass_tasks else "нет", mass_tasks_list=mass_tasks_list ), parse_mode="Markdown" )
def pin_critical_task(executor: Executor, new_task: IntraserviceTask): old_task = executor.intraservice_task_active executor.intraservice_task_active = new_task executor.save() new_task.long_execution_notification = timezone.now() new_task.executor_notification_count = 0 new_task.admin_notification = timezone.now() new_task.admin_notification_count = 0 new_task.save() old_task.postponed_type = POSTPONED_TYPE['Критическая завка'] old_task.postponed_executor = executor old_task.save() api.new_api.change_task(old_task.id, status_id=TASK_STATUSES['Отложена'], comment='Переведен на критическую заявку') api.new_api.change_task(new_task.id, status_id=TASK_STATUSES['В работе'], executor_ids=[executor.intraservice_user.id]) old_url = api.new_api.get_task_url(old_task.id) new_url = api.new_api.get_task_url(new_task.id) bot.send_message(executor.telegram_user.user_id, text=r.CHANGE_TO_CRITICAL_MESSAGE.format( old_task_id=old_task.id, new_task_id=new_task.id, old_url=old_url, new_url=new_url, executors=len(get_ready_executors()), open_tasks=len(get_opened_tasks()), mass_tasks=len(get_mass_tasks())), parse_mode='Markdown')
def executor_ready(message): try: executor = Executor.objects.get(telegram_user__user_id=message.from_user.id) except ObjectDoesNotExist: bot.send_message(message.from_user.id, 'Вы не являетесь работником ТП.') return if executor.status == 'Не готов': logging.debug(f'Change status of {executor} to (Ready)!') executor.status = 'Готов' executor.last_status_change = timezone.now() executor.save() bot.send_message(executor.telegram_user.user_id, text=r.EXECUTOR_READY.format(executors_ready=len(get_ready_executors()))) elif executor.status == 'Готов': bot.send_message(executor.telegram_user.user_id, text=r.EXECUTOR_READY.format(executors_ready=len(get_ready_executors()))) elif executor.status == 'Занят': task = executor.intraservice_task_active task_url = api.new_api.get_task_url(task.id) bot.send_message(message.from_user.id, text=r.EXECUTOR_HAVE_TASK.format(task_id=task.id, task_url=task_url, open_tasks=len(get_ready_executors())), parse_mode='Markdown')
def blockage_notify(self): # Оповещения о завалах if len(get_opened_tasks()) >= 5: if not self.blockage: self.blockage_start_time = timezone.now() if len(get_ready_executors()): message_to_admins( ('🆘 Начался завал в работе сотрудников ТП: ' 'уже больше 5 открытых заявок и все сотрудники заняты' )) else: message_to_admins(( '🆘 Начался завал в работе сотрудников ТП: ' 'уже больше 5 открытых заявок и все сотрудники отсутствуют' )) self.blockage = True else: if self.blockage: message_to_admins('🆗 Закончился завал в работе сотрудников ТП') BlockageJournal.objects.create( from_time=self.blockage_start_time, to_time=timezone.now()) self.blockage = False
def run(self): logging.info("Start status listener thread") self.check_tasks_in_db() pool = ThreadPool(5) last_update = timezone.now() - timedelta(hours=6) new_update = None self.update_enable.set() while self.run_enabled: self.new_task_count = 0 logging.debug('Enabled creating tasks!') self.create_task_enable.set() if new_update: time.sleep( max(0, UPDATE_TIME - (new_update - last_update).seconds)) else: time.sleep(UPDATE_TIME) self.update_enable.wait(UPDATE_TIME) logging.debug('Disabled creating tasks!') self.create_task_enable.clear() new_update = timezone.now() # получаем все изменения заданий logging.info('Get updates...') try: tasks_updates = api.get_tasks(last_update) except api.new_api.APIError as e: logging.error(e) tasks_updates = [] updated = False else: updated = True logging.debug('Updates received!') # обработка обновлений for task in tasks_updates: self.processing_update(task) # проверка всех заданий logging.debug('Start sync tasks from db...') start_time = time.time() pool.map(self.task_sync, list(IntraserviceTask.objects.filter(~Q(status=29)))) logging.debug('Finish sync tasks from db! (' + str(time.time() - start_time) + ' seconds)') # Смена статуса у подзадач for mass_task in IntraserviceTask.objects.filter(~Q( parent_id=None)): for task in IntraserviceTask.objects.filter( parent_id=mass_task): if task.status != mass_task.status: logging.debug("Sync status of children {task}!") api.new_api.change_task( task.id, status_id=mass_task.status, comment='Синхронизация статуса с родителем.') # Удаляем сотрудников, у открытых заданий, которые были отложены for task in IntraserviceTask.objects.filter( status=TASK_STATUSES['Открыта']).filter( postponed_type=POSTPONED_TYPE['Отложена сотрудником']): remove_executor(task) # Проверяем сотрудников, которые отложили задания for ex in Executor.objects.filter( intraservice_task_active__status=TASK_STATUSES["Отложена"] ): task_delay(ex) # Освобождаем работников, от решенных задач for ex in Executor.objects.filter( Q(intraservice_task_active__status=TASK_STATUSES[ 'Выполнена']) | Q(intraservice_task_active__status=TASK_STATUSES[ 'Отменена'])): close_task(ex) # Удаляем закрытые и отмененные задания for task in IntraserviceTask.objects.filter( # type: IntraserviceTask Q(status=TASK_STATUSES['Закрыта']) | Q(status=TASK_STATUSES['Отменена'])): if not list(IntraserviceTask.objects.filter(parent=task)): task.delete() # Освобождаем работников, у которых удалены задачи for ex in Executor.objects.filter( intraservice_task_active=None).filter(status='Занят'): close_task(ex) # Оповещения о долгом выполнении for task in IntraserviceTask.objects.filter(~Q(executor=None) & Q( executor__status='Занят')): executor = Executor.objects.get(intraservice_task_active=task) task_url = api.new_api.get_task_url(task.id) if (timezone.now() - task.long_execution_notification ).seconds > 60 * NOTIFY_TASK_MIN: bot.send_message( executor.telegram_user.user_id, text=r.LONG_WORK_EXECUTOR_NOTIFICATION.format( task_id=task.id, task_url=task_url, NOTIFY_TASK_MIN=NOTIFY_TASK_MIN * (task.executor_notification_count + 1)), parse_mode='Markdown') task.executor_notification_count += 1 task.long_execution_notification = timezone.now() if (timezone.now() - task.admin_notification).seconds > 60 * MAX_TASK_MIN: message_to_admins( r.LONG_WORK_ADMIN_NOTIFICATION.format( executor=executor.intraservice_user.name, task_id=task.id, task_url=task_url, MAX_TASK_MIN=MAX_TASK_MIN * (task.admin_notification_count + 1), uid=executor.telegram_user.user_id)) task.admin_notification_count += 1 task.admin_notification = timezone.now() task.save() self.postponed_notify() # Объединяем похожие заявки от одного пользователя for task in IntraserviceTask.objects.filter(~Q( telegram_client=None)).filter(parent_id=None).filter( created__gte=last_update): # type: IntraserviceTask try: client = Client.objects.get( intraservicetask=task) # type: Client except ObjectDoesNotExist: continue for c_task in IntraserviceTask.objects.filter( telegram_client=client).filter(created__gte=( timezone.now() - timedelta(minutes=60) )).filter(~Q(description=None)).filter( parent_id=None): # type: IntraserviceTask if task.id == c_task.id: continue for problem in MASS_PROBLEMS: # type: IntraserviceTask if problem in task.description and problem in c_task.description: logging.debug( f'Making {c_task} parent to {task}...') task.parent_id = c_task api.new_api.change_task(task.id, parent_id=c_task.id) task.save() break self.group_mass_tasks() # Возвращаем заявки исполнителю for ex in Executor.objects.filter(~Q( intraservice_task_active=None)).filter( status='Готов').filter(last_status_change__lte=( timezone.now() - timedelta(seconds=SEC_TO_PIN) )).filter( intraservice_task_active__parent__id=None).filter( intraservice_task_active__executor_group= EXECUTOR_GROUP_IDS['Техподдержка']): re_pin_to_task(ex) # Новые заявки и нет сотрудников if len(get_ready_executors()) == 0 and self.new_task_count: message_to_admins(r.NEW_TASK_NO_EXECUTORS) # Возвращаем отложеные (из-за критической заявки) заявки исполнителю (Критические) for task in IntraserviceTask.objects.filter( postponed_type=POSTPONED_TYPE['Критическая завка'] ).filter(priority=PRIORITY_STATUSES['Критический']).filter( parent_id=None).filter( executor_group=EXECUTOR_GROUP_IDS['Техподдержка'] ).filter(): if task.postponed_executor.intraservice_task_active: if task.postponed_executor.intraservice_task_active.priority != PRIORITY_STATUSES[ 'Критический'] and task.postponed_executor.intraservice_task_active.postponed_type == \ POSTPONED_TYPE['Критическая завка']: pin_critical_task(task.postponed_executor, task) else: pin_to_task_after_critical(task) self.pin_critical_tasks() # Возвращаем отложеные (из-за критической заявки) заявки исполнителю for task in IntraserviceTask.objects.filter( postponed_type=POSTPONED_TYPE['Критическая завка'] ).filter(postponed_executor__status='Готов').filter( parent_id=None).filter( executor_group=EXECUTOR_GROUP_IDS['Техподдержка'] ).filter(~Q(status=TASK_STATUSES['Закрыта']) & ~Q(status=TASK_STATUSES["Выполнена"])): pin_to_task_after_critical(task) self.pin_non_critical_tasks() self.blockage_notify() if updated: last_update = new_update pool.close()