Создание и изменение объектов
Создаём из кода новые элементы справочников и документы, заполняем реквизиты и сохраняем их в базу — с проверкой перед записью и проведением документа.
Запись (
.Записать()) — это момент, когда объект из памяти сохраняется в базу данных. До вызова.Записать()все ваши изменения существуют только в переменной и пропадут, если не сохранить.
В прошлом уроке мы читали данные. Теперь научимся их создавать и менять. Это ежедневная работа 1С-разработчика: обработка загружает номенклатуру из внешнего файла, при регистрации сделки автоматически создаётся документ, по кнопке заводится новый контрагент. Во всех случаях схема одна: получить объект (новый или существующий), заполнить его реквизиты и вызвать .Записать(). Дьявол — в деталях: что заполнять, как проверять и когда документ нужно ещё и провести.
Зачем это нужно на практике
Ручной ввод данных — это долго и с ошибками. Код позволяет создавать сотни записей за секунды: загрузить прайс поставщика, сформировать документы по расписанию, синхронизировать данные с сайтом. Но у автоматической записи есть цена: если заполнить объект неверно или пропустить обязательный реквизит, в базе окажется «мусор», который потом придётся вычищать вручную. Поэтому важно не просто «записать», а записать корректно.
Создаём элемент справочника
Новый элемент справочника рождается методом СоздатьЭлемент() у менеджера справочника. Он возвращает пустой объект, у которого надо заполнить реквизиты и вызвать .Записать():
// Создаём новый элемент справочника Контрагенты
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
// Заполняем реквизиты
НовыйКонтрагент.Наименование = "ООО Ромашка";
НовыйКонтрагент.ИНН = "7701234567";
НовыйКонтрагент.КПП = "770101001";
// Сохраняем в базу
НовыйКонтрагент.Записать();
Сообщить("Создан контрагент, ссылка: " + НовыйКонтрагент.Ссылка);
Пока .Записать() не вызван, контрагента в базе нет — есть только заполненный объект в переменной. Кстати, Код элемента обычно можно не заполнять: если у справочника настроена автонумерация, платформа присвоит следующий код сама при записи. А чтобы создать не элемент, а группу (папку), есть парный метод СоздатьГруппу().
Изменение существующего элемента отличается лишь тем, как мы получаем объект — не создаём новый, а берём объект уже имеющегося элемента через .ПолучитьОбъект() из прошлого урока:
// Меняем ИНН у существующего контрагента
КонтрагентСсылка = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");
Если НЕ КонтрагентСсылка.Пустая() Тогда
КонтрагентОбъект = КонтрагентСсылка.ПолучитьОбъект();
КонтрагентОбъект.ИНН = "7707777777";
КонтрагентОбъект.Записать();
КонецЕсли;
Проверяем перед записью: ЗначениеЗаполнено()
Прежде чем сохранять объект, стоит убедиться, что ключевые реквизиты действительно заполнены. Для этого есть глобальная функция ЗначениеЗаполнено() — она возвращает Ложь для «пустых» значений: пустой строки, нуля, пустой даты, пустой ссылки, Неопределено. Это удобнее, чем сравнивать с "" вручную, потому что работает для любого типа:
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.Наименование = "ООО Василёк";
НовыйКонтрагент.ИНН = ""; // забыли заполнить
// Проверяем ДО записи
Если НЕ ЗначениеЗаполнено(НовыйКонтрагент.Наименование) Тогда
Сообщить("Не заполнено наименование — запись отменена");
ИначеЕсли НЕ ЗначениеЗаполнено(НовыйКонтрагент.ИНН) Тогда
Сообщить("Не заполнён ИНН — запись отменена");
Иначе
НовыйКонтрагент.Записать();
Сообщить("Контрагент записан");
КонецЕсли;
Результат:
Не заполнён ИНН — запись отменена
Проверять реквизиты лучше в самом объекте — в его модуле есть событие
ОбработкаПроверкиЗаполнения, которое платформа вызывает автоматически при записи. Но пока вы пишете обработки, ручная проверка черезЗначениеЗаполнено()— простой и надёжный приём.
Создаём документ и проводим его
Документы создаются похоже — методом СоздатьДокумент(), но у них есть своя специфика: дата, табличные части (строки товаров) и понятие проведения. Проведение — это когда документ не просто сохраняется, а формирует движения в регистрах (например, списывает товар со склада). Разберём на приходной накладной:
// Создаём новый документ ПоступлениеТоваров
Поступление = Документы.ПоступлениеТоваров.СоздатьДокумент();
Поступление.Дата = ТекущаяДата();
Поступление.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");
// Добавляем строку в табличную часть "Товары"
НоваяСтрока = Поступление.Товары.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000000001");
НоваяСтрока.Количество = 10;
НоваяСтрока.Цена = 250;
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;
// Записываем С ПРОВЕДЕНИЕМ — документ сформирует движения в регистрах
Поступление.Записать(РежимЗаписиДокумента.Проведение);
Ключевая строка — последняя. Метод .Записать() у документа принимает режим записи. Если передать РежимЗаписиДокумента.Проведение, документ будет проведён (сформирует движения). Если вызвать .Записать() без параметра — документ просто сохранится как черновик, но склад не изменится. Есть и обратная операция — РежимЗаписиДокумента.ОтменаПроведения, чтобы отменить проведение.
Как это работает
Когда вы вызываете .Записать(), платформа делает несколько вещей по порядку. Сначала срабатывают события модуля объекта: ОбработкаПроверкиЗаполнения (для проверки обязательных полей), затем ПередЗаписью, потом данные пишутся в базу, и наконец ПриЗаписи. Для документа с проведением после записи вызывается ещё и ОбработкаПроведения — именно там формируются движения по регистрам. Всё это платформа заворачивает в неявную транзакцию: если на любом шаге возникнет ошибка, изменения откатятся целиком, и в базе не останется полузаписанного документа. Про транзакции подробно — в следующем уроке.
Важная деталь: после успешной записи нового объекта его свойство Ссылка становится «настоящей» — теперь на этот элемент можно ссылаться из других объектов. До первой записи ссылка у нового объекта ещё не привязана к реальной записи в базе.
Частые ошибки
- Забывают
.Записать(). Заполнили объект, а сохранить не вызвали — и удивляются, что в базе ничего не появилось. Изменения живут в памяти до записи. - Пишут документ без проведения, ожидая движений. Простой
.Записать()сохраняет документ, но не формирует движения. Нужны движения — передавайтеРежимЗаписиДокумента.Проведение. - Не проверяют заполненность и получают «мусор» в базе. Автоматическая запись без
ЗначениеЗаполнено()легко заносит записи с пустыми обязательными реквизитами. - Сравнивают строку с
""вместоЗначениеЗаполнено(). Для ссылок, чисел и дат сравнение с пустой строкой не работает;ЗначениеЗаполнено()корректно проверяет любой тип. - Забывают заполнить
Датадокумента. У нового документа дата пустая; без неё документ либо не проведётся корректно, либо встанет не в тот период.
Итоги
- Новый элемент —
СоздатьЭлемент(), новый документ —СоздатьДокумент(); изменение существующего — через.ПолучитьОбъект(). - Изменения в объекте сохраняются в базу только вызовом
.Записать(). - Перед записью проверяйте ключевые реквизиты функцией
ЗначениеЗаполнено()— она понимает «пустоту» для любого типа. - Строки документа добавляются в табличную часть методом
.Добавить(). - Чтобы документ сформировал движения, записывайте его с
РежимЗаписиДокумента.Проведение; без режима это просто сохранение.