В процессе разработки многопользовательских систем на платформе 1С:Предприятие 8.3 часто возникает ситуация, когда одна и та же обработка запущена у нескольких сотрудников одновременно. Одной из специфических проблем является корректное заполнение данных из внешних источников (например, торгового оборудования) так, чтобы данные попадали именно в ту форму, из которой был инициирован запрос. Разберем ситуацию на примере работы с весами через HTTP-запрос и выясним, почему данные могут «пересекаться» и как этого избежать.
Рассмотрим ситуацию: у нескольких пользователей открыта форма ФормаГВХ. Один из них нажимает кнопку «Получить ГВХ», и данные с весов заполняют поля не только у него, но и (как кажется на первый взгляд) у других пользователей. Прежде всего, важно понимать архитектуру 1С: сеансы пользователей изолированы друг от друга. Данные одного сеанса физически не могут напрямую попасть в оперативную память другого сеанса без использования специальных механизмов (например, системы взаимодействия или записи в общую базу данных).
Если вы столкнулись с подобным эффектом, проанализируем возможные причины:
РегистрСведений или Константу, а на других формах настроено автоматическое обновление (например, через ПодключитьОбработчикОжидания), то пользователи увидят чужие данные.Для того чтобы 1С понимала, что каждое открытое окно обработки — это независимый объект, мы должны использовать параметр КлючУникальности. Этот ключ позволяет платформе различать экземпляры одной и той же формы в рамках одного сеанса.
Разберем, как правильно открывать форму, чтобы гарантировать её уникальность. Вместо стандартного вызова без параметров, используем генерацию УникальныйИдентификатор. Это особенно актуально, если один пользователь может открыть несколько окон приемки товара одновременно.
// Пример открытия уникальной формы
Ключ = Новый УникальныйИдентификатор;
ПараметрыФормы = Новый Структура("Ключ", "Значение");
ОткрытьФорму("ВнешняяОбработка.ПриемкаТовара.Форма.ФормаГВХ", ПараметрыФормы, ЭтаФорма, Ключ);
В этом случае платформа создаст новое окно, которое не будет конфликтовать с уже открытыми окнами той же обработки внутри вашего сеанса.
В сценарии с весами критически важно понимать, кто именно запрашивает данные. Если весы подключены к конкретному компьютеру, адрес запроса не должен быть «зашит» в коде. Его нужно определять динамически. Посмотрим на решение, которое позволяет разграничить доступ к оборудованию по имени компьютера.
Проанализируем пример реализации, где мы проверяем, имеет ли право текущее рабочее место работать с весами:
// В процедуре открытия или инициализации
ИмяКомпьютераСеанса = ИмяКомпьютера();
Если ИмяКомпьютераСеанса = "СКЛАД_ПК_1" Тогда
// Это рабочее место с весами
ФормаИзм = ПолучитьФорму("ФормаГВХ", , "ФормаСВесами");
ФормаИзм.Номенклатура = ТекущаяНоменклатура;
ФормаИзм.Открыть();
Иначе
// Обычное рабочее место для ручного ввода
ФормаИзм = ПолучитьФорму("ФормаГВХ");
ФормаИзм.Номенклатура = ТекущаяНоменклатура;
ФормаИзм.Открыть();
КонецЕсли;
Затем, непосредственно в процедуре получения данных, мы проверяем, является ли текущая форма «той самой», которая работает с оборудованием:
Процедура ПолучитьГВХСВесовНажатие(Элемент)
// Проверяем ключ уникальности, заданный при открытии
Если ЭтаФорма.КлючУникальности <> "ФормаСВесами" Тогда
Сообщить("Это рабочее место не подключено к весам. Введите данные вручную.");
Возврат;
КонецЕсли;
// Код обращения к HTTP-серверу весов
HTTP = Новый HTTPСоединение("192.168.1.100", , , , , , );
// ... логика запроса ...
ЭтаФорма.ФШирина = Число(НаборГВХ["width"]);
ЭтаФорма.ФВес = Число(НаборГВХ["weight"]);
КонецПроцедуры
Для более чистого кода рекомендуется использовать ПараметрыСеанса или настройки пользователя в базе данных. Выясним, как это улучшит архитектуру. Вместо жесткого сравнения строк (имен компьютеров), создадим в конфигурации регистр сведений НастройкиРабочихМест, где укажем IP-адрес весов для каждого ПК.
Рассмотрим алгоритм работы:
Это исключает ситуацию, когда пользователь с другого конца склада случайно нажимает кнопку и получает данные с чужих весов, так как запрос пойдет на корректный IP-адрес, соответствующий его рабочему месту.
При проектировании подобных интерфейсов следует придерживаться нескольких правил, чтобы избежать «затирания» данных:
1. Отказ от модальности. В современном интерфейсе «Такси» рекомендуется использовать ОткрытьФорму вместо ОткрытьМодально. Это позволяет пользователю переключаться между окнами и не блокирует весь интерфейс программы, что особенно важно при ожидании ответа от медленного оборудования.
2. Проверка модифицированности. Перед заполнением данных из весов в код стоит добавить проверку: Если ЭтаФорма.Модифицированность Тогда.... Это позволит предупредить пользователя, что он уже начал вводить данные вручную, а автоматика может их затереть.
3. Изоляция бизнес-логики. Выносите код работы с HTTP в общий модуль с флагом ВызовСервера. Это позволит централизованно управлять подключениями и логировать ошибки связи с оборудованием в одном месте.
4. Обработка оповещений. Если вам все же нужно передать данные из одной формы в другую, используйте метод Оповестить() и обработчик ОбработкаОповещения. Помните, что стандартное оповещение работает в пределах одного клиентского приложения (одного окна 1С).
Таким образом, проблема «пересечения» данных чаще всего кроется в отсутствии четкой идентификации источника (весов) или неправильном управлении экземплярами форм. Используя КлючУникальности и привязку оборудования к настройкам рабочего места, вы обеспечите стабильную и независимую работу всех сотрудников склада.