В процессе сопровождения типовых конфигураций, таких как 1С:Бухгалтерия предприятия 3.0, часто возникает задача по ужесточению контроля вводимых данных. Одной из классических задач является проверка уникальности входящих номеров накладных и счетов-фактур от конкретного контрагента в пределах календарного года. Это необходимо для исключения дублирования первичных документов и ошибок при зачете НДС.
Поскольку конфигурация находится на поддержке, наиболее корректным методом реализации будет использование механизма расширений. В данной статье мы подробно разберем, какой архитектурный подход выбрать, как обеспечить производительность системы и защитить данные от потери.
Прежде чем приступать к разработке собственного механизма, проанализируем текущие возможности БП 3.0. В типовом решении уже реализован функционал проверки дублей, однако он часто работает в режиме предупреждения, а не жесткой блокировки. Для начала проверим настройки в разделе «Администрирование» — «Параметры учета» — «Заполнение реквизитов объектов». Если типовой логики недостаточно для ваших бизнес-требований (например, требуется блокировка записи при совпадении пары «Номер накладной + Номер СФ»), тогда переходим к созданию расширения.
В сообществе разработчиков 1С часто возникают споры: использовать ли прямой запрос к таблицам документов или создавать вспомогательный РегистрСведений. Рассмотрим обе ситуации подробно.
Вариант 1: Использование вспомогательного регистра сведений (РС)
Идея заключается в создании регистра, где измерениями будут выступать Контрагент, НомерВходящегоДокумента и Год, а ресурсом — ссылка на сам документ.
Плюсы:
Минусы:
Вариант 2: Использование прямого запроса к документам
Этот метод считается более современным и надежным для баз на SQL-платформах. Плюсы:
ПоступлениеТоваровУслуг поля Контрагент и Дата уже проиндексированы платформой. Запрос по ним отрабатывает мгновенно.Разберем по шагам, как реализовать проверку с помощью прямого запроса. Мы будем использовать обработчик события ПередЗаписью в расширении для документа ПоступлениеТоваровУслуг. Нам важно убедиться, что проверка не срабатывает при обмене данными.
Рассмотрим пример программного кода для реализации такой проверки:
&НаСервере
Процедура ПроверитьУникальностьВходящихНомеров(Источник, Отказ, РежимЗаписи, РежимПроведения)
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Поступление.Ссылка КАК Ссылка
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК Поступление
|ГДЕ
| Поступление.Контрагент = &Контрагент
| И Поступление.НомерВходящегоДокумента = &НомерВходящегоДокумента
| И Поступление.Дата МЕЖДУ &НачалоГода И &КонецГода
| И Поступление.Ссылка <> &ТекущаяСсылка";
Запрос.УстановитьПараметр("Контрагент", Источник.Контрагент);
Запрос.УстановитьПараметр("НомерВходящегоДокумента", Источник.НомерВходящегоДокумента);
Запрос.УстановитьПараметр("НачалоГода", НачалоГода(Источник.Дата));
Запрос.УстановитьПараметр("КонецГода", КонецГода(Источник.Дата));
Запрос.УстановитьПараметр("ТекущаяСсылка", Источник.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
"Документ с таким входящим номером уже существует для данного контрагента в текущем году! Ссылка: %1",
Выборка.Ссылка));
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Проанализируем ситуацию: два бухгалтера одновременно создают документы с одинаковыми номерами. Если мы просто выполним запрос, оба сеанса могут получить пустой результат, так как транзакции еще не зафиксированы. В итоге в базе появятся дубли.
Чтобы этого избежать, необходимо перед запросом установить управляемую блокировку. Мы блокируем комбинацию данных, которую проверяем. Выясним, как это сделать правильно:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Документ.ПоступлениеТоваровУслуг");
ЭлементБлокировки.УстановитьПараметр("Контрагент", Источник.Контрагент);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Установка исключительной блокировки по контрагенту гарантирует, что другой сеанс не сможет начать проверку уникальности для этого же контрагента, пока текущая транзакция не завершится.
Существует опасение, что при «отвале» расширения (например, из-за изменения версии совместимости платформы при обновлении) данные могут быть потеряны. Разберем этот момент:
Именно поэтому использование метода прямого запроса к документам является более безопасным: данные хранятся в основных таблицах конфигурации, которые не зависят от состояния расширения. Даже если расширение временно отключится, вы не потеряете историю входящих номеров, а лишь временно лишитесь механизма автоматической проверки.
Посмотрим на специфику БП 3.0: СчетФактураПолученный часто является отдельным подчиненным документом. Если ваша задача — контролировать уникальность и по СФ, проверку стоит вынести в общую процедуру (подписку на событие) или реализовать аналогичный код в расширении для документа счета-фактуры.
Важно помнить, что связка «Поступление — Счет-фактура» может создаваться не одновременно. Поэтому правильнее всего анализировать уникальность именно в контексте Контрагента и Периода, обращаясь к соответствующим метаданным.
Подводя итог нашему анализу, рекомендуем придерживаться следующего алгоритма:
ПередЗаписью или ОбработкаПроверкиЗаполнения.ДополнительныеРеквизиты для таких задач, так как поиск по ним значительно медленнее и сложнее в реализации контроля уникальности.Такой подход обеспечит стабильную работу системы, высокую производительность и легкость в поддержке при последующих обновлениях типовой конфигурации 1С.