Как исправить ошибку «Процедура или функция не определена» при использовании аннотации &После в расширении 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке расширений для управляемых форм в среде «1С:Предприятие 8.3» программисты часто сталкиваются с ситуацией, когда добавленный в расширение метод не «видит» существующие процедуры и функции основной конфигурации. Типичный симптом этой проблемы — возникновение ошибки компиляции вида «Процедура или функция с указанным именем не определена» при попытке вызвать стандартный метод формы, а также игнорирование точек останова при отладке.

В этой статье мы подробно разберем, почему возникает данная ошибка на примере доработки Рабочего места кассира (РМК) в конфигурации «Управление торговлей», выясним правила взаимодействия контекстов основной конфигурации и расширения, а также рассмотрим лучшие практики бесконфликтной доработки типового кода.

Анализ проблемы: почему платформа выдает ошибку

Рассмотрим ситуацию: перед нами стоит задача сделать так, чтобы в форме РМК (форма документа ЧекККМ) сразу после успешной оплаты и пробития чека автоматически открывался новый, чистый чек. Для этого мы создаем расширение, заимствуем в него форму ФормаДокументаРМК и пытаемся переопределить обработчик завершения оплаты с помощью аннотации &После.

Исходный (ошибочный) код в модуле расширения выглядит следующим образом:


&После("ЗавершениеОплаты")
Процедура НовыйЧек_ЗавершениеОплаты(РезультатОплаты, ДополнительныеПараметры)
    
    Если Строка(Объект.Статус) = "Чек пробит" Тогда
        ЗагрузитьНовыйЧек();                                                     
    КонецЕсли;    
    
КонецПроцедуры

При попытке запуска конфигурации в режиме отладки система выдает ошибку: «Процедура или функция с указанным именем не определена (ЗагрузитьНовыйЧек)». При этом сама процедура ЗагрузитьНовыйЧек() гарантированно существует в модуле оригинальной формы основной конфигурации.

Проанализируем причину такого поведения платформы. В управляемом приложении модули форм разделены на контексты выполнения: клиентский (&НаКлиенте) и серверный (&НаСервере, &НаСервереБезКонтекста). Если при объявлении процедуры или функции в модуле управляемой формы явно не указать директиву компиляции, платформа по умолчанию пытается скомпилировать этот метод на сервере.

Процедура ЗагрузитьНовыйЧек() является клиентским методом формы (работает с интерфейсом на стороне пользователя). Пытаясь вызвать ее из серверного контекста нашего расширения, платформа закономерно сообщает, что на сервере такой метод не определен. Более того, из-за несовпадения контекстов выполнения платформа полностью игнорирует точки останова в данном расширяющем методе при отладке на клиенте.

Решение проблемы: правильное позиционирование директив

Для исправления ошибки нам необходимо явно указать платформе, в каком контексте должен компилироваться наш расширяющий метод. Для этого нужно добавить директиву компиляции &НаКлиенте.

При этом критически важен порядок написания директив и аннотаций. Согласно стандартам разработки фирмы «1С», директива компиляции всегда должна предшествовать аннотации расширения. Наш код должен выглядеть следующим образом:


&НаКлиенте
&После("ЗавершениеОплаты")
Процедура НовыйЧек_ЗавершениеОплаты(РезультатОплаты, ДополнительныеПараметры)
    
    Если Строка(Объект.Статус) = "Чек пробит" Тогда
        ЗагрузитьНовыйЧек();                                                     
    КонецЕсли;    
    
КонецПроцедуры

Давайте разберем по шагам, что изменилось после добавления директивы:

  1. Благодаря директиве &НаКлиенте метод расширения компилируется в том же клиентском контексте, что и оригинальная форма.
  2. Платформа успешно связывает контекст расширения с контекстом основной формы. Это дает нам прямой доступ ко всем экспортным и неэкспортным клиентским переменным, процедурам и функциям основной формы (включая метод ЗагрузитьНовыйЧек()) без необходимости копировать их код в расширение.
  3. Точки останова теперь корректно срабатывают, позволяя комфортно отлаживать логику работы формы РМК.

Использование инструментов автоматизации конфигуратора

Чтобы избежать подобных синтаксических ошибок, опечаток в именах процедур или несоответствия количества передаваемых параметров, настоятельно рекомендуется отказаться от написания заголовков методов расширения вручную. Вместо этого задействуем штатный механизм автоматической генерации шаблонов методов:

  1. Откройте основную конфигурацию и найдите нужный метод в модуле заимствованной формы (в нашем случае — процедуру ЗавершениеОплаты).
  2. Нажмите правой кнопкой мыши по названию метода и выберите в контекстном меню пункт «Добавить в расширение...».
  3. В открывшемся окне выберите ваше расширение и укажите тип переопределения (в данном случае — После).
  4. Платформа автоматически сгенерирует в модуле формы расширения правильную структуру заголовка с точным соблюдением всех параметров и корректным порядком директив (сначала директива компиляции, затем аннотация расширения).

Решение проблемы модификации кода «в середине» процедуры

Часто разработчики сталкиваются с ограничением аннотаций &Перед и &После, когда логику требуется изменить не до или после выполнения основного метода, а непосредственно внутри него (в середине длинного типового алгоритма). Долгое время для этого приходилось использовать радикальную аннотацию &Вместо, которая полностью замещала типовой метод, вынуждая копировать сотни строк кода в расширение. Это приводило к колоссальным сложностям при последующих обновлениях конфигурации.

Начиная с версии платформы 8.3.15, мы можем использовать современную аннотацию &ИзменениеИКонтроль. Этот механизм позволяет точечно изменять фрагменты кода с помощью инструкций препроцессора.

Рассмотрим пример использования аннотации &ИзменениеИКонтроль:


&ИзменениеИКонтроль("ЗавершениеОплаты")
Процедура Расш1_ЗавершениеОплаты(РезультатОплаты, ДополнительныеПараметры)
    // Оригинальный код начала процедуры...
    
    #Вставка
    // Наша кастомная логика, внедренная в середину метода
    Если РезультатОплаты Тогда
        ЗагрузитьНовыйЧек();
    КонецЕсли;
    #КонецВставки
    
    // Оригинальный код окончания процедуры...
КонецПроцедуры

Этот подход гарантирует, что при обновлении типовой конфигурации платформа сама предупредит вас, если контролируемый участок кода в оригинальном методе изменился вендором, существенно снижая риски появления скрытых ошибок.

Типовая альтернатива в современных конфигурациях РМК

Если вы работаете в актуальных версиях конфигураций «1С:Управление торговлей 11.5», «1С:Розница 3.0» или «1С:Управление нашей фирмой», перед написанием собственного кода обязательно проверьте встроенные функциональные возможности системы.

Разработчики фирмы «1С» предусмотрели штатную настройку для реализации требуемого поведения без программирования:

  1. Перейдите в раздел настроек РМК в вашей конфигурации.
  2. Найдите опцию «Оставлять последний чек на экране».
  3. Если эта опция отключена, система автоматически после успешного пробития и фискализации чека очистит экран кассира и инициализирует открытие новой продажи (что эквивалентно автоматическому вызову метода ЗагрузитьНовыйЧек()).

Использование встроенных настроек системы всегда является более приоритетным решением, так как оно не требует поддержки кастомного программного кода при переходе на новые релизы платформы и конфигурации.

Важные нюансы работы с торговым оборудованием

При ручном переопределении процедур оплаты (таких как ЗавершениеОплаты) крайне важно помнить об асинхронном характере взаимодействия программы с кассовым аппаратом (фискальным регистратором) и эквайринговым терминалом.

Код, добавленный через аннотацию &После, начинает выполняться сразу по завершении локального кода оригинальной процедуры на стороне «1С». Однако в этот момент само торговое оборудование еще может завершать печать чека или проводить транзакцию связи с банком. Если открыть новую форму чека слишком рано, транзакции могут наложиться друг на друга, вызвав зависание драйвера оборудования.

Для безопасной смены интерфейса рекомендуется привязывать открытие нового чека к событиям гарантированного изменения статуса документа в базе данных или использовать обработчики ожидания (ПодключитьОбработчикОжидания), чтобы дать оборудованию завершить все физические операции печати.

← На главную