суббота, 21 февраля 2015 г.

1с специалист задача 3.17

Условие задачи из сборника:

Начисление зарплаты сотрудникам предприятия осуществляется ежемесячно с использованием метода отклонений. Все сотрудники работают по пятидневному графику работы, однако в решении необходимо предусмотреть возможность работы по нескольким различным графикам. Сотрудники предприятия получают оплату по окладу пропорционально
отработанному времени в днях. Сумма начисления по окладу определяется как дневная ставка, умноженная на количество фактически отработанных дней. Дневная ставка оклада одинакова для всех сотрудников и должна быть определена по специальной шкале в зависимости от общего трудового стажа работы сотрудника. При решении задачи необходимо иметь в виду, что на момент начала ведения учета у сотрудника может быть трудовой стаж отличный от нуля.
Трудовой стаж        Размер ставки
до 1 года                      100
от 1 года до 3 лет        200
от 3 лет                        300
Сотруднику предприятия выплачивается надбавка, рассчитываемая как общая сумма продаж товаров за два предыдущих месяца по подразделению, в котором работает сотрудник, умноженная на определенный процент. Значение процента для надбавки может быть задано в документе. Сумма надбавки не может быть меньше некоторой гарантированной суммы, задаваемой отдельно для каждого подразделения и зафиксированной в информационной базе.
За каждый день невыхода сотрудника на работу без уважительной причины сотруднику начисляется штраф в размере 10% от дневной ставки по окладу.
Создать обработку «Перерасчет зарплаты», в котором пользователь должен не только увидеть записи регистра расчета, которые возможно требуется пересчитать, но и выполнить саму процедуру перерасчета.
Объектперерасчета Вид расчета Сотрудник Подразделение
Ввод всех начислений происходит документом «Начисление зарплаты». Считать, что все данные вводятся только в пределах одного месяца, например, можно указать начисление оклада с 10.01 по 31.01, а запись: оклад с 10.01 по 03.02 вводить нельзя. Необходимо предоставить пользователю возможность самостоятельно создавать новые виды расчетов и привязывать их к существующим алгоритмам расчета.

Решение:


Скачать решение задачи 3.17
1) Так как пользователю необходимо предоставить возможность самому создавать ВР. то заведем перечисление "Способы расчета" со значениями (По окладу, невыход, ПремияПроцентомОтПродаж). 
2)  ПВР. В ПВР "Основные начисления" и "Дополнительные начисления" добавим реквизит "Способ расчета" этого типа. ПВР будет использовать период действий и не зависеть от базы.
ПВР не использует  период действий и зависит  от базы по периоду действия. Это небольшая хитрость для того чтобы создать перерасчет для надбавки.
3) Создаем Регистры расчета с перерасчетами в каждом из них.
4) Добавляем реквизиты "ДатаПриема" и "СтажДоПриемаНаработу" в справочник "Физ. лица" для получения общего стажа.
5) Немножко дорабатываем обработку заполнения графика. (подробнее)
6) Дорабатываем документ "Начисление ЗП", добавляем ТЧ "дополнительные начисления".
Пишем обработку проведения, в которой сформируются первичные записи регистров расчета.
Для расчета оклада необходимо определить общий рабочий стаж и согласно данной таблице получить значение дневного оклада. Полученное значение умножаем на фактически отработанные дни. Аналогично и считаем и невыход только результат умножаем еще на -0,1.
Интереснее с надбавкой от продаж. Заведем регистр "Продажи" с измерением подразделение и ресурсом сумма. Сделаем простейшую обработку проведения расходной накладной.

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.Продажи.Записывать = Истина;
Движение = Движения.Продажи.Добавить();
Движение.Период = Дата;
Движение.Подразделение = Подразделение;
Движение.сумма = СуммаПоДокументу;
КонецПроцедуры

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

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.ДополнительныеНачисления.Записывать = Истина;
Движения.ОсновныеНачисления.Записывать = Истина;
Запрос = Новый("Запрос");
Запрос.Текст ="ВЫБРАТЬ
| НачислениеЗарплатыОсновныеНачисления.Сотрудник,
| НачислениеЗарплатыОсновныеНачисления.Подразделение,
| НачислениеЗарплатыОсновныеНачисления.ВидРасчета,
| НачислениеЗарплатыОсновныеНачисления.График,
| НачислениеЗарплатыОсновныеНачисления.ДатаНачала КАК ПериодДействияНачало,
| КОНЕЦПЕРИОДА(НачислениеЗарплатыОсновныеНачисления.ДатаОкончания, ДЕНЬ) КАК ПериодДействияКонец,
| НачислениеЗарплатыОсновныеНачисления.Ссылка.ПериодРегистрации,
| РАЗНОСТЬДАТ(НачислениеЗарплатыОсновныеНачисления.Сотрудник.ДатаПриема, НачислениеЗарплатыОсновныеНачисления.Ссылка.ПериодРегистрации, ГОД) + НачислениеЗарплатыОсновныеНачисления.Сотрудник.СтажДоПриема КАК ОбщийСтаж
|ИЗ
| Документ.НачислениеЗарплаты.ОсновныеНачисления КАК НачислениеЗарплатыОсновныеНачисления
|ГДЕ
| НачислениеЗарплатыОсновныеНачисления.Ссылка = &Ссылка
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| НачислениеЗарплатыДополнительныеНачисления.Сотрудник,
| НачислениеЗарплатыДополнительныеНачисления.Подразделение,
| НачислениеЗарплатыДополнительныеНачисления.ВидРасчета,
| НачислениеЗарплатыДополнительныеНачисления.ИсходныеДанные,
| НачислениеЗарплатыДополнительныеНачисления.Ссылка.ПериодРегистрации,
| ЕСТЬNULL(ПродажиОбороты.суммаОборот, 0) КАК СуммаПродаж
|ИЗ
| Документ.НачислениеЗарплаты.ДополнительныеНачисления КАК НачислениеЗарплатыДополнительныеНачисления
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&НачалоПродаж, &КонецПродаж, , ) КАК ПродажиОбороты
| ПО НачислениеЗарплатыДополнительныеНачисления.Подразделение = ПродажиОбороты.Подразделение
|ГДЕ
| НачислениеЗарплатыДополнительныеНачисления.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка",Ссылка);
Запрос.УстановитьПараметр("НачалоПродаж",ДобавитьМесяц(ПериодРегистрации,-2));
Запрос.УстановитьПараметр("КонецПродаж",ПериодРегистрации-1);
Результат = Запрос.ВыполнитьПакет();
Если Не Результат[0].Пустой() Тогда
Выборка = Результат[0].Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.ОсновныеНачисления.Добавить();
ЗаполнитьЗначенияСвойств(Движение,Выборка);
Движение.ИсходныеДанные = Выборка.ОбщийСтаж;
КонецЦикла;
КонецЕсли;
Если Не Результат[1].Пустой() Тогда
Выборка = Результат[1].Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.ДополнительныеНачисления.Добавить();
ЗаполнитьЗначенияСвойств(Движение,Выборка);
Движение.Результат = Выборка.СуммаПродаж*Выборка.ИсходныеДанные/100;
КонецЦикла;
КонецЕсли;
Движения.ДополнительныеНачисления.Записать();
Движения.ОсновныеНачисления.Записать();
СотрудникиОсн = ОсновныеНачисления.ВыгрузитьКолонку("Сотрудник");
СотрудникиДоп = ДополнительныеНачисления.ВыгрузитьКолонку("Сотрудник");
Расчет.РассчитатьНачисления(Движения.ОсновныеНачисления, Перечисления.СпособыРасчета.Оклад, СотрудникиОсн);
Движения.ОсновныеНачисления.Записать(,Истина);
Расчет.РассчитатьНачисления(Движения.ОсновныеНачисления, Перечисления.СпособыРасчета.Невыход, СотрудникиОсн);
Движения.ОсновныеНачисления.Записать(,Истина);

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

7) Довольно компактно выглядит и процедура расчета общего модуля

Процедура РассчитатьНачисления(Набор,СпособРасчета,МассивСотрудников) Экспорт
Регистратор = Набор.Отбор.Регистратор.Значение;
Запрос = Новый("Запрос");
Запрос.Текст = "ВЫБРАТЬ
| ЕСТЬNULL(ОсновныеНачисленияДанныеГрафика.ЗначениеФактическийПериодДействия, 0) КАК ФактДней,
| ОсновныеНачисленияДанныеГрафика.НомерСтроки
|ИЗ
| РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
| Сотрудник В (&МассивСотрудников)
| И Регистратор = &Регистратор
| И ВидРасчета.СпособРасчета = &СпособРасчета) КАК ОсновныеНачисленияДанныеГрафика";
Запрос.Параметры.Вставить("МассивСотрудников",МассивСотрудников);
Запрос.Параметры.Вставить("Регистратор",Регистратор);
Запрос.Параметры.Вставить("СпособРасчета",СпособРасчета);
Выборка = Запрос.Выполнить().Выбрать();
Для Каждого Запись Из Набор Цикл
Если Запись.Видрасчета.Способрасчета <> СпособРасчета Тогда
Продолжить;
КонецЕсли;
Отбор = Новый("Структура");
Отбор.Вставить("НомерСтроки",Запись.НомерСтроки);
Если Выборка.НайтиСледующий(Отбор) Тогда
ДневнойОклад = ПолучитьОклад(Запись.Исходныеданные);
Запись.Результат = ?(СпособРасчета = Перечисления.СпособыРасчета.Оклад,Выборка.ФактДней*ДневнойОклад,Выборка.ФактДней*ДневнойОклад*(-0.1));  
КонецЕсли;
КонецЦикла;
КонецПроцедуры

Функция ПолучитьОклад(Стаж)
Если Стаж>3 Тогда
Возврат 300
Иначеесли Стаж<1 Тогда
Возврат 100
Иначе
Возврат 200
КонецЕсли;
КонецФункции


8) Осталось дело за перерасчетами. Если для основных начислений система формирует записи перерасчета автоматически, то для надбавки сформируем записи при обработке проведения,

Процедура СформироватьЗаписиПерерасчета()
Запрос = Новый Запрос;
Запрос.Текст= "ВЫБРАТЬ
             | ДополнительныеНачисления.Сотрудник,
             | ДополнительныеНачисления.ВидРасчета,
             | ДополнительныеНачисления.Регистратор КАК Регистратор,
             | РасходнаяНакладная.Дата
             |ИЗ
             | Документ.РасходнаяНакладная КАК РасходнаяНакладная
             | ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.ДополнительныеНачисления КАК ДополнительныеНачисления
             | ПО РасходнаяНакладная.Подразделение = ДополнительныеНачисления.Подразделение
             | И (РасходнаяНакладная.Дата > ДОБАВИТЬКДАТЕ(ДополнительныеНачисления.ПериодРегистрации, МЕСЯЦ, -2))
             | И (РасходнаяНакладная.Дата < КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(ДополнительныеНачисления.ПериодРегистрации, МЕСЯЦ, -1), МЕСЯЦ))
             |ГДЕ
             | РасходнаяНакладная.Ссылка = &Ссылка
             | И ДополнительныеНачисления.ВидРасчета.Способрасчета = &Способрасчета
             |ИТОГИ ПО
             | Регистратор";
 Запрос.УстановитьПараметр("Ссылка",Ссылка);
   Запрос.УстановитьПараметр("Способрасчета",Перечисления.СпособыРасчета.НадбавкаПроцентомОтПродаж);
 ВыборкаИтоги = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
 Перерасчет = РегистрыРасчета.ДополнительныеНачисления.Перерасчеты.ПерерасчетДоп;
 Пока ВыборкаИтоги.Следующий() Цикл
Набор = Перерасчет.СоздатьНаборЗаписей();
Набор.Отбор.ОбъектПерерасчета.Значение = ВыборкаИтоги.регистратор;
Выборка = ВыборкаИтоги.Выбрать();
Пока Выборка.Следующий() Цикл
Запись = Набор.Добавить();
ЗаполнитьЗначенияСвойств(Запись,Выборка);
Запись.Подразделение = Подразделение;
КонецЦикла;
   Набор.Записать();

 КонецЦикла;
КонецПроцедуры
9) И на конец добавляем обработку перерасчета.
На форму кидаем 2 процедуры заполнения и перерасчета.


&НаСервере
Процедура ВыполнитьПерерасчетНаСервере()
МассивДок = Новый Массив;
Для Каждого ТекЭлемент Из ТаблицаПерерасчетов Цикл
Если МассивДок.Найти(ТекЭлемент.ОбъектПерерасчета) = Неопределено Тогда 
МассивДок.Добавить(ТекЭлемент.ОбъектПерерасчета);
КонецЕсли;
КонецЦикла;
Для Каждого Док Из МассивДок Цикл
ДокОбъект = Док.ПолучитьОбъект();
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьПерерасчет(Команда)
ВыполнитьПерерасчетНаСервере();
КонецПроцедуры

&НаСервере
Процедура     ЗаполнитьНаСервере()
Запрос = Новый("Запрос");
Запрос.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ
| ПерерасчетДоп.ОбъектПерерасчета КАК ОбъектПерерасчета,
| ПерерасчетДоп.Подразделение,
| ПерерасчетДоп.ВидРасчета,
| ПерерасчетДоп.Сотрудник
|ИЗ
| РегистрРасчета.ДополнительныеНачисления.ПерерасчетДоп КАК ПерерасчетДоп
|
|СГРУППИРОВАТЬ ПО
| ПерерасчетДоп.ОбъектПерерасчета,
| ПерерасчетДоп.ВидРасчета,
| ПерерасчетДоп.Подразделение,
| ПерерасчетДоп.Сотрудник
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ПерерасчетОсн.ОбъектПерерасчета,
| ПерерасчетОсн.Подразделение,
| ПерерасчетОсн.ВидРасчета,
| ПерерасчетОсн.Сотрудник
|ИЗ
| РегистрРасчета.ОсновныеНачисления.ПерерасчетОсн КАК ПерерасчетОсн";
ТаблицаПерерасчетов.Загрузить(  Запрос.Выполнить().Выгрузить());
КонецПроцедуры
&НаКлиенте
Процедура Заполнить(Команда)                          
ЗаполнитьНаСервере();
КонецПроцедуры




Комментариев нет:

Отправить комментарий