Создание процедуры расчета записей регистра Начисления
До сих пор мы с вами просто заносили в регистр расчета "Начисления" записи о том, что необходимо выполнить какой-либо вид расчета. Но каким именно образом получать эти результаты мы не говорили. Теперь настало время описать алгоритмы формирования различных видов расчетов.
Поскольку эти алгоритмы нам понадобится использовать не только в документе "Начисление сотрудникам", удобнее всего будет разместить их в отдельном общем модуле.
Откроем в конфигураторе текст обработчика проведения документа "НачислениеСотрудникам" и добавим в него вызов процедуры из общего модуля:
Процедура ОбработкаПроведения(Отказ, Режим)
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаНачисления Из Начисления Цикл
// регистр Начисления
Движение = Движения.Начисления.Добавить();
Движение.Сторно = Ложь;
Движение.ВидРасчета = ТекСтрокаНачисления.ВидРасчета;
Движение.ПериодДействияНачало = ТекСтрокаНачисления.ДатаНачала;
Движение.ПериодДействияКонец = КонецДня(ТекСтрокаНачисления.ДатаОкончания);
Движение.ПериодРегистрации = ТекСтрокаНачисления.ДатаНачала;
Движение.БазовыйПериодНачало = ТекСтрокаНачисления.ДатаНачала;
Движение.БазовыйПериодКонец = КонецДня(ТекСтрокаНачисления.ДатаОкончания);
Движение.Сотрудник = ТекСтрокаНачисления.Сотрудник;
Движение.ГрафикРаботы = ТекСтрокаНачисления.ГрафикРаботы;
Движение.ИсходныеДанные = ТекСтрокаНачисления.Результат;
КонецЦикла;
// записываем движения регистров
Движения.Начисления.Записать();
// получим список всех сотрудников, содержащихся в документе
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| НачисленияСотрудникамНачисления.Сотрудник [349]
|ИЗ
| Документ.НачисленияСотрудникам.Начисления КАК НачисленияСотрудникамНачисления
|ГДЕ
| НачисленияСотрудникамНачисления.Ссылка = &ТекущийДокумент");
Запрос.УстановитьПараметр("ТекущийДокумент", Ссылка);
//сформируем список сотрудников
ТаблЗнач = Запрос.Выполнить().Выгрузить();
МассивСотрудников = ТаблЗнач.ВыгрузитьКолонку("Сотрудник");
СписокСотрудников = Новый СписокЗначений;
СписокСотрудников.ЗагрузитьЗначения(МассивСотрудников);
РасчитатьНачисления(Движения.Начисления, ПланыВидовРасчета.ОсновныеНачисления.Оклад, СписокСотрудников);
Движения.Начисления.Записать(,Истина);
РасчитатьНачисления(Движения.Начисления, ПланыВидовРасчета.ОсновныеНачисления.Премия, СписокСотрудников);
Движения.Начисления.Записать(,Истина);
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Перед вызовом процедуры из общего модуля мы формируем список сотрудников, содержащихся в документе, чтобы передать его в вызываемую процедуру. [350]
Теперь создадим в ветке "Общие" новый общий модуль "ПроведениеРасчетов". Добавим в него заготовку процедуры "РасчитатьНачисления":
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
КонецЕсли;
КонецПроцедуры
При расчете первичных записей нам понадобятся данные графика из регистра расчета, поэтому добавим в первую ветку условия запрос по виртуальной таблице регистра расчета "РегистрРасчета.Начисления.ДанныеГрафика":
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияДанныеГрафика.ЗначениеПериодДействия КАК Норма,
| НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия КАК Факт,
| НачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.ДанныеГрафика(
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);[351]
Запрос.УстановитьПараметр("ВидРасчета", ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников",СписокСотрудников);
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
КонецЕсли;
КонецПроцедуры
Теперь добавим обход переданного в процедуру набора записей и расчет записей, для которых получены значения графика:
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияДанныеГрафика.ЗначениеПериодДействия КАК Норма,
| НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия КАК Факт,
| НачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.ДанныеГрафика(
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ВидРасчета", ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников",СписокСотрудников);[352]
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл
СтруктураНомер = Новый Структура("НомерСтроки");
СтруктураНомер.НомерСтроки = ЗаписьРегистра.НомерСтроки;
ВыборкаРезультата.Сбросить();
Если ВыборкаРезультата.НайтиСледующий(СтруктураНомер) Тогда
Если ВыборкаРезультата.Норма = 0 Тогда
Сообщить("Вид расчета: Оклад - Нет рабочих дней в заданном периоде",);
ЗаписьРегистра.Результат = 0;
Иначе
// рассчитать оклад по фактическому периоду и исходным данным
ЗаписьРегистра.Результат = (ЗаписьРегистра.ИсходныеДанные / ВыборкаРезультата.Норма) * ВыборкаРезультата.Факт;
Сообщить("Выполнен расчет "+ЗаписьРегистра.Регистратор+" - "+ЗаписьРегистра.ВидРасчета+" - "+ЗаписьРегистра.Сотрудник,);
КонецЕсли;
КонецЕсли;
КонецЦикла;
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
КонецЕсли;
КонецПроцедуры
Теперь добавим текст запроса во вторую ветку условия Если... с той лишь разницей, что теперь мы будем получать значения базы, используя виртуальную таблицу регистра расчета "РегистрРасчета.Начисления.БазаНачисления":
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
...
// Рассчитать вторичные записи [353]
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияБазаНачисления.РезультатБаза КАК База,
| НачисленияБазаНачисления.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.БазаНачисления(
| &ИзмеренияОсновного,
| &ИзмеренияБазового,
| ,
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияБазаНачисления";
Измер = Новый Массив(1);
Измер[0] = "Сотрудник";
Запрос.УстановитьПараметр("ИзмеренияОсновного", Измер);
Запрос.УстановитьПараметр("ИзмеренияБазового", Измер);
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ВидРасчета",ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников", СписокСотрудников);
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
КонецЕсли;
КонецПроцедуры
В заключение осталось добавить во второе условие Если... обход набора записей регистра расчета и вычисление результата вторичных записей:
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
... [354]
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияБазаНачисления.РезультатБаза КАК База,
| НачисленияБазаНачисления.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.БазаНачисления(
| &ИзмеренияОсновного,
| &ИзмеренияБазового,
| ,
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияБазаНачисления";
Измер = Новый Массив(1);
Измер[0] = "Сотрудник";
Запрос.УстановитьПараметр("ИзмеренияОсновного", Измер);
Запрос.УстановитьПараметр("ИзмеренияБазового", Измер);
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ВидРасчета",ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников", СписокСотрудников);
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл
СтруктураНомер = Новый Структура("НомерСтроки");
СтруктураНомер.НомерСтроки = ЗаписьРегистра.НомерСтроки;
ВыборкаРезультата.Сбросить();
Если ВыборкаРезультата.НайтиСледующий(СтруктураНомер) Тогда
ЗаписьРегистра.Результат = ВыборкаРезультата.База * (10/100);
Сообщить("Выполнен расчет "+ЗаписьРегистра.Регистратор+" - "+ЗаписьРегистра.ВидРасчета+" - "+ЗаписьРегистра.Сотрудник,);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и проверим правильность работы процедуры расчета.
Отменим проведение документа Начисление сотрудникам №3 и перепроведем документы Начисление сотрудникам №1 и №2. Регистр расчета Начисления должен выглядеть следующим образом:
Гусакову и Деловому начислена премия в размере 10% от суммы начисления по окладу.
Проведем документ Начисление сотрудникам №3, а затем №1 и№2. Состояние регистра изменится следующим образом:
В результате невыхода Гусакова на работу, сумма его оплаты по окладу будет уменьшена и соответствующим образом уменьшится начисленная ему премия. [356]