167 lines
6.9 KiB
Python
167 lines
6.9 KiB
Python
"""
|
|
===============================================================================
|
|
FILE: services/scud_etl/sql_queries.py
|
|
ROLE: Изолированные SQL-шаблоны для MS SQL Server (СКУД Орион Pro).
|
|
===============================================================================
|
|
"""
|
|
|
|
# 1. Основной срез СКУД с учетом двухконтурного правого турникета
|
|
SQL_QUERY_TEMPLATE = r"""
|
|
DECLARE @InputDate DATE = '{target_date}';
|
|
DECLARE @TargetDate DATE = @InputDate;
|
|
|
|
DECLARE @StartDate DATETIME = CAST(@TargetDate AS DATETIME);
|
|
DECLARE @EndDate DATETIME = {end_datetime_sql};
|
|
|
|
WITH PercoPassages AS (
|
|
-- Физические факты прохода (Event = 32)
|
|
SELECT
|
|
log.HozOrgan AS EmployeeID,
|
|
log.TimeVal,
|
|
CASE
|
|
WHEN log.Mode = 1 THEN 'IN'
|
|
WHEN log.Mode = 2 THEN 'OUT'
|
|
ELSE 'OTHER'
|
|
END AS Direction
|
|
FROM pLogData log WITH (NOLOCK)
|
|
INNER JOIN pList p WITH (NOLOCK) ON log.HozOrgan = p.ID
|
|
LEFT JOIN PDivision div WITH (NOLOCK) ON p.Section = div.ID
|
|
WHERE log.TimeVal BETWEEN @StartDate AND @EndDate
|
|
AND log.HozOrgan IS NOT NULL
|
|
AND log.HozOrgan > 0
|
|
AND log.Event = 32
|
|
AND log.Mode IN (1, 2)
|
|
AND (
|
|
-- Контур 1: Левый турникет открыт для всех
|
|
log.DoorIndex = 1
|
|
OR
|
|
-- Контур 2: Правый турникет разрешен только для реестра двора
|
|
(
|
|
log.DoorIndex = 2
|
|
AND ({turnstile_filter_sql})
|
|
)
|
|
)
|
|
),
|
|
Passages AS (
|
|
SELECT
|
|
EmployeeID,
|
|
MIN(TimeVal) AS FirstRawEvent,
|
|
MAX(TimeVal) AS LastRawEvent,
|
|
MIN(CASE WHEN Direction = 'IN' THEN TimeVal END) AS FirstIn,
|
|
MAX(CASE WHEN Direction = 'OUT' THEN TimeVal END) AS FinalOut
|
|
FROM PercoPassages
|
|
GROUP BY EmployeeID
|
|
),
|
|
EvaluatedPassages AS (
|
|
SELECT
|
|
p.*,
|
|
CASE
|
|
WHEN p.FinalOut IS NOT NULL
|
|
AND p.FirstIn IS NOT NULL
|
|
AND p.FinalOut > DATEADD(MINUTE, 5, p.FirstIn)
|
|
THEN p.FinalOut
|
|
ELSE NULL
|
|
END AS FilteredLastOut
|
|
FROM Passages p
|
|
)
|
|
SELECT
|
|
N'ЛЕНМОРНИИПРОЕКТ' AS [Фирма],
|
|
ISNULL(CAST(div.Name AS NVARCHAR(255)), N'Без подразделения') AS [Подразделение],
|
|
LTRIM(RTRIM(
|
|
ISNULL(CAST(p.Name AS NVARCHAR(255)), N'') +
|
|
CASE WHEN p.FirstName IS NOT NULL AND CAST(p.FirstName AS NVARCHAR(255)) <> ''
|
|
THEN N' ' + CAST(p.FirstName AS NVARCHAR(255)) ELSE N'' END +
|
|
CASE WHEN p.MidName IS NOT NULL AND CAST(p.MidName AS NVARCHAR(255)) <> ''
|
|
THEN N' ' + CAST(p.MidName AS NVARCHAR(255)) ELSE N'' END
|
|
)) AS [Сотрудник],
|
|
ISNULL(CAST(post.Name AS NVARCHAR(255)), N'—') AS [Должность],
|
|
ISNULL(CAST(p.TabNumber AS NVARCHAR(50)), N'—') AS [Таб_№],
|
|
CONVERT(VARCHAR(10), @TargetDate, 104) AS [Дата],
|
|
ISNULL(CAST(CONVERT(VARCHAR(8), pass.FirstIn, 108) AS NVARCHAR(20)), N'Нет входа') AS [Начало_дня],
|
|
CASE
|
|
WHEN pass.FirstIn IS NULL AND pass.FirstRawEvent IS NOT NULL
|
|
THEN CAST(CONVERT(VARCHAR(8), pass.FirstRawEvent, 108) AS NVARCHAR(20))
|
|
ELSE N'—'
|
|
END AS [Первая_активность],
|
|
CASE
|
|
WHEN pass.FilteredLastOut IS NOT NULL
|
|
THEN CAST(CONVERT(VARCHAR(8), pass.FilteredLastOut, 108) AS NVARCHAR(20))
|
|
ELSE N'Нет выхода'
|
|
END AS [Конец_дня],
|
|
CASE
|
|
WHEN pass.EmployeeID IS NOT NULL AND (pass.FirstIn IS NOT NULL OR pass.FirstRawEvent IS NOT NULL) THEN
|
|
RIGHT('0' + CAST(DATEDIFF(MINUTE,
|
|
ISNULL(pass.FirstIn, pass.FirstRawEvent),
|
|
CASE
|
|
WHEN pass.FilteredLastOut IS NOT NULL THEN pass.FilteredLastOut
|
|
ELSE @EndDate
|
|
END) / 60 AS VARCHAR), 2) + ':' +
|
|
RIGHT('0' + CAST(DATEDIFF(MINUTE,
|
|
ISNULL(pass.FirstIn, pass.FirstRawEvent),
|
|
CASE
|
|
WHEN pass.FilteredLastOut IS NOT NULL THEN pass.FilteredLastOut
|
|
ELSE @EndDate
|
|
END) % 60 AS VARCHAR), 2)
|
|
ELSE N'00:00'
|
|
END AS [Находился_в_здании],
|
|
CASE
|
|
WHEN pass.EmployeeID IS NOT NULL THEN N'Присутствовал'
|
|
ELSE N'Отсутствовал (Нет событий)'
|
|
END AS [Статус]
|
|
FROM pList p WITH (NOLOCK)
|
|
LEFT JOIN PDivision div WITH (NOLOCK) ON p.Section = div.ID
|
|
LEFT JOIN PPost post WITH (NOLOCK) ON p.Post = post.ID
|
|
LEFT JOIN EvaluatedPassages pass ON p.ID = pass.EmployeeID
|
|
WHERE
|
|
ISNULL(p.StatusRecord, 0) = 0
|
|
AND p.DateTimeInArchive IS NULL
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Аренд%'
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT IN (N'Без подразделения', N'')
|
|
AND p.Name NOT LIKE N'бр.%'
|
|
AND p.Name NOT LIKE N'Гость%'
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT IN (N'БГИ', N'КНР')
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Рабоч%'
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Врем%'
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Практика%'
|
|
AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'тест%'
|
|
AND ISNULL(CAST(post.Name AS NVARCHAR(255)), N'') NOT LIKE N'Практикант%'
|
|
ORDER BY p.Name ASC;
|
|
"""
|
|
|
|
# 2. Сырые события физических проходов турникетов
|
|
SQL_RAW_EVENTS_QUERY = r"""
|
|
DECLARE @InputDate DATE = '{target_date}';
|
|
DECLARE @StartDate DATETIME = CAST(@InputDate AS DATETIME);
|
|
DECLARE @EndDate DATETIME = {end_datetime_sql};
|
|
|
|
SELECT
|
|
log.TimeVal,
|
|
log.HozOrgan,
|
|
LTRIM(RTRIM(
|
|
ISNULL(CAST(p.Name AS NVARCHAR(255)), N'') +
|
|
CASE WHEN p.FirstName IS NOT NULL AND CAST(p.FirstName AS NVARCHAR(255)) <> ''
|
|
THEN N' ' + CAST(p.FirstName AS NVARCHAR(255)) ELSE N'' END +
|
|
CASE WHEN p.MidName IS NOT NULL AND CAST(p.MidName AS NVARCHAR(255)) <> ''
|
|
THEN N' ' + CAST(p.MidName AS NVARCHAR(255)) ELSE N'' END
|
|
)) AS [Сотрудник],
|
|
ISNULL(CAST(div.Name AS NVARCHAR(255)), N'Без подразделения') AS [Подразделение],
|
|
log.Event,
|
|
log.Mode,
|
|
log.DoorIndex,
|
|
CASE
|
|
WHEN log.Mode = 2 THEN 'OUT'
|
|
WHEN log.Mode = 1 THEN 'IN'
|
|
WHEN log.Event IN (2, 27, 29, 33, 55, 65) THEN 'OUT'
|
|
WHEN log.Event IN (1, 21, 26, 54, 64) THEN 'IN'
|
|
ELSE 'OTHER'
|
|
END AS Direction
|
|
FROM pLogData log WITH (NOLOCK)
|
|
INNER JOIN pList p WITH (NOLOCK) ON log.HozOrgan = p.ID
|
|
LEFT JOIN PDivision div WITH (NOLOCK) ON p.Section = div.ID
|
|
WHERE log.TimeVal BETWEEN @StartDate AND @EndDate
|
|
AND log.HozOrgan IS NOT NULL
|
|
AND log.HozOrgan > 0
|
|
AND log.Event IN (28, 32)
|
|
AND ISNULL(p.StatusRecord, 0) = 0
|
|
ORDER BY log.TimeVal ASC;
|
|
""" |