Многие пользователи и администраторы 1С сталкиваются с неприятной ситуацией: в справочнике «Рабочие места» со временем накапливаются дублирующиеся записи для одного и того же пользователя на одном и том же компьютере. Часто это происходит после стандартных процедур, таких как очистка кэша, и приводит к необходимости заново настраивать торговое оборудование и другие персональные параметры. Давайте вместе разберемся, почему это происходит и как раз и навсегда решить эту проблему.
Основной вопрос заключается в поведении системного параметра ИдентификаторКлиента (ClientID). В официальной справке 1С (Синтакс-помощнике) сказано, что это уникальный идентификатор, который должен быть неизменным для связки «компьютер + пользователь операционной системы». Однако на практике мы видим, что он меняется. Проанализируем, в чем тут дело.
Начнем с главного: утверждение в справке технически верно, но с одним важным нюансом. ClientID действительно уникален и постоянен, но только до тех пор, пока цел файл, в котором он хранится. Этот идентификатор не вычисляется каждый раз на основе аппаратной конфигурации компьютера, а генерируется один раз и записывается в файл настроек профиля пользователя 1С.
Этот файл, как правило, называется 1cv8u.pfl и находится в папке с глобальными настройками пользователя, например, по пути:
C:\Users\<ИмяПользователяОС>\AppData\Local\1C\1cv8\
Содержимое этого файла может выглядеть примерно так, как выяснили участники форума:
{
{""},
{
{"Universal",
{"ClientID",
{"#",fc01b5df-97fe-449b-83d4-218a090e681e,083241ee-94b4-486f-af56-c5f8ed879014},""},
{
{""}
}
},
{""}
}
}
Здесь fc01b5df-97fe-449b-83d4-218a090e681e и есть тот самый ClientID. А теперь рассмотрим самую частую причину его смены.
Когда в 1С возникают ошибки или странное поведение, первый и самый популярный совет от службы поддержки или системного администратора — «почистить кэш». К сожалению, под этой фразой часто подразумевается полное удаление пользовательских папок 1С, таких как %AppData%\Roaming\1C\1cv8 и %AppData%\Local\1C\1cv8. В результате вместе с временными файлами кэша удаляется и файл 1cv8u.pfl. При следующем запуске платформа 1С не находит старый идентификатор и генерирует новый.
Вывод: ClientID меняется не сам по себе, а потому что файл, где он хранится, удаляется при «грубой» очистке кэша. Для системы 1С это выглядит так, как будто пользователь зашел с абсолютно нового, ранее неизвестного рабочего места, что и приводит к созданию новой записи в справочнике.
Эта проблема особенно актуальна для конфигураций, использующих торговое оборудование (1С:Розница, 1С:Управление торговлей), где к каждому рабочему месту привязаны сканеры штрихкодов, фискальные регистраторы, принтеры чеков и т.д. Смена идентификатора заставляет заново выполнять все эти настройки, что отнимает время и создает путаницу.
Поскольку мы выяснили, что стандартный ClientID — это «синтетический ключ», который не является достаточно стабильным, логичным решением будет перейти на использование «естественного ключа». Естественный ключ — это комбинация данных, которая уникально идентифицирует сущность (в нашем случае — рабочее место) и не меняется при программных сбоях или обслуживании.
Для рабочего места идеальным естественным ключом является связка: Имя компьютера + Имя пользователя операционной системы. Эти параметры остаются неизменными при очистке кэша 1С.
Рассмотрим, как реализовать этот механизм, желательно с помощью расширения конфигурации, чтобы не изменять типовую логику.
Создадим механизм, который будет привязывать непостоянный ClientID к нашей стабильной связке. Это позволит системе «узнавать» рабочее место, даже если системный идентификатор изменится.
Шаг 1. Создаем объект для хранения соответствий
В расширении добавим новый объект — независимый, непериодический Регистр сведений. Назовем его, например, СоответствиеИдентификаторовРабочихМест.
ИмяКомпьютера (Тип: Строка, длина 100)ИмяПользователяОС (Тип: Строка, длина 100)РабочееМесто (Тип: СправочникСсылка.РабочиеМеста)Этот регистр будет хранить нашу надежную привязку.
Шаг 2. Добавляем код для получения данных и поиска рабочего места
Нам понадобится функция, которая будет определять текущее рабочее место. Лучше всего разместить ее в общем модуле расширения с флагами «Клиент (обычное приложение)», «Клиент (управляемое приложение)» и «Вызов сервера».
Сначала напишем код для получения имени компьютера и пользователя ОС. Это можно сделать с помощью объекта WScript.Network на клиенте под Windows.
&НаКлиенте
Функция ПолучитьПараметрыИдентификацииКлиента()
Перем ИмяКомпьютера, ИмяПользователяОС;
// Этот код работает только на клиенте под ОС Windows
#Если ТонкийКлиент ИЛИ ТолстыйКлиент Тогда
Попытка
Network = Новый COMОбъект("WScript.Network");
ИмяКомпьютера = Network.ComputerName;
ИмяПользователяОС = Network.UserName;
Исключение
// Если COM-объект недоступен (например, на Linux или в веб-клиенте),
// можно использовать альтернативные методы или сообщить об ошибке.
// Для простоты оставим пустыми.
ИмяКомпьютера = "";
ИмяПользователяОС = "";
КонецПопытки;
#КонецЕсли
Результат = Новый Структура;
Результат.Вставить("ИмяКомпьютера", ВРег(ИмяКомпьютера));
Результат.Вставить("ИмяПользователяОС", ВРег(ИмяПользователяОС));
Возврат Результат;
КонецФункции
Шаг 3. Заполняем регистр и определяем рабочее место при старте системы
Теперь создадим процедуру, которая будет выполняться при каждом запуске сеанса. Для этого в расширении создадим Модуль сеанса и добавим обработчик события УстановкаПараметровСеанса.
Логика будет следующей:
СоответствиеИдентификаторовРабочихМест по этому ключу.ClientID. В этом случае мы позволяем типовому механизму создать новое рабочее место (или найти его по новому ClientID), а затем сохраняем связь между нашим «естественным ключом» и найденным/созданным элементом справочника в наш регистр.Примерный код для модуля сеанса (серверный вызов):
&НаСервере
Процедура ОпределитьИЗаписатьРабочееМесто(ПараметрыИдентификации)
Если НЕ ЗначениеЗаполнено(ПараметрыИдентификации.ИмяКомпьютера) Тогда
// Не удалось определить параметры, выходим
Возврат;
КонецЕсли;
// 1. Ищем запись в нашем регистре
Отбор = Новый Структура("ИмяКомпьютера, ИмяПользователяОС",
ПараметрыИдентификации.ИмяКомпьютера, ПараметрыИдентификации.ИмяПользователяОС);
ЗаписьРегистра = РегистрыСведений.СоответствиеИдентификаторовРабочихМест.Получить(Отбор);
Если ЗаписьРегистра.РабочееМесто <> Неопределено Тогда
// 2. Запись найдена! Мы знаем рабочее место.
// Здесь можно установить его в параметры сеанса или глобальную переменную,
// чтобы другие механизмы использовали именно его.
ПараметрыСеанса.ТекущееРабочееМесто = ЗаписьРегистра.РабочееМесто;
Иначе
// 3. Запись не найдена. Позволяем сработать типовому механизму.
// Предположим, что типовая функция возвращает нам текущее рабочее место.
// В разных конфигурациях она может называться по-разному.
// Для примера назовем ее `ТиповаяФункцияОпределенияРабочегоМеста()`.
ТекущееРабочееМесто = ОбщегоНазначения.ОпределитьТекущееРабочееМестоПоClientID(); // Это условное название!
Если ЗначениеЗаполнено(ТекущееРабочееМесто) Тогда
// 4. Записываем новую связку в наш регистр для будущих сеансов.
МенеджерЗаписи = РегистрыСведений.СоответствиеИдентификаторовРабочихМест.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИмяКомпьютера = ПараметрыИдентификации.ИмяКомпьютера;
МенеджерЗаписи.ИмяПользователяОС = ПараметрыИдентификации.ИмяПользователяОС;
МенеджерЗаписи.РабочееМесто = ТекущееРабочееМесто;
Попытка
МенеджерЗаписи.Записать();
Исключение
// Обработка возможной ошибки записи
КонецПопытки;
ПараметрыСеанса.ТекущееРабочееМесто = ТекущееРабочееМесто;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важно: этот код является концептуальным. Вам нужно будет адаптировать его под вашу конфигурацию, найти, где и как вызывается типовой механизм определения рабочего места, и аккуратно встроить свою логику, возможно, через подписку на событие или перехват вызова в расширении.
Если вы не готовы вносить изменения в конфигурацию, можно решить проблему административно. Научите себя и своих пользователей правильно чистить кэш.
Не нужно удалять всю папку 1C в AppData!
Кэш конкретных информационных баз хранится в подпапках с длинными именами, похожими на GUID. Именно их и нужно удалять.
%AppData%\Roaming\1C\1cv8 и %AppData%\Local\1C\1cv8. Внутри них будут папки с именами вида c1e7cf34-e6e2-4a0b-8499-e6884f323565.1cv8u.pfl, 1cestart.cfg).Этот способ требует большей аккуратности, но он позволяет избежать смены ClientID без доработки системы.
Мы выяснили, что ClientID — это хрупкий идентификатор, который легко «слетает» при стандартных процедурах обслуживания. Опираться на него для постоянной привязки настроек рабочего места, особенно торгового оборудования, — плохая практика. Наиболее надежным решением является создание собственного механизма идентификации на основе стабильных системных параметров (имя компьютера и имя пользователя ОС) с помощью расширения конфигурации. Это раз и навсегда избавит вас от проблемы дублирования рабочих мест и необходимости их постоянной перенастройки.