Каждый разработчик 1С рано или поздно сталкивается с задачей программного изменения или добавления контактной информации (адресов, телефонов, email) для контрагентов, физических лиц или партнеров. На первый взгляд задача кажется тривиальной: получить менеджер записи регистра сведений, заполнить измерения и ресурсы, после чего вызвать метод Записать(). Однако на практике код часто отрабатывает без ошибок, транзакция завершается успешно, но при проверке в базе данных новые сведения так и не появляются.
В этой статье мы подробно разберем причины этой проблемы. Мы изучим классические ошибки при работе с объектом РегистрСведенийМенеджерЗаписи, выясним, почему "тихое" незаполнение данных происходит без вызова исключений, и рассмотрим современную архитектуру хранения контактной информации в конфигурациях на базе БСП (Библиотеки стандартных подсистем), которая принципиально отличается от старых версий 1С.
Давайте по шагам разберем все возможные ситуации и найдем правильные решения.
---
Рассмотрим исходный код, который часто используют начинающие разработчики (именно такой пример привел автор темы на форуме):
МенеджерЗаписи = РегистрыСведений.КонтактнаяИнформация.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = Ссылка;
МенеджерЗаписи.Тип = Перечисления.ТипыКонтактнойИнформации.Другое;
МенеджерЗаписи.Вид = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента;
МенеджерЗаписи.Представление = Телефон;
МенеджерЗаписи.Записать();
Почему этот код может не работать или работать некорректно? Дело в специфике жизненного цикла менеджера записи. Когда мы работаем с менеджером записи независимого регистра сведений, платформа должна четко понимать: мы создаем абсолютно новую запись или пытаемся перезаписать (модифицировать) уже существующую.
Если в базе данных уже существует запись с аналогичным набором ключевых полей (измерений), простая попытка присвоить значения свойствам менеджера записи и вызвать метод Записать() без предварительного чтения может привести к конфликтам, блокировкам или молчаливому игнорированию операции платформой.
Правильный алгоритм работы с РегистрСведенийМенеджерЗаписи выглядит следующим образом:
Прочитать(). Этот метод попытается найти запись в базе данных по указанным измерениям. Если запись найдена, менеджер заполнит свои ресурсы актуальными значениями из БД и установит свойство Выбран() в значение Истина.Записать(Истина), где параметр Истина указывает на необходимость замещения существующей записи.Давайте посмотрим на пример правильного, отказоустойчивого кода:
МенеджерЗаписи = РегистрыСведений.КонтактнаяИнформация.СоздатьМенеджерЗаписи();
// Шаг 1. Устанавливаем ключевые поля (измерения)
МенеджерЗаписи.Объект = Ссылка;
МенеджерЗаписи.Тип = Перечисления.ТипыКонтактнойИнформации.Другое;
МенеджерЗаписи.Вид = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента;
// Шаг 2. Пытаемся прочитать существующую запись
МенеджерЗаписи.Прочитать();
// Шаг 3. Если запись отсутствует в БД, инициализируем ключевые поля заново
Если Не МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Объект = Ссылка;
МенеджерЗаписи.Тип = Перечисления.ТипыКонтактнойИнформации.Другое;
МенеджерЗаписи.Вид = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента;
КонецЕсли;
// Шаг 4. Заполняем ресурсы (не ключевые поля)
МенеджерЗаписи.Представление = Телефон;
// Шаг 5. Записываем запись с замещением
МенеджерЗаписи.Записать(Истина);
При использовании такой схемы мы гарантируем платформе корректность транзакции, и перезапись пройдет без непредвиденных коллизий.
---
Если вы исправили код, но данные все равно не сохраняются, и при этом платформа не выдает никаких ошибок на экран, велика вероятность "тихого" отказа внутри самой конфигурации. Проанализируем, где именно это может происходить:
КонтактнаяИнформация, откройте его модуль и проверьте обработчик события ПередЗаписью. Разработчики часто внедряют туда проверки заполнения полей. Если какое-то условие не выполняется, переменной Отказ присваивается значение Истина. Если при этом разработчик забыл вызвать процедуру Сообщить() или записать ошибку в журнал регистрации, запись просто прервется без предупреждений.ПередЗаписьюРегистраСведений.... Логика в них работает аналогично: если проверка структуры переданного телефона или адреса завершается неудачей, подписка устанавливает Отказ = Истина, блокируя сохранение.Рекомендация: Чтобы локализовать эту проблему, запустите сеанс под отладчиком, установите точку останова в модуле регистра в процедуре ПередЗаписью и пошагово пройдите весь процесс записи. Обратите внимание на значение переменной Отказ перед выходом из процедур.
---
Это самая частая и неочевидная причина проблем в современных конфигурациях 1С (таких как 1С:ERP, Комплексная автоматизация, Управление торговлей 11, Бухгалтерия предприятия 3.0, УНФ).
В старых конфигурациях (например, УПП 1.3 или Бухгалтерия 2.0) контактная информация действительно физически и первично хранилась в независимом регистре сведений КонтактнаяИнформация. Однако разработчики БСП полностью изменили эту архитектуру:
КонтактнаяИнформация) самого объекта-владельца (например, справочника Контрагенты, Партнеры, ФизическиеЛица или Пользователи).Кроме того, современные конфигурации требуют хранения декомпозированных контактных данных. Попытка записать просто строку в поле Представление ни к чему не приведет. БСП требует заполнения системных полей:
ЗначенияПолей — строка, содержащая сложную XML-структуру по специальной XDTO-схеме.Значение — строка во внутреннем формате JSON, содержащая разбитые на составляющие данные (код страны, код города, номер без форматирования и т.д.).Если эти поля пустые, система при первой же валидации посчитает запись некорректной и сотрет ее.
---
Чтобы не нарушать целостность данных и не писать сложные парсеры XML и JSON вручную, мы должны использовать готовые функции общего модуля УправлениеКонтактнойИнформацией.
Для быстрой и корректной программной записи контактной информации в конфигурациях на БСП предусмотрен метод ДобавитьКонтактнуюИнформацию(). Система сама определит тип данных, сформирует необходимые XML/JSON структуры, запишет их в табличную часть объекта и обновит регистры-кэши.
Рассмотрим пример добавления или обновления номера телефона контрагента:
// Определяем вид контактной информации, который хотим записать
ВидКИ = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента;
// СсылкаНаКонтрагента - это ссылка на элемент справочника Контрагенты
УправлениеКонтактнойИнформацией.ДобавитьКонтактнуюИнформацию(
СсылкаНаКонтрагента,
"89991112233", // Номер телефона в виде обычной строки
ВидКИ,
ТекущаяДата(),
Истина // Параметр Замещать: Истина перезапишет существующий телефон этого вида
);
Этот способ максимально безопасен, лаконичен и гарантирует, что данные не пропадут при обновлении конфигурации или перезаписи контрагента.
Если вы создаете нового контрагента программно (или модифицируете существующий объект, когда у вас на руках уже есть переменная типа СправочникОбъект.Контрагенты), использовать метод из Способа А не всегда удобно, так как объект еще может быть не записан в базу. В таком случае мы должны подготовить данные с помощью служебных методов БСП и записать их непосредственно в табличную часть объекта:
// Наш условный объект контрагента (может быть как новым, так и прочитанным из БД)
КонтрагентОбъект = СсылкаНаКонтрагента.ПолучитьОбъект();
// 1. Получаем вид и тип контактной информации
ВидКИ = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента;
ТипКИ = ВидКИ.Тип; // Перечисления.ТипыКонтактнойИнформации.Телефон
// 2. Преобразуем обычную строку с телефоном в XML-структуру через XDTO-пакет БСП
ОбъектXDTO = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(
"89991112233",
ТипКИ
);
ЗначенияПолей = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOВXML(ОбъектXDTO);
// 3. Записываем подготовленные структурированные данные в табличную часть нашего объекта
УправлениеКонтактнойИнформацией.ЗаписатьКонтактнуюИнформацию(
КонтрагентОбъект,
ЗначенияПолей,
ВидКИ,
ТипКИ
);
// 4. Записываем самого контрагента (при этом автоматически обновятся все регистры-кэши)
КонтрагентОбъект.Записать();
Используя этот подход, мы полностью имитируем интерактивный ввод пользователя через форму элемента, соблюдая все стандарты и правила платформы 1С:Предприятие 8.
---
Если у вас не записывается контактная информация, выполните следующие действия:
УправлениеКонтактнойИнформацией.Прочитать(), и только после этого меняете ресурсы и вызываете Записать(Истина).Отказ = Истина.