Как в 1С:УТ 11 проверить, что дата счета-фактуры совпадает с датой реализации?

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

В работе с документами часто возникает необходимость в дополнительных проверках для избежания ошибок. Распространенная задача — контроль соответствия дат связанных документов. Например, важно, чтобы дата выписанного счета-фактуры совпадала с датой документа отгрузки (реализации). Давайте пошагово разберемся, как реализовать такую проверку в конфигурации "1С: Управление торговлей 11" при записи документа "Счет-фактура выданный".

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

Шаг 1: Первая попытка и анализ ошибок

Самая очевидная идея — добавить код в обработчик события ПередЗаписью в модуле объекта или формы. Начнем с простого условия, которое было предложено на форуме.

Первоначальный вариант кода:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
  Если НачалоДня(Дата) <> НачалоДня(ДокументОснование.Дата) Тогда
     Сообщить("Даты документов с/ф и документа-основания разные!");
     Отказ = Истина;
     Возврат;
  КонецЕсли;
КонецПроцедуры

При попытке использовать этот код можно столкнуться с ошибкой "Преобразование значения к типу Дата не может быть выполнено". Почему она возникает? Проблема в том, что счет-фактуру можно создать не на основании другого документа, а как самостоятельный документ. В этом случае реквизит ДокументОснование будет не заполнен, и попытка получить у него свойство .Дата приведет к ошибке.

Вывод: Перед обращением к свойствам реквизита-ссылки всегда нужно проверять, заполнена ли сама ссылка.

Шаг 2: Добавление проверки и работа с контекстом формы

Усовершенствуем код, добавив проверку на заполненность документа-основания с помощью функции ЗначениеЗаполнено(). Также учтем, что при написании кода в модуле управляемой формы, для доступа к реквизитам документа необходимо обращаться к основному реквизиту формы, который по умолчанию называется Объект.

Скорректированный код для модуля формы:


Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
  Если ЗначениеЗаполнено(Объект.ДокументОснование) Тогда
    Если НачалоДня(Объект.Дата) <> НачалоДня(Объект.ДокументОснование.Дата) Тогда
      Сообщить("Даты документов с/ф и документа-основания разные!");
      Отказ = Истина;
      Возврат;
    КонецЕсли;
  КонецЕсли;
КонецПроцедуры

Этот код уже гораздо лучше: он проверяет наличие основания и правильно обращается к реквизитам документа через Объект. Однако и он может вызывать ошибку, но уже другую: "Поле объекта не обнаружено (Дата)". Это происходит из-за особенностей клиент-серверного взаимодействия в управляемых формах. Событие ПередЗаписью на клиенте не всегда имеет полный доступ к данным связанных объектов (в нашем случае, к дате документа-основания). Для надежного получения данных из базы необходимо выполнить серверный вызов.

Шаг 3: Рабочее решение с использованием клиент-серверной архитектуры

Чтобы корректно получить дату документа-основания, нужно вынести логику проверки на сервер. Сделаем это, создав отдельную серверную процедуру и вызвав ее из клиентского обработчика ПередЗаписью.

  1. В модуле формы документа "СчетФактураВыданный" создаем серверную процедуру ПроверкаДатНаСервере.
  2. В клиентском обработчике события ПередЗаписью вызываем эту серверную процедуру.

Пример реализации:


&НаСервере
Процедура ПроверкаДатНаСервере(Отказ)
    
    Если ЗначениеЗаполнено(Объект.ДокументОснование) Тогда
        // На сервере мы гарантированно получаем доступ к данным объекта-основания
        ДокументОснованиеСсылка = Объект.ДокументОснование;
        
        Если НачалоДня(Объект.Дата) <> НачалоДня(ДокументОснованиеСсылка.Дата) Тогда
            Сообщить("Даты документов с/ф и документа-основания разные!");
            Отказ = Истина;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    // Вызываем серверную процедуру для выполнения проверки
    ПроверкаДатНаСервере(Отказ);
    
    Если Отказ Тогда
        Возврат; // Если проверка не пройдена, прерываем запись
    КонецЕсли;
КонецПроцедуры

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

Шаг 4: Оптимальное решение — использование "ПередЗаписьюНаСервере"

Хотя предыдущее решение работает, его можно сделать еще лучше и эффективнее. В управляемых формах существует специальное событие ПередЗаписьюНаСервере, которое идеально подходит для подобных проверок. Его использование избавляет от необходимости делать лишний вызов "клиент-сервер" и делает код более лаконичным и производительным.

В этом обработчике нам доступен параметр ТекущийОбъект, который представляет собой записываемый объект документа со всеми его данными.

Рекомендуемый код для модуля формы документа "СчетФактураВыданный":


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Проверяем, что документ-основание указан
    Если ЗначениеЗаполнено(ТекущийОбъект.ДокументОснование) Тогда
        
        // Сравниваем даты, приведенные к началу дня для корректности
        Если НачалоДня(ТекущийОбъект.Дата) <> НачалоДня(ТекущийОбъект.ДокументОснование.Дата) Тогда
            
            // Формируем информативное сообщение для пользователя
            ТекстСообщения = "Дата счета-фактуры (" + Формат(ТекущийОбъект.Дата, "ДФ=dd.MM.yyyy") + 
                            ") не совпадает с датой документа-основания (" + Формат(ТекущийОбъект.ДокументОснование.Дата, "ДФ=dd.MM.yyyy") + "). Запись отменена.";
            
            // Используем стандартный механизм вывода сообщений
            ОбщегоНазначения.СообщитьПользователю(ТекстСообщения);
            
            // Отменяем запись документа
            Отказ = Истина;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Почему этот вариант лучше:

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

← На главную