Только та революция чего-нибудь стоит, у которой есть своя 1С.
(из полного собрания сочинений)
Ранее в публикации //infostart.ru/public/177179/ был описан сервис обработки выборки запроса подсистемы
«COMExchange», позволяющий выполнять сложные действия с данными в информационной базе. Этот сервис реализован
на поддержке пользовательских событий «ПередВыборкой», «Выборка» и «ПослеВыборки» в специальной форме
«ОбработкаВыборки» консоли запросов (смотри детали в описании консоли), основной смысл которых заключается
в выполнении заданного пользователем кода на языке 1С, определяющего алгоритм обработки данных.
В настоящей статье описываются возможности сервиса для работы с регистрами, подчинёнными регистратору.
Описание задачи:
В архиве файла поставки в папке .\COMExchange-8x\Sampels\ находится файл (скачать)
!ВеликаяОктябрьскаяРеволюция.selx с примером запросов, выполняющих следующие действия:
- «Обнуляются» итоги на текущую дату следующих регистров накопления:
«ДенежныеСредства», «РасчетыСКонтрагентами», «ВзаиморасчетыСКонтрагентами»; - Для регистра сведений «ЦеныНоменклатурыКонтрагентов» для среза последних на текущую дату
в регистр прописываются пустые значения всех ресурсов; - Для регистра бухгалтерии «Хозрасчётный» (если он есть в конфигурации) остатки по счетам
01, 02, 03, 04, 05, 50, 51, 52, 55, 60, 62, 75 и 76
списываются с корреспонденцией на счёт с кодом “ВОР” и наименованием “Великая Октябрьская Революция”.
Если такого счета в плане счетов нет, он создаётся. - Для записи наборов записей регистров в качестве регистратора используется ссылка на типовой документ вида
«КорректировкаЗаписейРегистра». После записи документ-регистратор открывается на просмотр (Рис.4).
Запросы из примера работают в типовых конфигурациях УТ-10.3, УПП-1.2, УПП-1.3 (обычное приложение).
При этом в конфигурациях УПП-1.2, УПП-1.3 можно посмотреть «финансовый результат экспроприации»
с помощью стандартных бухгалтерских отчетов (Рис.5, Рис.6).
Для описываемого примера установка подсистемы «COMExchange» в полном объёме не требуется,
достаточно обработки “Консоль запросов 1С + ADO”, сохранённой в виде внешней обработки.
Рекомендуемая версия консоли 8.1.1.2-а.Посмотреть версию консоли можно в описании или в меню «Действия» (Рис.1).
Описываемый пример является задачей коррекции регистров учёта на основании данных из самой информационной базы 1С.
Другой распространённой задачей является загрузка начальных итогов (сведений) по регистрам из внешних файлов.
Эта задача так же решается с использованием описанной в примере методики.
Только таблица движений регистров в запросах строится не по данным из информационной базы 1С, а по данным,
загруженных из внешнего файла во временную таблицу и синхронизованных с объектами в базе 1С.
Как можно загрузить и синхронизовать данные из внешнего файла описано в статье //infostart.ru/public/177179/
на примере загрузки курса валюты из файла *.xls, *.dbf.
Комментарии к запросам (Рис.2):
- «Корневой» запрос «ВеликаяОктябрьскаяРеволюция» - не выполняет никаких действий, он просто открывает форму «ОбработкаВыборки».
В этой форме после нажатия на кнопку «Обработать» (Рис.4) обработчики пользовательских событий выполняются все остальные действия:
получение необходимых выборок запросов и запись документа-регистратора с наборами записей регистров. - Запрос «ДвиженияУТ-10» - выполняет пакет запросов, формирующий таблицы движений по регистрам для конфигурации УТ-10.3;
- Запрос «ДвиженияУПП» - выполняет пакет запросов, формирующий таблицы движения по регистрам для конфигурации УПП-1.2 и УПП-1.3. (включая данные бухучета);
- Запрос «ДанныеБухУчета» - формирует временные таблицы по данным бухгалтерских итогов, используемые в запросе «ДвиженияУПП»
для формирования движений по регистру бухгалтерии «Хозрасчетный». Перед выполнением пакета запросов проверяется наличие в плане счетов счета “ВОР”.
При необходимости такой счёт создаётся (Рис.4); - Запрос «СчетаЭкспроприации» - укладывает во временную таблицу список бухгалтерских счетов, по которым будут списываться остатки;
Остальные запросы играют вспомогательную роль.
Комментарии к коду обработчиков пользовательских событий:
Модули обработчиков событий обработки получены модификацией кода, установленного при авто-заполнении
по шаблону «Корректировка регистров» (Рис.3). Полный текст кода смотрите ниже в приложении статье.
1. Событие ПередВыборкой():
Сначала по метаданным конфигурации вычисляется имя запроса, формирующего набор таблиц движений по регистрам.
Для непредусмотренной конфигурации обработка прерывается с установкой флага Отказ = Истина и выводом сообщения.
Далее в соответствии ДополнительныеСвойства устанавливаются параметры обработки, используемые в событии ПослеВыборки():
- Имя запроса, формирующего данные для движений в регистрах;
- Флаг ВыборкаОбновить = Истина (для обновления выборки запроса);
- Флаг ВыборкаПропустить = Истина (для пропуска события Выборка());
- Вид документа регистратора – «КорректировкаЗаписейРегистра»;
- Имя запроса, значения параметров которого используются для установки свойств документа-регистратора
(в рассматриваемом примере не указывается); - Номер и дата документа (00000000001 от 07.11.2017);
- Содержание комментария документа-регистратора;
Затем заполняется массив имён регистров, для которых будут записываться наборы движений.
Важен порядок следования имён в этом массиве!
Он должен соответствовать порядку отдельных «батчей» в пакете запросов, формирующем набор таблиц движений по регистрам. - 2. Событие Выборка():
В шаблоне авто-заполнения «Корректировка регистров» это событие не используется.
При выполнении оно фактически пропускается одновременной установкой в событии ПередВыборкой()
аргумента СтандартнаяОбработка = Ложь и параметра обработки ВыборкаПропустить = Истина.
Модуль события содержит комментарии с информацией справочного характера. - 3. Событие ПослеВыборки():
Содержит универсальный код, выполняющий с учётом установленных в событии ПередВыборкой() параметров следующие действия:
- Сначала по переданному имени получается результат запроса, содержащий набор таблиц с движениями регистров.
Если имя не задано – используется результат текущего запроса. При необходимости результат запроса обновляется. - Далее по переданному номеру и дате ищется документ-регистратор, указанного вида. Если документ не находится – создаётся новый.
Если номер не указан – номер устанавливается авто-нумерацией. - Затем для найденного документа – очищаются табличные части и движения. Если документ помечен на удаление – пометка удаления снимается.
- Потом как для нового, так и для существующего документа устанавливаются свойства по значениям параметров запроса,
с указанным именем, если это имя задано. Также заново устанавливается ответственный и формируется комментарий документа. - И наконец, заполняются движения документа-регистратора для регистров, перечисленных в массиве имен.
В наборы записей движений документа для перечисленных в массиве регистров загружаются таблицы значений с движениями из результата запроса.
Таблицы движений получаются из результата запроса по индексу в массиве имен регистров.
При заполнении движений также согласованно заполняются табличные части документа. - В завершение после удачной записи документа он открывается на просмотр.
Благодарности:
Выражаю огромную благодарность alexk-is за его замечательную обработку,
без которой оформление приложения к этой статье вызвало бы определенные сложности.
Приложение (код обработчиков событий):
// ПередВыборкой(Отказ, СтандартнаяОбработка)
// ********** КОРРЕКТИРОВКА ЗАПИСЕЙ РЕГИСТРОВ, ПОДЧИНЕННЫХ РЕГСТРАТОРАМ **********
// флагОК, стПарам, Объект, пр0 ... пр9 и ф0, ф1 - переменные модуля формы
// В выборках пакета запросов требуется сформировать полные таблицы значений
// с движениями корректируемых регистров, включая поля Период и ВидДвижения !
// Соответствие таблиц движений - по индексу в списке имен регистров
СтандартнаяОбработка = Ложь;
флагОК = Ложь; // предохранитель
флагОК = Истина; // не уверен - не снимай!!!
ВыборкаЗапрос = "";
СвойстваЗапрос = "";
// только для УТ10.3, УПП1.2, УПП1.3 !!!
МетаданныеИмя = Метаданные.Имя; МетаданныеВерсия = Метаданные.Версия;
Если МетаданныеИмя = "УправлениеТорговлей" Тогда
Если Лев(МетаданныеВерсия,3) = "10." Тогда
ВыборкаЗапрос = "ДвиженияУТ-10";
КонецЕсли;
ИначеЕсли МетаданныеИмя = "УправлениеПроизводственнымПредприятием" Тогда
ВыборкаЗапрос = "ДвиженияУПП";
КонецЕсли;
Если ВыборкаЗапрос = "" Тогда Отказ = Истина;
Сообщить("Непредусмотренная конфигурация базы данных: '"+МетаданныеИмя+"("+МетаданныеВерсия+")'",СтатусСообщения.Информация);
Отказ = Истина;
Перейти ~Возврат;
КонецЕсли;
ДополнительныеСвойства = Новый Соответствие;
ДополнительныеСвойства["ВыборкаЗапрос"] = ВыборкаЗапрос; // имя запроса выборки данных (по умолчанию - текущий запрос)
ДополнительныеСвойства["ВыборкаОбновить"] = Истина; // флаг обновления выборки данных
ДополнительныеСвойства["ВыборкаПропустить"] = Истина; // пропускаем событие выборка
ДополнительныеСвойства["СвойстваЗапрос"] = СвойстваЗапрос; // имя запроса для установки свойств документа-регистратора
ДополнительныеСвойства["ИмяРегистратора"] = "КорректировкаЗаписейРегистров";
//ДополнительныеСвойства["ИмяРегистратора"] = "ОперацияБух";
Комментарий = "Берем банк и кассу, Экспроприируем экспроприаторов.";
НомерДок = "00000000001"; //
ДатаДок = '2017-11-07';
ДополнительныеСвойства["Комментарий"] = Комментарий;
ДополнительныеСвойства["НомерДок"] = НомерДок;
ДополнительныеСвойства["ДатаДок"] = ДатаДок;
// формируем список имен регистров, соответствие таблиц движений в результате пакета запросов - по индексу в списке
СписокДвижений = Новый Массив;
ДополнительныеСвойства["СписокДвижений"] = СписокДвижений;
СписокДвижений.Добавить("ДенежныеСредства");
СписокДвижений.Добавить("ЦеныНоменклатурыКонтрагентов");
СписокДвижений.Добавить("РасчетыСКонтрагентами");
СписокДвижений.Добавить("ВзаиморасчетыСКонтрагентами");
Если ВыборкаЗапрос = "ДвиженияУПП" Тогда
СписокДвижений.Добавить("Хозрасчетный");
КонецЕсли;
~Возврат:
// Выборка(Отказ)
// тзВыборкаЗапроса - обрабатываемая таблица выборки запроса,
// Выборка - обрабатываемая строка выборки запроса.
// По умолчанию обрабатывается результат запроса, показанный в форме консоли,
// при выполнении функции ЗапросВыполнить() - автоматически не обновляется!
// В событии ПередВыборкой() тзВыборкаЗапроса можно переопределить, если СтандартнаяОбработка = Ложь
// ПослеВыборки(Отказ)
// флагОК, стПарам, Объект, пр0 ... пр9 и ф0, ф1 - переменные модуля формы
Если флагОК <> Истина Тогда
Отказ = Истина;
Перейти ~Возврат;
КонецЕсли;
ВыборкаЗапрос = СокрЛП(ДополнительныеСвойства["ВыборкаЗапрос"]);
Если ПустаяСтрока(ВыборкаЗапрос) Тогда
ВыборкаЗапрос = ЭтотЗапрос;
КонецЕсли;
Отказ = Ложь;
СписокДвижений = ДополнительныеСвойства["СписокДвижений"];
Если СписокДвижений.Количество() = 0 Тогда
Сообщить("Не задан список корректируемых регистров !", СтатусСообщения.Внимание);
Отказ = Истина;
КонецЕсли;
Если Отказ = Ложь И ДополнительныеСвойства["ВыборкаОбновить"] = Истина Тогда
Рез = Обработка.ЗапросВыполнить(ВыборкаЗапрос,);
Если Рез <> Истина Тогда
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Если Отказ <> Истина Тогда
тзРезультат = Обработка.РезультатПолучить(ВыборкаЗапрос,0,"Список");
Если Обработка.ЛокIsEmpty(ВыборкаЗапрос.тзРезультаты,Истина) = Истина Тогда
Сообщить("Таблица с результатами выполнения пакета запросов - пустая !", СтатусСообщения.Внимание);
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Если Отказ = Истина Тогда
Перейти ~Возврат;
КонецЕсли;
СвойстваЗапрос = СокрЛП(ДополнительныеСвойства["СвойстваЗапрос"]);
стПарам = Неопределено;
Если НЕ ПустаяСтрока(СвойстваЗапрос) Тогда
стПарам = ПараметрыЗапроса(СвойстваЗапрос,);
//ViewValue(стПарам,""Структура параметров запроса '""+СвойстваЗапрос+""' для установки свойств документа-регистратора"")
КонецЕсли;
ИмяРегистратора = ДополнительныеСвойства["ИмяРегистратора"];
Комментарий = ДополнительныеСвойства["Комментарий"];
НомерДок = ДополнительныеСвойства["НомерДок"];
ДатаДок = ДополнительныеСвойства["ДатаДок"]; ДатаДок = ?(ЗначениеЗаполнено(ДатаДок),ДатаДок,ТекущаяДата());
МетаРегистратор = Метаданные.Документы[ИмяРегистратора];
Ссылка = Документы[ИмяРегистратора].НайтиПоНомеру(НомерДок,?(ЗначениеЗаполнено(ДатаДок),ДатаДок,Неопределено));
Если ЗначениеЗаполнено(Ссылка) Тогда
Объект = Ссылка.ПолучитьОбъект();
Если Объект.ПометкаУдаления Тогда
// сбрасываем пометку удаления
Объект.ПометкаУдаления = Ложь;
КонецЕсли;
Если Объект.Проведен Тогда
// сбрасываем флаг проведения
Объект.Проведен = Ложь;
КонецЕсли;
// сбрасываем флаг заполнения по конкретным документам
Если ИмяРегистратора = "КорректировкаЗаписейРегистров" Тогда
Объект.ИспользоватьЗаполнениеДвижений = Ложь;
Иначе
СпособЗаполнения = "Вручную";
КонецЕсли;
// для существующего документа очищаем табличные части
Для каждого МетаТЧ Из МетаРегистратор.ТабличныеЧасти Цикл
Объект[МетаТЧ.Имя].Очистить();
КонецЦикла;
// для существующего документа чистим движения
Для каждого Движение Из Объект.Движения Цикл
Движение.Очистить();
КонецЦикла;
Объект.Дата = ДатаДок;
Иначе
Объект = Документы[ИмяРегистратора].СоздатьДокумент();
Объект.Дата = ДатаДок;
Если ПустаяСтрока(НомерДок) Тогда
Объект.УстановитьНовыйНомер("");
Иначе
Объект.Номер = НомерДок;
КонецЕсли;
КонецЕсли;
Если стПарам <> Неопределено Тогда
ЗаполнитьЗначенияСвойств(Объект, стПарам);
КонецЕсли;
Объект.Ответственный = глЗначениеПеременной("глТекущийПользователь");
Объект.Комментарий = Комментарий + "; Выполненно: "+ТекущаяДата();
ИндексБатча = 0;
Для каждого ИмяРег Из СписокДвижений Цикл
// загружаем таблицу движений из результата выполнения пакета запросов по индексу регистра в списке
тзРезультат = Обработка.РезультатПолучить(ВыборкаЗапрос,ИндексБатча,"Список",Истина);
Объект.Движения[ИмяРег].Загрузить(тзРезультат);
// заполняем табличные части
МетаРег1 = Метаданные.РегистрыСведений.Найти(ИмяРег);
МетаРег2 = Метаданные.РегистрыНакопления.Найти(ИмяРег);
МетаРег3 = Метаданные.РегистрыБухгалтерии.Найти(ИмяРег);
МетаРег4 = Метаданные.РегистрыРасчета.Найти(ИмяРег);
Если МетаРег1 <> Неопределено Тогда
Стр = Объект.ТаблицаРегистровСведений.Добавить();
Стр.Имя = ИмяРег;
Стр.Представление = МетаРег1.Синоним;
ИначеЕсли МетаРег2 <> Неопределено Тогда
Стр = Объект.ТаблицаРегистровНакопления.Добавить();
Стр.Имя = ИмяРег;
Стр.Представление = МетаРег2.Синоним;
ИначеЕсли МетаРег3 <> Неопределено Тогда
Если ИмяРегистратора = "КорректировкаЗаписейРегистров" Тогда
Стр = Объект.ТаблицаРегистровБухгалтерии.Добавить();
Стр.Имя = ИмяРег;
Стр.Представление = МетаРег3.Синоним;
КонецЕсли;
ИначеЕсли МетаРег4 <> Неопределено Тогда
КонецЕсли;
ИндексБатча = ИндексБатча + 1;
КонецЦикла;
Еррор = Ложь;
Попытка
Объект.Проведен = Истина;
Объект.Записать(РежимЗаписиДокумента.Запись,РежимПроведенияДокумента.Неоперативный);
Исключение
Еррор = Истина;
Сообщить(ОписаниеОшибки(),СтатусСообщения.Важное);
КонецПопытки;
Если Еррор = Ложь Тогда
Объект.ПолучитьФорму(,,).Открыть();
КонецЕсли;
Объект = Неопределено;
~Возврат: