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