Данная статья инициирована тем, что приводимая ниже информация не была найдена мной на сайте в открытом виде. Поэтому мне пришлось потратить несколько драгоценных минут, чтобы все это сделать самому.
Суть кода — удалить/добавить/скорректировать движения документа "извне". Не трогая сам документ. Для "подстановки" движений в регистр документ должен быть записан, желательно (но не обязательно) проведен. Встречал случаи, когда делаешь выверку данных и не понимаешь, откуда лезут движения; тратишь кучу времени и потом выясняешь, что движения делает не проведенный документ; долго и с выражением ругаешься 🙂
Делают это обычно тремя методами:
1) делают подписку на событие ПриПроведении
2) делают дописку в конце процедуры ОбработкаПроведения в модуле документа (стало особенно актуально с появлением расширения)
3) делают внешнюю обработку, которая правит движения по таймеру или по ручному нажатию на кнопку
В общем, суть методов одна и та же, меняется только небольшая часть. Рассмотрим все варианты
1. Дописка движений с помощью подписки на событие (на примере УТ 11)
Добавляем общий серверный модуль:
Добавляем подписку на событие:
Ниже сам модуль
Процедура РТУ_ПроведениеОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
// получаем ссылку на документ
Регистратор=Источник.Ссылка;
НаборЗаписей = РегистрыНакопления.СебестоимостьТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписей.Прочитать();
// предыдущие движения удаляем
// можно этого не делать, тогда движения добавятся к существующим
НаборЗаписей.Очистить();
Для каждого Строка из Регистратор.ВидыЗапасов Цикл
// Делаем новые движения
ЗаписьРегистра = НаборЗаписей.Добавить();
ЗаписьРегистра.ВидДвижения = ВидДвиженияНакопления.Приход; // эта строчка только для регистров остатков
ЗаписьРегистра.Период=Регистратор.Дата;
ЗаписьРегистра.Регистратор=Регистратор;
ЗаписьРегистра.АналитикаУчетаНоменклатуры=Строка.АналитикаУчетаНоменклатуры;
ЗаписьРегистра.РазделУчета=Перечисления.РазделыУчетаСебестоимостиТоваров.ТоварыНаСкладах;
ЗаписьРегистра.ВидЗапасов=Строка.ВидЗапасов;
ЗаписьРегистра.Организация=Регистратор.Организация;
ЗаписьРегистра.ВидДеятельностиНДС=Перечисления.ТипыНалогообложенияНДС.ПродажаОблагаетсяНДС;
// при необходимости добавить заполнение остальных измерений
ЗаписьРегистра.Количество=Строка.Количество;
ЗаписьРегистра.Стоимость=Строка.СуммаСНДС;
ЗаписьРегистра.СтоимостьРегл=Строка.СуммаСНДС;
ЗаписьРегистра.СтоимостьУпр=Строка.СуммаСНДС;
// при необходимости добавить заполнение остальных ресурсов
ЗаписьРегистра.ХозяйственнаяОперация=Перечисления.ХозяйственныеОперации.РеализацияКлиенту;
// при необходимости добавить заполнение остальных реквизитов
КонецЦикла;
// все. фиксируем проводки в регистре
НаборЗаписей.Записать();
КонецПроцедуры
Правильность кода в смысле бизнес-правил не преследовалась. Это просто пример того, как можно перезаполнить движения документа по какому-то из регистров, в качестве "жертвы" был выбран СебестоимостьТоваров.
Ниже еще вариант правки кода в подписке на событие (для конфигурации БП20 — меняем счет списания для документа Списание товаров):
Процедура ОбработкаПроведенияСписаниеТоваровОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
// тут движения уже отфильтрованы по Регистратору, потому просто берем их и используем
НаборДвижений = Источник.Движения.Хозрасчетный;
ТаблицаПроводок = НаборДвижений.Выгрузить();
// тут приведена некоторая функция, которая гипотетически, по какому-то алгоритму, получает счет Плана счетов
// а также Статью прочих доходов и расходов для субконто
СтатьяЗатрат="";
СчетЗамены=ПолучитьСчетЗамены(СтатьяЗатрат);
// ниже мы поменяем счет, на который делает проводки документ СписаниеТоваров в типовой БП20 (это счет 94)
// на какой-то свой счет, у которого есть субконто со статьей прочих доходов и расходов
Если ЗначениеЗаполнено(СчетЗамены) Тогда
Отбор = Новый Структура;
Отбор.Вставить("СчетДт",ПланыСчетов.Хозрасчетный.НедостачиИПотериОтПорчиЦенностей);
МассивСтрок = ТаблицаПроводок.НайтиСтроки(Отбор);
Для Каждого СтрокаТип Из МассивСтрок Цикл
// делаем новую проводку (старую потом удалим)
НоваяСтрока = ТаблицаПроводок.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока,СтрокаТип);
НоваяСтрока.СчетДт = СчетЗамены;
НоваяСтрока.ВидСубконтоДт1 = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПрочиеДоходыИРасходы;
НоваяСтрока.СубконтоДт1 = СтатьяЗатрат;
// удаляем старую проводку
ТаблицаПроводок.Удалить(СтрокаТип);
КонецЦикла;
КонецЕсли;
НаборДвижений.Загрузить(ТаблицаПроводок);
КонецПроцедуры
Можно заметить, что в двух процедурах выше немного меняется способ получения набора записей для их редактирования. В первом случае приходится делать отбор по новому набору, так как простое использование Источник.Движения.СебестоимостьТоваров дает следующую ошибку при проведении:
Документ Реализация товаров и услуг А0ТП-000065 от 31.01.2024 12:37:53 не проведен: Попытка использования закрытого менеджера временных таблиц
Подробно проблему не исследовал, но видимо при записи регистра для набора записей есть своя подписка на события, которая не дает идти по короткому пути. В любому случае, полезно знать оба метода получения набора записей.
2. Изменение движений с помощью дописки в конец процедуры ОбработкаПроведения в Расширении
&После("ОбработкаПроведения")
Процедура Общ_ОбработкаПроведения(Отказ, РежимПроведения)
Св_ва=УправлениеСвойствами.СвойстваОбъекта(Ссылка, Ложь, Истина);
Для каждого Св_во из Св_ва Цикл
Если Св_во.Имя="ПодразделениеКорр._ПРС" Тогда
ПодрКорр=УправлениеСвойствами.ЗначениеСвойства(Ссылка, Св_во);
Если ЗначениеЗаполнено(ПодрКорр) Тогда
Общ_СкорректироватьПроводки(ПодрКорр);
КонецЕсли;
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура Общ_СкорректироватьПроводки(ПодрКорр)
Для каждого Движ из Движения.Хозрасчетный Цикл
Движ.ПодразделениеКт=ПодрКорр;
КонецЦикла;
КонецПроцедуры
Пример выше вообще взят из конкретного кейса: необходимо было, если пользователь устанавливал доп. свойство "Подразделение корр." для документа, менять в кредитовой части подразделение (до этой доработки пользователи это делали просто изменяя проводки вручную).
Также можно набор записей выгрузить в таблицу значений, что-то с ней сделать, потом загрузить обратно в набор записей и снова его записать.
Ну, и наконец
3. Обработка для изменения движений (вообще, это может быть просто процедура, которая вызывается из регламентного задания или откуда-то еще)
Сама обработка:
Код в модуле формы:
&НаСервереБезКонтекста
Процедура КорректированиДвиженияНаСервере(Регистратор)
НаборЗаписей = РегистрыНакопления.СебестоимостьТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписей.Прочитать();
// предыдущие движения удаляем
// можно этого не делать, тогда движения добавятся к существующим
НаборЗаписей.Очистить();
Для каждого Строка из Регистратор.ВидыЗапасов Цикл
// Делаем новые движения
ЗаписьРегистра = НаборЗаписей.Добавить();
ЗаписьРегистра.ВидДвижения = ВидДвиженияНакопления.Приход; // эта строчка только для регистров остатков
ЗаписьРегистра.Период=Регистратор.Дата;
ЗаписьРегистра.Регистратор=Регистратор;
ЗаписьРегистра.АналитикаУчетаНоменклатуры=Строка.АналитикаУчетаНоменклатуры;
ЗаписьРегистра.РазделУчета=Перечисления.РазделыУчетаСебестоимостиТоваров.ТоварыНаСкладах;
ЗаписьРегистра.ВидЗапасов=Строка.ВидЗапасов;
ЗаписьРегистра.Организация=Регистратор.Организация;
ЗаписьРегистра.ВидДеятельностиНДС=Перечисления.ТипыНалогообложенияНДС.ПродажаОблагаетсяНДС;
// при необходимости добавить заполнение остальных измерений
ЗаписьРегистра.Количество=Строка.Количество;
ЗаписьРегистра.Стоимость=Строка.СуммаСНДС;
ЗаписьРегистра.СтоимостьРегл=Строка.СуммаСНДС;
ЗаписьРегистра.СтоимостьУпр=Строка.СуммаСНДС;
// при необходимости добавить заполнение остальных ресурсов
ЗаписьРегистра.ХозяйственнаяОперация=Перечисления.ХозяйственныеОперации.РеализацияКлиенту;
ЗаписьРегистра.ЗаказКлиента=Регистратор.ЗаказКлиента;
ЗаписьРегистра.Подразделение=Регистратор.Подразделение;
ЗаписьРегистра.ПериодПродажи=НачалоМесяца(Регистратор.Дата);
ЗаписьРегистра.ДокументИсточник=Регистратор;
// при необходимости добавить заполнение остальных реквизитов
КонецЦикла;
// все. фиксируем проводки в регистре
НаборЗаписей.Записать();
КонецПроцедуры
&НаКлиенте
Процедура КорректированиДвижения(Команда)
КорректированиДвиженияНаСервере(ДокументРТУ);
КонецПроцедуры
Видно, что код очень похож на самый первый пример, где мы отбираем набор записей по Источник.Ссылка
Конечно же, эти сведения не уникальны, но собранные в одной статье помогут сэкономить некоторое количество времени.
В приложенном файле — обработка коррекции движений, полный код которой представлен в статье. Обработка тестировалась на платформе версии 1С:Предприятие 8.3 (8.3.14.1630), конфигурация Управление торговлей, редакция 11 (11.4.6.207).