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