- •От автора курса
- •Содержание Урок 1.
- •Урок 2.
- •Урок 3.
- •Урок 4.
- •Занятие 1.01
- •Занятие 1.02
- •Занятие 1.03
- •Занятие 1.04
- •Занятие 1.05
- •Занятие 1.06
- •Занятие 1.07
- •Занятие 1.08
- •Занятие 1.09
- •Занятие 1.10
- •Занятие 1.11
- •Занятие 1.12
- •Занятие 1.13
- •Занятие 1.14
- •Занятие 1.15
- •Занятие 1.16
- •Занятие 1.17
- •Занятие 1.18
- •Занятие 2.19
- •С корреспонденцией
- •Без корреспонденции
- •Занятие 2.20
- •Занятие 2.21
- •Занятие 2.22
- •Занятие 2.23
- •Занятие 2.24
- •Занятие 3.25 расчет
- •Занятие 3.26
- •Занятие 3.27
- •Занятие 3.28
- •Занятие 3.29
- •Занятие 3.30
- •Перерасчеты
Занятие 3.30
Оптимизация работы с Регистрами расчета
Общий модуль «Расчеты» - процедура «Рассчитать»:
Данные по Норме и Факту дней, а также дополнительные данные, которые нам понадобятся для расчета записей регистра, получим с помощью запроса:
Чтобы между этим запросом и запросом, который будет получать Базу, можно было передавать данные, получим Менеджер временных таблиц. В запросе нам надо получить то же самое, что мы получали при расчете Основных начислений:
Можно обратиться к реальной таблице или таблице «ДанныеГрафика». Они практически идентичны, но у таблицы «ДанныеГрафика» есть дополнительные поля. Они автоматически рассчитываются системой и представляют собой Количество отработанных дней за указанный период:
Действия.
Фактический.
Базовый.
Регистрации.
Установим параметры виртуальной таблицы «НачисленияСотрудниковДанныеГрафика»:
В параметрах установим отбор по документу-регистратору и по периоду регистрации. Отбор по периоду регистрации не повлияет на результат выборки, но увеличит скорость отработки, т.к. Индекс таблицы Данные графика составной:
Документ + ПериодРегистрации.
Поля:
НомерСтроки – нужен для получения результата записи – суммы.
Приоритет – нужен для отбора данных при получении таблицы Базы (ограничение данных Базы только нужным Приоритетом).
ПризнакПериодДействия – норма дней.
ПризнакФактическийПериодДействия – факт дней.
Назначим псевдонимы:
Итого процедура «Рассчитать»:
Процедура Рассчитать(Регистратор) Экспорт
// получим копию набора записей регистра
НаборЗаписей = РегистрыРасчета.НачисленияСотрудников.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписей.Прочитать();
Запрос = Новый Запрос;
МВТ = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияСотрудниковДанныеГрафика.НомерСтроки,
| НачисленияСотрудниковДанныеГрафика.ВидРасчета.Способ КАК Способ,
| НачисленияСотрудниковДанныеГрафика.ВидРасчета.УвеличиваетОтработанныеДни
КАК УвеличиваетОтработанныеДни,
| НачисленияСотрудниковДанныеГрафика.ВидРасчета.Приоритет КАК Приоритет,
| НачисленияСотрудниковДанныеГрафика.Сторно,
| НачисленияСотрудниковДанныеГрафика.Параметр,
| НачисленияСотрудниковДанныеГрафика.ПризнакПериодДействия КАК НормаДней,
| НачисленияСотрудниковДанныеГрафика.ПризнакФактическийПериодДействия КАК ФактДней
|ПОМЕСТИТЬ ДанныеГрафика
|ИЗ
| РегистрРасчета.НачисленияСотрудников.ДанныеГрафика(
| Регистратор = &Регистратор
| И ПериодРегистрации = &ПериодРегистрации) КАК НачисленияСотрудниковДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", Регистратор);
Запрос.УстановитьПараметр("ПериодРегистрации", НачалоМесяца(Регистратор.Дата));
Запрос.Выполнить();
//Получим копию набора записей регистра
ДопНаборЗаписей = РегистрыРасчета.ДопНачисления.СоздатьНаборЗаписей();
ДопНаборЗаписей.Отбор.Регистратор.Установить(Регистратор);
ДопНаборЗаписей.Прочитать();
СписокПриоритетов = ПолучитьСписокПриоритетов(Регистратор);
Для Каждого Приоритет Из СписокПриоритетов Цикл
РассчитатьОсновные(НаборЗаписей, МВТ, Приоритет);
РассчитатьДополнительные(ДопНаборЗаписей, Приоритет);
КонецЦикла;
КонецПроцедуры
Параметр «ПериодРегистрации» - берем дату документа-регистратора. Значение параметра должно быть равно первому числу периода, за который будут вычисляться данные.
Результат запроса поместим во временную таблицу «ДанныеГрафика»:
|ПОМЕСТИТЬ ДанныеГрафика
Поместим объект с результатом запроса (МВТ) в память – выполним запрос:
Запрос.Выполнить();
МВТ передадим в процедуру «РассчитатьОсновные()».
В процедуре «РассчитатьОсновные()» объектный метод получения Базы заменим на запрос:
Было:
ОтборПоИзмерениям = Новый Структура;
ОтборПоИзмерениям.Вставить("Сотрудник", "НачисленияСотрудников.Сотрудник");
СписокРесурсов = Новый Массив(2);
СписокРесурсов[0] = "НачисленияСотрудников.Сумма";
СписокРесурсов[1] = "НачисленияСотрудников.ОтработаноДней";
ОтборПоРегистратору = Новый Структура;
Регистратор = НаборЗаписей.Отбор.Регистратор.Значение;
ОтборПоРегистратору.Вставить("Регистратор", Регистратор);
ТЗ_База = РегистрыРасчета.НачисленияСотрудников.ПолучитьБазу(
ОтборПоРегистратору,
СписокРесурсов,
ОтборПоИзмерениям);
В конструкторе запроса опишем виртуальную таблицу «ДанныеГрафика», которую мы передали в процедуру:
К ней надо присоединить таблицу с Базой регистра расчета «НачисленияСотрудников». Опишем параметры данной виртуальной таблицы:
Первые два параметра – это как отбор по измерениям в объектной модели. Базу надо получать только по одному сотруднику, поэтому в измерения Основного и Базового регистра надо передать два массива:
1. «ИзмеренияОсновногоРегистра» - названия полей набора записей регистра, который содержит значения отбора. В примере это поле «Сотрудник».
2. «ИзмеренияБазовогоРегистра» - названия измерений в Базовом регистре, в котором установится отбор.
Т.к. в примере Базу получаем саму из себя, то отбор устанавливается также по Измерению «Сотрудник».
Условия:
«Регистратор = &Регистратор» - это отбор по документу, т.к. База нам нужна только по одному документу.
«ПериодРегистрации = &ПериодРегистрации» - для увеличения быстродействия. Поле «ПериодРегистрации» состоит в индексе таблицы регистра.
«ВидРасчета.Приоритет = &Приоритет» - это отбор по определенному Приоритету.
НомерСтроки – это единственное поле, точно идентифицирующее запись по позиции регистратора.
Поля:
НормаДней
ФактДней
База
БазаДней
могут быть не рассчитаны, т.е. вернут NULL, поэтому воспользуемся функцией ЕСТЬNULL.
Итого запрос:
ВЫБРАТЬ
ДанныеГрафика.НомерСтроки,
ДанныеГрафика.Способ,
ДанныеГрафика.УвеличиваетОтработанныеДни,
ДанныеГрафика.Приоритет,
ДанныеГрафика.Сторно,
ДанныеГрафика.Параметр,
ЕСТЬNULL(ДанныеГрафика.НормаДней, 0) КАК НормаДней,
ЕСТЬNULL(ДанныеГрафика.ФактДней, 0) КАК ФактДней,
ЕСТЬNULL(НачисленияСотрудниковБазаНачисленияСотрудников.СуммаБаза, 0) КАК База,
ЕСТЬNULL(НачисленияСотрудниковБазаНачисленияСотрудников.ОтработаноДнейБаза, 0) КАК БазаДней
ИЗ
ДанныеГрафика КАК ДанныеГрафика
ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.НачисленияСотрудников.БазаНачисленияСотрудников(
&МассивМзмерений,
&МассивМзмерений,
,
Регистратор = &Регистратор
И ПериодРегистрации = &ПериодРегистрации
И ВидРасчета.Приоритет = &Приоритет) КАК НачисленияСотрудниковБазаНачисленияСотрудников
ПО ДанныеГрафика.НомерСтроки = НачисленияСотрудниковБазаНачисленияСотрудников.НомерСтроки
ГДЕ
ДанныеГрафика.Приоритет = &Приоритет
Итого код:
Процедура Рассчитать(Регистратор) Экспорт
// получим копию набора записей регистра
НаборЗаписей = РегистрыРасчета.НачисленияСотрудников.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписей.Прочитать();
//ОтборПоРегистратору = Новый Структура;
//ОтборПоРегистратору.Вставить("Регистратор", Регистратор);
//
//ТЗ_ФактДней = РегистрыРасчета.НачисленияСотрудников.ПолучитьДанныеГрафика(
//ОтборПоРегистратору,
//ВидПериодаРегистраРасчета.ФактическийПериодДействия);
//
//ТЗ_НормаДней = РегистрыРасчета.НачисленияСотрудников.ПолучитьДанныеГрафика(
//ОтборПоРегистратору,
//ВидПериодаРегистраРасчета.ПериодДействия);
//ТЗ_БазаДней = РегистрыРасчета.НачисленияСотрудников.ПолучитьДанныеГрафика(
//ОтборПоРегистратору,
//ВидПериодаРегистраРасчета.БазовыйПериод);
Запрос = Новый Запрос;
МВТ = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияСотрудниковДанныеГрафика.НомерСтроки,
| НачисленияСотрудниковДанныеГрафика.ВидРасчета.Способ КАК Способ,
| НачисленияСотрудниковДанныеГрафика.ВидРасчета.УвеличиваетОтработанныеДни
КАК УвеличиваетОтработанныеДни,
| НачисленияСотрудниковДанныеГрафика.ВидРасчета.Приоритет КАК Приоритет,
| НачисленияСотрудниковДанныеГрафика.Сторно,
| НачисленияСотрудниковДанныеГрафика.Параметр,
| НачисленияСотрудниковДанныеГрафика.ПризнакПериодДействия КАК НормаДней,
| НачисленияСотрудниковДанныеГрафика.ПризнакФактическийПериодДействия КАК ФактДней
|ПОМЕСТИТЬ ДанныеГрафика
|ИЗ
| РегистрРасчета.НачисленияСотрудников.ДанныеГрафика(
| Регистратор = &Регистратор
| И ПериодРегистрации = &ПериодРегистрации) КАК НачисленияСотрудниковДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", Регистратор);
Запрос.УстановитьПараметр("ПериодРегистрации", НачалоМесяца(Регистратор.Дата));
Запрос.Выполнить();
//Получим копию набора записей регистра
ДопНаборЗаписей = РегистрыРасчета.ДопНачисления.СоздатьНаборЗаписей();
ДопНаборЗаписей.Отбор.Регистратор.Установить(Регистратор);
ДопНаборЗаписей.Прочитать();
СписокПриоритетов = ПолучитьСписокПриоритетов(Регистратор);
Для Каждого Приоритет Из СписокПриоритетов Цикл
РассчитатьОсновные(НаборЗаписей, МВТ, Приоритет);
РассчитатьДополнительные(ДопНаборЗаписей, Приоритет);
КонецЦикла;
КонецПроцедуры
Процедура РассчитатьОсновные(НаборЗаписей, МВТ, Приоритет)
//ОтборПоИзмерениям = Новый Структура;
//ОтборПоИзмерениям.Вставить("Сотрудник", "НачисленияСотрудников.Сотрудник");
//
//СписокРесурсов = Новый Массив(2);
//СписокРесурсов[0] = "НачисленияСотрудников.Сумма";
//СписокРесурсов[1] = "НачисленияСотрудников.ОтработаноДней";
//
//ОтборПоРегистратору = Новый Структура;
//Регистратор = НаборЗаписей.Отбор.Регистратор.Значение;
//ОтборПоРегистратору.Вставить("Регистратор", Регистратор);
//
//ТЗ_База = РегистрыРасчета.НачисленияСотрудников.ПолучитьБазу(
//ОтборПоРегистратору,
//СписокРесурсов,
//ОтборПоИзмерениям);
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ДанныеГрафика.НомерСтроки,
| ДанныеГрафика.Способ,
| ДанныеГрафика.УвеличиваетОтработанныеДни,
| ДанныеГрафика.Приоритет,
| ДанныеГрафика.Сторно,
| ДанныеГрафика.Параметр,
| ЕСТЬNULL(ДанныеГрафика.НормаДней, 0) КАК НормаДней,
| ЕСТЬNULL(ДанныеГрафика.ФактДней, 0) КАК ФактДней,
| ЕСТЬNULL(НачисленияСотрудниковБазаНачисленияСотрудников.СуммаБаза, 0) КАК База,
| ЕСТЬNULL(НачисленияСотрудниковБазаНачисленияСотрудников.ОтработаноДнейБаза, 0) КАК БазаДней
|ИЗ
| ДанныеГрафика КАК ДанныеГрафика
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.НачисленияСотрудников.БазаНачисленияСотрудников(
| &МассивМзмерений,
| &МассивМзмерений,
| ,
| Регистратор = &Регистратор
| И ПериодРегистрации = &ПериодРегистрации
| И ВидРасчета.Приоритет = &Приоритет)
КАК НачисленияСотрудниковБазаНачисленияСотрудников
| ПО ДанныеГрафика.НомерСтроки = НачисленияСотрудниковБазаНачисленияСотрудников.НомерСтроки
|ГДЕ
| ДанныеГрафика.Приоритет = &Приоритет";
Массив = Новый Массив(1);
Массив[0] = "Сотрудник";
Запрос.УстановитьПараметр("МассивМзмерений", Массив);
Запрос.УстановитьПараметр("Регистратор", НаборЗаписей.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ПериодРегистрации", НачалоМесяца(НаборЗаписей.Отбор.Регистратор.Значение.Дата));
Запрос.УстановитьПараметр("Приоритет", Приоритет);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Запись = НаборЗаписей[Выборка.НомерСтроки - 1];
База = Выборка.База;
СпособРасчета = Выборка.Способ;
ФактДней = Выборка.ФактДней;
НормаДней = Выборка.НормаДней;
БазаДней = Выборка.БазаДней;
Параметр = Выборка.Параметр;
УвеличиваетОтработанныеДни = Запись.ВидРасчета.УвеличиваетОтработанныеДни;
//Для Каждого Запись Из НаборЗаписей Цикл
//
// Если Запись.ВидРасчета.Приоритет <> Приоритет Тогда
// Продолжить;
// КонецЕсли;
//
// //Индекс = Запись.НомерСтроки - 1;
// Индекс = НаборЗаписей.Индекс(Запись);
// База = ТЗ_База[Индекс].Сумма;
// СпособРасчета = Запись.ВидРасчета.Способ;
// ФактДней = ТЗ_ФактДней[Индекс].Признак;
// НормаДней = ТЗ_НормаДней[Индекс].Признак;
// //БазаДней = ТЗ_БазаДней[Индекс].Признак;
// БазаДней = ТЗ_База[Индекс].ОтработаноДней;
// Параметр = Запись.Параметр;
// УвеличиваетОтработанныеДни = Запись.ВидРасчета.УвеличиваетОтработанныеДни;
Если СпособРасчета = Перечисления.СпособыРасчета.Процентом Тогда
Запись.Сумма = База * Параметр / 100;
ИначеЕсли СпособРасчета = Перечисления.СпособыРасчета.ФиксированнаяСумма Тогда
Запись.Сумма = Параметр;
ИначеЕсли СпособРасчета = Перечисления.СпособыРасчета.ПоДням Тогда
Запись.Сумма = ФактДней * Параметр;
ИначеЕсли СпособРасчета = Перечисления.СпособыРасчета.ПропорциональноОтработанномуВремени Тогда
Запись.Сумма = ФактДней / НормаДней * Параметр;
ИначеЕсли СпособРасчета = Перечисления.СпособыРасчета.ПоСреднему Тогда
Запись.Сумма = База / БазаДней * ФактДней * Параметр / 100;
КонецЕсли;
Если УвеличиваетОтработанныеДни тогда
Запись.ОтработаноДней = ФактДней;
КонецЕсли;
Если Запись.Сторно Тогда
Запись.Сумма = - Запись.Сумма;
Запись.ОтработаноДней = - Запись.ОтработаноДней;
КонецЕсли;
КонецЦикла;
НаборЗаписей.Записать( , , Ложь);
КонецПроцедуры
Процедура РассчитатьДополнительные(НаборЗаписей, Приоритет)
ОтборПоИзмерениям = Новый Структура;
ОтборПоИзмерениям.Вставить("Сотрудник", "НачисленияСотрудников.Сотрудник,
|ДопНачисления.Сотрудник");
СписокРесурсов = Новый Массив(1);
СписокРесурсов[0] = "НачисленияСотрудников.Сумма, ДопНачисления.Сумма";
ОтборПоРегистратору = Новый Структура;
Регистратор = НаборЗаписей.Отбор.Регистратор.Значение;
ОтборПоРегистратору.Вставить("Регистратор", Регистратор);
ТЗ_База = РегистрыРасчета.ДопНачисления.ПолучитьБазу(
ОтборПоРегистратору,
СписокРесурсов,
ОтборПоИзмерениям);
Для Каждого Запись Из НаборЗаписей Цикл
Если Запись.ВидРасчета.Приоритет <> Приоритет Тогда
Продолжить;
КонецЕсли;
Индекс = НаборЗаписей.Индекс(Запись);
База = ТЗ_База[Индекс].Сумма;
СпособРасчета = Запись.ВидРасчета.Способ;
Параметр = Запись.Параметр;
Если СпособРасчета = Перечисления.СпособыРасчета.Процентом Тогда
Запись.Сумма = База * Параметр / 100;
ИначеЕсли СпособРасчета = Перечисления.СпособыРасчета.ФиксированнаяСумма Тогда
Запись.Сумма = Параметр;
КонецЕсли;
Если Запись.Сторно Тогда
Запись.Сумма = - Запись.Сумма;
КонецЕсли;
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры
Функция ПолучитьСписокПриоритетов(Регистратор)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВложенныйЗапрос.Приоритет КАК Приоритет
|ИЗ
| (ВЫБРАТЬ
| НачисленияСотрудников.ВидРасчета.Приоритет КАК Приоритет
| ИЗ
| РегистрРасчета.НачисленияСотрудников КАК НачисленияСотрудников
| ГДЕ
| НачисленияСотрудников.Регистратор = &Регистратор
|
| ОБЪЕДИНИТЬ
|
| ВЫБРАТЬ
| ДопНачисления.ВидРасчета.Приоритет
| ИЗ
| РегистрРасчета.ДопНачисления КАК ДопНачисления
| ГДЕ
| ДопНачисления.Регистратор = &Регистратор) КАК ВложенныйЗапрос
|
|УПОРЯДОЧИТЬ ПО
| Приоритет";
Запрос.УстановитьПараметр("Регистратор", Регистратор);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Возврат РезультатЗапроса.ВыгрузитьКолонку("Приоритет");
КонецФункции
В режиме исполнения:
Перепроведем документ «Ввод произвольных начислений» № 000000007:
Было:
Стало:
Аналогично. Вывод: начисление считается правильно.
