При работе с документами в 1С:Предприятии, особенно в бухгалтерских, таких как "Поступление товаров и услуг", пользователи часто сталкиваются с необходимостью оперативного изменения артикула номенклатуры прямо из табличной части документа. Однако по умолчанию поле "Артикул" обычно не является редактируемым. В этой статье мы подробно разберем, почему возникает такая ситуация и какие существуют эффективные решения для реализации этой функциональности, учитывая особенности управляемых форм 1С.
Давайте сначала выясним причину, по которой поле "Артикул" в табличной части документа не редактируется, даже если мы устанавливаем для него флаг "Доступность" и меняем тип на "Поле ввода" в свойствах элемента формы.
Дело в том, что поле "Артикул" в большинстве типовых конфигураций (например, в документе "Поступление (акт, накладная, УПД)" в 1С:Бухгалтерии или аналогичных в других конфигурациях) не является прямым реквизитом табличной части документа. Вместо этого оно представляет собой динамическое отображение значения реквизита Артикул из справочника Номенклатура, который связан с текущей строкой табличной части. Путь к данным для такого поля обычно выглядит как Объект.Товары.Номенклатура.Артикул.
Это означает, что мы видим значение артикула, хранящееся в карточке номенклатуры, а не в самом документе. Изменение свойств элемента формы влияет только на его визуальное представление, но не меняет логику работы с данными, лежащими в основе. Для изменения артикула нам необходимо внести изменения непосредственно в объект справочника Номенклатура.
Рассмотрим несколько подходов к решению этой задачи.
Это один из наиболее гибких и рекомендуемых способов, позволяющий сделать поле артикула полноценно редактируемым прямо в табличной части документа. Он требует внесения изменений в структуру метаданных, что лучше всего делать с использованием расширений конфигурации.
Изменение конфигурации (использование расширения):
Прежде всего, мы должны добавить новый реквизит в табличную часть документа, чтобы у нас было место для хранения редактируемого артикула. Если мы работаем с типовой конфигурацией, то крайне рекомендуется использовать расширения, чтобы сохранить конфигурацию на поддержке и упростить будущие обновления.
Откроем конфигуратор и создадим новое расширение или откроем существующее.
Заимствуем в расширение необходимый документ (например, "Поступление (акты, накладные, УПД)") и его табличную часть (например, "Товары"). Для этого в дереве объектов конфигурации найдем нужный документ, вызовем контекстное меню и выберем "Добавить в расширение". Аналогично поступим с его табличной частью.
После заимствования в расширении появится копия структуры документа. Развернем табличную часть "Товары" в расширении и добавим новый реквизит. Назовем его, например, АртикулДок. Тип данных установим как Строка с соответствующей длиной (например, 20 или 50 символов), чтобы он мог вмещать различные форматы артикулов.
Добавление поля на форму документа:
Теперь, когда у нас есть новый реквизит в табличной части, мы можем отобразить его на форме документа и сделать редактируемым.
Заимствуем форму документа в наше расширение. В форме документа найдем табличное поле, отображающее табличную часть "Товары".
В свойствах табличного поля перейдем на вкладку "Элементы". Мы можем либо добавить новую колонку, соответствующую нашему реквизиту АртикулДок, либо заменить существующую колонку "Артикул" (которая отображает Номенклатура.Артикул) на нашу новую. В большинстве случаев удобнее добавить новую колонку, чтобы видеть и изначальный артикул, и возможность редактирования.
Перетащим реквизит АртикулДок из списка реквизитов формы в список колонок табличной части. Установим для него свойства "Вид" как "Поле ввода" и убедимся, что флаг "Доступность" установлен.
Заполнение нового реквизита при выборе номенклатуры:
Чтобы наш новый реквизит АртикулДок автоматически заполнялся при выборе номенклатуры, нам потребуется написать обработчик события для поля "Номенклатура" в табличной части.
В форме документа найдем элемент "Номенклатура" в табличном поле "Товары".
В его свойствах на вкладке "События" создадим обработчик события ПриИзменении. Этот обработчик будет выполняться на сервере (&НаСервере).
В этом обработчике мы будем брать артикул из выбранной номенклатуры и присваивать его нашему новому реквизиту АртикулДок.
Пример кода для обработчика ПриИзменении:
&НаСервере
Процедура ТоварыНоменклатураПриИзмененииНаСервере(Элемент)
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
Если Не ТекущаяСтрока.Номенклатура.Пустая() Тогда
// Получаем артикул из выбранной номенклатуры
// Если артикул также может быть в разных регистрах, можно добавить приведение к верхнему/нижнему
ТекущаяСтрока.АртикулДок = ТекущаяСтрока.Номенклатура.Артикул;
Иначе
ТекущаяСтрока.АртикулДок = ""; // Очищаем, если номенклатура не выбрана
КонецЕсли;
КонецПроцедуры
Запись измененного артикула в карточку номенклатуры:
Самый важный шаг – это сохранение изменений из нашего АртикулДок обратно в справочник Номенклатура. Это необходимо делать при записи документа.
В форме документа создадим или модифицируем обработчик события ПередЗаписьюНаСервере для объекта документа.
В этом обработчике мы будем перебирать все строки табличной части "Товары", сравнивать наш АртикулДок с текущим артикулом номенклатуры и, если они отличаются, обновлять артикул в справочнике.
Пример кода для обработчика ПередЗаписьюНаСервере:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ПараметрыЗаписи)
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
// Проверяем, что номенклатура выбрана и наш артикулДок не пустой
Если Не СтрокаТЧ.Номенклатура.Пустая() И Не ПустаяСтрока(СтрокаТЧ.АртикулДок) Тогда
// Проверяем, отличается ли артикул в документе от артикула в справочнике
Если СтрокаТЧ.АртикулДок <> СтрокаТЧ.Номенклатура.Артикул Тогда
Попытка
// Получаем объект номенклатуры для изменения
НоменклатураОбъект = СтрокаТЧ.Номенклатура.ПолучитьОбъект();
// Дополнительная проверка на случай, если артикул был изменен другим пользователем
// или фоновым заданием после открытия документа.
// Если мы хотим, чтобы изменение из документа было приоритетным, эту проверку можно убрать.
Если НоменклатураОбъект.Артикул <> СтрокаТЧ.АртикулДок Тогда
НоменклатураОбъект.Артикул = СтрокаТЧ.АртикулДок;
НоменклатураОбъект.Записать();
КонецЕсли;
Исключение
// Информируем пользователя об ошибке, но не отменяем запись всего документа,
// если это не критично для бизнес-процесса.
Сообщить("Не удалось обновить артикул для номенклатуры " + СтрокаТЧ.Номенклатура + ". Причина: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот подход позволяет пользователю напрямую редактировать артикул в табличной части, и изменения будут сохраняться в карточке номенклатуры.
Если мы не хотим добавлять новый реквизит в табличную часть или нам нужно более контролируемое изменение артикула, мы можем использовать механизм диалога ввода строки. Пользователь будет инициировать изменение через команду или двойной клик, и ему будет предложено ввести новый артикул.
Обработчик события (двойной клик или команда контекстного меню):
Мы можем реализовать эту функциональность двумя основными способами:
По двойному клику на колонке "Артикул": Для этого можно использовать обработчик ОбработкаВыбора для колонки, или ПриАктивизацииЯчейки, а затем проверять, какая именно колонка была активизирована.
Через команду в контекстном меню табличной части: Этот способ является более явным и "по фэншую", как было предложено в обсуждении. Мы добавляем новую команду на форму документа, помещаем ее в контекстное меню табличной части и привязываем к ней действие.
В расширении заимствуем форму документа.
На форме создадим новую команду (например, ИзменитьАртикул).
Перетащим эту команду в контекстное меню табличного поля "Товары" или в подменю "Заполнить" (если оно есть).
Установим для команды свойство "Действие" (например, ТоварыИзменитьАртикул).
Использование ПоказатьВводСтроки для управляемых форм:
Как было подмечено в обсуждении, в управляемых формах (УФ) напрямую использовать модальные функции, такие как ВвестиСтроку(), не рекомендуется, и система будет выдавать ошибку о неиспользовании модальности. Для этого в УФ следует применять немодальные аналоги. Для ввода строки таким аналогом является функция ПоказатьВводСтроки().
Эта функция работает асинхронно: она открывает окно ввода, а после его закрытия вызывает процедуру-оповещение, которой передается результат ввода. Это позволяет избежать блокировки интерфейса пользователя.
Пример кода для команды контекстного меню "Изменить артикул" с использованием ПоказатьВводСтроки:
&НаКлиенте
Процедура ТоварыИзменитьАртикул(Команда)
// Получаем данные текущей строки табличной части
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Или ТекущиеДанные.Номенклатура.Пустая() Тогда
Сообщить("Выберите строку с номенклатурой для изменения артикула.");
Возврат;
КонецЕсли;
// Создаем описание оповещения, которое будет вызвано после закрытия окна ввода строки
// Передаем текущую ссылку на номенклатуру в ДополнительныеПараметры,
// чтобы потом использовать ее на сервере.
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВводаАртикула", ЭтотОбъект, ТекущиеДанные.Номенклатура);
// Вызываем немодальное окно для ввода строки
// Параметры: ОписаниеОповещения, ИсходнаяСтрока (текущий артикул), Подсказка, МаксимальнаяДлина, Многострочность
ПоказатьВводСтроки(ОписаниеОповещения, ТекущиеДанные.Номенклатура.Артикул, "Введите новый артикул для " + ТекущиеДанные.Номенклатура.Наименование, 100, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВводаАртикула(НовыйАртикул, ДополнительныеПараметры) Экспорт
// Проверяем, не отменил ли пользователь ввод (НовыйАртикул будет Неопределено)
Если НовыйАртикул = Неопределено Тогда
Возврат;
КонецЕсли;
НоменклатураСсылка = ДополнительныеПараметры; // Из ДополнительныхПараметров получаем ссылку на номенклатуру
// Сравниваем новый артикул с текущим, чтобы избежать лишней записи
Если НовыйАртикул <> НоменклатураСсылка.Артикул Тогда
// Вызываем серверную процедуру для фактического изменения артикула в справочнике
ИзменитьАртикулНаСервере(НоменклатураСсылка, НовыйАртикул);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ИзменитьАртикулНаСервере(НоменклатураСсылка, НовыйАртикул)
Попытка
// Получаем объект номенклатуры по ссылке
НоменклатураОбъект = НоменклатураСсылка.ПолучитьОбъект();
// Повторно проверяем артикул, чтобы учесть возможные изменения другими пользователями
Если НоменклатураОбъект.Артикул <> НовыйАртикул Тогда
НоменклатураОбъект.Артикул = НовыйАртикул;
НоменклатураОбъект.Записать();
// Можно уведомить пользователя об успешном изменении
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Артикул номенклатуры " + НоменклатураСсылка + " успешно обновлен.");
КонецЕсли;
Исключение
// Сообщаем об ошибке, если запись не удалась
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось обновить артикул для номенклатуры " + НоменклатураСсылка + ". Причина: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
КонецПроцедуры
Обратите внимание на использование директивы &НаСервереБезКонтекста для серверной процедуры. Это позволяет вызывать ее без передачи контекста формы, что делает код более универсальным и производительным.
В некоторых случаях, особенно когда требуется массовое изменение артикулов, или если мы хотим предоставить более сложный интерфейс для их согласования, можно рассмотреть использование внешних обработок или создание специализированных кнопок на форме документа.
Внешняя обработка:
Мы можем разработать отдельную внешнюю обработку, которая будет открываться из документа или как самостоятельный инструмент. Эта обработка может получать данные из текущего документа (например, список номенклатуры и ее артикулов), предоставлять удобный интерфейс для их изменения (возможно, с подбором из других систем) и затем записывать изменения обратно в справочник Номенклатура.
Такой подход особенно полезен, когда:
Нужно изменить много артикулов сразу.
Требуется сложная логика проверки и согласования артикулов (например, уникальность, соответствие внешним справочникам).
Мы не хотим изменять типовую конфигурацию даже через расширения, а хотим использовать внешний подключаемый объект.
Специализированная кнопка на форме:
Вместо контекстного меню, можно добавить отдельную кнопку на форму документа, например, "Установить артикул текущей номенклатуре". При нажатии на эту кнопку будет вызываться та же логика с ПоказатьВводСтроки, что и в предыдущем решении. Это может быть удобнее для пользователей, которые предпочитают кнопки вместо контекстных меню.
При реализации функциональности редактирования артикулов следует учитывать несколько важных моментов:
Использование расширений конфигурации: Как уже упоминалось, всегда старайтесь использовать расширения для доработки типовых конфигураций. Это значительно упрощает процесс обновления и снижает риски.
Контроль уникальности артикулов: Если ваш бизнес-процесс требует уникальности артикулов, обязательно реализуйте проверку на уникальность при их изменении. Это можно сделать в серверной процедуре перед записью объекта Номенклатура, выполняя запрос к справочнику.
// Пример проверки уникальности артикула (добавлять в ИзменитьАртикулНаСервере перед записью)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул = &НовыйАртикул
| И Номенклатура.Ссылка <> &ТекущаяНоменклатура";
Запрос.УстановитьПараметр("НовыйАртикул", НовыйАртикул);
Запрос.УстановитьПараметр("ТекущаяНоменклатура", НоменклатураОбъект.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
// Артикул уже существует у другой номенклатуры
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Артикул '" + НовыйАртикул + "' уже используется номенклатурой: " + Выборка.Ссылка + ". Изменение отменено.", СтатусСообщения.Важное);
Возврат; // Отменяем запись
КонецЕсли;
Многопользовательская работа: Помните, что в многопользовательской среде несколько операторов могут одновременно работать с одной и той же номенклатурой. Ваши решения должны учитывать возможные конфликты. Использование объектов ПолучитьОбъект() и последующая запись автоматически обрабатывают некоторые базовые блокировки, но для сложных сценариев может потребоваться дополнительная логика (например, предупреждение пользователя о том, что артикул был изменен другим оператором).
Обновление отображения на форме: После изменения артикула в справочнике, убедитесь, что отображение в документе или на форме корректно обновляется. Если вы используете подход с новым реквизитом АртикулДок, то изменения видны сразу. Если используется контекстное меню и ПоказатьВводСтроки, возможно потребуется обновить текущую строку табличной части или форму документа, чтобы увидеть актуальный артикул.
Информирование пользователя: Всегда предоставляйте пользователю обратную связь об успешности операции или возникших ошибках, используя функцию Сообщить() или ОбщегоНазначенияКлиентСервер.СообщитьПользователю().
Мы рассмотрели различные подходы к решению задачи редактирования поля "Артикул" в табличной части документа 1С. Выбор конкретного метода зависит от требований к гибкости, сложности конфигурации и предпочтений в пользовательском интерфейсе. Наиболее универсальным и рекомендуемым является добавление нового реквизита в табличную часть с помощью расширения, так как это дает полную свободу в управлении полем. Однако, для быстрых и точечных изменений, подход с контекстным меню и ПоказатьВводСтроки также является эффективным и удобным решением.