Version 3.1 by admin on 2026/06/07 17:10

Show last authors
1 Часто бывает полезно выявить неактивные пропуска, то есть пропуска, по которым давно не было никаких событий доступа. Для решения этой задачи в Платформе НЕЙРОСС реализован скрипт автоматизации, позволяет автоматически обнаружить неактивные пропуска и поместить их в отдельную группу, а также, при необходимости, — выполнить бессрочную приостановку пропуска.
2
3 Контролируются не все пропуска, а только пропуска выбранных владельцев.
4
5 Посредством настройки свойств скрипта автоматизации вы можете:
6
7 * задать имя группы для помещения пропусков;
8 * определить, требуется ли автоматически выполнять изъятие пропусков, либо решение будет принимать оператор бюро пропусков;
9 * задать период неактивности — временной интервал в днях, по истечении которого при отсутствии событий доступа пропуск считается неактивным;
10 * указать, требуется ли учитывать факт изменения пропуска совместно с событием доступа — пропуск будет считаться неактивным, если за заданный период не было ни события доступа, ни факта изменения пропуска оператором бюро пропусков;
11 * пометить, что пропуск приостановлен скриптом автоматизации.
12
13 {{info}}
14 Задание автоматизации может запускаться оператором вручную, по расписанию (например, раз в неделю по воскресеньям), либо по какому-либо событию/системному действию.
15 {{/info}}
16
17 **Пример: Найти пропуска, по которым не было событий доступа в течение 60 дней и поместить их в группу «Устаревшие пропуска»**
18
19 Задание автоматизации запускается автоматически ежедневно в 23:00, производится поиск за интервал в 60 дне. Найденные неактивные пропуска не приостанавливаются, остаются действительными и принадлежащими «своим» группам, но дополнительно помещаются в группу «Устаревшие пропуска». Анализируются только события доступа, факт изменения пропуска оператором АРМ Доступ не анализируется.
20
21 [[image:attach:card_inactivity_scrypt.png]]
22
23 \\
24
25 === {{id name="Контрольактивностипропуска-НастройкиСКУД"/}}Настройки СКУД ===
26
27 Вам потребуется:
28
29 1. Создать пользовательское свойство владельца пропуска для указания перечня лиц, для которых требуется проводить контроль активности пропуска.
30 1. Добавить свойство на форму владельца пропуска и задать в значение true для владельцев, чьи пропуска требуется анализировать.
31 1. Создать пользовательское свойство пропуска для пометок о том, что пропуск приостановлен скриптом.
32 1. Добавить свойство на форму пропуска.
33
34 Порядок действий:
35
36 (% class="wrapped" %)
37 |=(((
38 Задача
39 )))|=(((
40 Комментарий
41 )))
42 |(((
43 Создание пользовательского свойства
44 )))|(((
45 (% class="content-wrapper" %)
46 (((
47 В разделе **Настройки СКУД** АРМ НЕЙРОСС Доступ:
48
49 1. На вкладке **Свойства владельца пропуска** добавьте новое свойство, задайте название и ключ свойства, укажите тип «Переключатель».
50 [[image:attach:card_inactivity_appprp.png||height="250"]]
51 1. На вкладке (% style="letter-spacing: 0.0px;" %)**Свойства пропуска** добавьте новое свойство, задайте название и ключ свойства, укажите тип «Переключатель».
52 [[image:attach:PausedByScrypt_addprp.png||height="250"]]
53
54 [[doc:neyross.Настройка Платформы НЕЙРОСС.Настройка функций контроля доступа.Добавление пользовательских свойств.WebHome]]
55 )))
56 )))
57 |(((
58 Изменение формы владельца пропуска
59 )))|(((
60 (% class="content-wrapper" %)
61 (((
62 (% style="color: rgb(23,43,77);" %)В разделе **Персонал** АРМ НЕЙРОСС Доступ выберите группу пропусков, для которой нужно настроить контроль активности, перейдите к вкладке **Настройки группы**:
63
64 1. (% style="color: rgb(23,43,77);" %)На вкладке (%%)**Форма ввода: Владелец пропуска** (% style="color: rgb(23,43,77);" %)добавьте поле **Контроль активности** (название может быть любым) на форму владельца пропуска.
65 1. (% style="color: rgb(23,43,77);" %)На вкладке **Форма ввода: Пропуск добавьте** поле **Приостановлен скриптом** (название может быть любым) на форму пропуска.
66
67 {{info}}
68 Рекомендуем использовать Конструктор форм. При использовании нестандартных форм, обратитесь к специалистам компании ИТРИУМ за услугой по доработке формы.
69 {{/info}}
70
71 [[doc:neyross.Настройка Платформы НЕЙРОСС.Настройка функций контроля доступа.Настройка форм ввода данных.WebHome]]
72
73 (% style="color: rgb(23,43,77);" %)При необходимости вывода информации в таблице пропусков, на вкладке **Настройка таблицы** добавьте вывод данных свойств.
74
75 (% style="color: rgb(23,43,77);" %)[[doc:neyross.Настройка Платформы НЕЙРОСС.Настройка функций контроля доступа.Настройка таблицы пропусков.WebHome]]
76 )))
77 )))
78 |(((
79 Включение необходимости контроля активности пропуска
80 )))|(((
81 (% class="content-wrapper" %)
82 (((
83 Выберите владельцев, для которых требуется проводить контроль активности пропуска, и в режиме редактирования пропуска / группы пропусков в поле **Контроль активности** установите переключатель в положение [[image:attach:ui.Параметры узла.WebHome@fa-on.png||thumbnail="true" height="18"]]**Включено**. Сохраните данные владельца.
84
85 [[image:attach:card_inactivity_person_form.png||width="500"]]
86
87 [[doc:neyross.АРМ НЕЙРОСС Доступ.Управление пропусками.WebHome]]
88 )))
89 )))
90 |(((
91 Просмотр результатов работы скрипта
92 )))|(((
93 Дождитесь выполнения условия запуска задания (в нашем примере это 23:00 текущего дня).
94 )))
95
96 == {{id name="Контрольактивностипропуска-Настройкиавтоматизации"/}}Настройки автоматизации ==
97
98 (% style="color: rgb(23,43,77);" %)Скопируйте приведённый ниже код скрипта (% class="auto-cursor-target" style="color: rgb(23, 43, 77); color: rgb(23, 43, 77)" %)и создайте файл с произвольным именем и расширением **JSON**, например: (%%)//задание_автоматизации_Контроль_устаревших пропусков.json//(% class="auto-cursor-target" style="color: rgb(23, 43, 77); color: rgb(23, 43, 77)" %). Для этого удобно использовать простые текстовые редакторы типа Блокнот или Notepad++. Вы также можете обратиться к специалистам компании ИТРИУМ, мы вышлем подготовленный файл.
99
100 {{code language="java"}}
101
102 import play.api.libs.json.Format
103 import beans.pacs.{PacsFolderBean, PassBean}
104 import extensions.automation.scripts.AutomationActionScript
105 import extensions.automation.signals.AutomationSignal
106 import models.common.UserIdentity
107 import models.neyross.{Pass, PassComponent}
108 import models.pacs.{PacsFolder, PacsFolderComponent}
109 import dto.pacs.PacsFolderMovementDto
110 import services.logging.web.{LoggerWithWeb => Logger}
111 import play.api.libs.json.{JsObject, Json}
112 import proto.neyross.PassProto
113 import services.common.{SystemLogService, SystemLogTag}
114 import services.neyross.NeyrossEmbedApiService
115 import slick.dbio.DBIOAction
116 import utils.TableExtension
117 import utils.bootstrap.CustomPostgresProfile
118 import utils.common.ScalaUtils
119
120 import java.time.OffsetDateTime
121 import java.util.UUID
122 import scala.concurrent.Future
123
124 class ObsoletePassControlAutomationScript extends AutomationActionScript {
125
126 val logger = Logger("ObsoletePassControlAutomationScript")
127
128 private val postgresProfile = ctx.dbConfig.profile.asInstanceOf[CustomPostgresProfile]
129
130 import postgresProfile.api._
131
132 implicit val ec = ctx.executionContext
133 private val neyrossEmbedApi = ctx.injector.instanceOf[NeyrossEmbedApiService]
134 private val pacsFolderBean = ctx.injector.instanceOf[PacsFolderBean]
135 private val systemLogService = ctx.injector.instanceOf[SystemLogService]
136 private val passBean = ctx.injector.instanceOf[PassBean]
137
138 private val folders = new PacsFolderComponent()(ctx.dbConfig)
139 private val passes = new PassComponent()(ctx.dbConfig, neyrossEmbedApi, ec)
140
141 // @parameter { "type": "string", "title": "Название группы для устаревших пропусков", "key": "workingFolder" }
142 val workingFolder = "Устаревшие пропуска"
143
144 // @parameter { "type": "string", "title": "Идентификатор свойства-признака контроля", "key": "shouldControlOutdateProperty", "description": "Контролироваться будут пропуска только тех владельцев, которые имеют данное свойство" }
145 val shouldControlOutdateProperty = "inactivity"
146
147 // @parameter { "type": "string", "title": "Значение свойства-признака контроля", "key": "shouldControlOutdatePropertyValue", "description": "Контролироваться будут пропуска только тех владельцев, которые имеют указанное значение данного свойства (true означает Да)" }
148 val shouldControlOutdatePropertyValue = "true"
149
150 // @parameter { "type": "select", "title": "Режим работы", "key": "mode", "options": [ { "value": "default", "label": "Помещение устаревших пропусков группу" }, { "value": "withStopping", "label": "Приостановка и помещение устаревших пропусков в группу" } ] }
151 val mode = "withStopping"
152
153 // @parameter { "type": "number", "title": "Максимальный период неактивности, дней", "key": "inactivityPeriod" }
154 val inactivityPeriod = 1
155
156 // @parameter { "type": "boolean", "title": "Анализировать время изменения пропуска", "key": "isUpdateTimeAnalysisEnabled", "description": "Если флаг установлен, при расчёте активности пропуска будут учитываться также события изменения пропуска оператором бюро пропусков. В противном случае будет анализироваться только время последнего прохода по данному пропуску" }
157 val isUpdateTimeAnalysisEnabled = false
158
159 // @parameter { "type": "string", "title": "Идентификатор свойства-маркера контроля", "key": "scriptMarkPropertyKey", "description": "При автоматической приостановке пропуска к нему будет добавлено свойство с данным идентификатором и значением true (Да). Вы можете вынести данное свойство на форму пропуска или в таблицу пропусков, при необходимости" }
160 val scriptMarkPropertyKey = "PausedByScrypt"
161
162 val modeLocalization: Map[String, String] =
163 Map(
164 "default" -> "Помещение устаревших пропусков в группу",
165 "withStopping" -> "Приостановка и помещение устаревших пропусков в группу"
166 )
167
168 logger.debug(s"mode: ${modeLocalization.getOrElse(mode, "")}")
169 logger.debug(s"modification time analysing: $isUpdateTimeAnalysisEnabled")
170 logger.debug(s"inactivity period: $inactivityPeriod")
171
172 override def onSignal(signal: AutomationSignal): Future[Unit] = {
173 workingFolder.trim match {
174 case "" =>
175 logger.warn("working folder name is empty. do nothing")
176 Future.unit
177 case nonEmptyFolderName =>
178 runWithNonEmptyFolderName(nonEmptyFolderName)
179 }
180 }
181
182 private def createFolderWithNameAndParent(name: String, parent: Option[String]) = {
183 val uuid = UUID.randomUUID().toString
184 val folder = PacsFolder(
185 id = None,
186 uuid = Some(uuid),
187 name = Some(name),
188 parent = parent,
189 isDefault = false,
190 templates = None,
191 defaultValues = None,
192 settings = None,
193 created = OffsetDateTime.now(),
194 deleted = false
195 )
196 folders.insert(folder).map(_ => Some(uuid))
197 }
198
199 private def getFolderUuidByName(folderName: String) = {
200 folders.folders
201 .filter(f => f.name === folderName && !f.deleted)
202 .result
203 .headOption
204 .flatMap({
205 case Some(folder) =>
206 DBIOAction.successful(folder.uuid)
207 case _ =>
208 folders
209 .findDefault()
210 .flatMap({
211 case Some(defaultFolder) if defaultFolder.uuid.nonEmpty =>
212 createFolderWithNameAndParent(folderName, defaultFolder.uuid)
213 case _ =>
214 logger.warn("there is no valid default folder. wtf?")
215 DBIOAction.successful(None)
216 })
217 })
218 }
219
220 private def isOutdated(timestamp: OffsetDateTime): Boolean = {
221 val threshold = OffsetDateTime.now().minusDays(inactivityPeriod)
222 logger.trace(s"checking if chosen timestamp $timestamp is older than threshold $threshold")
223 threshold.isAfter(timestamp)
224 }
225
226 private def isStoppedOrInOutdatedFolder(
227 pass: Pass,
228 outdatedFolderUuid: String,
229 passFolders: List[String]
230 ): Boolean = {
231 pass.getState.contains(PassProto.Pass.State.sSTOPPED) || passFolders.contains(outdatedFolderUuid)
232 }
233
234 private def isOutdatedPassRecord(record: PassRecord): Boolean = {
235 // from all pass times, choose latest one and check if it outdated
236 val lastAccessGrantedAtOption = record._2
237 val created = record._3
238 val lastUpdatedAtOption = record._4
239 logger.trace(s"last access granted: $lastAccessGrantedAtOption, created: $created, last updated: $lastUpdatedAtOption")
240 // in any cases, pass has "created" time
241 var latestTimeToCheck: OffsetDateTime = created
242 if (
243 lastAccessGrantedAtOption.isDefined &&
244 lastAccessGrantedAtOption.get.isAfter(latestTimeToCheck)
245 ) {
246 // last access event was later than created time - using it
247 latestTimeToCheck = lastAccessGrantedAtOption.get
248 }
249 if (isUpdateTimeAnalysisEnabled) {
250 if (
251 lastUpdatedAtOption.isDefined &&
252 lastUpdatedAtOption.get.isAfter(latestTimeToCheck)
253 ) {
254 // last update event was later than created time and last access time - using it
255 latestTimeToCheck = lastUpdatedAtOption.get
256 }
257 }
258 isOutdated(latestTimeToCheck)
259 }
260
261 private def getPassesToMove(records: Seq[PassRecord], outdatedFolderUuid: String): Seq[Pass] = {
262 records
263 .filter(record => {
264 logger.trace(s"pass ${record._5.uuid} handling")
265 !isStoppedOrInOutdatedFolder(record._5, outdatedFolderUuid, record._1.getOrElse(Nil)) &&
266 isOutdatedPassRecord(record)
267 })
268 .map(_._5)
269 }
270
271 type PassFolders = Option[List[String]]
272 type LastAccessGrantedAt = Option[OffsetDateTime]
273 type Created = OffsetDateTime
274 type LastUpdatedAt = Option[OffsetDateTime]
275 type PassRecord = (PassFolders, LastAccessGrantedAt, Created, LastUpdatedAt, Pass)
276
277 type PersonUUID = String
278 type PersonFolders = Option[Seq[String]]
279 type PersonRecord = (PersonUUID, PersonFolders)
280
281 private def personToControlHandler(
282 outdatedFolderUuid: String,
283 personRecord: PersonRecord
284 ): Future[Seq[String]] = {
285 val dbAction =
286 passes
287 .extendedPasses4(
288 TableExtension.folders(ctx.dbConfig),
289 TableExtension.lastAccessGrantedAt(ctx.dbConfig),
290 TableExtension.created(ctx.dbConfig),
291 TableExtension.lastUpdatedAt(ctx.dbConfig)
292 )
293 .filter(r => r.person === personRecord._1 && !r.deleted)
294 .result
295
296 ctx
297 .dbRun(dbAction)
298 .flatMap(result => {
299 logger.trace(s"found passes of person ${personRecord._1}: ${result.map(_._5.uuid)}")
300 val passesToMove = getPassesToMove(result, outdatedFolderUuid)
301 logger.trace(s"found outdated passes of person ${personRecord._1}: ${passesToMove.map(_.uuid)}")
302 if (passesToMove.nonEmpty) {
303 val isPersonInOutdatedFolder = personRecord._2.exists(_.contains(outdatedFolderUuid))
304 val personsToMove = Option.when(!isPersonInOutdatedFolder)(personRecord._1).toList
305 val dto = PacsFolderMovementDto(personsToMove, passesToMove.map(_.uuid))
306 pacsFolderBean.copyToFolder(outdatedFolderUuid, dto)(ui = null, None).map(_ => passesToMove.map(_.uuid))
307 } else {
308 Future.successful(Nil)
309 }
310 })
311 }
312
313 private def getPersonsToControl: Future[Vector[PersonRecord]] = {
314 val personsToControl =
315 sql"""
316 SELECT DISTINCT uuid, folders
317 FROM
318 neyross_person,
319 jsonb_to_recordset((person_json->>'properties'):: jsonb) AS props(key text, value text)
320 WHERE
321 key = '#${shouldControlOutdateProperty}' AND
322 value = '#${shouldControlOutdatePropertyValue}' AND
323 neyross_person.deleted = false
324 """.as[PersonRecord]
325
326 ctx.dbRun(personsToControl)
327 }
328
329 case class Property(key: String, value: String, index: Option[Long] = None)
330
331 object Property {
332 implicit val jsonFormat: Format[Property] = Json.format[Property]
333 }
334
335 private def stopPassesWithUuid(uuids: Seq[String]): Future[Unit] = {
336 ctx
337 .dbRun(passes.findByUuids(uuids))
338 .flatMap(updatedPasses => {
339 ScalaUtils
340 .sequentialTraverse(updatedPasses)(updatedPass => {
341 logger.trace(s"stopping pass ${updatedPass.uuid}; setting property $scriptMarkPropertyKey and disabled_from fields")
342 val passJson = updatedPass.toFullJson.asOpt[JsObject].get
343 val passProperties = (passJson \ "properties").asOpt[List[Property]].getOrElse(Nil)
344
345 val newPassProperties = passProperties.filter(p => {
346 p.key != scriptMarkPropertyKey
347 }) :+ Property(
348 scriptMarkPropertyKey,
349 "true"
350 )
351 val newPassJson = passJson ++ Json.obj(
352 "disabled_from" -> OffsetDateTime.now().toInstant.getEpochSecond.toInt,
353 "properties" -> Json.toJson(newPassProperties)
354 )
355 logger.trace(s"new pass json is: $newPassJson")
356 passBean
357 .updateV2(updatedPass.uuid, newPassJson)(UserIdentity.getFakeUserIdentityFor("Автоматизация"), None)
358 })
359 .map(_ => ())
360 })
361 }
362
363 private def runWithNonEmptyFolderName(folderName: String): Future[Unit] = {
364 systemLogService
365 .log(
366 SystemLogTag.NORMAL,
367 SystemLogTag.AUTOMATION
368 )(s"Запущен процесс контроля устаревших пропусков")
369 .map(_ => ())
370 ctx
371 .dbRun(getFolderUuidByName(folderName))
372 .flatMap({
373 case Some(folderUUID) =>
374 logger.debug(s"working folder is $folderName ($folderUUID)")
375 getPersonsToControl
376 .flatMap(persons => {
377 logger.debug(s"found persons to control: $persons")
378 ScalaUtils.sequentialTraverse(persons)(personToControlHandler(folderUUID, _))
379 })
380 .flatMap(uuids => {
381 val flatUuidsList = uuids.flatten.distinct
382 if (flatUuidsList.nonEmpty) {
383 val stopping = if (mode == "withStopping") {
384 stopPassesWithUuid(flatUuidsList)
385 } else {
386 Future.unit
387 }
388 stopping.flatMap(_ => {
389 val yesOrNo = Option
390 .when(isUpdateTimeAnalysisEnabled)("да")
391 .getOrElse("нет")
392 logger.debug(s"were moved ${flatUuidsList.size} passes")
393 val message =
394 s"""В группу '$folderName' было помещено ${flatUuidsList.size} пропусков.
395 |Режим работы: ${modeLocalization.getOrElse(mode, "")}.
396 |Анализировать время изменения пропуска: $yesOrNo
397 |Максимальный период неактивности: $inactivityPeriod дней""".stripMargin
398 systemLogService
399 .log(
400 SystemLogTag.NORMAL,
401 SystemLogTag.AUTOMATION
402 )(
403 message = message,
404 data = Some(Json.toJson(flatUuidsList))
405 )
406 .map(_ => ())
407 })
408 } else {
409 logger.debug("not found persons with obsolete persons or passes")
410 systemLogService
411 .log(
412 SystemLogTag.NORMAL,
413 SystemLogTag.AUTOMATION
414 )(s"Не найдено владельцев для контроля устаревших пропусков, либо все пропуска таких владельцев не являются устаревшими")
415 .map(_ => ())
416 }
417 })
418 case _ =>
419 Future.unit
420 })
421 Future.unit
422 }
423 }
424
425 new ObsoletePassControlAutomationScript
426 {{/code}}
427
428 (% class="auto-cursor-target" style="color: rgb(23, 43, 77); color: rgb(23, 43, 77)" %)Добавьте задание автоматизации
429
430 1. (% class="auto-cursor-target" style="color: rgb(23, 43, 77); color: rgb(23, 43, 77)" %)В разделе **Автоматизация** нажмите на кнопку  **Добавить новое задание [[image:attach:ui.Параметры узла.WebHome@btn_add_new.png||thumbnail="true" height="18"]]**, нажмите на кнопку **Импорт** и укажите путь к подготовленному на предыдущем этапе файлу ~[[[Автоматизация>>doc:ui.Параметры узла.Автоматизация.WebHome||style="" shape="rect"]]].
431 1. В блоке **Параметры сигнала** выберите **По расписанию**, настройте расписание (например, 0 23 * * * для ежедневного запуска, или 0 23 * * 1 для запуска раз в неделю по воскресеньям).
432 1. (((
433 В блоке **Параметры действия** настройте параметры задания автоматизации согласно таблице ниже.
434
435 (% class="wrapped" %)
436 |=(((
437 Параметр
438 )))|=(((
439 Комментарий
440 )))
441 |(((
442 Название группы устаревших пропусков
443 )))|(((
444 Название группы. При запуске скрипта проверяется наличие группы с указанным именем в группе **Все**. При отсутствии, — она будет создана. В эту группу помещаться все найденные пропуска и их владельцы. Если название пустое, задание не выполняется.
445 )))
446 |(((
447 Идентификатор свойства — признака контроля
448 )))|(((
449 Уникальный идентификатор пользовательского свойства владельца пропуска, созданный на этапе [[#Настройки СКУД>>doc:||anchor="Контрольактивностипропуска-НастройкиСКУД"]]. В нашем примере: inactivity
450 )))
451 |(((
452 Значение свойства — признака контроля
453 )))|(((
454 (% class="content-wrapper" %)
455 (((
456 * true — если требуется проверять пропуска, для владельцев которого в поле **Контроль пропусков** переключатель установлен в положение [[image:attach:ui.Параметры узла.WebHome@fa-on.png||thumbnail="true" height="18"]] **Включено**.
457 * false — если требуется проверять пропуска, для владельцев которого в поле **Контроль пропусков** переключатель установлен в положение [[image:attach:ui.Параметры узла.WebHome@fa-off.png||thumbnail="true" height="18"]] **Выключено**.
458
459 В нашем примере: true
460 )))
461 )))
462 |(((
463 Режим работы
464 )))|(((
465 Выберите из раскрывающегося списка требуемые действия с пропусками:  требуется ли просто помещать пропуска в дополнительную группу для принятия решения оператором о дальнейших действиях с пропуском, либо необходимо приостанавливать действие найденных пропусков и помещать в группу.
466
467 * Помещение устаревших пропусков в группу — просто помещать пропуска в дополнительную группу для принятия решения оператором о дальнейших действиях с пропуском. Пропуск остаётся действительным. Доступ по нему возможен.
468 * Приостановка и помещение устаревших пропусков в группу — приостанавливать пропуск и помещать в дополнительную группу. (% style="color: rgb(23,43,77);" %)Пропуск не удаляется из контроллеров доступа, но доступ блокируется.
469 )))
470 |(((
471 Максимальный период неактивности, дней
472 )))|(((
473 Укажите временной интервал в днях (количество дней), по истечению которого пропуск без событий доступа считается устаревшим.
474 )))
475 |(((
476 Анализировать время изменения пропуска
477 )))|(((
478 Установите флаг в поле, если, помимо событий доступа при расчёте активности пропуска требуется учитывать не только события доступа, но и события изменения пропуска оператором бюро пропусков.
479 )))
480 |(((
481 (% style="color: rgb(70,70,70);" %)Идентификатор свойства-маркера контроля
482 )))|(((
483 Уникальный идентификатор пользовательского свойства пропуска, значение которого будет устанавливаться в true для пропусков, которые приостановлены данным скриптом. В нашем примере: PausedByScrypt
484 )))
485
486 === {{id name="Контрольактивностипропуска-Алгоритмработы"/}}Алгоритм работы ===
487
488 (% class="wiki-list0" %)
489 1. Поиск владельцев, для которых в поле с указанным идентификатором задано указанное значение.
490 1. Поиск активных пропусков для найденных владельцев (если пропуск уже приостановлен или находится в группе устаревших пропусков операции с ним не выполняются).
491 1. Поиск времени «активизации пропуска»:
492 (% class="wiki-list0" %)
493 11. Если флаг в поле **Анализировать время изменения пропуска** установлен, то выбирается наиболее позднее из времени последнего редактирования и времени последнего прохода по пропуску
494 11. Если флаг не установлен, выбирается время последнего прохода по пропуску.
495 1. Если «время активизации» раньше чем (% class="inline-code" %)##текущее время минус **Максимальный период неактивности**,##(%%) пропуск дополнительно помещается в группу устаревших пропусков.
496 1. Если указан режим работы «Приостановка и перемещение устаревших пропусков в группу», все найденные пропуска бессрочно приостанавливаются. В поле** Приостановлен с** задаётся текущее время.
497 )))
498 1. Нажмите на кнопку **Сохранить задание**.
499
500 {{error}}
501 **ВАЖНО**
502
503 В НЕЙРОСС пропуск не «привязывается» жёстко к одной группе. Принадлежность пропуска группе пропусков является просто свойством пропуска. Пропуск может принадлежать нескольким группам одновременно. При помещении пропуска в группу **Устаревшие пропуска**, пропуск остаётся также и в групе, в которой он располагался до запуска скрипта. Изъятие пропуска из группы осуществляется оператором АРМ Доступ с помощью команды (% style="text-align: left;" %)**Другие действия**(% style="color: rgb(23,43,77);" %) (% style="text-align: left;" %)**> Действие с группами > Изъять из текущей группы.**
504 {{/error}}
505
506 === {{id name="Контрольактивностипропуска-Запускзадания"/}}Запуск задания ===
507
508 Дождитесь выполнения условия запуска задания или запустите задание вручную. Для ручного запуска в поле **Тип сигнала** выберите значение **По HTTP-запросу**, сохраните задание и нажмите (% style="color: rgb(0,0,255);" %)отправить запрос(%%).
509
510 [[image:attach:task_run_manually.png||height="205"]]
511
512 Вы можете отслеживать процедуру инициализации и выполнения задания в Журнале аудита ~[[[doc:ui.Журнал аудита.WebHome]]].
513
514 [[image:attach:card_inactivity_scrypt_log.png||width="900"]]
515
516 Запуск и выполненные скриптом действия фиксируются в системном журнале ~[[[doc:ui.Системный журнал.WebHome]]].
517
518 [[image:attach:card_inactivity_journal.png]]
519
520 Если в поле** Режим работы** задана необходимость приостановки пропуска. В системном журнале отражается факт блокировки действия на контроллерах и задания срока приостановки с текущего времени:
521
522 [[image:attach:card_inactivity_journal1.png]]
523
524 Пропуска приостанавливаются с текущего времени, свойство **Приостановлен скриптом** у приостановленных пропусков устанавливается в значение **Да** (true).
525
526 [[image:attach:card_inactivity_card_form.png||height="250"]]

Платформа НЕЙРОСС