584 документа
← К списку

В 1C:EDT

страница

Процедура расчета записей регистра расчета

В 1C:EDT

До сих пор вы просто заносили в регистр расчета Начисления записи о том, что необходимо выполнить какой-либо вид расчета. Но каким именно образом получать эти результаты, вы не указывали.

Теперь настало время описать алгоритмы формирования различных видов расчетов.

Поскольку эти алгоритмы нужно будет использовать не только в документе Начисление сотрудникам, удобнее всего будет разместить их в отдельном общем модуле.

Откройте в модуле документа НачисленияСотрудникам процедуру обработчика проведения и добавьте в нее после завершения создания движений в регистре Начисления вызов процедуры РассчитатьНачисления() из общего модуля ПроведениеРасчетов (листинг 19.2).

Листинг 19.2. Обработчик проведения документа «НачисленияСотрудникам»

Процедура ОбработкаПроведения(Отказ, Режим)

…

КонецЦикла;

 

// Записать движения регистров.

Движения.Начисления.Записать();

 

// Получить список всех сотрудников, содержащихся в документе.

Запрос = Новый Запрос(

"ВЫБРАТЬ РАЗЛИЧНЫЕ

|   НачисленияСотрудникамНачисления.Сотрудник

|ИЗ

|   Документ.НачисленияСотрудникам.Начисления КАК НачисленияСотрудникамНачисления

|

|ГДЕ

|   НачисленияСотрудникамНачисления.Ссылка = &ТекущийДокумент");

 

Запрос.УстановитьПараметр("ТекущийДокумент", Ссылка);

 

// Сформировать список сотрудников.

ТаблЗнач = Запрос.Выполнить().Выгрузить();

МассивСотрудников = ТаблЗнач.ВыгрузитьКолонку("Сотрудник");

 

// Вызов процедуры РассчитатьНачисления из общего модуля

ПроведениеРасчетов.РассчитатьНачисления(Движения.Начисления, ПланыВидовРасчета.ОсновныеНачисления.Оклад, МассивСотрудников);

Движения.Начисления.Записать( , Истина);

 

ПроведениеРасчетов.РассчитатьНачисления(Движения.Начисления, ПланыВидовРасчета.ОсновныеНачисления.Премия, МассивСотрудников);

Движения.Начисления.Записать( , Истина);

 

КонецПроцедуры

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

Эту процедуру вы вызываете сначала для расчета первичных записей (Оклад), а затем для расчета вторичных (Премия).

Процедура расчета на основе описанных в ней алгоритмов и данных, содержащихся в записях регистра, должна сформировать значения ресурсов регистра.

После того как ресурсы будут рассчитаны, вы перезаписываете набор записей регистра без формирования записей перерасчета (второй параметр в методе Записать() – Истина).

Перед вызовом процедуры из общего модуля вы с помощью запроса формируете массив сотрудников, перечисленных в документе, чтобы передать его в вызываемую процедуру.

Для параметра запроса ТекущийДокумент вы устанавливаете значение стандартного реквизита документа – Ссылка. Используя метод запроса Запрос.Выполнить().Выгрузить(), выгружаете результат запроса в таблицу значений (переменную ТаблЗнач). Затем формируете массив МассивСотрудников, содержащий колонку Сотрудник из этой таблицы значений.

Теперь создайте новый общий модуль ПроведениеРасчетов.

Установите флажок Вызов сервера для видимости его экспортных процедур и функций (рис. 19.10).

Рис. 19.10. Свойства общего модуля

Добавьте в него заготовку процедуры РассчитатьНачисления() (листинг 19.3).

Листинг 19.3. Заготовка процедуры «РассчитатьНачисления()»

Процедура РассчитатьНачисления(НаборЗаписейРегистра, ТребуемыйВидРасчета, СписокСотрудников) Экспорт

 

Регистратор = НаборЗаписейРегистра.Отбор.Регистратор.Значение;

 

// Рассчитать первичные записи.

Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда

 

// Рассчитать вторичные записи.

ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда

 

КонецЕсли;

 

КонецПроцедуры

Алгоритм расчета начислений будет различным при расчете первичных (вид расчета – Оклад) и вторичных записей (вид расчета – Премия), и каждая из его частей будет находиться в своей ветке условия Если...

При расчете первичных записей вам понадобятся данные графика из регистра расчета, поэтому добавьте в первую ветку условия запрос к виртуальной таблице регистра расчета РегистрРасчета.Начисления.ДанныеГрафика (листинг 19.4).

Листинг 19.4. Изменение процедуры «РассчитатьНачисления()»

Процедура РассчитатьНачисления(НаборЗаписейРегистра, ТребуемыйВидРасчета, СписокСотрудников) Экспорт

 

Регистратор = НаборЗаписейРегистра.Отбор.Регистратор.Значение;

 

// Рассчитать первичные записи.

Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда

 

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

|   ЕСТЬNULL(НачисленияДанныеГрафика.ЗначениеПериодДействия, 0) КАК Норма,

|   ЕСТЬNULL(НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия, 0) КАК Факт,

|   НачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки

|ИЗ

|   РегистрРасчета.Начисления.ДанныеГрафика(Регистратор = &Регистратор И ВидРасчета = &ВидРасчета И Сотрудник В (&СписокСотрудников))

|   КАК НачисленияДанныеГрафика";

Запрос.УстановитьПараметр("Регистратор", Регистратор);

Запрос.УстановитьПараметр("ВидРасчета", ТребуемыйВидРасчета);

Запрос.УстановитьПараметр("СписокСотрудников", СписокСотрудников);

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

 

// Рассчитать вторичные записи.

ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда

 

КонецЕсли;    

 

КонецПроцедуры

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

Кроме того, вы проверяете на NULL значения полей записей виртуальной таблицы, удовлетворяющих наложенным условиям. Чтобы можно было использовать эти значения в дальнейших математических расчетах, вы используете функцию ЕстьNULL(), которая заменяет все пустые значения на 0.

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

Теперь добавьте обход переданного в процедуру набора записей и расчет записей, для которых получены значения графика (листинг 19.5).

Листинг 19.5. Добавление обхода набора записей и расчета первичных записей

Процедура РассчитатьНачисления(НаборЗаписейРегистра, ТребуемыйВидРасчета, СписокСотрудников) Эспорт

 

Регистратор = НаборЗаписейРегистра.Отбор.Регистратор.Значение;

 

// Рассчитать первичные записи.

Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда

…

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

 

Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл

СтруктураНомер = Новый Структура("НомерСтроки");

СтруктураНомер.НомерСтроки = ЗаписьРегистра.НомерСтроки;

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

Если ВыборкаРезультата.НайтиСледующий(СтруктураНомер) Тогда

Если ВыборкаРезультата.Норма = 0 Тогда

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "Вид расчета: Оклад – Нет рабочих дней в заданном периоде";

Сообщение.Сообщить();

ЗаписьРегистра.Результат = 0;

Иначе

// Рассчитать оклад по фактическому периоду и исходным данным.

ЗаписьРегистра.Результат = (ЗаписьРегистра.ИсходныеДанные / ВыборкаРезультата.Норма) * ВыборкаРезультата.Факт;

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "Выполнен расчет " + ЗаписьРегистра.Регистратор + " – " + ЗаписьРегистра.ВидРасчета + " – " + ЗаписьРегистра.Сотрудник;

Сообщение.Сообщить();

КонецЕсли;

КонецЕсли;

КонецЦикла;

 

// Рассчитать вторичные записи.

ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда

 

КонецЕсли;    

 

КонецПроцедуры

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

Если в результате запроса есть запись с таким номером строки, вы рассчитываете результат записи регистра расчета. То есть вы получаете начисление по окладу для каждого сотрудника как результат от деления начисленной суммы (поле регистра ИсходныеДанные) на количество рабочих дней в месяце (Норма) и умножения на фактически отработанные рабочие дни (Факт).

Затем добавьте текст запроса во вторую ветку условия Если… – с той лишь разницей, что теперь вы будете получать значения базы, используя виртуальную таблицу регистра расчета РегистрРасчета.Начисления.БазаНачисления (листинг 19.6).

Листинг 19.6. Добавление текста запроса во вторую ветку условия

Процедура РассчитатьНачисления(НаборЗаписейРегистра, ТребуемыйВидРасчета, СписокСотрудников) Экспорт

 

Регистратор = НаборЗаписейРегистра.Отбор.Регистратор.Значение;

 

// Рассчитать первичные записи.    

Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда

…

// Рассчитать вторичные записи.

ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда

 

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

|   НачисленияБазаНачисления.РезультатБаза КАК База,

|   НачисленияБазаНачисления.НомерСтроки КАК НомерСтроки

|ИЗ

|   РегистрРасчета.Начисления.БазаНачисления(&ИзмеренияОсновного,

|        &ИзмеренияБазового, , Регистратор = &Регистратор И ВидРасчета = &ВидРасчета И Сотрудник В (&СписокСотрудников))

|   КАК НачисленияБазаНачисления";

Измер = Новый Массив(1);

Измер[0] = "Сотрудник";

Запрос.УстановитьПараметр("ИзмеренияОсновного", Измер);

Запрос.УстановитьПараметр("ИзмеренияБазового", Измер);

Запрос.УстановитьПараметр("Регистратор", Регистратор);

Запрос.УстановитьПараметр("ВидРасчета", ТребуемыйВидРасчета);

Запрос.УстановитьПараметр("СписокСотрудников", СписокСотрудников);

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

 

КонецЕсли;

 

КонецПроцедуры

В параметрах виртуальной таблицы запроса вы кроме привычных для вас регистратора, вида расчета и списка сотрудников задаете еще измерения основного и базового регистров. В вашем случае это будет один и тот же регистр Начисления, а нужное вам измерение – Сотрудник.

В заключение осталось добавить во второе условие Если… обход набора записей регистра расчета и вычисление результата вторичных записей (листинг 19.7).

Листинг 19.7. Добавление обхода набора записей регистра и вычисления результата вторичных записей

Процедура РассчитатьНачисления(НаборЗаписейРегистра, ТребуемыйВидРасчета, СписокСотрудников) Экспорт

 

Регистратор = НаборЗаписейРегистра.Отбор.Регистратор.Значение;

 

// Рассчитать первичные записи.    

Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда

…

// Рассчитать вторичные записи.

ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда

 

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

 

Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл

СтруктураНомер = Новый Структура("НомерСтроки");

СтруктураНомер.НомерСтроки = ЗаписьРегистра.НомерСтроки;

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

Если ВыборкаРезультата.НайтиСледующий(СтруктураНомер) Тогда

ЗаписьРегистра.Результат = ВыборкаРезультата.База * (10 / 100);

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "Выполнен расчет " + ЗаписьРегистра.Регистратор + " – " + ЗаписьРегистра.ВидРасчета + " – " + ЗаписьРегистра.Сотрудник;

Сообщение.Сообщить();

КонецЕсли;

КонецЦикла;

 

КонецЕсли;

 

КонецПроцедуры

Сумма начисленной премии рассчитывается как 10 % от рассчитанной оплаты по окладу.