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