Учет опозданий сотрудников — различия между версиями

Материал из Oktell
Перейти к: навигация, поиск
м (Результат работы)
 
(не показано 9 промежуточных версии этого же участника)
Строка 1: Строка 1:
 
[[Практики|Наверх]]
 
[[Практики|Наверх]]
 +
 +
__TOC__
  
 
'''Задача:''' вести статистику по опозданиям сотрудников.  
 
'''Задача:''' вести статистику по опозданиям сотрудников.  
  
Каждый руководитель хочет быть уверен в соблюдении правил внутреннего распорядка своими сотрудниками. Одним из критериев ответственности сотрудника является время появления на работе. Oktell позволяет автоматизировать эту проверку.  
+
Каждый руководитель хочет быть уверен в соблюдении правил внутреннего распорядка своими сотрудниками. Одним из критериев ответственности сотрудника является время появления на работе. '''Oktell''' позволяет автоматизировать эту проверку.  
  
  
Строка 46: Строка 48:
  
 
В этой статье рассматривается смешанный вариант учета опозданий.  
 
В этой статье рассматривается смешанный вариант учета опозданий.  
 +
 +
 +
=== Создание таблицы ===
 +
 +
Предварительно создается таблица '''latecomers''', в которой будет храниться вся информация по сотрудникам. Таблица имеет следующие поля:
 +
 +
* '''Id''' - номер записи в списке. Тип '''Int''', создается автоматически.
 +
* '''date''' - дата и время проверки. Тип '''Datetime'''.
 +
* '''user''' - имя пользователя. Тип '''NVarchar (auto)'''.
 +
* '''status''' - результат проверки. Тип '''NVarchar (auto)'''.
 +
* '''time''' - время, с которого у пользователя включено клиентское приложение. Тип '''Datetime'''.
 +
* '''iduser''' - идентификатор пользователя. Нужен для нахождения внутреннего номера. Тип '''NVarchar (auto)'''.
  
  
Строка 60: Строка 74:
 
* Цикла по пользователям. Блок взят из статьи [[Построковая обработка sql выборки в сценарии]] (Вариант 1)
 
* Цикла по пользователям. Блок взят из статьи [[Построковая обработка sql выборки в сценарии]] (Вариант 1)
 
* Дозвон до пользователя и занесение результата
 
* Дозвон до пользователя и занесение результата
 +
 +
 +
Компонент "'''Проверка по таблице'''" - SQL-запрос определяет запущено ли клиентское приложение у сотрудника и записывает результаты в таблицу.
 +
 +
with ausers as
 +
(
 +
select getdate() ddt,us.Name,'На месте' status,uh.TimeEnter, us.ID
 +
from  [oktell].[dbo].[A_CallCenter_UserStateHistory] uh
 +
inner join A_Users us
 +
on uh.operatorid=us.ID
 +
where GETDATE()>TimeEnter
 +
and (GETDATE()<TimeLeave or TimeLeave is null)
 +
and uh.State =0
 +
)
 +
 +
insert into latecomers (date,[user],status,time,iduser)
 +
select * from ausers
 +
union all
 +
select getdate(),Name,'0',null, ID
 +
from A_Users
 +
where id not in (select id from ausers)
 +
 +
 +
Компонент "'''id_before'''" - присваивает переменной '''id_before''' (строковая) значение "'''-1000'''". Нужен для перебора сотрудников в таблице latecomers, у которых еще нет статуса (не определены с прошлого шага).
 +
 +
 +
Компонент "'''Определяем следующего'''" - SQL-запрос определяет следующего пользователя в таблице latecomers, которому нужно позвонить.
 +
 +
select top 1 @id=id, @iduser=iduser, @user=[user]
 +
from latecomers
 +
where id > @id_before
 +
and status='0'
 +
and cast(floor(cast(getdate() as float)) as datetime) = cast(floor(cast(date as float)) as datetime)
 +
 +
set @rowcount=@@rowcount
 +
 +
где
 +
 +
*'''@id''' - переменная id_after (строковая). Переменная содержит номер найденного пользователя в таблице latecomers.
 +
*'''@id_before''' - переменная id_before.
 +
*'''@iduser''' - переменная iduser (строковая). Переменная содержит id пользователя.
 +
*'''@rowcount''' - переменная rowcount (строковая). Переменная содержит количество найденных строк.
 +
*'''@user''' - переменная user (строковая). Переменная содержит имя пользователя.
 +
 +
 +
Компонент "'''Проверка на завершение'''" - определяет завершен ли перебор по пользователям. Сравнение переменной rowcount с "'''0'''".
 +
 +
 +
Компонент "'''id_before=id_after'''" - переприсваивает переменную '''id_before''', чтобы найти следующего пользователя. Также обнуляет переменную '''prefix'''.
 +
* переменной '''idbefore''' присваивает переменную id_after
 +
* переменной '''prefix''' присваивает пустую строку
 +
 +
 +
Компонент "'''Внутренний номер по id'''" - SQL-запрос находит по таблице внутренний номер пользователя по его идентификатору iduser.
 +
 +
<span style="color:red"> ВНИМАНИЕ: У пользователя должен быть "нативный" номер, то есть такой стандартный внутренний номер, в котором только один объект - данный пользователь. Иначе запрос не найдет внутренний номер этого пользователя.
 +
 +
SELECT TOP 1 @prefix=np.Prefix FROM A_NumberPlan np
 +
INNER JOIN A_NumberPlanAction npa ON np.ID=npa.NumID AND npa.ExtraId IN
 +
(SELECT RuleID FROM A_RuleRecords
 +
WHERE reactid=@userid AND InnerAddressType=0
 +
AND RuleID IN
 +
(SELECT RuleID FROM A_RuleRecords
 +
GROUP BY RuleID HAVING COUNT(*)=1))
 +
ORDER BY np.Prefix
 +
 +
где
 +
 +
*'''@prefix''' - переменная prefix, содержит внутренний номер пользователя
 +
*'''@userid''' - переменная iduser
 +
 +
 +
Компонент "'''Дозвон'''" - происходит дозвон до пользователя. Если пользователь поднимет трубку или занят (в разговоре) - считается, что он на месте.
 +
 +
* '''Номер/команда''' - prefix
 +
* '''Среда''' - Внутренний номерной план
 +
* '''Обслуживание''' - IVR
 +
* '''Сценарий IVR''' - предварительно созданный IVR сценарий "Учет опозданий IVR". Сценарий достаточно простой - после того, как сотрудник берет трубку, связь обрывается. Здесь можно поставить звуковое оповещение сотрудника о том, что это проверка.
 +
 +
 +
[[Файл:Учет опозданий-002.png | center]]
 +
 +
 +
* '''Caller ID''' - "Proverka" (устанавливается по желанию, сотрудники будут видеть это название на табло телефона)
 +
* '''Caller Name''' - "Proverka" (аналогично полю Caller ID)
 +
* '''Очередь ожидания''' - Нет
 +
* '''Время ожидания''' - 40 секунд. Максимальное время за которое сотрудник должен поднять трубку, чтобы система отметила его как на месте.
 +
 +
 +
Компоненты "'''На месте'''" , "'''Занято'''" или "'''Нет на месте'''" - SQL-запросы для обновления статуса в таблице '''latecomers'''. Переход к этим компонентам происходит по веткам от предыдущего компонента "'''Дозвон'''". Соответственно:
 +
 +
update latecomers
 +
set status = 'На месте (Взял трубку)'
 +
where iduser=@iduser
 +
 +
update latecomers
 +
set status = 'На месте (Занято)'
 +
where iduser=@iduser
 +
 +
update latecomers
 +
set status = 'Нет на месте'
 +
where iduser=@iduser
 +
 +
где
 +
 +
*'''@iduser''' - переменная iduser (во всех запросах).
 +
 +
 +
=== Создание служебной задачи===
 +
 +
Данный сценарий необходимо назначить на служебную задачу. Переходим «'''Администрирование'''» - «'''Общие настройки'''» - вкладка «'''Служебные задачи'''» - «'''Добавить'''»
 +
 +
* Выбираем для запуска данный сценарий.
 +
* Указываем расписание - с понедельника по пятницу, с 9:05 до 9:10.
 +
* Тип запуска - периодический, раз в сутки.
 +
* Нажимаем «'''Сохранить'''» и активируем служебную задачу.
 +
 +
<span style="color:red"> Служебный сценарий не рекомендуется отдельно запускать, так как служебная задача не будет работать. Если вы запустили отдельно служебный сценарий, то вам надо переактивировать служебную задачу.
 +
 +
 +
[[Файл:Учет опозданий-004.png | center | 600px]]
 +
 +
 +
=== Результат работы ===
 +
 +
В таблице latecomers формируется следующая информация:
 +
 +
 +
[[Файл:Учет опозданий-003.png|center]]
 +
 +
 +
'''Файл сценария:''' [[Media:%D0%A3%D1%87%D0%B5%D1%82_%D0%BE%D0%BF%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B9.zip|Учет опозданий.zip]]
 +
 +
 +
'''Запрос для создания таблицы:'''
 +
 +
USE [oktell]
 +
GO
 +
SET ANSI_NULLS ON
 +
GO
 +
SET QUOTED_IDENTIFIER ON
 +
GO
 +
CREATE TABLE [dbo].[latecomers](
 +
[Id] [int] IDENTITY(1,1) NOT NULL,
 +
[date] [datetime] NULL,
 +
[user] [nvarchar](2000) NULL,
 +
[status] [nvarchar](2000) NULL,
 +
[time] [datetime] NULL,
 +
[iduser] [nvarchar](2000) NULL,
 +
PRIMARY KEY CLUSTERED
 +
(
 +
[Id] ASC
 +
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
 +
) ON [PRIMARY]
 +
GO

Текущая версия на 11:21, 31 марта 2023

Наверх

Задача: вести статистику по опозданиям сотрудников.

Каждый руководитель хочет быть уверен в соблюдении правил внутреннего распорядка своими сотрудниками. Одним из критериев ответственности сотрудника является время появления на работе. Oktell позволяет автоматизировать эту проверку.


Способы проверки

Существует несколько способов проверки появления сотрудника на работе. Рассмотрим их на примере. Пусть компания начинает работу в 9-00.


Способ 1. Проверка дозвоном.

Каждый день в 9-05 производится обзвон всех сотрудников. Если сотрудник снимает трубку, то считается, что он на рабочем месте.

Достоинства:

  • Проверяет наличие сотрудника на рабочем месте

Недостатки:

  • Вместо проверяемого сотрудника, трубку может снять его коллега.
  • Возможность установить софтфон на телефоне, используя технологию SIP Forking, позволяет сотруднику взять трубку где угодно при наличии интернета. Однако, чаще всего сотрудники не знают паролей от своих устройств.


Способ 2. Проверка по клиентскому приложению.

В 9-05 служебный сценарий обращается в таблицу [oktell].[dbo].[A_CallCenter_UserStateHistory]. В этой таблице хранится время запуска клиентского приложения (столбец TimeEnter) и время, когда клиентское приложение было закрыто (столбец TimeLeave). Для того, чтобы использовать эту идею необходимо включенное клиентское приложение.

Достоинства:

  • Не отвлекает сотрудника от работы

Недостатки:

  • Клиентское приложение должно быть обязательно включено
  • При наличии домена для веб-клиента или веб-оператора, сотрудник может отметиться, зайдя на веб-сервис со своего смартфона.


Способ 3. Смешанный вариант.

Если при проверке SQL-запросом сотрудник показан, как отсутствующий в системе (не включено клиентское приложение), то вполне возможно, что он забыл включить клиентское приложение или возникли технические неполадки. Если сотрудник отмечен как пользователь по умолчанию для своего телефона, то ему можно сделать дозвон и проверить на месте ли он находится.

Достоинства:

  • Если у сотрудника не включено клиентское приложение, система пытается дозвонится до сотрудника.

Недостатки:

  • Такие же, как у варианта 1 - трубку могут поднять другие сотрудники. Однако, этот вариант можно обработать отдельно и записать в отчет с особой пометкой.

В этой статье рассматривается смешанный вариант учета опозданий.


Создание таблицы

Предварительно создается таблица latecomers, в которой будет храниться вся информация по сотрудникам. Таблица имеет следующие поля:

  • Id - номер записи в списке. Тип Int, создается автоматически.
  • date - дата и время проверки. Тип Datetime.
  • user - имя пользователя. Тип NVarchar (auto).
  • status - результат проверки. Тип NVarchar (auto).
  • time - время, с которого у пользователя включено клиентское приложение. Тип Datetime.
  • iduser - идентификатор пользователя. Нужен для нахождения внутреннего номера. Тип NVarchar (auto).


Реализация сценария

Сценарий выглядит следующим образом:


Учет опозданий-001.png


Структурно сценарий состоит из


Компонент "Проверка по таблице" - SQL-запрос определяет запущено ли клиентское приложение у сотрудника и записывает результаты в таблицу.

with ausers as
(
select getdate() ddt,us.Name,'На месте' status,uh.TimeEnter, us.ID
from  [oktell].[dbo].[A_CallCenter_UserStateHistory] uh 
inner join A_Users us 
on uh.operatorid=us.ID
where GETDATE()>TimeEnter 
and (GETDATE()<TimeLeave or TimeLeave is null)
and uh.State =0 
)

insert into latecomers (date,[user],status,time,iduser)
select * from ausers 
union all
select getdate(),Name,'0',null, ID
from A_Users 
where id not in (select id from ausers)


Компонент "id_before" - присваивает переменной id_before (строковая) значение "-1000". Нужен для перебора сотрудников в таблице latecomers, у которых еще нет статуса (не определены с прошлого шага).


Компонент "Определяем следующего" - SQL-запрос определяет следующего пользователя в таблице latecomers, которому нужно позвонить.

select top 1 @id=id, @iduser=iduser, @user=[user]
from latecomers 
where id > @id_before
and status='0' 
and cast(floor(cast(getdate() as float)) as datetime) = cast(floor(cast(date as float)) as datetime)

set @rowcount=@@rowcount

где

  • @id - переменная id_after (строковая). Переменная содержит номер найденного пользователя в таблице latecomers.
  • @id_before - переменная id_before.
  • @iduser - переменная iduser (строковая). Переменная содержит id пользователя.
  • @rowcount - переменная rowcount (строковая). Переменная содержит количество найденных строк.
  • @user - переменная user (строковая). Переменная содержит имя пользователя.


Компонент "Проверка на завершение" - определяет завершен ли перебор по пользователям. Сравнение переменной rowcount с "0".


Компонент "id_before=id_after" - переприсваивает переменную id_before, чтобы найти следующего пользователя. Также обнуляет переменную prefix.

  • переменной idbefore присваивает переменную id_after
  • переменной prefix присваивает пустую строку


Компонент "Внутренний номер по id" - SQL-запрос находит по таблице внутренний номер пользователя по его идентификатору iduser.

ВНИМАНИЕ: У пользователя должен быть "нативный" номер, то есть такой стандартный внутренний номер, в котором только один объект - данный пользователь. Иначе запрос не найдет внутренний номер этого пользователя.

SELECT TOP 1 @prefix=np.Prefix FROM A_NumberPlan np 
INNER JOIN A_NumberPlanAction npa ON np.ID=npa.NumID AND npa.ExtraId IN 
(SELECT RuleID FROM A_RuleRecords 
WHERE reactid=@userid AND InnerAddressType=0 
AND RuleID IN 
(SELECT RuleID FROM A_RuleRecords 
GROUP BY RuleID HAVING COUNT(*)=1)) 
ORDER BY np.Prefix 

где

  • @prefix - переменная prefix, содержит внутренний номер пользователя
  • @userid - переменная iduser


Компонент "Дозвон" - происходит дозвон до пользователя. Если пользователь поднимет трубку или занят (в разговоре) - считается, что он на месте.

  • Номер/команда - prefix
  • Среда - Внутренний номерной план
  • Обслуживание - IVR
  • Сценарий IVR - предварительно созданный IVR сценарий "Учет опозданий IVR". Сценарий достаточно простой - после того, как сотрудник берет трубку, связь обрывается. Здесь можно поставить звуковое оповещение сотрудника о том, что это проверка.


Учет опозданий-002.png


  • Caller ID - "Proverka" (устанавливается по желанию, сотрудники будут видеть это название на табло телефона)
  • Caller Name - "Proverka" (аналогично полю Caller ID)
  • Очередь ожидания - Нет
  • Время ожидания - 40 секунд. Максимальное время за которое сотрудник должен поднять трубку, чтобы система отметила его как на месте.


Компоненты "На месте" , "Занято" или "Нет на месте" - SQL-запросы для обновления статуса в таблице latecomers. Переход к этим компонентам происходит по веткам от предыдущего компонента "Дозвон". Соответственно:

update latecomers 
set status = 'На месте (Взял трубку)'
where iduser=@iduser
update latecomers 
set status = 'На месте (Занято)'
where iduser=@iduser
update latecomers 
set status = 'Нет на месте'
where iduser=@iduser

где

  • @iduser - переменная iduser (во всех запросах).


Создание служебной задачи

Данный сценарий необходимо назначить на служебную задачу. Переходим «Администрирование» - «Общие настройки» - вкладка «Служебные задачи» - «Добавить»

  • Выбираем для запуска данный сценарий.
  • Указываем расписание - с понедельника по пятницу, с 9:05 до 9:10.
  • Тип запуска - периодический, раз в сутки.
  • Нажимаем «Сохранить» и активируем служебную задачу.

Служебный сценарий не рекомендуется отдельно запускать, так как служебная задача не будет работать. Если вы запустили отдельно служебный сценарий, то вам надо переактивировать служебную задачу.


Учет опозданий-004.png


Результат работы

В таблице latecomers формируется следующая информация:


Учет опозданий-003.png


Файл сценария: Учет опозданий.zip


Запрос для создания таблицы:

USE [oktell]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[latecomers](
	[Id] [int] IDENTITY(1,1) NOT NULL, 
	[date] [datetime] NULL,
	[user] [nvarchar](2000) NULL,
	[status] [nvarchar](2000) NULL,
	[time] [datetime] NULL,
	[iduser] [nvarchar](2000) NULL,
PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO