Цель лекции: научиться программно рассчитывать результаты начислений в
Предыдущая лекция завершилась на том, что мы сформировали движения по регистрам накопления и вызвали процедуру общего модуля РассчитатьЗарплату. Эта процедура находится в модуле РасчетЗарплаты, ниже приведен ее код:
Процедура РассчитатьЗарплату(Регистратор) Экспорт
//Набор записей регистра расчета ОсновныеНачисления
НаборЗаписейОсн=РегистрыРасчета.ОсновныеНачисления.СоздатьНаборЗаписей();
НаборЗаписейОсн.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписейОсн.Прочитать();
//Набор записей регистра расчета ДополнительныеНачисления
НаборЗаписейДоп
=РегистрыРасчета.ДополнительныеНачисления.СоздатьНаборЗаписей();
НаборЗаписейДоп.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписейДоп.Прочитать();
//Перебор категорий расчета
Для Каждого Категория из Перечисления.КатегорииРасчета Цикл
РассчитатьОсновныеНачисления(Регистратор, НаборЗаписейОсн, Категория);
РассчитатьДополнительныеНачисления(Регистратор, НаборЗаписейДоп, Категория)
КонецЦикла;
Сообщить("Расчет зарплаты по документу "
+Регистратор+" завершен");
КонецПроцедуры
Процедура РассчитатьОсновныеНачисления(Регистратор, НаборЗаписейОсн, Категория)
//Получаем базу
Измерения=Новый Структура;
Измерения.Вставить
("Сотрудник", "ОсновныеНачисления.Сотрудник");
Ресурсы=Новый Массив(2);
Ресурсы[0]="ОсновныеНачисления.Сумма";
Ресурсы[1]="ОсновныеНачисления.ДнейОтработано";
ОтборРегистратор = Новый Структура;
ОтборРегистратор.Вставить("Регистратор", Регистратор);
База=РегистрыРасчета.ОсновныеНачисления.ПолучитьБазу
(ОтборРегистратор, Ресурсы, Измерения);
Для Каждого Запись из НаборЗаписейОсн Цикл
Если Запись.ВидРасчета.КатегорияРасчета = Категория Тогда
//Получаем данные для расчета записей
Индекс=НаборЗаписейОсн.Индекс(Запись);
БазаЗаписи=База[Индекс].Сумма;
МетодРасчета=Запись.ВидРасчета.МетодРасчета;
ДнейФактЗаписи=Запись.ПолучитьДанныеГрафика
(ВидПериодаРегистраРасчета.ФактическийПериодДействия);
//ДнейФакт[Индекс].РабочийДень;
ДнейПланЗаписи=Запись.ПолучитьДанныеГрафика
(ВидПериодаРегистраРасчета.ПериодДействия);
//ДнейПлан[Индекс].РабочийДень;
ДнейБазаЗаписи=База[Индекс].ДнейОтработано;
ИсходныеДанные=Запись.ИсходныеДанные;
ВлияетНаОтработанноеВремя=Запись.ВидРасчета.ВлияетНаОтработанноеВремя;
//Различные алгоритмы расчета, зависящие от метода расчета
Если МетодРасчета=Перечисления.МетодыРасчета.ФиксированнаяСумма Тогда
Запись.Сумма=ИсходныеДанные;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.Процент Тогда
Запись.Сумма=БазаЗаписи*ИсходныеДанные/100;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.ПоДням Тогда
Запись.Сумма=ДнейФактЗаписи[0].РабочийДень*ИсходныеДанные;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.ПоСреднему Тогда
Запись.Сумма=БазаЗаписи/ДнейБазаЗаписи*ДнейФактЗаписи[0].РабочийДень;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.ПоОтработанномуВремени
Тогда Запись.Сумма=ИсходныеДанные*ДнейФактЗаписи[0].РабочийДень
/ДнейПланЗаписи[0].РабочийДень;
КонецЕсли;
//Записываем отработанное время
Если ВлияетНаОтработанноеВремя Тогда
Запись.ДнейОтработано=ДнейФактЗаписи[0].РабочийДень;
КонецЕсли;
//Если сторно - записываем показатели со знаком "-"
Если Запись.Сторно Тогда
Запись.Сумма=-Запись.Сумма;
Запись.ДнейОтработано=-Запись.ДнейОтработано;
КонецЕсли;
КонецЕсли;
КонецЦикла;
НаборЗаписейОсн.Записать(,,Ложь);
КонецПроцедуры
Процедура РассчитатьДополнительныеНачисления
(Регистратор, НаборЗаписейДоп, Категория)
Измерения=Новый Структура;
Измерения.Вставить("Сотрудник", "ОсновныеНачисления.Сотрудник,
ДополнительныеНачисления.Сотрудник");
Ресурсы=Новый Массив(1);
Ресурсы[0]="ОсновныеНачисления.Сумма, ДополнительныеНачисления.Сумма";
ОтборРегистратор = Новый Структура;
ОтборРегистратор.Вставить("Регистратор", Регистратор);
База=РегистрыРасчета.ДополнительныеНачисления.ПолучитьБазу
(ОтборРегистратор, Ресурсы, Измерения);
Для Каждого Запись из НаборЗаписейДоп Цикл
Если Запись.ВидРасчета.КатегорияРасчета=Категория Тогда
Индекс=НаборЗаписейДоп.Индекс(Запись);
БазаЗаписи=База[Индекс].Сумма;
МетодРасчета=Запись.ВидРасчета.МетодРасчета;
ИсходныеДанные=Запись.ИсходныеДанные;
Если МетодРасчета=Перечисления.МетодыРасчета.ФиксированнаяСумма Тогда
Запись.Сумма=ИсходныеДанные;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.Процент Тогда
Запись.Сумма=БазаЗаписи*ИсходныеДанные/100;
КонецЕсли;
КонецЕсли;
КонецЦикла;
НаборЗаписейДоп.Записать();
КонецПроцедуры
Рассмотрим этот код. Когда мы завершили формирование (но не расчет) записей РассчитатьЗарплату() из общего модуля РасчетЗарплаты. В свою очередь, из этой процедуры производится вызов еще двух методов – один – РассчитатьОсновныеНачисления() вызывается для расчета начислений, внесенных в регистр ОсновныеНачисления документом, из которого была вызвана процедура РассчитатьЗарплату(), вторая – РассчитатьДополнительныеНачисления() – для расчета дополнительных начислений.
В процедуре РассчитатьЗарплату мы создаем копии наборов записей Регистратор – то есть – по ссылке на документ, из которого была вызвана процедура.
После создания копий необходимых записей, мы открываем цикл перебора перечисления КатегорииРасчета. При переборе значения перечисления присваиваются переменной цикла Категория в соответствии с порядком их расположения в настройках перечисления в Конфигураторе. Таким образом, этот цикл последовательно проходит по категориям расчета Первичное, Зависимое первого уровня, Зависимое второго уровня. Смысл этого цикла заключается в том, чтобы Первичное, могут быть рассчитаны независимо от других Зависимое первого уровня опираются на первичные Зависимые второго уровня могут опираться на две предыдущие категории.
В цикле мы вызываем процедуры РассчитатьОсновныеНачисления() и РассчитатьДополнительныеНачисления(). При вызове этих процедур мы передаем им схожие наборы параметров. Так, это параметр Регистратор – он пригодится нам для дальнейшей работы, это параметры НаборЗаписейОсн и НаборЗаписейДоп – наборы записей регистров, полученные ранее, а так же параметр Категория – основываясь на переданной категории расчета мы будем, внутри процедур расчета записей, принимать решения о том, какие записи нужно рассчитать при текущем значении категории расчета.
Рассмотрим метод РассчитатьОсновныеНачисления().
В начале мы получаем параметры базы для расчета начислений, использующих
База=РегистрыРасчета.ОсновныеНачисления.ПолучитьБазу(ОтборРегистратор, Ресурсы, Измерения);
Перед вызовом данной команды мы формируем структуры данных для получения базы. Во-первых – это структура Измерения, в которой находятся измерения Ресурсы – он содержит значения, которые позволяют нам получить, суммовые показатели расчетной базы и показатели количества отработанных дней по ОтборРегистратор – она позволяет отобрать данные по регистратору.
Полученная переменная База – это таблица значений, содержащая нужные данные по
Далее, мы открываем цикл перебора записей в полученном ранее наборе записей регистра НаборЗаписейОсн, и, при входе в цикл, проверяем, принадлежит ли запись к рассчитываемой при данном вызове метода РассчитатьОсновныеНачисления() категории расчета. Если это так, мы переходим к формированию расчетных показателей, в противном случае переходим к следующей итерации цикла перебора записей.
При выполнении условия на проверку категории расчета мы получаем следующие данные:
БазаЗаписи – суммовой показатель по расчетной базе. Расчетная база собирается в соответствии с базовым периодом, указанным при вводе записи, и в соответствии с набором Отпуск, базой для которого служит Оклад и Отпуск равняется трем месяцам, в показатель БазаЗаписи попадут все начисления Оклада за эти три месяца. Если в один из месяцев оклад равнялся 10000 рублей, во втором – 12000, в третьем – 11000, в показателе БазаЗаписи мы получим 10000+12000+11000=33000 рублей.
МетодРасчета – метод расчета, указанный для
ДнейФактЗаписи – фактический период для текущей записи. Например, если мы рассчитываем оклад, с которым связан график Пятидневка и в месяце, за который производится оклад, 21 день, причем, за счет вытеснения другими видами расчета (прогулом, например), оказывается, что фактически работник отработал лишь 19 дней, в переменной ДнейФактЗаписи окажется значение именно 19 дней.
ДнейПланЗаписи – показатель, характеризующий общее число дней в 21 день.
ДнейБазаЗаписи – в этой переменной окажется количество дней, которое соответствует отработанным дням для Оклад, причем, в одном из месяцев работник отработал 19 дней, во втором – 11, в третьем – 20 – мы получим в данном показателе 19+11+20=50 отработанных дней.
ИсходныеДанные – это тот показатель, который мы задаем при вводе информации о начислении. Для
ВлияетНаОтработанноеВремя – сюда мы записываем значение реквизита ВлияетНаОтработанноеВремя
Далее следует ряд проверок показателя МетодРасчета на соответствии его значениям перечисления МетодыРасчета. В зависимости от значения этого показателя используются различные методы расчета.
Для метода ФиксированнаяСумма мы, без каких-либо дополнительных изменений, переносим значение из свойства ИсходныеДанные в свойство Сумма.
Для метода Процент мы умножаем расчетную базу на процент, заданный при вводе записи. Так как проценты мы вводим в виде 10%, 50% и т.д., мы, для получения верного результата, делим ИсходныеДанные на 100.
Для метода По дням мы получаем количество фактически отработанных дней и умножаем полученное число дней на ИсходныеДанные, в которых, в данном случае, хранится сумма оплаты за один день.
Для метода ПоСреднему мы делим суммовой показатель базы (БазаЗаписи) на количество отработанных дней в ДнейБазаЗаписи) и умножаем полученный результат (то есть – размер среднедневной оплаты труда) на количество дней, которое должно быть оплачено по начислению, для которого производится расчет.
Для метода ПоОтработанномуВремени мы умножаем ИсходныеДанные на отношение фактически отработанного времени к полному времени, которое мог бы отработать сотрудник в периоде, для которого производится расчет.
После завершения расчета в соответствии с методом расчета, мы проверяем, влияет ли рассчитываемая запись на количество отработанных дней, если влияет – устанавливаем параметр ДнейОтработано в значение фактически отработанных дней по данной записи.
Далее мы проверяем, является ли обрабатываемая запись сторнировочной, то есть – такой, которая отражает в текущем периоде уточнения для записей, выполненных в предыдущем периоде. Если является – инвертируем знак у суммы, которая ранее была записана, и у количества отработанных дней. Если оказалось, что в текущем периоде был введен вид расчета, который уменьшает показатели начислений предыдущих периодов (например, в текущем периоде введен Прогул за предыдущий период, вытесняющий Оклад, который уже начислен), сторнировочная запись позволит отразить в текущем периоде корректировочный показатель, не затрагивая данных предыдущих периодов.
В итоге мы записываем набор записей командой НаборЗаписейОсн.Записать;
Теперь рассмотрим метод РассчитатьДополнительныеНачисления(). В начале мы получаем расчетую базу (База) такими же методами, как и выше, для записей регистра ОсновныеНачисления. Разница здесь заключается лишь в том, что записи ДополнительныеНачисления могут включать расчетную базу, сформированную как в регистре ДополнительныеНачисления, так и в регистре ОсновныеНачисления. Поэтому, создавая структуру отбора по измерениям мы указываем измерения двух регистров, создавая массив отбора по ресурсам мы, так же, указываем два суммовых показателя, на которые нужно ориентироваться системе при формировании расчетной базы.
Далее мы входим в цикл обработки набора записей регистра ДополнительныеНачисления, сверяем категорию расчета текущей записи с категорией расчета, которая передана в процедуру при ее вызове (это, напомним, позволяет нам рассчитать записи в соответствии с порядком их расчета, что позволит правильно получить расчетную базу для зависимых
Показатели данного регистра не оперируют понятием
ДополнительныеНачисления не увеличивают отработанное время, для них мы не формируем сторнировочных записей (механизмы вытеснения в данном регистре не используются), в итоге, после расчета показателей мы записываем сформированные записи.
После завершения в процедуре РассчитатьЗарплату цикла обхода перечисления КатегорииРасчета мы выводим пользователю сообщение о том, что расчет зарплаты по текущему документу завершен.
Нужно отметить, что главная цель вышеприведенного кода – максимально понятная демонстрация достаточно сложных механизмов работы с регистрами расчета. Для повышения быстродействия данного кода его следует проанализировать и вынести как можно больше команд, формирующих запросы к системе (ПолучитьДанныеГрафика, ПолучитьБазу) из циклов, оформив их в виде запросов. Количество запросов так же следует минимизировать. Однако, наш код выполняет возложенные на него функции, поэтому мы не будем заниматься его оптимизацией, перейдем к проверке результатов расчета.
После написания любого кода, как и в процессе написания, следует постоянно проверять правильность его работы. В случае с достаточно сложными расчетными механизмами следует внимательно проверить результаты их работы. В частности, нужно проверить расчет всех возможных
В проверке весьма полезно использовать инструменты отладки – точки останова, остановку по ошибке (Отладка > Остановка по ошибке), окно вычисления выражения.
Прикладные решения принято снабжать справочной информацией. Оснастим справочной страницей документ , и, нажав на кнопку Справочная информация, откроем HTML-редактор, который предназначен для создания справочных разделов.
(рис 5.1) Включение справочной информации по объекту в состав справки
В HTML-редакторе можно видеть три закладки, рис 5.2
(рис 5.2) Редактирование текста справки по объекту
На закладке Редактирование осуществляется редактирование справочного раздела в визуальном режиме. При этом можно пользоваться панелями инструментов Редактирование HTML, Форматирование, командами главного меню Таблица (для вставки таблиц и работы с ними), Элементы (это меню содержит подменю Ссылка, Закладка, Картинка, Надпись, Линия).
Закладка Текст содержит HTML-код, который является отражением элементов страницы, созданных в визуальном режиме, и который, при необходимости и наличии должных знаний, можно править самостоятельно.
Закладка Просмотр позволяет просмотреть результаты работы в виде, максимально приближенном к тому, который увидят пользователи при просмотре справочного раздела.
В пользовательском режиме созданный раздел справки по документу , доступен в общем содержании справки (Главное меню > Справка > Содержание справки), этот же раздел открывается при нажатии на кнопку Открыть справку (или клавиши F1) в форме списка документов или в форме документа/
(рис 5.3) Справка в пользовательском режиме
Заполняя параметры
Создадим в
(рис 5.4) Создание нового перерасчета и его измерения
После того, как перерасчет создан, мы можем воспользоваться им для того, чтобы принять решение о необходимости перерасчета записей регистра, которые, возможно, изменились при изменении ведущих
Построим отчет, который будет отображать информацию о данных, перерасчет которых требуется выполнить, основываясь на текущей ситуации в системе.
Создадим новый отчет. Назовем его Перерасчеты, включим в состав подсистемы РасчетЗаработнойПлаты, на закладке Основные откроем основную схему компоновки данных, добавим новый набор данных – Запрос, создадим следующий запрос:
ВЫБРАТЬ Перерасчет.ОбъектПерерасчета, Перерасчет.ВидРасчета, Перерасчет.Сотрудник ИЗ РегистрРасчета.ОсновныеНачисления.Перерасчет КАК Перерасчет УПОРЯДОЧИТЬ ПО Перерасчет.ОбъектПерерасчета.Дата
С его помощью мы получим из таблицы РегистрРасчета.ОсновныеНачисления.Перерасчет данные об объекте перерасчета,
На закладке Настройки редактора СКД нажмем на кнопку Открыть конструктор настроек, выберем в качестве типа отчета Список, в окне выбора полей, которые будут отображаться в отчете, выберем поля ВидРасчета, ОбъектПерерасчета и Сотрудник, нажмем на кнопку ОК.
Откроем конфигурацию в режиме 1С:Предприятие, перепроведем один из документов, который содержит вид расчета, влияющий на другие
(рис 5.5) Отчет Перерасчеты
Мы видим в отчете сведения о том, что в таблицу перерасчета попали данные по видам расчета Отпуск и Оклад, которые внесены в систему соответствующими им документами (поле Регистратор в отчете – это объект перерасчета), по сотруднику Александрову А.А.. Для того, чтобы очистить таблицу перерасчета, то есть – выполнить рекомендации, полученные из таблицы перерасчета, нам, в данном случае, нужно перепровести указанные документы. Перерасчеты не обязывают нас пересчитывать записи, они лишь дают рекомендации о том, какие записи, возможно, потеряли актуальность после изменения других, связанных с ними, записей. Механизмы выполнения перерасчета можно реализовать программно.
Создадим отчет, который позволяет представить в графическом виде начисления, отраженные в
Создадим новый отчет, назовем его ОсновныеНачисления, включим в подсистему РасчетЗаработнойПлаты. Не будем пользоваться схемой компоновки данных, построим отчет программно.
Создадим форму отчета, добавим в набор реквизитов формы новый реквизит, назовем его ДиаграммаНачислений, установим тип – ДиаграммаГанта, перетащим на закладку Элементы. Диаграмма Ганта – это популярный инструмент для визуализации различных планов работ и прочих подобных процессов, протекающих во времени. Ее еще называют ленточной диаграммой.
Добавим новую команду формы, назовем ее .
(рис 5.6) Отчет ОсновныеНачисления
Теперь перейдем в модуль формы и создадим там следующий код:
НаКлиенте
Процедура СформироватьОтчет(Команда)
СформироватьНаСервере(ДиаграммаНачислений)
КонецПроцедуры
НаСервереБезКонтекста
Процедура СформироватьНаСервере(Диаграмма)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОснФакт.Сотрудник,
| ОснФакт.ВидРасчета,
| ОснФакт.Регистратор,
| ОснФакт.ПериодДействияНачало,
| ОснФакт.ПериодДействияКонец
|ИЗ
| РегистрРасчета.ОсновныеНачисления.ФактическийПериодДействия
| КАК ОснФакт";
Результат = Запрос.Выполнить();
ВыборкаДЗ = Результат.Выбрать();
Диаграмма.Обновление = Ложь;
Диаграмма.Очистить();
Пока ВыборкаДЗ.Следующий() Цикл
Точка = Диаграмма.УстановитьТочку(ВыборкаДЗ.Сотрудник);
Серия = Диаграмма.УстановитьСерию(ВыборкаДЗ.ВидРасчета);
Значение = Диаграмма.ПолучитьЗначение(Точка, Серия);
Интервал = Значение.Добавить();
Интервал.Начало = ВыборкаДЗ.ПериодДействияНачало;
Интервал.Конец = ВыборкаДЗ.ПериодДействияКонец;
Интервал.Расшифровка=ВыборкаДЗ.Регистратор;
КонецЦикла;
Диаграмма.Обновление = Истина;
КонецПроцедуры
Здесь мы вызываем из клиентской процедуры обработчика команды СформироватьОтчет серверную внеконтектсную процедуру СформироватьНаСервере, передавая ей диаграмму, которую нужно заполнить.
В серверной процедуре мы, с помощью запроса, получаем сведения о сотруднике, ФактическийПериодДействия ОсновныеНачисления.
Далее, мы запрещаем обновление диаграммы для того, чтобы в процессе ее формирования не нагружать систему ненужными вычислениями, и, в цикле перебора полученной из результатов запроса выборки формируем диаграмму.
С помощью методов УстановитьТочку и УстановитьСерию, мы, соответственно, получаем точки и серии диаграммы. Они могут иметь произвольный тип.
Далее, с помощью метода ПолучитьЗначение мы, на основе только что полученных точки и серии, формируем переменную Значение типа ЗначениеДиаграммыГанта, и, пользуясь его методом Добавить, добавляем новый интервал.
Интервал имеет свойства Начало и Конец, мы устанавливаем их в значения начала и конца Расшифровка записываем ссылку на документ-регистратор – двойной щелчок по элементу диаграммы позволит открыть соответствующий этому элементу документ.
После выхода из цикла перебора выборки из результатов запроса мы разрешаем обновление диаграммы и пользователь видит ее.
Перейдем в режим 1С:Предприятие, добавим начисления для различных сотрудников и сформируем отчет .
(рис 5.7) Отчет ОсновныеНачисления
Поясним данные, визуализированные в отчете. Он отражает сведения по начислениям, хранящимся в
Точки в отчете – это сотрудники (слева), серии – это
Сотрудник Иванов И.И. получал Оклад лишь в сентябре, других начислений в регистре ОсновныеНачисления за ним не зафиксировано.
Васильев П.П. получал Оклад в Ноябре, причем, несколько дней в ноябре он прогулял – об этом говорит наличие среди его видов начислений вида Прогул. Обратите внимание на то, как ввод Прогул "разрывает" Оклад. Это – демонстрация вытеснения Оклада Прогулом.
Петров П.П. получал в сентябре Оклад, в октябре – Оклад по дням, а в ноябре весь месяц провел в отпуске.
Александров А.А. демонстрирует нам наиболее сложную картину начислений. Оклад ему начислялся все три месяца. Кроме того, некоторый период он получал так же и Оклад по дням. Эти два Оклад и Оклад по дням отображаются на диаграмме параллельно, не прерывая друг друга. Несколько дней в ноябре пришлись на вид начисления Отпуск. Отпуск, как видно по диаграмме, вытесняет Оклад. Оклад уменьшен за счет Прогула, который отражен в том же периоде, что и оклад. Обратите внимание на то, что октябрьский Оклад соседствует с октябрьским же Прогулом, но Прогул не прерывает в данном случае оклад – период Оклада, совпадающий с периодом Прогула, окрашен в другой цвет. Все дело в том, что информация об октябрьском Прогуле была внесена в систему в ноябре, а так как мы реализовали механизм сторно-записей, часть октябрьского оклада была сторнирована – именно сторно-запись и отражается на линии октябрьского Оклада напротив Прогула.
Как видите, построенная диаграмма позволяет наглядно и удобно отобразить сложные взаимоотношения различных видов расчетов в
В этой лекции мы рассмотрели разработку механизмов расчета показателей в
Для данной лекции подготовлен видеоурок.
Цель лекции: научиться программно рассчитывать результаты начислений в
Предыдущая лекция завершилась на том, что мы сформировали движения по регистрам накопления и вызвали процедуру общего модуля РассчитатьЗарплату. Эта процедура находится в модуле РасчетЗарплаты, ниже приведен ее код:
Процедура РассчитатьЗарплату(Регистратор) Экспорт
//Набор записей регистра расчета ОсновныеНачисления
НаборЗаписейОсн=РегистрыРасчета.ОсновныеНачисления.СоздатьНаборЗаписей();
НаборЗаписейОсн.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписейОсн.Прочитать();
//Набор записей регистра расчета ДополнительныеНачисления
НаборЗаписейДоп
=РегистрыРасчета.ДополнительныеНачисления.СоздатьНаборЗаписей();
НаборЗаписейДоп.Отбор.Регистратор.Установить(Регистратор);
НаборЗаписейДоп.Прочитать();
//Перебор категорий расчета
Для Каждого Категория из Перечисления.КатегорииРасчета Цикл
РассчитатьОсновныеНачисления(Регистратор, НаборЗаписейОсн, Категория);
РассчитатьДополнительныеНачисления(Регистратор, НаборЗаписейДоп, Категория)
КонецЦикла;
Сообщить("Расчет зарплаты по документу "
+Регистратор+" завершен");
КонецПроцедуры
Процедура РассчитатьОсновныеНачисления(Регистратор, НаборЗаписейОсн, Категория)
//Получаем базу
Измерения=Новый Структура;
Измерения.Вставить
("Сотрудник", "ОсновныеНачисления.Сотрудник");
Ресурсы=Новый Массив(2);
Ресурсы[0]="ОсновныеНачисления.Сумма";
Ресурсы[1]="ОсновныеНачисления.ДнейОтработано";
ОтборРегистратор = Новый Структура;
ОтборРегистратор.Вставить("Регистратор", Регистратор);
База=РегистрыРасчета.ОсновныеНачисления.ПолучитьБазу
(ОтборРегистратор, Ресурсы, Измерения);
Для Каждого Запись из НаборЗаписейОсн Цикл
Если Запись.ВидРасчета.КатегорияРасчета = Категория Тогда
//Получаем данные для расчета записей
Индекс=НаборЗаписейОсн.Индекс(Запись);
БазаЗаписи=База[Индекс].Сумма;
МетодРасчета=Запись.ВидРасчета.МетодРасчета;
ДнейФактЗаписи=Запись.ПолучитьДанныеГрафика
(ВидПериодаРегистраРасчета.ФактическийПериодДействия);
//ДнейФакт[Индекс].РабочийДень;
ДнейПланЗаписи=Запись.ПолучитьДанныеГрафика
(ВидПериодаРегистраРасчета.ПериодДействия);
//ДнейПлан[Индекс].РабочийДень;
ДнейБазаЗаписи=База[Индекс].ДнейОтработано;
ИсходныеДанные=Запись.ИсходныеДанные;
ВлияетНаОтработанноеВремя=Запись.ВидРасчета.ВлияетНаОтработанноеВремя;
//Различные алгоритмы расчета, зависящие от метода расчета
Если МетодРасчета=Перечисления.МетодыРасчета.ФиксированнаяСумма Тогда
Запись.Сумма=ИсходныеДанные;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.Процент Тогда
Запись.Сумма=БазаЗаписи*ИсходныеДанные/100;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.ПоДням Тогда
Запись.Сумма=ДнейФактЗаписи[0].РабочийДень*ИсходныеДанные;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.ПоСреднему Тогда
Запись.Сумма=БазаЗаписи/ДнейБазаЗаписи*ДнейФактЗаписи[0].РабочийДень;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.ПоОтработанномуВремени
Тогда Запись.Сумма=ИсходныеДанные*ДнейФактЗаписи[0].РабочийДень
/ДнейПланЗаписи[0].РабочийДень;
КонецЕсли;
//Записываем отработанное время
Если ВлияетНаОтработанноеВремя Тогда
Запись.ДнейОтработано=ДнейФактЗаписи[0].РабочийДень;
КонецЕсли;
//Если сторно - записываем показатели со знаком "-"
Если Запись.Сторно Тогда
Запись.Сумма=-Запись.Сумма;
Запись.ДнейОтработано=-Запись.ДнейОтработано;
КонецЕсли;
КонецЕсли;
КонецЦикла;
НаборЗаписейОсн.Записать(,,Ложь);
КонецПроцедуры
Процедура РассчитатьДополнительныеНачисления
(Регистратор, НаборЗаписейДоп, Категория)
Измерения=Новый Структура;
Измерения.Вставить("Сотрудник", "ОсновныеНачисления.Сотрудник,
ДополнительныеНачисления.Сотрудник");
Ресурсы=Новый Массив(1);
Ресурсы[0]="ОсновныеНачисления.Сумма, ДополнительныеНачисления.Сумма";
ОтборРегистратор = Новый Структура;
ОтборРегистратор.Вставить("Регистратор", Регистратор);
База=РегистрыРасчета.ДополнительныеНачисления.ПолучитьБазу
(ОтборРегистратор, Ресурсы, Измерения);
Для Каждого Запись из НаборЗаписейДоп Цикл
Если Запись.ВидРасчета.КатегорияРасчета=Категория Тогда
Индекс=НаборЗаписейДоп.Индекс(Запись);
БазаЗаписи=База[Индекс].Сумма;
МетодРасчета=Запись.ВидРасчета.МетодРасчета;
ИсходныеДанные=Запись.ИсходныеДанные;
Если МетодРасчета=Перечисления.МетодыРасчета.ФиксированнаяСумма Тогда
Запись.Сумма=ИсходныеДанные;
ИначеЕсли МетодРасчета=Перечисления.МетодыРасчета.Процент Тогда
Запись.Сумма=БазаЗаписи*ИсходныеДанные/100;
КонецЕсли;
КонецЕсли;
КонецЦикла;
НаборЗаписейДоп.Записать();
КонецПроцедуры
Рассмотрим этот код. Когда мы завершили формирование (но не расчет) записей РассчитатьЗарплату() из общего модуля РасчетЗарплаты. В свою очередь, из этой процедуры производится вызов еще двух методов – один – РассчитатьОсновныеНачисления() вызывается для расчета начислений, внесенных в регистр ОсновныеНачисления документом, из которого была вызвана процедура РассчитатьЗарплату(), вторая – РассчитатьДополнительныеНачисления() – для расчета дополнительных начислений.
В процедуре РассчитатьЗарплату мы создаем копии наборов записей Регистратор – то есть – по ссылке на документ, из которого была вызвана процедура.
После создания копий необходимых записей, мы открываем цикл перебора перечисления КатегорииРасчета. При переборе значения перечисления присваиваются переменной цикла Категория в соответствии с порядком их расположения в настройках перечисления в Конфигураторе. Таким образом, этот цикл последовательно проходит по категориям расчета Первичное, Зависимое первого уровня, Зависимое второго уровня. Смысл этого цикла заключается в том, чтобы Первичное, могут быть рассчитаны независимо от других Зависимое первого уровня опираются на первичные Зависимые второго уровня могут опираться на две предыдущие категории.
В цикле мы вызываем процедуры РассчитатьОсновныеНачисления() и РассчитатьДополнительныеНачисления(). При вызове этих процедур мы передаем им схожие наборы параметров. Так, это параметр Регистратор – он пригодится нам для дальнейшей работы, это параметры НаборЗаписейОсн и НаборЗаписейДоп – наборы записей регистров, полученные ранее, а так же параметр Категория – основываясь на переданной категории расчета мы будем, внутри процедур расчета записей, принимать решения о том, какие записи нужно рассчитать при текущем значении категории расчета.
Рассмотрим метод РассчитатьОсновныеНачисления().
В начале мы получаем параметры базы для расчета начислений, использующих
База=РегистрыРасчета.ОсновныеНачисления.ПолучитьБазу(ОтборРегистратор, Ресурсы, Измерения);
Перед вызовом данной команды мы формируем структуры данных для получения базы. Во-первых – это структура Измерения, в которой находятся измерения Ресурсы – он содержит значения, которые позволяют нам получить, суммовые показатели расчетной базы и показатели количества отработанных дней по ОтборРегистратор – она позволяет отобрать данные по регистратору.
Полученная переменная База – это таблица значений, содержащая нужные данные по
Далее, мы открываем цикл перебора записей в полученном ранее наборе записей регистра НаборЗаписейОсн, и, при входе в цикл, проверяем, принадлежит ли запись к рассчитываемой при данном вызове метода РассчитатьОсновныеНачисления() категории расчета. Если это так, мы переходим к формированию расчетных показателей, в противном случае переходим к следующей итерации цикла перебора записей.
При выполнении условия на проверку категории расчета мы получаем следующие данные:
БазаЗаписи – суммовой показатель по расчетной базе. Расчетная база собирается в соответствии с базовым периодом, указанным при вводе записи, и в соответствии с набором Отпуск, базой для которого служит Оклад и Отпуск равняется трем месяцам, в показатель БазаЗаписи попадут все начисления Оклада за эти три месяца. Если в один из месяцев оклад равнялся 10000 рублей, во втором – 12000, в третьем – 11000, в показателе БазаЗаписи мы получим 10000+12000+11000=33000 рублей.
МетодРасчета – метод расчета, указанный для
ДнейФактЗаписи – фактический период для текущей записи. Например, если мы рассчитываем оклад, с которым связан график Пятидневка и в месяце, за который производится оклад, 21 день, причем, за счет вытеснения другими видами расчета (прогулом, например), оказывается, что фактически работник отработал лишь 19 дней, в переменной ДнейФактЗаписи окажется значение именно 19 дней.
ДнейПланЗаписи – показатель, характеризующий общее число дней в 21 день.
ДнейБазаЗаписи – в этой переменной окажется количество дней, которое соответствует отработанным дням для Оклад, причем, в одном из месяцев работник отработал 19 дней, во втором – 11, в третьем – 20 – мы получим в данном показателе 19+11+20=50 отработанных дней.
ИсходныеДанные – это тот показатель, который мы задаем при вводе информации о начислении. Для
ВлияетНаОтработанноеВремя – сюда мы записываем значение реквизита ВлияетНаОтработанноеВремя
Далее следует ряд проверок показателя МетодРасчета на соответствии его значениям перечисления МетодыРасчета. В зависимости от значения этого показателя используются различные методы расчета.
Для метода ФиксированнаяСумма мы, без каких-либо дополнительных изменений, переносим значение из свойства ИсходныеДанные в свойство Сумма.
Для метода Процент мы умножаем расчетную базу на процент, заданный при вводе записи. Так как проценты мы вводим в виде 10%, 50% и т.д., мы, для получения верного результата, делим ИсходныеДанные на 100.
Для метода По дням мы получаем количество фактически отработанных дней и умножаем полученное число дней на ИсходныеДанные, в которых, в данном случае, хранится сумма оплаты за один день.
Для метода ПоСреднему мы делим суммовой показатель базы (БазаЗаписи) на количество отработанных дней в ДнейБазаЗаписи) и умножаем полученный результат (то есть – размер среднедневной оплаты труда) на количество дней, которое должно быть оплачено по начислению, для которого производится расчет.
Для метода ПоОтработанномуВремени мы умножаем ИсходныеДанные на отношение фактически отработанного времени к полному времени, которое мог бы отработать сотрудник в периоде, для которого производится расчет.
После завершения расчета в соответствии с методом расчета, мы проверяем, влияет ли рассчитываемая запись на количество отработанных дней, если влияет – устанавливаем параметр ДнейОтработано в значение фактически отработанных дней по данной записи.
Далее мы проверяем, является ли обрабатываемая запись сторнировочной, то есть – такой, которая отражает в текущем периоде уточнения для записей, выполненных в предыдущем периоде. Если является – инвертируем знак у суммы, которая ранее была записана, и у количества отработанных дней. Если оказалось, что в текущем периоде был введен вид расчета, который уменьшает показатели начислений предыдущих периодов (например, в текущем периоде введен Прогул за предыдущий период, вытесняющий Оклад, который уже начислен), сторнировочная запись позволит отразить в текущем периоде корректировочный показатель, не затрагивая данных предыдущих периодов.
В итоге мы записываем набор записей командой НаборЗаписейОсн.Записать;
Теперь рассмотрим метод РассчитатьДополнительныеНачисления(). В начале мы получаем расчетую базу (База) такими же методами, как и выше, для записей регистра ОсновныеНачисления. Разница здесь заключается лишь в том, что записи ДополнительныеНачисления могут включать расчетную базу, сформированную как в регистре ДополнительныеНачисления, так и в регистре ОсновныеНачисления. Поэтому, создавая структуру отбора по измерениям мы указываем измерения двух регистров, создавая массив отбора по ресурсам мы, так же, указываем два суммовых показателя, на которые нужно ориентироваться системе при формировании расчетной базы.
Далее мы входим в цикл обработки набора записей регистра ДополнительныеНачисления, сверяем категорию расчета текущей записи с категорией расчета, которая передана в процедуру при ее вызове (это, напомним, позволяет нам рассчитать записи в соответствии с порядком их расчета, что позволит правильно получить расчетную базу для зависимых
Показатели данного регистра не оперируют понятием
ДополнительныеНачисления не увеличивают отработанное время, для них мы не формируем сторнировочных записей (механизмы вытеснения в данном регистре не используются), в итоге, после расчета показателей мы записываем сформированные записи.
После завершения в процедуре РассчитатьЗарплату цикла обхода перечисления КатегорииРасчета мы выводим пользователю сообщение о том, что расчет зарплаты по текущему документу завершен.
Нужно отметить, что главная цель вышеприведенного кода – максимально понятная демонстрация достаточно сложных механизмов работы с регистрами расчета. Для повышения быстродействия данного кода его следует проанализировать и вынести как можно больше команд, формирующих запросы к системе (ПолучитьДанныеГрафика, ПолучитьБазу) из циклов, оформив их в виде запросов. Количество запросов так же следует минимизировать. Однако, наш код выполняет возложенные на него функции, поэтому мы не будем заниматься его оптимизацией, перейдем к проверке результатов расчета.
После написания любого кода, как и в процессе написания, следует постоянно проверять правильность его работы. В случае с достаточно сложными расчетными механизмами следует внимательно проверить результаты их работы. В частности, нужно проверить расчет всех возможных
В проверке весьма полезно использовать инструменты отладки – точки останова, остановку по ошибке (Отладка > Остановка по ошибке), окно вычисления выражения.
Прикладные решения принято снабжать справочной информацией. Оснастим справочной страницей документ , и, нажав на кнопку Справочная информация, откроем HTML-редактор, который предназначен для создания справочных разделов.
(рис 5.1) Включение справочной информации по объекту в состав справки
В HTML-редакторе можно видеть три закладки, рис 5.2
(рис 5.2) Редактирование текста справки по объекту
На закладке Редактирование осуществляется редактирование справочного раздела в визуальном режиме. При этом можно пользоваться панелями инструментов Редактирование HTML, Форматирование, командами главного меню Таблица (для вставки таблиц и работы с ними), Элементы (это меню содержит подменю Ссылка, Закладка, Картинка, Надпись, Линия).
Закладка Текст содержит HTML-код, который является отражением элементов страницы, созданных в визуальном режиме, и который, при необходимости и наличии должных знаний, можно править самостоятельно.
Закладка Просмотр позволяет просмотреть результаты работы в виде, максимально приближенном к тому, который увидят пользователи при просмотре справочного раздела.
В пользовательском режиме созданный раздел справки по документу , доступен в общем содержании справки (Главное меню > Справка > Содержание справки), этот же раздел открывается при нажатии на кнопку Открыть справку (или клавиши F1) в форме списка документов или в форме документа/
(рис 5.3) Справка в пользовательском режиме
Заполняя параметры
Создадим в
(рис 5.4) Создание нового перерасчета и его измерения
После того, как перерасчет создан, мы можем воспользоваться им для того, чтобы принять решение о необходимости перерасчета записей регистра, которые, возможно, изменились при изменении ведущих
Построим отчет, который будет отображать информацию о данных, перерасчет которых требуется выполнить, основываясь на текущей ситуации в системе.
Создадим новый отчет. Назовем его Перерасчеты, включим в состав подсистемы РасчетЗаработнойПлаты, на закладке Основные откроем основную схему компоновки данных, добавим новый набор данных – Запрос, создадим следующий запрос:
ВЫБРАТЬ Перерасчет.ОбъектПерерасчета, Перерасчет.ВидРасчета, Перерасчет.Сотрудник ИЗ РегистрРасчета.ОсновныеНачисления.Перерасчет КАК Перерасчет УПОРЯДОЧИТЬ ПО Перерасчет.ОбъектПерерасчета.Дата
С его помощью мы получим из таблицы РегистрРасчета.ОсновныеНачисления.Перерасчет данные об объекте перерасчета,
На закладке Настройки редактора СКД нажмем на кнопку Открыть конструктор настроек, выберем в качестве типа отчета Список, в окне выбора полей, которые будут отображаться в отчете, выберем поля ВидРасчета, ОбъектПерерасчета и Сотрудник, нажмем на кнопку ОК.
Откроем конфигурацию в режиме 1С:Предприятие, перепроведем один из документов, который содержит вид расчета, влияющий на другие
(рис 5.5) Отчет Перерасчеты
Мы видим в отчете сведения о том, что в таблицу перерасчета попали данные по видам расчета Отпуск и Оклад, которые внесены в систему соответствующими им документами (поле Регистратор в отчете – это объект перерасчета), по сотруднику Александрову А.А.. Для того, чтобы очистить таблицу перерасчета, то есть – выполнить рекомендации, полученные из таблицы перерасчета, нам, в данном случае, нужно перепровести указанные документы. Перерасчеты не обязывают нас пересчитывать записи, они лишь дают рекомендации о том, какие записи, возможно, потеряли актуальность после изменения других, связанных с ними, записей. Механизмы выполнения перерасчета можно реализовать программно.
Создадим отчет, который позволяет представить в графическом виде начисления, отраженные в
Создадим новый отчет, назовем его ОсновныеНачисления, включим в подсистему РасчетЗаработнойПлаты. Не будем пользоваться схемой компоновки данных, построим отчет программно.
Создадим форму отчета, добавим в набор реквизитов формы новый реквизит, назовем его ДиаграммаНачислений, установим тип – ДиаграммаГанта, перетащим на закладку Элементы. Диаграмма Ганта – это популярный инструмент для визуализации различных планов работ и прочих подобных процессов, протекающих во времени. Ее еще называют ленточной диаграммой.
Добавим новую команду формы, назовем ее .
(рис 5.6) Отчет ОсновныеНачисления
Теперь перейдем в модуль формы и создадим там следующий код:
НаКлиенте
Процедура СформироватьОтчет(Команда)
СформироватьНаСервере(ДиаграммаНачислений)
КонецПроцедуры
НаСервереБезКонтекста
Процедура СформироватьНаСервере(Диаграмма)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОснФакт.Сотрудник,
| ОснФакт.ВидРасчета,
| ОснФакт.Регистратор,
| ОснФакт.ПериодДействияНачало,
| ОснФакт.ПериодДействияКонец
|ИЗ
| РегистрРасчета.ОсновныеНачисления.ФактическийПериодДействия
| КАК ОснФакт";
Результат = Запрос.Выполнить();
ВыборкаДЗ = Результат.Выбрать();
Диаграмма.Обновление = Ложь;
Диаграмма.Очистить();
Пока ВыборкаДЗ.Следующий() Цикл
Точка = Диаграмма.УстановитьТочку(ВыборкаДЗ.Сотрудник);
Серия = Диаграмма.УстановитьСерию(ВыборкаДЗ.ВидРасчета);
Значение = Диаграмма.ПолучитьЗначение(Точка, Серия);
Интервал = Значение.Добавить();
Интервал.Начало = ВыборкаДЗ.ПериодДействияНачало;
Интервал.Конец = ВыборкаДЗ.ПериодДействияКонец;
Интервал.Расшифровка=ВыборкаДЗ.Регистратор;
КонецЦикла;
Диаграмма.Обновление = Истина;
КонецПроцедуры
Здесь мы вызываем из клиентской процедуры обработчика команды СформироватьОтчет серверную внеконтектсную процедуру СформироватьНаСервере, передавая ей диаграмму, которую нужно заполнить.
В серверной процедуре мы, с помощью запроса, получаем сведения о сотруднике, ФактическийПериодДействия ОсновныеНачисления.
Далее, мы запрещаем обновление диаграммы для того, чтобы в процессе ее формирования не нагружать систему ненужными вычислениями, и, в цикле перебора полученной из результатов запроса выборки формируем диаграмму.
С помощью методов УстановитьТочку и УстановитьСерию, мы, соответственно, получаем точки и серии диаграммы. Они могут иметь произвольный тип.
Далее, с помощью метода ПолучитьЗначение мы, на основе только что полученных точки и серии, формируем переменную Значение типа ЗначениеДиаграммыГанта, и, пользуясь его методом Добавить, добавляем новый интервал.
Интервал имеет свойства Начало и Конец, мы устанавливаем их в значения начала и конца Расшифровка записываем ссылку на документ-регистратор – двойной щелчок по элементу диаграммы позволит открыть соответствующий этому элементу документ.
После выхода из цикла перебора выборки из результатов запроса мы разрешаем обновление диаграммы и пользователь видит ее.
Перейдем в режим 1С:Предприятие, добавим начисления для различных сотрудников и сформируем отчет .
(рис 5.7) Отчет ОсновныеНачисления
Поясним данные, визуализированные в отчете. Он отражает сведения по начислениям, хранящимся в
Точки в отчете – это сотрудники (слева), серии – это
Сотрудник Иванов И.И. получал Оклад лишь в сентябре, других начислений в регистре ОсновныеНачисления за ним не зафиксировано.
Васильев П.П. получал Оклад в Ноябре, причем, несколько дней в ноябре он прогулял – об этом говорит наличие среди его видов начислений вида Прогул. Обратите внимание на то, как ввод Прогул "разрывает" Оклад. Это – демонстрация вытеснения Оклада Прогулом.
Петров П.П. получал в сентябре Оклад, в октябре – Оклад по дням, а в ноябре весь месяц провел в отпуске.
Александров А.А. демонстрирует нам наиболее сложную картину начислений. Оклад ему начислялся все три месяца. Кроме того, некоторый период он получал так же и Оклад по дням. Эти два Оклад и Оклад по дням отображаются на диаграмме параллельно, не прерывая друг друга. Несколько дней в ноябре пришлись на вид начисления Отпуск. Отпуск, как видно по диаграмме, вытесняет Оклад. Оклад уменьшен за счет Прогула, который отражен в том же периоде, что и оклад. Обратите внимание на то, что октябрьский Оклад соседствует с октябрьским же Прогулом, но Прогул не прерывает в данном случае оклад – период Оклада, совпадающий с периодом Прогула, окрашен в другой цвет. Все дело в том, что информация об октябрьском Прогуле была внесена в систему в ноябре, а так как мы реализовали механизм сторно-записей, часть октябрьского оклада была сторнирована – именно сторно-запись и отражается на линии октябрьского Оклада напротив Прогула.
Как видите, построенная диаграмма позволяет наглядно и удобно отобразить сложные взаимоотношения различных видов расчетов в
В этой лекции мы рассмотрели разработку механизмов расчета показателей в
Для данной лекции подготовлен видеоурок.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.