Version 1.3 by admin on 2026/05/30 23:27

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

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