При работе с программным созданием и перезаписью документов в 1С, особенно таких специфичных, как "Операция (бухгалтерский и налоговый учет)", часто возникают сложности. Одна из наиболее распространенных проблем – это некорректное отображение данных в отчетах (например, в оборотно-сальдовой ведомости) после программной перезаписи документа, в то время как при первичном создании или интерактивном сохранении все работает правильно. Давайте разберемся, почему возникает такая "чертовщина" и как ее избежать, используя правильные подходы к работе с движениями документа.
Суть проблемы: Когда мы программно "пересоздаем" документ "Операция (бухгалтерский и налоговый учет)", нам необходимо не просто создать новый набор проводок, но и убедиться, что старые проводки по этому документу были корректно удалены. Без этого новые записи будут наслаиваться на старые, приводя к задвоению данных и, как следствие, к неверным цифрам в отчетах.
Прежде чем перейти к решениям, давайте уясним одну ключевую особенность документа "Операция (бухгалтерский и налоговый учет)" (часто сокращенно "ОперацияБух"):
РежимЗаписиДокумента.Проведение или пытаться установить свойство ДокументОбъект.Проведен = Истина. Попытки сделать это могут привести к ошибкам или игнорированию действия.Для корректной записи движений нам потребуется использовать РежимЗаписиДокумента.Запись.
Этот способ является наиболее предпочтительным и типовым для большинства документов в 1С, которые являются регистраторами для определенных регистров. Платформа 1С берет на себя управление связью между документом и его движениями, что упрощает код и снижает вероятность ошибок.
ДокументОбъект.Движения.Хозрасчетный.Записывать коллекции движений в Истина. Это критически важный шаг при перезаписи.
// Предположим, что ИзменитьСтарый - это булево,
// СтарыйДокумент - это ссылка на существующий документ
// или Документы.Операция.СоздатьДокумент() для нового.
Перем ДокументОбъект;
Если ИзменитьСтарый Тогда
// Получаем объект существующего документа
ДокументОбъект = Объект.СтарыйДокумент.ПолучитьОбъект();
Иначе
// Создаем новый документ
ДокументОбъект = Документы.ОперацияБух.СоздатьДокумент();
ДокументОбъект.Дата = ТекущаяДата();
ДокументОбъект.Организация = ПолучитьЗначениеПоУмолчанию("ОсновнаяОрганизация"); // Пример заполнения
ДокументОбъект.Содержание = "Автоматическое создание операции";
КонецЕсли;
// 1. Обязательно записываем документ, если он новый и мы хотим получить его Ссылку
// (хотя для ДокументОбъект.Движения это не так критично, как для НабораЗаписей,
// но это хорошая практика для установки базовых реквизитов)
// ДокументОбъект.Записать(РежимЗаписиДокумента.Запись); // Можно записать здесь, если нужно получить ссылку раньше
// 2. Обращаемся к коллекции движений по регистру бухгалтерии Хозрасчетный
ДвиженияХозрасчетный = ДокументОбъект.Движения.Хозрасчетный;
// 3. Устанавливаем режим перезаписи
// Это указывает платформе, что при записи документа нужно сначала очистить
// все старые движения этого документа по данному регистру, а затем записать новые.
ДвиженияХозрасчетный.Записывать = Истина;
// 4. Очищаем существующие движения в коллекции (необязательно, но полезно для наглядности,
// хотя Записывать = Истина уже обеспечит удаление старых при записи документа)
ДвиженияХозрасчетный.Очистить();
// 5. Добавляем новые проводки
// Пример одной проводки: Дт 76.05 Кт 51
НоваяПроводка = ДвиженияХозрасчетный.Добавить();
НоваяПроводка.Период = ДокументОбъект.Дата;
НоваяПроводка.СчетДт = ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами; // Пример получения счета
НоваяПроводка.СчетКт = ПланыСчетов.Хозрасчетный.РасчетныеСчета; // Пример получения счета
НоваяПроводка.Сумма = 1000;
НоваяПроводка.Валюта = ДокументОбъект.Организация.ВалютаРегламентированногоУчета; // Пример получения валюты
НоваяПроводка.СуммаВВалюте = 1000;
НоваяПроводка.Содержание = "Пример проводки";
// Заполняем субконто, если требуется
// НоваяПроводка.СубконтоДт.Контрагенты = СсылкаНаКонтрагента;
// НоваяПроводка.СубконтоКт.БанковскиеСчета = СсылкаНаБанковскийСчет;
// Добавим еще одну проводку для примера
НоваяПроводка = ДвиженияХозрасчетный.Добавить();
НоваяПроводка.Период = ДокументОбъект.Дата;
НоваяПроводка.СчетДт = ПланыСчетов.Хозрасчетный.Касса;
НоваяПроводка.СчетКт = ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами;
НоваяПроводка.Сумма = 500;
НоваяПроводка.Содержание = "Еще одна проводка";
// 6. Записываем документ
// Используем РежимЗаписиДокумента.Запись, так как "ОперацияБух" не проводится
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
// Показываем пользователю созданный/измененный документ
Показать(ДокументОбъект.Ссылка);
Использование ДокументОбъект.Движения.Хозрасчетный.Записывать = Истина; является наиболее надежным способом для перезаписи движений, поскольку оно автоматически обеспечивает удаление старых проводок перед записью новых при сохранении документа.
Этот метод является более универсальным и может использоваться для записи данных в регистр независимо от документа-регистратора. Однако при работе с документом важно правильно установить отбор по регистратору и вручную управлять очисткой старых движений.
РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей().НаборЗаписей.Отбор.Регистратор.Установить(ДокументОбъект.Ссылка).Очистить(). Этот шаг критически важен для предотвращения "чертовщины".НаборЗаписей.Добавить() для создания новых элементов записей и заполняем их реквизиты, обязательно указывая Регистратор.НаборЗаписей.Записать().
// Предположим, что ИзменитьСтарый - это булево,
// СтарыйДокумент - это ссылка на существующий документ
// или Документы.Операция.СоздатьДокумент() для нового.
Перем ДокументОбъект;
Если ИзменитьСтарый Тогда
// Получаем объект существующего документа
ДокументОбъект = Объект.СтарыйДокумент.ПолучитьОбъект();
Иначе
// Создаем новый документ
ДокументОбъект = Документы.ОперацияБух.СоздатьДокумент();
ДокументОбъект.Дата = ТекущаяДата();
ДокументОбъект.Организация = ПолучитьЗначениеПоУмолчанию("ОсновнаяОрганизация");
ДокументОбъект.Содержание = "Автоматическое создание операции (через НаборЗаписей)";
КонецЕсли;
// 1. Обязательно записываем документ, чтобы получить его Ссылку.
// Если документ уже был записан, эта операция его просто перезапишет.
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
// 2. Создаем объект НаборЗаписей для регистра Хозрасчетный
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
// 3. Устанавливаем отбор по регистратору
// Это гарантирует, что мы будем работать только с движениями,
// созданными данным документом.
НаборЗаписей.Отбор.Регистратор.Установить(ДокументОбъект.Ссылка);
// 4. Прочитываем существующие записи и очищаем их
// Это критически важно при перезаписи, чтобы избежать дублирования.
НаборЗаписей.Прочитать(); // Читаем текущие движения документа
НаборЗаписей.Очистить(); // Удаляем все прочитанные движения
// 5. Добавляем новые проводки
// Пример одной проводки: Дт 60.01 Кт 51
Запись = НаборЗаписей.Добавить();
Запись.Регистратор = ДокументОбъект.Ссылка; // Обязательно указываем регистратор для каждой записи
Запись.Период = ДокументОбъект.Дата;
Запись.СчетДт = ПланыСчетов.Хозрасчетный.РасчетыСПоставщикамиИПодрядчиками;
Запись.СчетКт = ПланыСчетов.Хозрасчетный.РасчетныеСчета;
Запись.Сумма = 2500;
Запись.Валюта = ДокументОбъект.Организация.ВалютаРегламентированногоУчета;
Запись.СуммаВВалюте = 2500;
Запись.Содержание = "Пример проводки через набор записей";
// Заполняем субконто, если требуется
// Запись.СубконтоДт.Контрагенты = СсылкаНаКонтрагента;
// Добавим еще одну проводку для примера
Запись = НаборЗаписей.Добавить();
Запись.Регистратор = ДокументОбъект.Ссылка;
Запись.Период = ДокументОбъект.Дата;
Запись.СчетДт = ПланыСчетов.Хозрасчетный.Товары;
Запись.СчетКт = ПланыСчетов.Хозрасчетный.РасчетыСПоставщикамиИПодрядчиками;
Запись.Сумма = 2000;
Запись.Содержание = "Еще одна проводка через набор записей";
// 6. Записываем набор записей
НаборЗаписей.Записать();
// Показываем пользователю созданный/измененный документ
Показать(ДокументОбъект.Ссылка);
Оба описанных подхода позволяют программно создавать и перезаписывать движения документа "Операция (бухгалтерский и налоговый учет)". Однако, есть некоторые важные различия:
ДокументОбъект.Движения) часто проще в реализации, поскольку платформа автоматически управляет многими аспектами, включая связь с документом и очистку старых движений (при установке Записывать = Истина).РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей()) предоставляет более низкоуровневый и детальный контроль. Это может быть полезно в специфических случаях, когда вам нужно манипулировать движениями независимо от их документа-регистратора (хотя в контексте изменения движений конкретного документа это менее применимо).ДокументОбъект.Движения: установка ДокументОбъект.Движения.Хозрасчетный.Записывать = Истина; перед записью документа автоматически позаботится об удалении старых движений, связанных с этим документом.НаборЗаписей: вам необходимо вручную выполнить НаборЗаписей.Прочитать(); НаборЗаписей.Очистить(); перед добавлением новых записей, чтобы избежать дублирования.Наша рекомендация: Для создания и изменения движений документа "Операция (бухгалтерский и налоговый учет)" предпочтительнее использовать его коллекцию движений (ДокументОбъект.Движения.Хозрасчетный). Этот подход более "1С-ный", интуитивно понятен и снижает вероятность ошибок при перезаписи благодаря свойству Записывать = Истина.
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись); для сохранения.ДокументОбъект.Движения это делается через Записывать = Истина, для НаборЗаписей – через Прочитать() и Очистить().НаборЗаписей, документ должен быть записан для получения его ссылки перед установкой отбора по регистратору.Следуя этим рекомендациям и примерам кода, вы сможете эффективно и корректно управлять программным созданием и перезаписью движений документа "Операция (бухгалтерский и налоговый учет)" в вашей системе 1С, избегая проблем с некорректными данными в отчетах.