При работе с конфигурацией 1С:Бухгалтерия Предприятия 3.0 часто возникает необходимость программно изменять существующие бухгалтерские проводки, например, после их ручного редактирования в таблице значений на форме. Мы рассмотрим подробный алгоритм, как получить проводки по регистратору, модифицировать их и корректно сохранить обратно в регистр бухгалтерии, уделяя особое внимание работе с субконто.
Для программного изменения проводок в 1С:Бухгалтерия Предприятия 3.0 мы используем объект НаборЗаписей регистра бухгалтерии Хозрасчетный. Этот подход позволяет нам получить все проводки, связанные с определенным документом-регистратором, внести в них необходимые изменения и затем записать обновленный набор обратно в базу данных.
Разберем по шагам, как это делается:
НаборЗаписей для регистра Хозрасчетный.НаборЗаписей. Теперь объект содержит все проводки, соответствующие указанному регистратору.НабораЗаписей в таблицу значений.НаборЗаписей. Затем мы записываем этот набор обратно в базу данных. Параметр Истина в методе Записать() указывает, что существующие записи по данному регистратору будут перезаписаны полностью.Посмотрим на пример кода, демонстрирующий этот процесс:
// Предположим, что 'стр.Док' – это ссылка на документ-регистратор
// Эта часть выполняется для выгрузки проводок на форму:
Проводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Проводки.Отбор.Регистратор.Установить(стр.Док);
Проводки.Прочитать();
ТЗПроводокНаФорме = Проводки.Выгрузить(); // Передаём ТЗ на форму для редактирования
// ... Пользователь изменяет ТЗПроводокНаФорме на форме ...
// Эта часть выполняется после получения измененной ТЗ с формы:
// Получаем измененную ТЗ обратно с формы (предположим, что это переменная ТЗИзФормы)
// Важно: структура ТЗИзФормы должна быть идентична структуре НабораЗаписей
ПроводкиДляЗаписи = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
ПроводкиДляЗаписи.Отбор.Регистратор.Установить(стр.Док);
// Прочитать текущие проводки, чтобы убедиться, что мы работаем с актуальным набором,
// хотя Загрузить/Записать(Истина) фактически перезапишет всё.
ПроводкиДляЗаписи.Прочитать();
ПроводкиДляЗаписи.Загрузить(ТЗИзФормы); // Загружаем измененные данные из ТЗ
ПроводкиДляЗаписи.Записать(Истина); // Перезаписываем весь набор для данного регистратора
Важный момент: структура таблицы значений, передаваемой на форму и затем обратно, должна быть идентичной структуре записей регистра бухгалтерии. Это означает, что все колонки, такие как Период, СчетДт, СчетКт, Сумма, СубконтоДт1, СубконтоДт2, СубконтоДт3, СубконтоКт1, СубконтоКт2, СубконтоКт3 и другие, должны присутствовать в ТЗ с соответствующими типами.
Одной из наиболее частых проблем при работе с проводками через таблицу значений на форме является некорректная обработка полей субконто, особенно если требуется очистка и изменение субконто в операциях, введенных вручную. Тип "Произвольный" для полей субконто в таблице значений формы недопустим и вызовет ошибку "РегистрБухгалтерииСубконто.Хозрасчетный" не может использоваться в данных формы".
Мы должны понимать, что элементы субконто имеют конкретные ссылочные типы (например, СправочникСсылка.Номенклатура, СправочникСсылка.Контрагенты и т.д.). При создании структуры ТЗ на форме для полей субконто (СубконтоДт1, СубконтоКт1 и т.д.) необходимо использовать следующие подходы:
СправочникСсылка.Контрагенты). Это предпочтительнее для строгой типизации и предотвращения ошибок.При загрузке данных из ТЗ обратно в НаборЗаписей, платформа 1С автоматически попытается преобразовать значения колонок ТЗ к соответствующим типам полей регистра. Главное — чтобы передаваемые значения были корректными ссылками на объекты базы данных, а не строками или пустыми значениями неверного типа.
Для корректной установки значений субконто в проводках, особенно при их изменении, настоятельно рекомендуется использовать стандартные функции из общих модулей 1С. Функция БухгалтерскийУчет.УстановитьСубконто() является идеальным инструментом для этой цели, так как она учитывает тип и вид субконто, а также обеспечивает правильную запись в структуры субконто регистра бухгалтерии.
Рассмотрим пример кода, который демонстрирует, как можно произвести замену статьи затрат в проводках в закрытом периоде для конкретных счетов (например, 91.01 и 91.02):
&НаСервере
Процедура ИзменитьПроводкиНаСервере()
// Предполагаем, что Объект.Документ - это реквизит формы,
// в котором выбран документ-регистратор
Если Объект.Документ.Пустая() Тогда
Сообщить("Не выбран документ для заполнения");
Возврат;
КонецЕсли;
ТекДок = Объект.Документ.ПолучитьОбъект();
Если ТекДок = Неопределено Тогда
Сообщить("Не выбран документ для заполнения");
Возврат;
Иначе
ДокОперацияСсылка = ТекДок.Ссылка;
// ДатаВДок = ТекДок.Дата; // Дата здесь может быть не нужна для изменения проводок, но полезно знать
Проводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Проводки.Отбор.Регистратор.Установить(ДокОперацияСсылка);
Проводки.Прочитать();
// Предполагаем, что Объект.ДиР9101 и Объект.ДиР9102 - это реквизиты формы
// типа СправочникСсылка.ПрочиеДоходыИРасходы, в которых пользователь выбрал новые значения субконто.
// Или же эти значения берутся из ТЗ с формы после редактирования.
Для Каждого пров Из Проводки Цикл
// Изменяем субконто по кредиту для счета 91.01
Если пров.СчетКт.Код = "91.01" Тогда
// Важно: БухгалтерскийУчет.УстановитьСубконто ожидает Счет, КоллекциюСубконто, НаименованиеВидаСубконто, ЗначениеСубконто
// "ПрочиеДоходыИРасходы" - это наименование вида субконто, которое мы хотим изменить.
БухгалтерскийУчет.УстановитьСубконто(пров.СчетКт, пров.СубконтоКт, "ПрочиеДоходыИРасходы", Объект.ДиР9101);
КонецЕсли;
// Изменяем субконто по дебету для счета 91.02
Если пров.СчетДт.Код = "91.02" Тогда
БухгалтерскийУчет.УстановитьСубконто(пров.СчетДт, пров.СубконтоДт, "ПрочиеДоходыИРасходы", Объект.ДиР9102);
КонецЕсли;
КонецЦикла;
Проводки.Записать(Истина); // Записываем измененные проводки
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ИзменитьПроводки(Команда)
ИзменитьПроводкиНаСервере();
КонецПроцедуры
В этом примере:
НаборЗаписей и устанавливаем отбор по этому регистратору.СчетКт или СчетДт) и, если они соответствуют нашим условиям, вызываем функцию БухгалтерскийУчет.УстановитьСубконто(). Эта функция автоматически определяет, какое именно субконто (Субконто1, Субконто2, Субконто3) соответствует указанному виду ("ПрочиеДоходыИРасходы") и присваивает ему новое значение (Объект.ДиР9101 или Объект.ДиР9102).Использование БухгалтерскийУчет.УстановитьСубконто() значительно упрощает работу с субконто, так как избавляет нас от необходимости вручную определять, в какое из полей СубконтоДт1, СубконтоДт2, СубконтоДт3 или СубконтоКт1, СубконтоКт2, СубконтоКт3 нужно записать значение. Эта функция сама найдет соответствующее измерение субконто по его виду.
Параметр Истина в методе Записать() для НабораЗаписей регистра бухгалтерии имеет важное значение. Он означает, что весь набор записей, соответствующий установленному отбору, будет полностью перезаписан. То есть, если мы получили набор записей по определенному регистратору, изменили его содержимое (путем прямого редактирования или через Загрузить(ТЗ)), а затем вызвали Записать(Истина), то все старые проводки, связанные с этим регистратором, будут удалены, а вместо них будут записаны новые, содержащиеся в нашем НабореЗаписей.
Это очень удобно, когда мы точно знаем, что хотим заменить весь блок проводок по документу. Однако, мы должны быть осторожны: если в процессе получения или загрузки данных мы потеряли какие-то проводки, или если в ТЗ на форме отсутствовали некоторые из них, то эти проводки будут безвозвратно утеряны при записи.
Если же мы хотим только добавить новые проводки к существующим, не затрагивая старые, то следует использовать Записать(Ложь). Но в сценарии редактирования уже существующих проводок, как правило, используется именно Записать(Истина) для полной замены.
При любом программном изменении данных в 1С, особенно в регистрах бухгалтерии, критически важно обеспечить целостность данных. Изменения должны происходить в рамках транзакции. Если в процессе сохранения возникает ошибка (например, из-за неверных данных, отсутствия прав, блокировки), все изменения должны быть отменены, чтобы база данных осталась в согласованном состоянии.
Платформа 1С:Предприятие во многих случаях автоматически управляет транзакциями при записи объектов (например, документов). Однако при прямой работе с наборами записей регистров через методы Прочитать(), Загрузить(), Записать() нам следует убедиться, что логика обработки ошибок и отката транзакций продумана. Если изменения затрагивают несколько регистров или другие объекты базы данных, может потребоваться явное управление транзакциями с использованием НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию().
Мы рекомендуем всегда тестировать такие изменения в тестовой базе данных, прежде чем применять их в продуктивной среде.
Хотя прямой доступ и изменение НаборовЗаписей является эффективным способом, мы рассмотрим также некоторые общие рекомендации и альтернативные подходы:
В нашем случае, когда речь идет о целенаправленном изменении сумм или субконто в уже сформированных проводках после ручного редактирования на форме, подход с использованием НабораЗаписей является вполне допустимым и эффективным решением. Главное — строго следовать правилам работы с типами данных, особенно применительно к субконто, и учитывать особенности метода Записать(Истина).