пятница, 21 ноября 2014 г.

Создание механизма начисления зарплаты менеджерам продаж

Была задача разработать в базе систему начисления зарплаты менеджерам продаж по документам реализации товаров и услуг.
Начисление должно быть настраиваемым пользователем: фиксированная сумма либо процент от суммы продажи по каждой позиции из документа реализации; должен быть выбор определенной номенклатуры или группы номенклатуры, по которой будет проходить начисление. Еще важный нюанс: если методов начислений несколько и они пересекаются, то выбирается максимальный из них.
Итак, начнем.
1) Добавляем Перечисление ВидНачисленияЗарплаты:
2) Добавляем Регистр сведений МетодыНачисленияЗарплаты:
3) Задачу делал в конфигурации "Управление торговлей", а так как в этой конфигурации нет универсальных форм выбора номенклатуры и пользователя соответственно, то пришлось писать свои формы.  Чтобы новом методе начисления можно было выбирать и пользователя, и группу пользователей, и номенклатуру, и группу номенклатуры, вызывать нужно именно свои написанные универсальные формы выбора, поэтому в регистре сведений МетодыНачисленияЗарплаты добавляем форму записи, модуль которой выглядит следующим образом:

Процедура ПриОткрытии()
    РегистрСведенийМенеджерЗаписи.Период = ТекущаяДата();
КонецПроцедуры

Процедура ТоварНачалоВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаВыбораУниверсальная", ,ЭтаФорма);
КонецПроцедуры

Процедура СотрудникНачалоВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    ОткрытьФорму("Справочник.Пользователи.Форма.ФормаВыбораЭлементаИГруппы", ,ЭтаФорма);
КонецПроцедуры


4) Добавляем новый регистр накопления ЗарплатаСотрудников:
Вид регистра - Остатки.

5) Теперь переходим к написанию кода. В необходимом документе (у меня это документ РеализацияТоваровУслуг), в модуле объекта прописываем код:

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


Процедура ДобавлениеЗаписиВРегистрЗарплатаСотрудников(ТабличнаяЧасть, ТабМетодыНачисления)
    Для Каждого СтрокаТовара ИЗ ТабличнаяЧасть ЦИКЛ           
        СтруктураПоиска = Новый Структура;
        СтруктураПоиска.Вставить("Сотрудник", Ссылка.Ответственный);
        СтруктураПоиска.Вставить("Товар", СтрокаТовара.Номенклатура);
        МассивСтрокаНачисления = ТабМетодыНачисления.НайтиСтроки(СтруктураПоиска);
       
        Если МассивСтрокаНачисления.Количество() = 0 Тогда
            СтруктураПоиска = Новый Структура;
            СтруктураПоиска.Вставить("Товар", СтрокаТовара.Номенклатура);
            МассивСтрокаНачисления = ТабМетодыНачисления.НайтиСтроки(СтруктураПоиска);
        КонецЕсли;
        Если МассивСтрокаНачисления.Количество() = 0 Тогда
            МассивРодителей = ПолучитьМассивРодителей(СтрокаТовара.Номенклатура);
            Если МассивРодителей.Количество() = 0 Тогда
                Продолжить;
            КонецЕсли;
            Для Каждого ЭлементМассива ИЗ МассивРодителей Цикл
                СтруктураПоиска = Новый Структура;
                СтруктураПоиска.Вставить("Товар", ЭлементМассива);
                МассивСтрокаНачисления = ТабМетодыНачисления.НайтиСтроки(СтруктураПоиска);
                Если МассивСтрокаНачисления.Количество() > 0 Тогда
                    Прервать;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
        Если МассивСтрокаНачисления.Количество() = 0 Тогда
            Продолжить;
        КонецЕсли;
       
  Для Каждого СтрокаНачисления ИЗ МассивСтрокаНачисления Цикл
            Запись = Ложь;
            Если СтрокаНачисления.ВидНачисления = Перечисления.ВидНачесленияЗарплаты.ФиксированнаяСумма Тогда
                СумНачисления = СтрокаНачисления.Сумма;
                Запись = Истина;
            ИначеЕсли СтрокаНачисления.ВидНачисления = Перечисления.ВидНачесленияЗарплаты.Процент Тогда
                СумНачисления = СтрокаНачисления.Процент/100*СтрокаТовара.Сумма;
                Запись = Истина;
            КонецЕсли;
            Если Запись Тогда
                ДвижениеЗарплатаСотрудников = Движения.ЗарплатаСотрудников.Добавить();
                ДвижениеЗарплатаСотрудников.ВидДвижения = ВидДвиженияНакопления.Приход;
                ДвижениеЗарплатаСотрудников.Документ = Ссылка;
                ДвижениеЗарплатаСотрудников.Период = Дата;
                ДвижениеЗарплатаСотрудников.Сотрудник = Ссылка.Ответственный;
                ДвижениеЗарплатаСотрудников.Товар = СтрокаТовара.Номенклатура;            
                ДвижениеЗарплатаСотрудников.Сумма = СумНачисления;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры


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


И вызываем необходимую процедуру:
//Начисление зарплаты
 ЗаписатьДанныеЗарплатыВРегистрЗарплатаСотрудников();


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

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