Как реализовать выбор суммы при создании ПКО на основании Реализации в УТ 11.4?

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

При разработке расширений для современных конфигураций 1С, таких как Управление торговлей 11.4, программисты часто сталкиваются с задачей изменения логики создания документов "на основании". Типичный сценарий: при создании Приходного кассового ордера (ПКО) на основании Реализации товаров и услуг необходимо предоставить пользователю выбор — заполнить сумму по документу отгрузки или по текущему остатку взаиморасчетов (например, если у клиента есть переплата). Рассмотрим подробно, как решить эту задачу, обходя архитектурные ограничения платформы и БСП.

Проблема: Клиент-серверное взаимодействие

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

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

Вариант 1: Перехват команды в форме источника (Реализации)

Это наиболее корректный с точки зрения архитектуры БСП способ. Мы изменим поведение кнопки "Приходный кассовый ордер" в меню "Создать на основании" документа-источника.

Шаг 1. Программное изменение команды в расширении формы.

В расширении формы документа РеализацияТоваровУслуг создадим обработчик события ПриСозданииНаСервере. Нам нужно найти команду ПКО в коллекции подключаемых команд и заменить её обработчик.


&НаСервере
&Вместо("ПриСозданииНаСервере")
Процедура Инт_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    ПродолжитьВызов(Отказ, СтандартнаяОбработка);
    
    // Поиск команды создания ПКО
    Для Каждого Команда Из ЭтаФорма.Команды Цикл
        Если СтрНайти(Команда.Имя, "ПриходныйКассовыйОрдер") > 0 Тогда
            // Перенаправляем на свой клиентский метод
            Команда.Действие = "Инт_ВыполнитьСозданиеПКО";
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Шаг 2. Клиентская логика и расчет суммы.

Теперь опишем клиентский метод Инт_ВыполнитьСозданиеПКО. Перед открытием формы нового документа мы выполним серверный вызов для получения суммы остатка.


&НаКлиенте
Процедура Инт_ВыполнитьСозданиеПКО(Команда)
    ДанныеВзаиморасчетов = Инт_ПолучитьДанныеДляЗаполнения(Объект.Ссылка);
    
    СуммаДокумента = Объект.СуммаДокумента;
    СуммаДолга = ДанныеВзаиморасчетов.ОстатокДолга;
    
    Если СуммаДолга <> СуммаДокумента И СуммаДолга > 0 Тогда
        ТекстВопроса = СтрШаблон("Создать ПКО на сумму реализации (%1) или на сумму долга (%2)?", 
            СуммаДокумента, СуммаДолга);
        
        Оповещение = Новый ОписаниеОповещения("Инт_ПослеВопроса", ЭтотОбъект, СуммаДолга);
        ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    Иначе
        // Если суммы равны, создаем стандартно
        Инт_ОткрытьФормуПКО(СуммаДокумента);
    КонецЕсли;
КонецПроцедуры

Вариант 2: Использование параметров заполнения

Продолжим логику первого варианта. Когда пользователь выбирает ответ, нам нужно передать это решение в новый документ ПКО. Для этого используются ПараметрыЗначенияЗаполнения.

Выясним, как передать данные в процедуру ОбработкаЗаполнения модуля объекта ПКО. В клиентском методе после ответа пользователя мы открываем форму:


&НаКлиенте
Процедура Инт_ПослеВопроса(Результат, ДополнительныеПараметры) Экспорт
    СуммаДолга = ДополнительныеПараметры;
    ВыбраннаяСумма = ?(Результат = КодВозвратаДиалога.Да, Объект.СуммаДокумента, СуммаДолга);
    
    Инт_ОткрытьФормуПКО(ВыбраннаяСумма);
КонецПроцедуры

&НаКлиенте
Процедура Инт_ОткрытьФормуПКО(Сумма)
    ПараметрыЗаполнения = Новый Структура;
    ПараметрыЗаполнения.Вставить("Основание", Объект.Ссылка);
    ПараметрыЗаполнения.Вставить("Инт_ВыбраннаяСумма", Сумма); // Наш кастомный параметр
    
    ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
    ОткрытьФорму("Документ.ПриходныйКассовыйОрдер.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры

Теперь в модуле объекта ПКО (также через расширение) перехватим процедуру заполнения:


&НаСервере
&Вместо("ЗаполнитьПоРеализацииТоваров")
Процедура Инт_ЗаполнитьПоРеализацииТоваров(ДанныеЗаполнения)
    // Вызываем стандартное заполнение
    ПродолжитьВызов(ДанныеЗаполнения);
    
    // Если передан наш параметр, перезаписываем сумму
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") 
        И ДанныеЗаполнения.Свойство("Инт_ВыбраннаяСумма") Тогда
        ЭтотОбъект.СуммаДокумента = ДанныеЗаполнения.Инт_ВыбраннаяСумма;
        // Не забудьте пересчитать валютную сумму или налоги, если это необходимо
    КонецЕсли;
КонецПроцедуры

Как программно узнать сумму взаиморасчетов

Рассмотрим подробнее серверную функцию получения остатка долга. В УТ 11.4 данные о расчетах хранятся в регистре накопления РасчетыСКлиентами. Нам важно учитывать ОбъектРасчетов, так как в системе может быть включена детализация по заказам или накладным.


&НаСервере
Функция Инт_ПолучитьДанныеДляЗаполнения(СсылкаНаРеализацию)
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	СУММА(РасчетыСКлиентамиОстатки.СуммаОстаток) КАК Остаток
    |ИЗ
    |	РегистрНакопления.РасчетыСКлиентами.Остатки(
    |			,
    |			АналитикаУчетаПоПартнерам = &Аналитика
    |				И ОбъектРасчетов = &ОбъектРасчетов) КАК РасчетыСКлиентамиОстатки";
    
    // Аналитику можно получить из данных документа или через функцию модуля менеджера
    Запрос.УстановитьПараметр("Аналитика", СсылкаНаРеализацию.АналитикаУчетаПоПартнерам);
    Запрос.УстановитьПараметр("ОбъектРасчетов", СсылкаНаРеализацию);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Результат = Новый Структура("ОстатокДолга", 0);
    Если Выборка.Следующий() Тогда
        Результат.ОстатокДолга = Выборка.Остаток;
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Вариант 3: Проверка при открытии формы ПКО

Если вмешательство в форму Реализации кажется слишком сложным из-за динамических команд БСП, проанализируем альтернативный путь. Можно оставить создание ПКО стандартным, но добавить логику в форму самого ПКО.

  1. В расширении формы документа Приходный кассовый ордер добавим обработчик ПриОткрытии.
  2. Если документ новый и заполнен на основании Реализации, выполняем расчет долга на сервере.
  3. Если сумма документа отличается от суммы долга, выдаем ПоказатьВопрос.
  4. В случае согласия пользователя меняем реквизит Объект.СуммаДокумента прямо в форме.

Преимущество этого метода: не нужно искать, где в БСП "спрятана" кнопка создания на основании. Логика сосредоточена в одном месте — в форме приемника.

Важные рекомендации по БСП

Работая с УТ 11.4, помните о следующих моментах:

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

← На главную