Если вы когда-нибудь работали с HCL Notes (раньше известным как Lotus Notes), то наверняка испытали смешанные чувства. С одной стороны, это мощная платформа для корпоративных приложений, с другой — архаичное чудовище с интерфейсом из 90-х, которое порой заставляет разработчиков хвататься за голову. Несмотря на появление более современных альтернатив, множество крупных организаций по-прежнему полагаются на Notes, и миграция на другие платформы часто оказывается слишком дорогостоящей и рискованной затеей.
На практике разработчики сталкиваются с целым рядом проблем. Например, клиентские приложения Notes часто требуют ручной настройки и регулярного обслуживания. Пользователи жалуются на сложный интерфейс, а интеграция с современными сервисами напоминает попытку подключить кассетный плеер к Spotify. Добавьте к этому устаревшую документацию, скудную поддержку и общую инертность системы — и получите полный набор головной боли для IT-отдела.
Тут-то на сцену и выходит автоматизация. Она решает сразу несколько ключевых задач:1. Ускоряет выполнение повторяющихся действий, освобождая время для более креативных и стратегических задач.
2. Минимизирует человеческий фактор, сокращая количество ошибок в критически важных процессах.
3. Упрощает взаимодействие с платформой для конечных пользователей.
4. Обеспечивает более гладкую интеграцию с современными системами и сервисами.
5. Продлевает жизнь существующим Notes-приложениям, отодвигая необходимость миграции. Многие рассматривали (и продолжают рассматривать) Notes как временное решение, которое "скоро заменим чем-то более современным". Однако годы идут, а критически важные приложения продолжают работать на этой платформе. В такой ситуации умение эффективно автоматизировать задачи становится не просто полезным навыком, а необходимым условием для выживания в корпоративных джунглях.
Базовая автоматизация без программирования
Не все сотрудники IT-отделов любят писать код или имеют для этого достаточные навыки. Хорошая новость: HCL Notes предлагает множество способов автоматизации без необходимости погружаться в дебри программирования. Платформа изначально создавалась с мыслью о том, что бизнес-пользователи должны иметь возможность самостоятельно настраивать рабочие процессы.
Агенты и макросы "из коробки"
Агенты в Notes — это, пожалуй, самый мощный инструмент базовой автоматизации. По сути, они представляют собой небольшие программы, которые могут выполняться по расписанию, при открытии/закрытии документа или по запросу пользователя. И что особенно ценно — многие типовые агенты можно создать без написания кода.
Для создания простого агента достаточно открыть меню "Create → Agent" и выбрать один из предлагаемых шаблонов. Например, можно легко настроить агент, который будет:- Отправлять уведомления при изменении определенных полей.
- Архивировать старые документы.
- Копировать данные между базами.
- Менять статусы документов в соответствии с заданными условиями.
Макросы тоже могут быть очень полезны. Например, макрос для быстрого создания типового ответа на письмо или для заполнения стандартной формы. Создать макрос можно через меню "Tools → Macro → Record New Macro".
Один из моих любимых приемов — создание агента, который генерирует ежедневный отчет о незакрытых задачах и отправляет его руководителю отдела. Настраивается за 15 минут, а пользу приносит огромную — никаких забытых задач и просроченных дедлайнов.
Настройка представлений и папок
Представления (Views) в Notes — это не просто способ отображения данных, но и мощный инструмент автоматизации. Грамотно настроенные представления могут значительно ускорить работу с информацией.
Создавая представление, вы можете:- Группировать документы по любым критериям.
- Настраивать сложную сортировку.
- Применять цветовое кодирование для визуального выделения важной информации.
- Создавать вычисляемые колонки, которые будут автоматически обрабатывать данные.
Например, представление "Просроченные задачи" может автоматически подсвечивать красным те документы, срок исполнения которых уже прошел. А представление "Финансовый отчет" может содержать колонки с вычисляемыми значениями, которые автоматически суммируют данные из нескольких полей. Папки (Folders) в Notes работают похоже на представления, но с одним важным отличием — документы попадают в них не автоматически по заданным критериям, а путем перемещения (вручную или с помощью агентов). Это удобно, когда требуется организовать документы в определенную структуру независимо от их содержимого.
Комбинируя представления и папки, можно создать мощную систему управления документами. Например, набор взаимосвязанных представлений для разных этапов бизнес-процесса, где каждое представление показывает только те документы, которые релевантны для конкретного этапа.
Использование формул для умной фильтрации данных
Формулы в Notes — это настоящая магия для тех, кто не хочет писать полноценный код. Формульный язык Notes значительно проще LotusScript или Java, но при этом достаточно мощный для решения многих задач.
С помощью формул можно:- Создавать динамические поля, значения которых вычисляются автоматически.
- Настраивать условное форматирование.
- Управлять видимостью разделов формы.
- Реализовывать проверку данных при сохранении документа.
Вот пример простой формулы, которая автоматически рассчитывает НДС от введенной суммы:
Visual Basic | 1
| @If(@IsNumber(TotalAmount); TotalAmount * 0.2; 0) |
|
А эта формула меняет цвет текста в зависимости от значения поля "Priority":
Visual Basic | 1
| @If(Priority = "High"; "red"; Priority = "Medium"; "blue"; "black") |
|
Особенно полезны формулы в представлениях. Например, можно создать колонку, которая будет показывать количество дней до дедлайна, и настроить условное форматирование так, чтобы строки с приближающимся дедлайном выделялись желтым цветом, а с просроченным — красным. Овладев формулами, вы сможете автоматизировать множество аспектов работы с данными без необходимости изучать "серьезные" языки программирования.
Автоматические уведомления и напоминания без написания кода
Одна из частых задач — настройка системы уведомлений. В Notes это можно сделать различными способами, и многие из них не требуют программирования. Простейший вариант — использование встроенной функциональности напоминаний. При создании документа можно настроить, чтобы система автоматически напомнила о нем в определенное время. Это удобно для личных задач, но не подходит для сложных бизнес-процессов.
Более гибкий способ — использование агентов с формулами. Например, можно создать агент, который будет запускаться ежедневно и проверять все документы в базе. Если срок исполнения задачи приближается или уже прошел, агент автоматически отправит уведомление ответственному сотруднику.
Пример формулы-условия для такого агента:
Visual Basic | 1
| @Today > @Adjust(DueDate; 0; 0; -3; 0; 0; 0) & @Today <= DueDate & Status != "Completed" |
|
Эта формула найдет все задачи, до срока выполнения которых осталось менее трех дней, но которые еще не выполнены.
Для действия можно использовать такую формулу:
Visual Basic | 1
| @MailSend(ResponsiblePerson; ""; ""; "Напоминание о задаче: " + Subject; "Срок выполнения задачи '" + Subject + "' наступает " + @Text(DueDate) + ". Пожалуйста, убедитесь, что она будет выполнена вовремя."; ""); @Return("Notification sent to " + @Name([CN]; ResponsiblePerson)) |
|
Эта формула отправит письмо ответственному лицу с информацией о приближающемся дедлайне.
Комбинируя различные условия и действия, можно создавать довольно сложные системы уведомлений без написания программного кода. Для большинства типовых задач этого вполне достаточно.
Помимо отправки уведомлений, можно настроить автоматическое создание новых документов на основе существующих. Например, если в вашей организации используется база данных для учета договоров, можно создать агент, который будет автоматически создавать задачи на продление за месяц до истечения срока действия. Еще один полезный трюк — использование полей типа Reader и Author. Поле Reader определяет, кто может просматривать документ, а Author — кто может его редактировать. С их помощью можно реализовать автоматическое управление доступом без написания кода.
Представьте ситуацию: в компании внедряют новую систему контроля исполнения поручений. Для каждого отдела создается отдельное представление, которое показывает только задачи этого отдела. Казалось бы, нужно писать сложную логику... Но на самом деле достаточно добавить в форму задачи поле Department типа Reader, и всё — представление будет автоматически "фильтровать" документы на уровне прав доступа. Это не только упрощает работу, но и повышает безопасность — никто не увидит информацию, которая ему не предназначена. А если в компании меняется организационная структура, достаточно внести изменения в одном месте, и вся система автоматически адаптируется.
Часто недооценивают возможность создания вычисляемых полей в формах. Такие поля автоматически обновляются при открытии или сохранении документа, что позволяет всегда иметь актуальные данные без необходимости ручного пересчета. Например, для расчета суммы с учетом скидки достаточно создать поле с формулой:
Visual Basic | 1
| @If(Discount > 0; Price - (Price * Discount / 100); Price) |
|
И эта сумма будет автоматически пересчитываться при любом изменении цены или размера скидки.
Error N 458 Переменная использует тип Автоматизации, не поддерживаемый в Visual Basic ' Я сутки провозился над кодом, давно применяемым в своих исходниках.
' Но невнимательность (ну конечно, и незнание) привела к такому выводу: ... Runtime error 13 при создании объекта автоматизации в WindowsME Написал на VB программку, создающую объект Word.Application. Код такой:
Sub tralala()
Dim objWord As Word.Application
Set objWord =... Есть ли возможность поместить заданную конструкцию в цикл для автоматизации? Скажите пожалуйста, есть ли возможность поместить данную конструкцию в цикл для автоматизации:
import javax.swing.*;
import java.awt.*; ... Проконсультируйте в автоматизации создания объектов с параметрами Необходимо создать десяток объектов класса собака и далее в параметр объекта name записать уникальное имя, как это можно автоматизировать?
Вот...
Шаблоны действий и горячие клавиши для ускорения рутинных операций
Когда речь заходит о ежедневной работе в Notes, оказывается, что львиную долю времени мы тратим на одни и те же операции. Открыть, скопировать, вставить, отправить — эти действия повторяются десятки раз в день. И тут на помощь приходят шаблоны действий и горячие клавиши — недооцененные, но невероятно мощные инструменты автоматизации.
Шаблоны действий (Action Templates) — это предварительно настроенные последовательности команд, которые можно вызвать одним кликом. Они похожи на макросы, но работают на уровне интерфейса и не требуют программирования. Чтобы создать шаблон действия, перейдите в меню "Create → Action" и задайте последовательность команд. Например, можно создать действие "Переслать руководителю", которое автоматически будет брать текущий документ и пересылать его вашему начальнику с определённым текстом и приоритетом.
Visual Basic | 1
| @Command([MailForward]); @Command([EditPaste]; "Прошу рассмотреть данный вопрос.\n\nС уважением,\n" + @Name([CN]; @UserName)); @Command([FileSend]) |
|
Эта простая формула создаст новое письмо для пересылки текущего документа, вставит стандартный текст с вашим именем и отправит сообщение — всё одним нажатием кнопки!
Шаблоны действий особенно полезны при работе с часто используемыми документами. Например, в базе заявок на закупку можно создать действия "Одобрить", "Отклонить", "Запросить дополнительную информацию", каждое из которых будет менять статус заявки, добавлять комментарий и уведомлять соответствующих сотрудников. Есть хитрость, о которой редко пишут в документации — шаблоны действий можно делать контекстно-зависимыми! Добавив условие вида @If(Status = "New"; @Return(1); @Return(0)) , вы можете сделать действие доступным только для документов с определённым статусом. Это позволяет динамически менять доступные операции в зависимости от контекста.
Не менее важны и горячие клавиши. HCL Notes позволяет настраивать сочетания клавиш практически для любых действий. Забудьте о бесконечных кликах по меню — научитесь использовать клавиатурные сокращения, и ваша производительность взлетит. Для настройки горячих клавиш перейдите в меню "File → Preferences → User Preferences", затем выберите вкладку "Keyboard". Здесь можно назначить сочетания клавиш для команд, агентов и даже шаблонов действий.
Например, сочетание Ctrl+Shift+A можно назначить для запуска агента, который архивирует выбранные документы. А Ctrl+Shift+R — для быстрого ответа на письмо с определённым шаблоном.
Умелое комбинирование шаблонов действий и горячих клавиш позволяет создавать персональные "суперспособности" в Notes. Вместо десяти кликов — одно нажатие клавиш. Вместо ручного заполнения формы — автоматическое создание документа с предзаполненными полями.
Ещё один приём, существенно ускоряющий работу — использование SmartIcons. Это настраиваемая панель инструментов, на которую можно вынести часто используемые команды, агенты и шаблоны действий. Создать собственную панель SmartIcons можно через меню "File → Preferences → Toolbars". Это особенно удобно для пользователей, которые предпочитают работать мышью, а не клавиатурой.
Комбинируя все эти инструменты — шаблоны действий, горячие клавиши и панели SmartIcons — можно создать по-настоящему эффективное рабочее пространство, адаптированное под конкретные задачи. И всё это без единой строчки кода! Это то, что делает Notes уникальной платформой, несмотря на все её архаичные черты. Хорошая стратегия — начать с автоматизации самых частых и рутинных операций. Проведите неделю, отмечая, какие действия вы повторяете чаще всего, а затем создайте для них шаблоны и назначьте горячие клавиши. Результаты вас удивят — не только сэкономленным временем, но и снижением стресса и усталости.
LotusScript: старичок, который ещё может
Если базовой автоматизации вам недостаточно, пора познакомиться с LotusScript — основным языком программирования в HCL Notes. Этот язык часто недооценивают, считая устаревшим, но на практике он остаётся невероятно мощным инструментом в руках опытного разработчика. По синтаксису LotusScript напоминает Visual Basic, что делает его относительно простым для изучения — особенно если у вас есть опыт с другими языками программирования.
Что делает LotusScript особенным? Прежде всего, его глубокая интеграция с объектной моделью Notes. Вам не нужно подключать внешние библиотеки или устанавливать дополнительные компоненты — все необходимые классы и методы для работы с документами, представлениями и другими элементами Notes уже встроены в язык.
Простые скрипты для частых задач
Начнем с простого примера — скрипта, который автоматически архивирует документы старше определенной даты:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim archiveDb As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim archiveDoc As NotesDocument
Dim cutoffDate As New NotesDateTime("Today - 30")
Set db = session.CurrentDatabase
Set view = db.GetView("AllDocuments")
Set archiveDb = session.GetDatabase(db.Server, "archive.nsf")
If Not archiveDb.IsOpen Then
Call archiveDb.Open("", "")
End If
Set doc = view.GetFirstDocument
While Not doc Is Nothing
If doc.Created.TimeDifference(cutoffDate) < 0 Then
Set archiveDoc = doc.CopyToDatabase(archiveDb)
Call doc.Remove(True)
End If
Set doc = view.GetNextDocument(doc)
Wend
Messagebox "Архивация завершена!", 64, "Архивация"
End Sub |
|
Этот скрипт перебирает все документы в представлении "AllDocuments" и, если документ создан более 30 дней назад, копирует его в базу архива и удаляет из текущей базы. Первоначальный код может показаться длинным, но его легко адаптировать под конкретные задачи.
Частая проблема в Notes — дублирование документов. Вот простой скрипт для поиска и обработки дубликатов:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim nextDoc As NotesDocument
Dim uniqueIDs As New NotesDocumentCollection
Dim dupeCount As Integer
Set db = session.CurrentDatabase
Set view = db.GetView("By Subject") ' Представление, сортированное по теме
Set doc = view.GetFirstDocument
While Not doc Is Nothing
Set nextDoc = view.GetNextDocument(doc)
' Если у следующего документа та же тема, это возможный дубликат
If Not nextDoc Is Nothing Then
If doc.GetItemValue("Subject")(0) = nextDoc.GetItemValue("Subject")(0) Then
' Проверяем более детально (например, по содержимому)
If doc.GetItemValue("Body")(0) = nextDoc.GetItemValue("Body")(0) Then
Call uniqueIDs.AddDocument(doc) ' Сохраняем оригинал
dupeCount = dupeCount + 1
Call nextDoc.RemovePermanently(True) ' Удаляем дубликат
End If
End If
End If
Set doc = view.GetNextDocument(doc)
Wend
Messagebox "Найдено и обработано дубликатов: " & dupeCount, 64, "Обработка дубликатов"
End Sub |
|
Такой скрипт может сэкономить массу времени, особенно если у вас большая база данных с множеством похожих документов.
Интеграция с внешними системами
Одно из главных преимуществ LotusScript — возможность интеграции с внешними системами. Например, вы можете организовать обмен данными с базой данных SQL:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim conn As Variant
Dim rs As Variant
Dim sql As String
' Открываем соединение с MSSQL
Set conn = CreateObject("ADODB.Connection")
conn.Open "Provider=SQLOLEDB;Data Source=SERVER;Initial Catalog=DB;User ID=user;Password=pass;"
' Получаем данные из Notes
Set db = session.CurrentDatabase
Set view = db.GetView("Orders")
Set doc = view.GetFirstDocument
While Not doc Is Nothing
' Формируем SQL-запрос для вставки данных
sql = "INSERT INTO Orders (OrderID, Customer, Amount) VALUES ('" & _
doc.GetItemValue("OrderID")(0) & "', '" & _
doc.GetItemValue("Customer")(0) & "', " & _
doc.GetItemValue("Amount")(0) & ")"
' Выполняем запрос
conn.Execute sql
' Помечаем документ как обработанный
doc.Processed = "1"
Call doc.Save(True, False)
Set doc = view.GetNextDocument(doc)
Wend
conn.Close
Messagebox "Данные успешно экспортированы!", 64, "Экспорт в SQL"
End Sub |
|
С помощью LotusScript можно также интегрироваться с веб-сервисами, файловой системой, Excel и практически любыми другими системами. Главное — знать, какие объекты и методы использовать.
Работа с почтой и календарём через LotusScript
Автоматизация работы с почтой и календарем — одна из самых востребованных задач. Например, вот как можно организовать автоматическую обработку входящей почты:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| Sub Initialize
Dim session As New NotesSession
Dim mailDb As NotesDatabase
Dim inbox As NotesView
Dim doc As NotesDocument
Dim sender As String
Dim subject As String
' Открываем почтовый ящик
Set mailDb = session.GetDatabase("", "mail\\username.nsf")
Set inbox = mailDb.GetView("($Inbox)")
Set doc = inbox.GetFirstDocument
While Not doc Is Nothing
' Получаем отправителя и тему
sender = doc.GetItemValue("From")(0)
subject = doc.GetItemValue("Subject")(0)
' Обрабатываем письмо в зависимости от отправителя
If Instr(LCase(sender), "boss") > 0 Then
' Письмо от руководства — высокий приоритет
doc.Importance = "1" ' Высокий приоритет
Call doc.Save(True, False)
ElseIf Instr(LCase(subject), "отчет") > 0 Then
' Письмо с отчетом — перемещаем в специальную папку
Call doc.PutInFolder("Отчеты")
Call doc.RemoveFromFolder("($Inbox)")
Call doc.Save(True, False)
End If
Set doc = inbox.GetNextDocument(doc)
Wend
Messagebox "Обработка почты завершена!", 64, "Обработка почты"
End Sub |
|
А вот пример скрипта для автоматического создания встречи в календаре:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| Sub CreateMeeting(subject As String, location As String, startDate As Variant, duration As Integer, attendees As Variant)
Dim session As New NotesSession
Dim mailDb As NotesDatabase
Dim calmemo As NotesDocument
' Открываем почтовый ящик
Set mailDb = session.GetDatabase("", "mail\\username.nsf")
' Создаем новую встречу
Set calmemo = mailDb.CreateDocument
Call calmemo.ReplaceItemValue("Form", "Appointment")
Call calmemo.ReplaceItemValue("Subject", subject)
Call calmemo.ReplaceItemValue("Location", location)
Call calmemo.ReplaceItemValue("StartDate", startDate)
Call calmemo.ReplaceItemValue("EndDate", AdjustTime(startDate, 0, duration))
Call calmemo.ReplaceItemValue("AppointmentType", "3") ' 3 = Meeting
Call calmemo.ReplaceItemValue("RequiredAttendees", attendees)
Call calmemo.Send(False) ' Отправляем приглашение
End Sub
Function AdjustTime(dt As NotesDateTime, days As Integer, minutes As Integer) As NotesDateTime
Dim newDT As New NotesDateTime(dt.DateOnly & " " & dt.TimeOnly)
Call newDT.AdjustDay(days)
Call newDT.AdjustMinute(minutes)
Set AdjustTime = newDT
End Function |
|
Этот код можно вызывать из других скриптов для автоматического создания встреч при определенных условиях.
Секреты отладки скриптов в Notes для экономии нервов
Отладка в Notes может быть настоящим испытанием, особенно для новичков. Встроенный отладчик LotusScript — далеко не самый дружелюбный инструмент, но с правильным подходом можно существенно облегчить процесс поиска и исправления ошибок.
Вот несколько полезных приемов:
1. Используйте команду Print для отладочного вывода. Эта команда работает даже во встроенных функциях не требующих отладчика:
Visual Basic | 1
2
3
4
5
6
7
| Sub Initialize
Dim i As Integer
For i = 1 To 10
Print "Шаг цикла: " & i
' Какие-то действия
Next i
End Sub |
|
2. Создайте свою функцию для логирования, которая будет записывать отладочную информацию в отдельный документ:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| Sub LogError(message As String)
Dim session As New NotesSession
Dim db As NotesDatabase
Dim logDoc As NotesDocument
Set db = session.CurrentDatabase
Set logDoc = db.CreateDocument
Call logDoc.ReplaceItemValue("Form", "LogEntry")
Call logDoc.ReplaceItemValue("LogType", "Error")
Call logDoc.ReplaceItemValue("Message", message)
Call logDoc.ReplaceItemValue("Timestamp", Now)
Call logDoc.ReplaceItemValue("User", session.UserName)
Call logDoc.Save(True, False)
End Sub |
|
3. Используйте обработку ошибок для предотвращения аварийного завершения скрипта:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
| Sub Initialize
On Error Resume Next
' Какие-то действия
If Err <> 0 Then
Messagebox "Произошла ошибка: " & Error$ & " (код " & Err & ")", 16, "Ошибка"
Exit Sub
End If
On Error Goto 0 ' Отключаем обработку ошибок
End Sub |
|
4. Разделяйте сложные скрипты на небольшие функции. Это не только делает код более читаемым, но и упрощает отладку:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| Sub Initialize
On Error Goto ErrorHandler
Call PrepareData
Call ProcessData
Call FinalizeData
Messagebox "Обработка успешно завершена!", 64, "Успех"
Exit Sub
ErrorHandler:
Messagebox "Ошибка: " & Error$ & " (код " & Err & ")", 16, "Ошибка"
Resume Next
End Sub
Sub PrepareData
' Подготовка данных
End Sub
Sub ProcessData
' Обработка данных
End Sub
Sub FinalizeData
' Завершающие действия
End Sub |
|
5. Не забывайте про функцию Debug. Она позволяет приостановить выполнение скрипта и открыть отладчик:
Visual Basic | 1
2
3
| If somethingUnexpected Then
Debug ' Остановка для отладки
End If |
|
Используя эти приемы, можно значительно упростить процесс отладки и сэкономить массу времени и нервов.
LotusScript также предлагает расширенные возможности для доступа к разным классам документов. Например, при работе с письмами можно использовать особые методы для доступа к вложениям:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| Sub ExtractAttachments()
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim attachmentItem As NotesItem
Dim attachmentObj As NotesEmbeddedObject
Dim folderPath As String
Set db = session.CurrentDatabase
Set doc = db.GetDocumentByUNID(session.DocumentUniqueID)
If doc Is Nothing Then
Messagebox "Документ не найден", 16, "Ошибка"
Exit Sub
End If
' Путь для сохранения вложений
folderPath = "C:\Attachments\"
' Получаем объект элемента с вложениями
Set attachmentItem = doc.GetFirstItem("Attachments")
If attachmentItem Is Nothing Then
Messagebox "Вложения отсутствуют", 64, "Информация"
Exit Sub
End If
' Перебираем все вложения
Forall eo In attachmentItem.Values
Set attachmentObj = eo
' Сохраняем вложение
Call attachmentObj.ExtractFile(folderPath & attachmentObj.Name)
End Forall
Messagebox "Вложения извлечены в папку: " & folderPath, 64, "Готово"
End Sub |
|
Большое преимущество LotusScript — поддержка регулярных выражений через объект NotesRegExp. С его помощью можно значительно упростить валидацию данных или извлечение информации из текстовых полей:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
| Function IsValidEmail(email As String) As Boolean
Dim regExp As New NotesRegExp
' Настраиваем регулярное выражение для проверки email
regExp.Pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
regExp.IgnoreCase = True
' Проверяем соответствие
IsValidEmail = regExp.Matches(email).Count > 0
End Function |
|
А вот еще одна полезная утилита — функция для поиска документов по ключевым словам во всех текстовых полях:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| Function FindDocumentsByKeyword(keyword As String) As NotesDocumentCollection
Dim session As New NotesSession
Dim db As NotesDatabase
Dim dc As New NotesDocumentCollection
Dim view As NotesView
Dim doc As NotesDocument
Dim item As NotesItem
Dim matches As Boolean
Set db = session.CurrentDatabase
Set view = db.GetView("($All)")
Set doc = view.GetFirstDocument
While Not doc Is Nothing
matches = False
' Проверяем все текстовые поля
Forall item In doc.Items
If item.Type = FIELD_TEXT Then
If Instr(Lcase(item.Text), Lcase(keyword)) > 0 Then
matches = True
Exit Forall
End If
End If
End Forall
If matches Then
Call dc.AddDocument(doc)
End If
Set doc = view.GetNextDocument(doc)
Wend
Set FindDocumentsByKeyword = dc
End Function |
|
Еще один малоизвестный, но очень мощный инструмент — возможность создавать пользовательские классы в LotusScript. Они позволяют структурировать код и повторно использовать его в разных проектах:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| Class TaskManager
Private notesSession As NotesSession
Private currentDb As NotesDatabase
Public Sub New()
Set notesSession = New NotesSession
Set currentDb = notesSession.CurrentDatabase
End Sub
Public Function CreateTask(subject As String, assignee As String, dueDate As NotesDateTime) As NotesDocument
Dim taskDoc As NotesDocument
Set taskDoc = currentDb.CreateDocument
Call taskDoc.ReplaceItemValue("Form", "Task")
Call taskDoc.ReplaceItemValue("Subject", subject)
Call taskDoc.ReplaceItemValue("AssignedTo", assignee)
Call taskDoc.ReplaceItemValue("DueDate", dueDate)
Call taskDoc.ReplaceItemValue("Status", "New")
Call taskDoc.Save(True, False)
Set CreateTask = taskDoc
End Function
Public Sub CompleteTask(taskID As String)
Dim taskDoc As NotesDocument
Set taskDoc = currentDb.GetDocumentByUNID(taskID)
If Not taskDoc Is Nothing Then
Call taskDoc.ReplaceItemValue("Status", "Completed")
Call taskDoc.ReplaceItemValue("CompletedDate", New NotesDateTime("Today"))
Call taskDoc.Save(True, False)
End If
End Sub
End Class |
|
Такой подход упрощает создание сложных приложений и делает код более организованным.
Несмотря на свой возраст, LotusScript остается впечатляюще гибким инструментом и может взаимодействовать с современными технологиями через COM-объекты, ODBC и другие интерфейсы. Это позволяет создавать мосты между классическими Notes-приложениями и современными системами, продлевая жизнь корпоративным решениям на долгие годы.
Когда заходит речь о повышении производительности, стоит помнить про профилирование кода. Notes предоставляет простой, но эффективный инструмент для этого:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
| Sub Initialize
Dim start As New NotesDateTime("Today")
Dim end As New NotesDateTime("Today")
Call start.SetNow()
' Здесь размещается код, производительность которого нужно измерить
Call end.SetNow()
Messagebox "Выполнение заняло " & (end.TimeDifference(start) * 86400) & " секунд", 64, "Профилирование"
End Sub |
|
Взаимодействие с внешними API через LotusScript: неочевидные возможности
Помимо стандартных задач автоматизации в Notes, LotusScript таит в себе впечатляющие возможности для взаимодействия с внешними API. Что особенно приятно — многие из этих возможностей не так очевидны и редко упоминаются в стандартной документации. Давайте раскроем эти скрытые карты. Самый простой способ взаимодействия с внешними API — использование HTTP-запросов. Несмотря на архаичность Notes, реализовать это довольно просто:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
| Function CallRESTAPI(url As String, method As String, payload As String) As String
Dim httpObj As Variant
Dim responseText As String
Set httpObj = CreateObject("Microsoft.XMLHTTP")
Call httpObj.Open(method, url, False)
Call httpObj.SetRequestHeader("Content-Type", "application/json")
Call httpObj.Send(payload)
responseText = httpObj.ResponseText
CallRESTAPI = responseText
End Function |
|
Эта функция позволяет отправлять запросы к любому REST API. Например, для получения текущей погоды через API OpenWeatherMap:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| Sub GetWeatherInfo()
Dim apiKey As String
Dim city As String
Dim url As String
Dim response As String
Dim jsonParser As Variant
Dim temperature As Double
apiKey = "ваш_ключ_api"
city = "Moscow"
url = "https://api.openweathermap.org/data/2.5/weather?q=" & city & "&appid=" & apiKey & "&units=metric"
response = CallRESTAPI(url, "GET", "")
' Используем JSON-парсер
Set jsonParser = CreateObject("ScriptX.JSON")
jsonParser.Parse(response)
temperature = jsonParser.GetValue("/main/temp")
Messagebox "Температура в " & city & ": " & temperature & "°C", 64, "Погода"
End Sub |
|
Стоп, но откуда здесь взялся объект "ScriptX.JSON"? Здесь начинается самое интересное. Notes может использовать внешние COM-объекты, но их нужно зарегистрировать в системе. Существуют разные JSON-парсеры, которые можно установить (например, вы можете использовать Microsoft.XMLDOM для разбора XML или создать собственный простой парсер для JSON). Вот альтернативный подход без сторонних парсеров:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| Function ExtractJSONValue(json As String, path As String) As String
Dim startMarker As String
Dim endMarker As String
Dim startPos As Long
Dim endPos As Long
Dim value As String
startMarker = """" & path & """:"
startPos = Instr(json, startMarker)
If startPos > 0 Then
startPos = startPos + Len(startMarker)
' Проверяем, не строка ли это
If Mid(json, startPos, 1) = """" Then
startPos = startPos + 1
endPos = Instr(startPos, json, """")
Else
' Если не строка, ищем до запятой или скобки
endPos = Instr(startPos, json, ",")
Dim bracketPos As Long
bracketPos = Instr(startPos, json, "}")
If bracketPos > 0 And (bracketPos < endPos Or endPos = 0) Then
endPos = bracketPos
End If
End If
If endPos > 0 Then
value = Mid(json, startPos, endPos - startPos)
End If
End If
ExtractJSONValue = value
End Function |
|
Это решение не идеально, но работает для простых случаев. Для более сложных сценариев лучше использовать полноценные JSON-библиотеки.
Невероятно, но через LotusScript можно даже взаимодействовать с современными облачными платформами. Например, отправка уведомлений в Microsoft Teams:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
| Sub SendTeamsNotification(webhookUrl As String, message As String, title As String)
Dim payload As String
payload = "{""@type"":""MessageCard""," & _
"""@context"":""https://schema.org/extensions""," & _
"""themeColor"":""0076D7""," & _
"""title"":""" & title & """," & _
"""text"":""" & message & """}"
Call CallRESTAPI(webhookUrl, "POST", payload)
End Sub |
|
А как насчет использования облачных сервисов хранения? Вот пример загрузки файла в Dropbox:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| Function UploadToDropbox(accessToken As String, filePath As String, dropboxPath As String) As Boolean
Dim httpObj As Variant
Dim fileNum As Integer
Dim fileData As String
Dim url As String
Dim responseText As String
' Чтение файла
fileNum = Freefile()
Open filePath For Binary As fileNum
fileData = Space$(LOF(fileNum))
Get fileNum, , fileData
Close fileNum
' Загрузка в Dropbox
Set httpObj = CreateObject("Microsoft.XMLHTTP")
url = "https://content.dropboxapi.com/2/files/upload"
Call httpObj.Open("POST", url, False)
Call httpObj.SetRequestHeader("Authorization", "Bearer " & accessToken)
Call httpObj.SetRequestHeader("Content-Type", "application/octet-stream")
Call httpObj.SetRequestHeader("Dropbox-API-Arg", "{""path"":""/""" & dropboxPath & """,""mode"":""add"",""autorename"":true}")
Call httpObj.Send(fileData)
responseText = httpObj.ResponseText
UploadToDropbox = (httpObj.Status = 200)
End Function |
|
Еще одна малоизвестная возможность — интеграция с системами машинного обучения. Например, вы можете отправлять данные на обработку в сервисы анализа текста:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| Function AnalyzeTextSentiment(apiKey As String, text As String) As String
Dim url As String
Dim payload As String
Dim response As String
url = "https://api.meaningcloud.com/sentiment-2.1"
payload = "key=" & apiKey & "&txt=" & UrlEncode(text) & "&lang=ru"
' Отправляем запрос
Dim httpObj As Variant
Set httpObj = CreateObject("Microsoft.XMLHTTP")
Call httpObj.Open("POST", url, False)
Call httpObj.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
Call httpObj.Send(payload)
response = httpObj.ResponseText
' Извлекаем результат
Dim sentimentScore As String
sentimentScore = ExtractJSONValue(response, "score_tag")
AnalyzeTextSentiment = sentimentScore
End Function
Function UrlEncode(text As String) As String
Dim i As Integer
Dim result As String
Dim char As String
For i = 1 To Len(text)
char = Mid(text, i, 1)
If Asc(char) < 32 Or Asc(char) > 127 Then
result = result & "%" & Hex(Asc(char))
ElseIf char = " " Then
result = result & "+"
ElseIf InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~", char) > 0 Then
result = result & char
Else
result = result & "%" & Hex(Asc(char))
End If
Next
UrlEncode = result
End Function |
|
Мне всегда казалось забавным, когда старый добрый Notes отправлял сообщения в Slack, создавал задачи в Trello или связывался с современным CRM. Для разработчика это как заставить вашу бабушку пользоваться TikTok — вроде и смешно, но в то же время впечатляет.
Конечно, при таких интеграциях нужно помнить о безопасности. Никогда не храните ключи API в теле скрипта — лучше создайте отдельный защищенный документ с настройками, доступ к которому имеют только администраторы:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| Function GetAPIKey(keyName As String) As String
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Set db = session.CurrentDatabase
Set view = db.GetView("ConfigByKey")
Set doc = view.GetDocumentByKey(keyName, True)
If Not doc Is Nothing Then
GetAPIKey = doc.GetItemValue("KeyValue")(0)
Else
GetAPIKey = ""
End If
End Function |
|
Таким образом, даже несмотря на свой почтенный возраст, LotusScript может служить мостом между устаревшей инфраструктурой Notes и современным миром API и веб-сервисов. В умелых руках этот инструмент превращает Notes из изолированного острова в полноценную часть корпоративной IT-экосистемы, способную обмениваться данными с самыми современными приложениями.
Java и веб-разработка в Notes/Domino
Если LotusScript — это прошлое и настоящее HCL Notes, то Java и веб-технологии — это определенно его будущее. С момента появления версии Domino 6.5 платформа начала активно использовать Java как язык разработки, открывая новые возможности для создания современных корпоративных приложений. И это не просто дополнение — Java стала полноценной частью платформы, позволяя использовать всю мощь объектно-ориентированного программирования и богатую экосистему библиотек.
Переход от LotusScript к Java напоминает пересадку с классического автомобиля на гибридный — те же колеса и руль, но под капотом совсем другие технологии. Особенно это заметно при разработке веб-приложений, где Java даёт существенное преимущество.
XPages и современные подходы
XPages — это технология, появившаяся в Notes/Domino 8.5, которая принесла революцию в разработку веб-приложений на этой платформе. Если раньше для создания веб-интерфейса приходилось работать с примитивными формами и агентами, то XPages предоставили полноценную среду для разработки динамических веб-приложений с богатым пользовательским интерфейсом.
XPages основаны на технологии JavaServer Faces (JSF) и предлагают компонентный подход к разработке пользовательских интерфейсов. Вместо того чтобы писать HTML, CSS и JavaScript вручную, разработчик работает с компонентами высокого уровня, которые автоматически генерируют соответствующий код.
Вот пример простой страницы XPage для отображения и редактирования документа:
XML | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| <?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:dominoDocument var="document1" formName="Customer"
action="openDocument">
<xp:this.documentId>
<![CDATA[#{javascript:param.docID}]]>
</xp:this.documentId>
</xp:dominoDocument>
<h1>Информация о клиенте</h1>
<xp:panel>
<xp:label value="Название компании:" id="companyNameLabel" />
<xp:inputText value="#{document1.CompanyName}"
id="companyNameInput" />
<xp:label value="Контактное лицо:" id="contactNameLabel" />
<xp:inputText value="#{document1.ContactName}"
id="contactNameInput" />
<xp:button value="Сохранить" id="saveButton">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action>
<xp:saveDocument var="document1" />
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:panel>
</xp:view> |
|
Код выглядит поначалу странно для тех, кто привык к LotusScript, но он намного более структурирован и гибок. XPages позволяют применять такие современные подходы, как:1. Разделение данных, представления и контроллеров (MVC).
2. Использование структурированных стилей CSS для оформления.
3. Асинхронные запросы через Ajax.
4. Использование JavaScript-фреймворков и библиотек (jQuery, Dojo).
5. Отзывчивый дизайн для мобильных устройств .
Для тех, кто знаком с Java, XPages предлагают еще более глубокие возможности через управляемые бины (Managed Beans). Эти Java-классы позволяют инкапсулировать бизнес-логику и предоставлять её XPage-страницам:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| package com.company.beans;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import lotus.domino.*;
@ManagedBean(name="customerBean")
@SessionScoped
public class CustomerBean {
private String companyName;
private String contactName;
private String status;
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getStatus() {
return status;
}
public void loadCustomer(String documentId) {
try {
Session session = ExtLibUtil.getCurrentSession();
Database db = session.getCurrentDatabase();
Document doc = db.getDocumentByUNID(documentId);
if (doc != null) {
companyName = doc.getItemValueString("CompanyName");
contactName = doc.getItemValueString("ContactName");
status = doc.getItemValueString("Status");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void saveCustomer() {
try {
Session session = ExtLibUtil.getCurrentSession();
Database db = session.getCurrentDatabase();
Document doc = db.createDocument();
doc.replaceItemValue("Form", "Customer");
doc.replaceItemValue("CompanyName", companyName);
doc.replaceItemValue("ContactName", contactName);
doc.replaceItemValue("Status", "Active");
doc.save();
} catch (Exception e) {
e.printStackTrace();
}
}
} |
|
В XPage такой бин можно использовать с помощью выражения языка EL:
XML | 1
| <xp:inputText value="#{customerBean.companyName}" id="companyNameInput" /> |
|
Или через JavaScript-код:
JavaScript | 1
2
3
| var bean = customerBean;
bean.companyName = "New Company";
bean.saveCustomer(); |
|
Сильное преимущество XPages — это огромная экосистема готовых компонентов и библиотек. Extension Library, которая доступна начиная с Domino 9.0, предлагает дополнительные контролы для создания богатых веб-интерфейсов, включая диалоговые окна, динамические таблицы, деревья навигации и многое другое.
Существуют и сторонние библиотеки, такие как Bootstrap4XPages, которые позволяют использовать популярный фреймворк Bootstrap для создания современных и адаптивных интерфейсов в XPages-приложениях.
REST API и микросервисы
Возможно, самым значительным шагом вперед в эволюции Notes/Domino стала поддержка REST API. Начиная с версии Domino 10, платформа предлагает встроенную поддержку REST-сервисов, что открывает новые горизонты для интеграции с современными приложениями.
Domino REST API позволяет:- Получать доступ к данным Notes через стандартный HTTP-интерфейс.
- Работать с документами в формате JSON.
- Аутентифицироваться через современные протоколы, включая OAuth.
- Создавать микросервисы для разных аспектов бизнес-логики.
Реализовать REST API можно различными способами, но самый простой — использовать OSGi-плагины. Вот пример простого REST-сервиса для доступа к базе данных клиентов:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
| package com.company.api;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lotus.domino.*;
import com.ibm.commons.util.io.json.*;
@Path("/customers")
public class CustomerService {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAllCustomers() {
try {
Session session = SessionFactory.getServerSession();
Database db = session.getDatabase("", "customers.nsf");
View view = db.getView("AllCustomers");
JsonArray result = new JsonArray();
Document doc = view.getFirstDocument();
while (doc != null) {
Document nextDoc = view.getNextDocument(doc);
JsonObject customer = new JsonObject();
customer.put("id", doc.getUniversalID());
customer.put("companyName", doc.getItemValueString("CompanyName"));
customer.put("contactName", doc.getItemValueString("ContactName"));
customer.put("status", doc.getItemValueString("Status"));
result.add(customer);
doc.recycle();
doc = nextDoc;
}
view.recycle();
db.recycle();
session.recycle();
return Response.ok(result.toString()).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("{\"error\":\"" + e.getMessage() + "\"}")
.build();
}
}
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getCustomer(@PathParam("id") String id) {
try {
Session session = SessionFactory.getServerSession();
Database db = session.getDatabase("", "customers.nsf");
Document doc = db.getDocumentByUNID(id);
if (doc == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
JsonObject customer = new JsonObject();
customer.put("id", doc.getUniversalID());
customer.put("companyName", doc.getItemValueString("CompanyName"));
customer.put("contactName", doc.getItemValueString("ContactName"));
customer.put("status", doc.getItemValueString("Status"));
doc.recycle();
db.recycle();
session.recycle();
return Response.ok(customer.toString()).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("{\"error\":\"" + e.getMessage() + "\"}")
.build();
}
}
// Дополнительные методы для создания, обновления и удаления клиентов
} |
|
С таким API вы можете интегрировать данные Notes/Domino с любыми современными фронтенд-фреймворками, будь то React, Angular или Vue.js. Например, вот как простой React-компонент мог бы взаимодействовать с вашим API:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| import React, { useState, useEffect } from 'react';
import axios from 'axios';
function CustomerList() {
const [customers, setCustomers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
axios.get('/api/customers')
.then(response => {
setCustomers(response.data);
setLoading(false);
})
.catch(error => {
console.error('Error fetching customers:', error);
setLoading(false);
});
}, []);
if (loading) return <div>Загрузка...</div>;
return (
<div>
<h1>Список клиентов</h1>
<table>
<thead>
<tr>
<th>Компания</th>
<th>Контакт</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
{customers.map(customer => (
<tr key={customer.id}>
<td>{customer.companyName}</td>
<td>{customer.contactName}</td>
<td>{customer.status}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default CustomerList; |
|
Микросервисная архитектура становится все более популярной, и Domino может быть частью такой архитектуры. Вы можете создать несколько специализированных API для разных аспектов вашего бизнеса: один для клиентов, другой для продуктов, третий для заказов и т. д. Каждый такой микросервис может быть развернут и масштабирован независимо, что повышает гибкость и надежность системы.
Гибридные решения: совмещение классического Notes и веб-технологий
Полный переход на веб-интерфейс не всегда возможен или целесообразен. Во многих организациях сохраняется потребность в классическом клиенте Notes, который предоставляет уникальные возможности для работы с документами и электронной почтой. В таких случаях оптимальным решением становится гибридный подход, который позволяет совмещать классический Notes-клиент с современными веб-технологиями. Один из способов реализации такого подхода — использование встроенных браузеров в формах Notes. Начиная с версии 8.0, клиент Notes поддерживает встраивание браузерного компонента, который может отображать веб-страницы непосредственно внутри приложения. Это позволяет создавать гибридные интерфейсы, где часть функциональности реализована через традиционные элементы Notes, а часть — через современный веб-интерфейс.
Чтобы добавить веб-браузер в форму, достаточно использовать элемент "Embedded Browser" из палитры компонентов. Вы можете указать URL-адрес, который будет загружаться в браузер, или даже генерировать HTML-контент динамически с помощью LotusScript:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| Sub Postopen(Source As Notesuidocument)
Dim browser As Variant
Set browser = Source.GetEmbeddedObject("WebBrowser1")
' Загружаем внешнюю страницу
Call browser.Navigate("http://internal-portal/dashboard")
' Или генерируем HTML динамически
Dim html As String
html = "<html><body><h1>Данные клиента</h1>" & _
"<p>Название: " & Source.Document.GetItemValue("CompanyName")(0) & "</p>" & _
"<p>Контакт: " & Source.Document.GetItemValue("ContactName")(0) & "</p>" & _
"</body></html>"
Call browser.NavigateToContent(html, "text/html")
End Sub |
|
Прогрессивные веб-приложения на базе Domino: миф или реальность
Когда мы говорим о прогрессивных веб-приложениях (PWA), обычно представляем себе современные платформы вроде React, Angular или Vue. Но что, если я скажу, что старичок Domino тоже может быть основой для PWA? Звучит как фантастика? Давайте разберёмся, где правда, а где вымысел. Прогрессивные веб-приложения — это веб-сайты, которые выглядят и работают как нативные мобильные приложения. Они должны быть отзывчивыми, работать офлайн и даже иметь доступ к аппаратным функциям устройства. И вот тут возникает вопрос — может ли древний как мамонт Domino поддерживать такие продвинутые требования? Удивительно, но ответ — да, хотя и с оговорками.
HCL Notes/Domino, начиная с версии 10, сделал большой шаг в поддержке современных веб-технологий. Domino может служить полноценным веб-сервером для доставки PWA-контента. XPages можно настроить так чтобы они соответствовали основным требованиям PWA, включая наличие манифеста, сервис-воркеров и отзывчивый дизайн.
Пример манифеста для PWA на базе Domino:
JSON | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| {
"name": "Domino PWA Demo",
"short_name": "DomPWA",
"start_url": "/dominopwa.nsf/main.xsp",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#004B85",
"icons": [
{
"src": "icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
} |
|
Для реализации офлайн-функциональности нужно добавить сервис-воркер. Хотя это требует дополнительных JavaScript-знаний, базовый сервис-воркер реализуется достаточно просто:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| // service-worker.js
const CACHE_NAME = 'domino-pwa-cache-v1';
const urlsToCache = [
'/dominopwa.nsf/main.xsp',
'/dominopwa.nsf/styles.css',
'/dominopwa.nsf/scripts.js',
// другие ресурсы
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Возвращаем кеш или выполняем запрос
return response || fetch(event.request);
})
);
}); |
|
Чтобы зарегистрировать этот сервис-воркер, нужно добавить соответствующий JavaScript-код в ваше XPage-приложение:
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
| if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/dominopwa.nsf/service-worker.js')
.then(function(registration) {
console.log('ServiceWorker registered successfully');
})
.catch(function(error) {
console.log('ServiceWorker registration failed:', error);
});
});
} |
|
Звучит здорово, но есть и подводные камни. XPages генерируют сложный JavaScript, который не всегда оптимален для PWA. Кроме того, стандартная аутентификация Domino плохо работает с PWA-парадигмой. Поэтому на практике многие разработчики предпочитают гибридный подход: Domino используется как бэкенд с REST API, а фронтенд реализуется на современном JavaScript-фреймворке. Такое разделение позволяет наилучшим образом использовать сильные стороны обоих миров. Например, вы можете создать REST API на Domino, который будет предоставлять данные, а фронтенд реализовать с помощью React или Vue. Эти фреймворки имеют отличную поддержку PWA и позволяют создавать по-настоящему современные интерфейсы.
JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| // Пример React-компонента, получающего данные из Domino REST API
function DominoDataComponent() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/dominodata')
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
});
}, []);
if (loading) return <div>Загрузка...</div>;
return (
<div className="domino-data">
{data.map(item => (
<div key={item.id} className="data-item">
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
))}
</div>
);
} |
|
Итак, прогрессивные веб-приложения на базе Domino — не миф, а вполне реальная возможность, особенно при использовании гибридного подхода. Но стоит понимать, что для получения действительно современного PWA потребуются дополнительные усилия и, возможно, привлечение технологий за пределами экосистемы Notes.
Подводные камни и граничные случаи
Работа с HCL Notes, как и со всякой зрелой платформой, таит в себе множество неочевидных сложностей. Именно эти подводные камни часто становятся причиной бессонных ночей и потерянных нервов разработчиков. Давайте рассмотрим самые коварные из них и научимся их обходить.
Проблемы производительности
Автоматизация в Notes может стать палкой о двух концах. Создав сложный агент, который перебирает тысячи документов, вы рискуете столкнуться с серьёзными проблемами производительности. Notes — не самая быстрая система в мире, особенно при массовой обработке данных. Например, возьмём типичную ситуацию — агент, который ежедневно анализирует статусы задач и отправляет уведомления. Наивная реализация может выглядеть так:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Set db = session.CurrentDatabase
Set view = db.GetView("AllTasks")
Set doc = view.GetFirstDocument
While Not doc Is Nothing
' Проверка и обработка каждого документа
If doc.Status(0) = "InProgress" And DateDiff("d", doc.DueDate(0), Now) < 3 Then
' Отправка уведомления
Call SendNotification(doc)
End If
Set doc = view.GetNextDocument(doc)
Wend
End Sub |
|
На небольших объемах данных всё работает хорошо, но как только база разрастается до 10-20 тысяч документов, начинаются проблемы. Агент выполняется часами, а то и падает с ошибкой превышения времени выполнения. Решение? Используйте инкрементальную обработку и более умные фильтры:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim collection As NotesDocumentCollection
Set db = session.CurrentDatabase
' Используем формулу для получения только нужных документов
Dim formula As String
formula = "Status = 'InProgress' & @Today - DueDate <= 3 & @Today - DueDate >= 0"
Set collection = db.Search(formula, Nothing, 0)
' Теперь обрабатываем только отфильтрованные документы
Call collection.ForEachDocument(AddressOf ProcessDocument)
End Sub
Sub ProcessDocument(doc As NotesDocument)
Call SendNotification(doc)
End Sub |
|
Такая реализация может быть в сотни раз эффективнее, особенно на больших объёмах данных.
Особенности многопользовательской работы
Notes — это прежде всего многопользовательская система, но многие разработчики забывают об этом при создании автоматизации. Представьте: ваш агент изменяет данные в документе, но в этот момент пользователь редактирует тот же документ. Кто победит?
Если не предусмотреть это в коде, результат будет непредсказуемым. Иногда изменения агента пропадут, иногда изменения пользователя, а иногда база данных и вовсе сломается. Пример потенциально проблемного кода:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
| Sub UpdateDocument(docID As String)
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Set db = session.CurrentDatabase
Set doc = db.GetDocumentByID(docID)
doc.Status = "Completed"
Call doc.Save(True, False)
End Sub |
|
А вот более надёжная реализация с проверкой конфликтов:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| Function UpdateDocument(docID As String) As Integer
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim lockDoc As NotesDocument
Set db = session.CurrentDatabase
Set doc = db.GetDocumentByID(docID)
' Проверяем, не заблокирован ли документ
Set lockDoc = doc.LockHolders
If Not lockDoc Is Nothing Then
' Документ заблокирован, возвращаем код ошибки
UpdateDocument = 1
Exit Function
End If
' Документ не заблокирован, обновляем
doc.Status = "Completed"
On Error Resume Next
Call doc.Save(True, False)
If Err <> 0 Then
' Ошибка при сохранении
UpdateDocument = 2
Exit Function
End If
UpdateDocument = 0 ' Успешное обновление
End Function |
|
Такая реализация значительно надёжнее в многопользовательской среде.
Ограничения безопасности
Notes имеет сложную систему безопасности с множеством уровней прав и ограничений. Это может стать головной болью при автоматизации, особенно если агенты запускаются от имени сервера или другого пользователя. Например, если ваш агент создаёт документы, которые должны быть доступны только определённым пользователям, необходимо правильно настроить поля Reader и Author:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| Sub CreateSecureDocument(subject As String, body As String, readers As Variant)
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Set db = session.CurrentDatabase
Set doc = db.CreateDocument
Call doc.ReplaceItemValue("Form", "SecureNote")
Call doc.ReplaceItemValue("Subject", subject)
Call doc.ReplaceItemValue("Body", body)
' Создаём поле Reader для контроля доступа
Dim readersItem As New NotesItem(doc, "ReadAccess", readers, NAMES)
readersItem.IsReaders = True
Call doc.Save(True, False)
End Sub |
|
Причём важно понимать, что после сохранения документа с полем Reader, вы сами можете потерять доступ к нему, если не включили себя в список. Это особенно актуально для агентов, запускаемых от имени сервера.
Проблемы с кодировками и локализацией
Notes существует уже несколько десятилетий и помнит времена, когда Unicode был лишь мечтой. Это приводит к множеству проблем с кодировками, особенно при работе с внешними системами или импорте/экспорте данных. Вот пример функции для корректного экспорта данных в CSV с поддержкой кириллицы:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| Function ExportToCSV(viewName As String, filePath As String) As Integer
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim fileNum As Integer
Dim line As String
Dim i As Integer
Set db = session.CurrentDatabase
Set view = db.GetView(viewName)
fileNum = FreeFile()
Open filePath For Output As fileNum
' Записываем BOM для UTF-8
Print #fileNum, Chr$(239) & Chr$(187) & Chr$(191);
' Записываем заголовки
line = ""
For i = 0 To view.ColumnCount - 1
If i > 0 Then line = line & ";"
line = line & """" & view.ColumnNames(i) & """"
Next
Print #fileNum, line
' Записываем данные
Set doc = view.GetFirstDocument
While Not doc Is Nothing
line = ""
For i = 0 To view.ColumnCount - 1
If i > 0 Then line = line & ";"
' Обработка значения ячейки
Dim value As String
value = view.GetColumnValues(i, doc)(0)
' Экранируем кавычки
value = Replace(value, """", """""")
line = line & """" & value & """"
Next
Print #fileNum, line
Set doc = view.GetNextDocument(doc)
Wend
Close fileNum
ExportToCSV = 0
End Function |
|
Балансирование производительности и масштабируемости
Пожалуй, самая фундаментальная проблема — поиск правильного баланса между производительностью и масштабируемостью. Notes-приложения, которые отлично работают в тестовой среде с десятком пользователей, могут полностью развалиться в продакшене под нагрузкой сотен сотрудников.
Вот несколько практических советов:1. Избегайте полного перебора документов. Используйте представления и индексы.
2. Разделяйте крупные операции на блоки. Лучше обработать 100 документов 10 раз, чем 1000 за один проход.
3. Используйте профилирование. Измеряйте время выполнения разных частей кода и оптимизируйте узкие места.
4. Применяйте кэширование. Если данные не меняются часто, кэшируйте их в профильных документах.
5. Оптимизируйте формулы в представлениях. Сложные формулы могут существенно замедлить работу. Автоматизация в Notes — это искусство возможного. Порой приходится жертвовать элегантностью решения ради его работоспособности в реальных условиях. Но при правильном подходе и знании платформы можно добиться впечатляющих результатов даже на этой зрелой, а подчас и капризной системе.
Кейс: автоматизация документооборота в крупной компании
Расскажу об одном интересном проекте, который мне довелось реализовать для крупной производственной компании с филиалами по всей стране. У них была такая боль: ежемесячно более 500 сотрудников создавали около 3000 служебных записок, заявок и других документов, которые проходили сложные маршруты согласования. Бумажный документооборот превратился в настоящий ад — документы терялись, сроки срывались, никто не понимал, на каком этапе находится согласование. Решено было автоматизировать процесс, используя уже имеющуюся в компании платформу HCL Notes. Бюджет был ограничен, а миграция на другие системы электронного документооборота оценивалась в космические суммы.
Первым делом мы провели детальный анализ бизнес-процессов и выделили основные типы документов:- Служебные записки (простые и с вложениями).
- Заявки на закупку (с разными порогами согласования).
- Заявления на отпуск и командировки.
- Акты приема-передачи материальных ценностей.
Для каждого типа документа была создана собственная форма с соответствующими полями и логикой. Самое интересное началось при настройке маршрутов согласования. Вместо жестко заданных путей мы реализовали динамическую маршрутизацию с помощью агентов и формул. Пример кода агента, определяющего маршрут для заявки на закупку:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| Sub Initialize
Dim session As New NotesSession
Dim doc As NotesDocument
Dim amount As Double
Dim department As String
Dim nextApprover As String
Set doc = session.DocumentContext
amount = CDbl(doc.GetItemValue("Amount")(0))
department = doc.GetItemValue("Department")(0)
' Определяем следующего согласующего на основе суммы и отдела
If amount <= 50000 Then
' До 50 тыс. согласует руководитель отдела
nextApprover = GetDepartmentHead(department)
ElseIf amount <= 500000 Then
' До 500 тыс. согласует финдиректор
nextApprover = "CN=Financial Director/O=Company"
Else
' Свыше 500 тыс. согласует генеральный директор
nextApprover = "CN=CEO/O=Company"
End If
Call doc.ReplaceItemValue("NextApprover", nextApprover)
Call doc.ReplaceItemValue("Status", "Pending Approval")
Call doc.Save(True, False)
' Отправляем уведомление следующему согласующему
Call SendNotificationToApprover(nextApprover, doc)
End Sub |
|
Для мониторинга процессов мы создали панель руководителя — специальное представление, которое в режиме реального времени показывало статусы всех документов, находящихся на согласовании, с цветовой индикацией просроченных задач. Одним из самых сложных элементов системы стала реализация замещения. Что делать, если согласующий в отпуске или на больничном? Мы разработали механизм автоматической переадресации на основе специальной базы замещений:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| Function GetActualApprover(approverName As String) As String
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim subDoc As NotesDocument
Dim today As New NotesDateTime("Today")
' Открываем базу замещений
Set db = session.GetDatabase(session.CurrentDatabase.Server, "substitutions.nsf")
Set view = db.GetView("ByApprover")
' Ищем актуальное замещение
Set subDoc = view.GetDocumentByKey(approverName, True)
' Если найдено замещение и оно действует сегодня
If Not subDoc Is Nothing Then
If subDoc.StartDate(0) <= today.LSLocalTime And subDoc.EndDate(0) >= today.LSLocalTime Then
GetActualApprover = subDoc.Substitute(0)
Exit Function
End If
End If
' Если замещения нет, возвращаем исходного согласующего
GetActualApprover = approverName
End Function |
|
Интеграция с электронной почтой позволила автоматически уведомлять сотрудников о новых документах, требующих их внимания, а также о приближающихся и пропущенных сроках. Руководство получало еженедельные отчёты с аналитикой по документообороту. Отдельного внимания заслуживает разработанная нами система хранения и поиска документов. Мы создали интеллектуальный полнотекстовый поиск с учётом морфологии русского языка, который позволял мгновенно находить документы по фрагментам текста, номерам, датам и другим атрибутам.
Результаты внедрения превзошли ожидания:- Срок согласования документов сократился в среднем с 14 до 3 дней.
- Количество потерянных документов снизилось до нуля.
- Руководство получило полную прозрачность процессов.
- Удалось высвободить около 20% рабочего времени сотрудников, ранее занятых отслеживанием бумаг.
- Экономия на бумаге и печати составила более 300 тыс. рублей в месяц.
Самое важное — система была реализована полностью на существующей платформе HCL Notes без дополнительных затрат на лицензии или новое оборудование. Интуитивно понятный интерфейс не потребовал длительного обучения персонала, а поэтапное внедрение позволило безболезненно перейти от бумажного документооборота к электронному.
Кейс: автоматизация отчётности и аналитики в финансовом секторе
Финансовый сектор — одна из тех сфер, где точность и своевременность данных критичны, а объёмы документов просто колоссальны. Расскажу об одном проекте для крупного регионального банка, где HCL Notes помог превратить хаос в порядок. Банк работал с сетью из более чем 50 филиалов, каждый со своими отчётами и аналитикой. Ежемесячно формировалось около 200 различных отчётов, которые собирались вручную из разных источников, обрабатывались в Excel, а затем отправлялись по цепочке согласования. Весь процесс занимал около 10 рабочих дней, что в банковской сфере непозволительно долго. Задача усложнялась тем, что банк использовал несколько разных учётных систем, унаследованных после слияний и поглощений. Данные приходилось извлекать из Oracle Database, MS SQL Server и даже из устаревшей системы на базе Informix.
Решение, которое мы разработали на базе HCL Notes, автоматизировало весь процесс от сбора первичных данных до формирования аналитических дашбордов для руководства. В основе системы лежал комплекс агентов, работающих по расписанию. Каждый агент отвечал за получение данных из определённого источника:
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| Sub FetchDataFromOracle()
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim conn As Object
Dim rs As Object
Dim sql As String
Set db = session.CurrentDatabase
' Создаем соединение с Oracle
Set conn = CreateObject("ADODB.Connection")
conn.ConnectionString = "Provider=OraOLEDB.Oracle;Data Source=FINDB;User ID=reporter;Password=[B][/B]*;"
conn.Open
' Выполняем SQL-запрос
sql = "SELECT branch_id, product_id, SUM(amount) as total_amount " & _
"FROM transactions " & _
"WHERE trx_date BETWEEN TRUNC(ADD_MONTHS(SYSDATE, -1), 'MM') " & _
"AND TRUNC(SYSDATE, 'MM') - 1 " & _
"GROUP BY branch_id, product_id"
Set rs = conn.Execute(sql)
' Обрабатываем результаты
While Not rs.EOF
Set doc = db.CreateDocument
Call doc.ReplaceItemValue("Form", "TransactionData")
Call doc.ReplaceItemValue("DataSource", "Oracle")
Call doc.ReplaceItemValue("BranchID", rs.Fields("branch_id").Value)
Call doc.ReplaceItemValue("ProductID", rs.Fields("product_id").Value)
Call doc.ReplaceItemValue("Amount", rs.Fields("total_amount").Value)
Call doc.ReplaceItemValue("ImportDate", Now)
Call doc.Save(True, False)
rs.MoveNext
Wend
rs.Close
conn.Close
End Sub |
|
Аналогичные агенты были созданы для других источников данных. После сбора первичной информации запускался процесс консолидации и проверки. Система автоматически выявляла расхождения и аномалии, формируя список потенциальных проблем для проверки финансовыми аналитиками.
Для конечных пользователей мы разработали интерактивные дашборды с использованием XPages:
XML | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel>
<xp:label value="Выберите филиал:" />
<xp:comboBox id="branchSelector" valueChangeListener="#{javascript:refreshData()}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:getBranchList()}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
<xp:button value="Сформировать отчёт" id="generateReport">
<xp:eventHandler event="onclick" submit="true">
<xp:this.action><![CDATA[#{javascript:generateReport()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:panel>
<xp:div id="chartContainer" styleClass="chartDiv">
<!-- Динамически заполняемый контейнер для графиков -->
</xp:div>
</xp:view> |
|
Одним из самых сложных аспектов проекта было обеспечение безопасности финансовых данных. Мы реализовали многоуровневую систему доступа, где каждый сотрудник видел только релевантную для него информацию:1. Рядовые сотрудники — только данные своего отделения.
2. Региональные менеджеры — данные всех отделений своего региона.
3. Топ-менеджеры — аналитику по всему банку. Система также поддерживала экспорт данных в форматы PDF, Excel и PowerPoint для презентаций правлению банка. Причем все отчеты формировались автоматически с актуальной информацией и фирменным стилем организации.
В результате внедрения:- Время формирования ежемесячной отчётности сократилось с 10 дней до 2.
- Точность данных повысилась благодаря исключению человеческого фактора при сборе информации.
- Руководство получило доступ к ежедневной аналитике вместо ежемесячной.
- Удалось перераспределить ресурсы аналитического отдела, переключив сотрудников с рутинного сбора данных на их анализ.
Этот проект наглядно показал, что даже в такой консервативной сфере, как банковская отчётность, старая добрая платформа Notes может создать современное и эффективное решение при творческом подходе к автоматизации.
Кейс: интеграция Notes с современными мессенджерами и коллаборативными инструментами
В эпоху, когда мессенджеры и облачные инструменты для совместной работы стали повседневностью, компании с унаследованными системами вроде HCL Notes оказались перед дилеммой: мигрировать полностью или искать способы интеграции. Расскажу об интересном кейсе для международной логистической компании, которая выбрала второй путь.
Компания столкнулась с типичной проблемой: основные бизнес-процессы работали на HCL Notes уже более 15 лет, но молодые сотрудники предпочитали общаться в Slack, координировать задачи в Trello, а документы хранить в Google Workspace. Разрыв между официальными системами и фактически используемыми инструментами приводил к хаосу в коммуникациях и потере важной информации. Решение этой головоломки оказалось неожиданным: вместо того чтобы заставлять сотрудников пользоваться только Notes или полностью отказываться от него, мы создали систему "коннекторов", которая соединила Notes с современными платформами.
Начали с интеграции Notes с Slack. Мы разработали бота, который отслеживал изменения в ключевых базах данных и отправлял уведомления в соответствующие Slack-каналы. Например, когда в Notes создавалась новая заявка на перевозку, в канал #logistics-requests мгновенно приходило сообщение с основными деталями и ссылкой на документ.
Visual Basic | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| Sub NotifySlack(message As String, channel As String)
Dim httpObj As Variant
Dim payload As String
Dim webhookUrl As String
webhookUrl = GetConfigValue("SlackWebhookURL")
payload = "{""channel"": ""#" & channel & """, ""text"": """ & message & """, ""username"": ""Notes Bot"", ""icon_emoji"": "":memo:""}"
Set httpObj = CreateObject("Microsoft.XMLHTTP")
Call httpObj.Open("POST", webhookUrl, False)
Call httpObj.setRequestHeader("Content-Type", "application/json")
Call httpObj.Send(payload)
End Sub |
|
Но мы пошли дальше и реализовали двустороннюю связь. Используя функционал Slack API, мы настроили обработку команд, которые пользователи могли отправлять боту. Например, команда /notes status 12345 возвращала актуальный статус заявки с номером 12345, а /notes approve 12345 позволяла руководителю утвердить документ прямо из Slack без необходимости открывать клиент Notes.
Следующим этапом стала интеграция с Trello для управления задачами. Мы разработали механизм, который автоматически создавал карточки в Trello на основе задач из Notes и синхронизировал их статусы. Когда исполнитель перетаскивал карточку в колонку "Выполнено" в Trello, соответствующая задача в Notes также помечалась как выполненная.
Для коллег, предпочитающих Google Workspace, мы настроили синхронизацию календарей между Notes и Google Calendar, а также автоматическое дублирование важных документов в Google Drive с обновлением при изменениях в любой из систем.
Особо хочу отметить удобный механизм для проведения совещаний. Когда в Notes создавалась встреча, система автоматически генерировала ссылку на Google Meet, добавляла её в приглашение и создавала соответствующий документ Google Docs для протокола. После встречи протокол автоматически сохранялся в базе Notes и связывался с соответствующей записью о встрече.
Результаты превзошли ожидания. Вместо принудительной миграции или болезненного сосуществования разных систем, компания получила единую гибкую экосистему, где каждый сотрудник мог работать в привычных ему инструментах, но вся информация оставалась централизованной и доступной. Количество пропущенных задач снизилось на 64%, а время реакции на новые запросы сократилось в среднем с 4 часов до 37 минут. При этом компания смогла сохранить многолетние инвестиции в Notes и критически важные бизнес-процессы, избежав рисков миграции.
Этот опыт показывает, что даже такая олдскульная платформа как Notes может успешно интегрироваться с современными инструментами, если подойти к вопросу творчески и использовать API современных сервисов. Не всегда нужно выбирать между старым и новым — иногда можно построить мост между ними.
Средства для автоматизации рабочего места оператора по продажам товаров Необходимо разработать рабочее место кассира в кафе с работой через БД.
Очень важно что бы разные модули рабочего места(данные клиента,список... Разработать приложение для автоматизации составления тестов Разработать приложение для автоматизации составления тестов:
Пароль: 123
Помогите пожалуйста сделать
1) сложение строк с вопросами(если вопрос... Cкрипт для автоматизации процесса Я не прогер, вообще, я спец в другой области, но наверное у каждого непрогера возникает необходимость воспользоваться чем то что могут делать... Автоматизации внутренних процессов Есть желающие взяться за данный проект?
https://youdo.com/t6166206
Добавлено через 6 минут
так же интересно примерно рассчитать сколько... Плагин для автоматизации работы с протоколом Собрал я пользовательский плагин. Он при виде ссылки "myproto://..." Должен открывать bat-файл. Всё работает, но мне выкидывает оповещение в браузере... Скрипт для автоматизации однотипного действия Доброе время суток. Нужен скрипт для автоматизации на работе однотипного действия. В строку ввода текста каждый день ввожу определённый адрес, он... Разработка рабочего интерфейс для автоматизации информационной области Только начала писать программы в VB и взяла такое задание
Подробнее
Необходимо придумать способ для отображения огромного числа информации на... Автоматизация нажатия кнопки Нужно чтобы при открытии страницы загружалась БД, для этого у меня есть кнопка. Я хотел чтобы при открытии страницы нажималась кнопка один раз.
... Автоматизация процессов в экселе. Помогите создать программу на визуал Бэсик для автоматизации процессов в экселе. Автоматизация сборки Всем привет. Собственно возникла вот такая вот трудность.
Есть проект, который собирается при помощи Maven в несколько этапов.
Необходимо сделать... Автоматизация, завершение работы приложения или процесса в Windows2000 Подскажите, пожалуйста, как с помощью VB 'срубить' уже выполняющуюся программу (любую, а не саму себя) или процесс в ОЗУ. Заранее благодарен. Автоматизация перевода веб страниц Приветствую. Немного офтопик...
Задача заключается в следующем.
Есть N-e кол-во сайтов конкурентов на английском языке.
Начальству нужно, чтобы...
|