В практике разработки на платформе 1С:Предприятие 8.3 часто возникает ситуация, когда одна и та же функция общего модуля используется множеством различных объектов (документами, справочниками, отчетами). Проблема наступает тогда, когда для одного конкретного документа, например, ЗаказПокупателя, требуется изменить алгоритм формирования результата, но при этом функция не получает в качестве параметров ссылку на сам документ или его тип.
Разберем, как решить эту задачу максимально элегантно, не прибегая к массовому переписыванию кода во всей конфигурации и сохраняя возможность легкого обновления системы.
Проанализируем структуру функции, представленной в вопросе. Она принимает множество параметров (номенклатура, характеристики, договора), но не имеет контекста вызова. Чтобы добавить этот контекст и не сломать работу других документов, мы можем добавить в конец списка аргументов новый параметр со значением по умолчанию Неопределено.
Рассмотрим, как будет выглядеть измененный заголовок функции в общем модуле:
Функция ПолучитьКолонкаАртикулКодЗначение(Колонки, НаДату = Неопределено, Номенклатура,
ЕдиницаИзмерения = Неопределено, Контрагент = Неопределено, Договор = Неопределено,
Характеристика = Неопределено, АртикулПоставщика="", ЗаменаДляОтчетов="",
ЭтоДокументЗаказ = Ложь) Экспорт
Благодаря тому, что мы указали ЭтоДокументЗаказ = Ложь, все старые вызовы этой функции в других документах продолжат работать в штатном режиме. Платформа просто проигнорирует отсутствие последнего аргумента при вызове и присвоит ему значение Ложь.
Теперь проанализируем, как внедрить новую логику внутри самой функции:
// В начале функции проверяем наш новый флаг
Если ЭтоДокументЗаказ Тогда
// Здесь размещаем ваш "переделанный" код специально для Заказа
Результат = "Специфические данные для заказа: " + Номенклатура.Артикул;
Возврат Результат;
КонецЕсли;
// Далее идет типовой код, который останется нетронутым для всех остальных случаев
Результат = "";
Если Колонки.Код Тогда
Результат = Результат + ?(Результат="", "", "/") + Номенклатура.Код;
КонецЕсли;
// ... (остальная часть типового кода)
При вызове из модуля документа ЗаказПокупателя (например, при формировании печатной формы), вам достаточно будет передать Истина в качестве последнего параметра:
Значение = ОбщийМодуль.ПолучитьКолонкаАртикулКодЗначение(Колонки, Дата, Ном, , , , , , , Истина);
Если вы работаете в конфигурации, поддерживающей механизм расширений, крайне рекомендуется не вносить изменения непосредственно в типовой общий модуль. Вместо этого создадим расширение и воспользуемся аннотацией &Вместо.
Это позволит нам перехватить вызов функции. Однако, так как параметры функции не меняются, нам все равно нужно как-то понять, что вызов пришел из документа Заказ. Рассмотрим пример реализации в расширении:
&Вместо("ПолучитьКолонкаАртикулКодЗначение")
Функция мо_ПолучитьКолонкаАртикулКодЗначение(Колонки, НаДату, Номенклатура, ЕдиницаИзмерения,
Контрагент, Договор, Характеристика, АртикулПоставщика, ЗаменаДляОтчетов)
// Если мы можем определить контекст через другие параметры (например, специфический договор)
Если ТипЗнч(Договор) = Тип("СправочникСсылка.ДоговорыКонтрагентов") Тогда
// Дополнительная проверка или специфическая логика
КонецЕсли;
// Вызываем основную логику, если наши условия не сработали
Возврат ПродолжитьВызов(Колонки, НаДату, Номенклатура, ЕдиницаИзмерения, Контрагент,
Договор, Характеристика, АртикулПоставщика, ЗаменаДляОтчетов);
КонецФункции
Если добавление нового параметра по каким-то причинам нежелательно, проанализируем входящие данные. В 1С для проверки типа объекта используется функция ТипЗнч(). Хотя в функцию не передается ссылка на сам документ, в нее передается Договор или Контрагент.
Выясним, можем ли мы идентифицировать "Заказ" по этим данным. Если в вашей бизнес-логике только заказы используют определенные виды договоров или специфические свойства контрагентов, можно выполнить проверку следующим образом:
Если ТипЗнч(Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
// Проверяем наличие специфического реквизита или свойства
// Это косвенный метод, используйте его с осторожностью
КонецЕсли;
Для версий платформы 8.3.9 и выше существует возможность программно проанализировать, из какого модуля была вызвана текущая функция. Рассмотрим этот метод как "крайнюю меру", если менять сигнатуру функции запрещено регламентом разработки.
Используем метод ПолучитьСтекВызова(). Он возвращает массив структур, описывающих цепочку вызовов. Проанализируем пример кода:
Стек = ПолучитьСтекВызова();
Для Каждого СтрокаСтека Из Стек Цикл
Если Найти(СтрокаСтека.Модуль, "Документ.ЗаказПокупателя") > 0 Тогда
// Мы понимаем, что вызов инициирован из модуля Заказа
// Применяем нашу логику
Прервать;
КонецЕсли;
КонецЦикла;
Важно: Этот метод существенно медленнее простой проверки булевского флага, поэтому его не стоит использовать в циклах с большим количеством итераций (например, при формировании строк отчета на тысячи позиций).
ТипЗнч() всегда сравнивайте результат с функцией Тип("ИмяМетаданных"), это гарантирует корректную работу при переименовании объектов в конфигураторе (если используется автоматический рефакторинг).ЭтоЗаказ = Истина (Способ 1) является самым надежным и производительным решением. Она понятна другим разработчикам и легко отлаживается.Выберем оптимальный путь: добавим необязательный параметр, установим для него значение по умолчанию и внедрим условие Если...Тогда в начало функции. Это обеспечит стабильность системы и решит поставленную задачу для документа Заказ.