Форум программистов, компьютерный форум, киберфорум
Mr. Docker
Войти
Регистрация
Восстановить пароль

Автоматизация задач в HCL Notes

Запись от Mr. Docker размещена 12.03.2025 в 17:27
Показов 1045 Комментарии 0

Нажмите на изображение для увеличения
Название: 81f1a38c-638c-4725-a50d-dc5f353f706f.jpg
Просмотров: 31
Размер:	67.5 Кб
ID:	10375
Если вы когда-нибудь работали с 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 минут так же интересно примерно рассчитать сколько...

Плагин для автоматизации работы с протоколом
Собрал я пользовательский плагин. Он при виде ссылки &quot;myproto://...&quot; Должен открывать bat-файл. Всё работает, но мне выкидывает оповещение в браузере...

Скрипт для автоматизации однотипного действия
Доброе время суток. Нужен скрипт для автоматизации на работе однотипного действия. В строку ввода текста каждый день ввожу определённый адрес, он...

Разработка рабочего интерфейс для автоматизации информационной области
Только начала писать программы в VB и взяла такое задание Подробнее Необходимо придумать способ для отображения огромного числа информации на...

Автоматизация нажатия кнопки
Нужно чтобы при открытии страницы загружалась БД, для этого у меня есть кнопка. Я хотел чтобы при открытии страницы нажималась кнопка один раз. ...

Автоматизация процессов в экселе.
Помогите создать программу на визуал Бэсик для автоматизации процессов в экселе.

Автоматизация сборки
Всем привет. Собственно возникла вот такая вот трудность. Есть проект, который собирается при помощи Maven в несколько этапов. Необходимо сделать...

Автоматизация, завершение работы приложения или процесса в Windows2000
Подскажите, пожалуйста, как с помощью VB 'срубить' уже выполняющуюся программу (любую, а не саму себя) или процесс в ОЗУ. Заранее благодарен.

Автоматизация перевода веб страниц
Приветствую. Немного офтопик... Задача заключается в следующем. Есть N-e кол-во сайтов конкурентов на английском языке. Начальству нужно, чтобы...

Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Java Micronaut в Docker: контейнеризация с Maven и Jib
Javaican 16.03.2025
Когда речь заходит о микросервисной архитектуре на Java, фреймворк Micronaut выделяется среди конкурентов. Он создан с учётом особенностей облачных сред и контейнеров, что делает его идеальным. . .
Управление зависимостями в Java: Сравнение Spring, Guice и Dagger 2
Javaican 16.03.2025
Инъекция зависимостей (Dependency Injection, DI) — один из фундаментальных паттернов проектирования, который радикально меняет подход к созданию гибких и тестируемых Java-приложений. Суть этого. . .
Apache Airflow для оркестрации и автоматизации рабочих процессов
Mr. Docker 16.03.2025
Управление сложными рабочими процессами — одна из главных головных болей инженеров данных и DevOps-специалистов. Представьте себе: каждый день нужно запускать десятки скриптов в определенной. . .
Оптимизация приложений Java для ARM
Javaican 16.03.2025
ARM-архитектура переживает настоящий бум популярности в технологическом мире. Когда-то воспринимаемая исключительно как решение для мобильных устройств и встраиваемых систем, сегодня она штурмует. . .
Управление состоянием в Vue 3 с Pinia и Composition API
Reangularity 16.03.2025
Когда я начал работать с Vue несколько лет назад, мне казалось достаточным использовать простую передачу данных через props и события между компонентами. Однако уже на среднем по сложности проекте. . .
Введение в DevSecOps: основные принципы и инструменты
Mr. Docker 16.03.2025
DevSecOps - это подход к разработке программного обеспечения, который объединяет в себе принципы разработки (Dev), безопасности (Sec) и эксплуатации (Ops). Суть подхода заключается в том, чтобы. . .
GitHub Actions vs Jenkins: Сравнение инструментов CI/CD
Mr. Docker 16.03.2025
В этой битве за эффективность и скорость выпуска программных продуктов ключевую роль играют специализированные инструменты. Два гиганта в этой области — GitHub Actions и Jenkins — предлагают разные. . .
Реактивное программировани­е с Kafka Stream и Spring WebFlux
Javaican 16.03.2025
Реактивное программирование – это программная парадигма, ориентированная на потоки данных и распространение изменений. Она позволяет выражать статические или динамические потоки данных и. . .
Простая нейросеть на КуМир: Учебное пособие по созданию и обучению нейронных сетей
EggHead 16.03.2025
Искусственные нейронные сети — удивительная технология, позволяющая компьютерам имитировать работу человеческого мозга. Если вы хотя бы немного интересуетесь современными технологиями, то наверняка. . .
Исполнитель Кузнечик в КуМир: Решение задач
EggHead 16.03.2025
Среди множества исполнителей в системе КуМир особое место занимает Кузнечик — простой, но невероятно полезный виртуальный персонаж, который перемещается по числовой прямой, выполняя ваши команды. На. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru