gifts2017

Заполняем или изменяем регистр без перепроведения документа

Опубликовал Яковлевич Никита (mrXoxot) в раздел Программирование - Практика программирования

При разработке дополнительного функционала может возникнуть необходимость добавить новый регистр в уже существующие документы. Или изменить принцип записи в регистр (например, изменился алгоритм расчета какого-либо показателя). Обычно после исправления мы запускаем перепроведение всех документов. Но это долго, попробуем рассмотреть другой вариант решения.

Задача:

Заказчик хочет добавить новый регистр накопления "ПродажиУслуг", который заполняется на основании табличной части "Услуги" документа "Реализация товаров и услуг". Но проблема в том, что база ведется уже давно и накопилось очень много документов. Полное перепроведение не желательно, так как может занять слишком длительное время.

Решение:

Для решения этой задачи мы будем отдельно записывать набор записей регистра накопления "ПродажиУслуг" в документах "Реализация товаров и услуг". Для этого напишем небольшую внешнюю обработку, но сначала подготовим нашу конфигурацию к условию данной задачи.

Подготовка:

1. Создадим новый регистр накопления "ПродажиУслуг" (измерение – Номенклатура, ресурс – Сумма).

2. В документе "Реализация товаров и услуг" добавим в "Движения" созданный регистр накопления.
Нужно, конечно, добавить в процедуру проведения документа запись в данный регистр, но для решения данной задачи это не принципиально.

3. Всё, на этом подготовка конфигурации выполнена, можно приступать к созданию обработки.

Обработка:

1. Создаем внешнюю обработку "ЗаполнениеРегистраПродажиУслуг".

2. Создаем форму и в ней новую команду – "ЗаполнитьРегистр",

3. Размещаем данную команду в командной панели формы и переходим к описанию процедуры.
Должно получится примерно так:

4. В процедуре находим все проведенные документы "Реализация товаров и услуг" и их табличные части с помощью запроса.

5. Создаем наборы записей для регистра накопления "ПродажиУслуг" с отбором по регистратору.
Данный отбор позволяет связать набор записей регистра накопления и выбранный документ.

6. Добавляем в набор записей необходимые данные из табличной части "Услуги".

7. Записываем набор записей регистра накопления "ПродажиУслуг".
В итоге должен получится примерно такой код:

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка,
| РеализацияТоваровУслуг.Дата,
| РеализацияТоваровУслуг.Услуги.(
| Номенклатура,
| Сумма
| )
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Проведен";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл
    
    НаборЗаписейПродажиУслуг = РегистрыНакопления.ПродажиУслуг.СоздатьНаборЗаписей();
    
    НаборЗаписейПродажиУслуг.Отбор.Регистратор.Использование = Истина;
    НаборЗаписейПродажиУслуг.Отбор.Регистратор.Значение	= Выборка.Ссылка;
    НаборЗаписейПродажиУслуг.Отбор.Регистратор.ВидСравнения  = ВидСравнения.Равно;
    НаборЗаписейПродажиУслуг.Прочитать();
    НаборЗаписейПродажиУслуг.Очистить();
    
    ТаблицаУслуг = Выборка.Услуги.Выгрузить();
    Для Каждого СтрокаУслуг Из ТаблицаУслуг Цикл
        ЗаписьПродажиУслуг              = НаборЗаписейПродажиУслуг.Добавить();
        ЗаписьПродажиУслуг.Период       = Выборка.Дата;
        ЗаписьПродажиУслуг.Номенклатура = СтрокаУслуг.Номенклатура;
        ЗаписьПродажиУслуг.Сумма        = СтрокаУслуг.Сумма;
    КонецЦикла;
    НаборЗаписейПродажиУслуг.Записать();
КонецЦикла;

8. Готово.
После выполнения данной обработки у документов "Реализация товаров и услуг", у которых есть заполненная табличная часть "Услуги" появятся записи в регистре накопления "ПродажиУслуг". Эта операция будет выполнятся гораздо быстрее, чем если бы мы перепроводили все документы.

Примечание:

Этот механизм положен в основу типового Допроведения документов, например в конфигурации "Управление Производственным Предприятием". Допроведение документов выполняется когда не требуется оперативно выполнять какие-либо движения. Например, необязательно списывать партии в момент оперативного проведения документа, так как это занимает продолжительное время. Допроведение может запускается по регламентному заданию и записывать наборы записей регистров к документам, то есть все длительные проверки и операции записи выполнятся в удобное для пользователей время.

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Константин Чернышов (rezerv) 18.11.15 09:57
Большое спасибо за информацию.
В верхней части статьи регистр называется ПродажиУслуг, а в коде ПродажиУслуги?
2. Кирилл Бондаренко (karapuzzzz) 18.11.15 12:19
А почему вместо
НаборЗаписейПродажиУслуг.Отбор["Регистратор"].Использование = Истина;
    НаборЗаписейПродажиУслуг.Отбор["Регистратор"].Значение    = Выборка.Ссылка;
    НаборЗаписейПродажиУслуг.Отбор["Регистратор"].ВидСравнения  = ВидСравнения.Равно;

не использовать
НаборЗаписейПродажиУслуг.Отбор.Регистратор.Установить(Выборка.Ссылка);
3. Яковлевич Никита (mrXoxot) 18.11.15 12:24
(1) rezerv, (2) karapuzzzz,
Спасибо, Ваши замечания поправил.
4. Игорь (IgorS) 18.11.15 16:26
Судя по количеству плюсовавших, читать жёлтые книжки начинающие спецы 1С не пробовали :(
kotloff; lx@; +2 1 Ответить 1
5. Vova Vova (Vova1900) 19.11.15 11:59
(4) IgorS,
Какие книги порекомендуете?
6. Андрей Акулов (DrAku1a) 24.11.15 02:42
Берём отладчик запросов (для управляемых форм 8.3 - соответственно, консоль запросов с Инфостарта, в которой есть возможность обрабатывать результат) - пишем простой запрос, которым получаем все услуги с итогами по документам, что-то вроде:
"ВЫБРАТЬ Ссылка, Ссылка.Дата КАК Период, Номенклатура, Сумма ИЗ Документ.РеализацияТоваровУслуг.Услуги ГДЕ Ссылка.Проведен ИТОГИ ПО Ссылка"
кстати, также можно и упорядочить.
выполняем, запрос - переходим к обработке результата. Там пишем код:
НЗ=неопределено;
Для каждого Строчка из РезультатЗапросаТаблицей Цикл
	Если Строчка.Номенклатура<>Null Тогда
		ЗаполнитьЗначенияСвойств(НЗ.Добавить(), Строчка);
		Продолжить;
	ИначеЕсли НЗ<>неопределено Тогда
		НЗ.ОбменДанными.Загрузка = Истина; //отключаем встроенные обработчики событий
		НЗ.Записать(Истина);
	КонецЕсли;
	НЗ = РегистрыНакопления.ПродажиУслуг.СоздатьНаборЗаписей();
	НЗ.Отбор.Регистратор.Установить(Строчка.Ссылка);
КонецЦикла;
Если НЗ<>неопределено Тогда
	НЗ.ОбменДанными.Загрузка = Истина; //отключаем встроенные обработчики событий
	НЗ.Записать(Истина);
КонецЕсли;
...Показать Скрыть

Если документов много, то рекомендую для циклов реализовать счетчик, а сами документы в запросе упорядочивать:
//Код для "Обычного приложения" (неуправляемые формы)
КолВо = РезультатЗапросаТаблицей.Количество(); //+++
стрКолВо = " / "+КолВо+" ("; //+++
сч = 0; //+++
НЗ=неопределено;
Для каждого Строчка из РезультатЗапросаТаблицей Цикл
	сч = сч + 1; // +++
	Если Строчка.Номенклатура<>Null Тогда
		ЗаполнитьЗначенияСвойств(НЗ.Добавить(), Строчка);
		Продолжить;
	ИначеЕсли НЗ<>неопределено Тогда
		НЗ.ОбменДанными.Загрузка = Истина; //отключаем встроенные обработчики событий
		НЗ.Записать(Истина);
	КонецЕсли;
	НЗ = РегистрыНакопления.ПродажиУслуг.СоздатьНаборЗаписей();
	НЗ.Отбор.Регистратор.Установить(Строчка.Ссылка);
	Состояние(""+сч+стрКолВо+Окр(сч*100/КолВо, 1)+"%) "+Строчка.Ссылка); // +++
	ОбработкаПрерыванияПользователя(); // +++
КонецЦикла;
Если НЗ<>неопределено Тогда
	НЗ.ОбменДанными.Загрузка = Истина; //отключаем встроенные обработчики событий
	НЗ.Записать(Истина);
КонецЕсли;
Состояние(); // +++ 
Сообщить("Выполнение завершено."); // +++
...Показать Скрыть
7. q_i 25.11.15 12:59
А потом если нужно будет поменять алгоритм формирования движения по новому регистру, то придётся изменять соответствующий код и в модуле документа, и в обработке. Возможно, для разового запуска это и не критично, но всё равно я бы сделал как-то так:
1. В модуле документа РеализацияТоваровУслуг создаем процедуру ОтразитьПродажиУслуг(...), которая заполняет наборы записей по новому регистру и добавляем её вызов в ОбработкаПроведения().
2. Объявляем процедуру ОтразитьПродажиУслуг(...) экспортной.
3. В обработке получаем список документов РеализацияТоваровУслуг, для которых нужно создать движения, и для каждого объекта вызываем ДокОбъект.ОтразитьПродажиУслуг(...), после чего записываем движения по этому регистру.
8. Яковлевич Никита (mrXoxot) 25.11.15 14:47
(7) q_i,
Да, это достойное решение. Спасибо!
Но обычно в типовых сначала готовятся куча таблиц и движений, а в конце одним махом записывают все движения. Это позволяет сократить время на запись. Поэтому не всегда будет удобно делать отдельное проведение, иногда стоит вписываться в типовой механизм.
9. Владимир Матлай (AneJIbcuH) 28.11.15 15:41
Большое спасибо за информацию, как раз необходимо было. А то есть у нас такая проблема в УПП, когда бухгалтер, например, в реализации вручную поправит проводки, а там ещё есть движения по Упр учету, то после перепроведения проводки восстанавливать приходится :)

Внесу свою лепту, я запрос всё же бы так построил:

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	РеализацияТоваровУслугТовары.Ссылка,
|	РеализацияТоваровУслугТовары.Ссылка.Дата КАК Период,
|	РеализацияТоваровУслугТовары.Номенклатура,
|	РеализацияТоваровУслугТовары.Сумма
|ИЗ
|	Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
|	РеализацияТоваровУслугТовары.Ссылка.Проведен
|
|УПОРЯДОЧИТЬ ПО
|	РеализацияТоваровУслугТовары.Ссылка.МоментВремени
|ИТОГИ ПО
|	РеализацияТоваровУслугТовары.Ссылка";

Результат = Запрос.Выполнить();
ВыборкаСсылка = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаСсылка.Следующий() Цикл
	
	НаборЗаписейПродажиУслуг = РегистрыНакопления.ПродажиУслуг.СоздатьНаборЗаписей();
	
	НаборЗаписейПродажиУслуг.Отбор.Регистратор.Установить(ВыборкаСсылка.Ссылка);
	НаборЗаписейПродажиУслуг.Прочитать();
	НаборЗаписейПродажиУслуг.Очистить();
	
	ВыборкаТовары = ВыборкаСсылка.Выбрать();
	
	Пока ВыборкаТовары.Следующий() Тогда 	   
		ЗаписьПродажиУслуг              = НаборЗаписейПродажиУслуг.Добавить();
		ЗаполнитьЗначенияСвойств(ЗаписьПродажиУслуг,ВыборкаТовары);	   
	КонецЦикла;   
	
	НаборЗаписейПродажиУслуг.Записать();
КонецЦикла;
...Показать Скрыть

10. Владимир Матлай (AneJIbcuH) 28.11.15 15:43
Нечто подобное как раз озвучил уважаемый DrAku1a, но далее его алгоритм не совсем понятен.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа