Часто начинающие разработчики 1С сталкиваются с учебными или практическими задачами, где требуется реализовать простую схему начисления заработной платы: «Мастер выполнил работу на сумму X, он получает Y% от этой суммы». При этом условие задачи строго ограничивает используемые объекты: Оборотный регистр накопления и Регистр сведений.
Возникает вопрос: почему не использовать предназначенный для этого РегистрРасчета? Ответ прост: для задач управленческого учета, простых CRM-систем или мотивационных схем «процент от продаж» использование тяжеловесного механизма сложных периодических расчетов (с вытеснением, графиками работы и больничными) является избыточным. Разберем подробно, как решить эту задачу правильно и эффективно.
Разберем условия задачи:
Исходя из этого, мы построим следующую схему данных:
Сначала создадим место, где будем хранить процентную ставку мастера. Для этого нам понадобится периодический регистр сведений.
Создадим объект РегистрСведений, назовем его, например, ТарифыМастеров.
Важные настройки:
Сотрудник (или Мастер) с типом СправочникСсылка.Сотрудники.Процент с типом Число.Теперь мы можем использовать стандартную виртуальную таблицу СрезПоследних, чтобы получать актуальный процент на любую дату.
Чтобы рассчитать зарплату, нам нужно знать, на какую сумму мастер оказал услуг. Для этого создадим РегистрНакопления, назовем его ПродажиУслуг.
Важные настройки:
Сотрудник (СправочникСсылка.Сотрудники).Сумма (Число).Движения в этот регистр должен делать документ, фиксирующий факт работы (например, документ «ОказаниеУслуг» или «ЗаказНаряд»). При проведении этого документа в регистр будет записываться: КТО сделал и на какую СУММУ.
Самая интересная часть — это получение итоговой суммы зарплаты. Обычно это реализуется в документе «НачислениеЗарплаты», который создается раз в месяц.
Нам необходимо написать запрос, который:
Разберем код процедуры обработки проведения или заполнения табличной части такого документа.
// Пример запроса для получения данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиОбороты.Сотрудник КАК Сотрудник,
| ПродажиОбороты.СуммаОборот КАК БазаРасчета,
| ЕСТЬNULL(ТарифыСрезПоследних.Процент, 0) КАК Процент
|ИЗ
| РегистрНакопления.ПродажиУслуг.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ТарифыМастеров.СрезПоследних(&КонецПериода, ) КАК ТарифыСрезПоследних
| ПО ПродажиОбороты.Сотрудник = ТарифыСрезПоследних.Сотрудник";
// Устанавливаем параметры. Важно!
// КонецПериода для оборотов и для среза последних может логически отличаться на 1 секунду
// (в зависимости от того, включаете вы границу или нет), но суть одна - берем данные за месяц.
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ПериодРегистрации));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ПериодРегистрации));
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// Рассчитываем зарплату
СуммаЗарплаты = Выборка.БазаРасчета * Выборка.Процент / 100;
// Здесь должен быть код добавления движения в регистр зарплаты или заполнения ТЧ
// ...
КонецЦикла;
Обратим внимание на важные детали в запросе:
ЕСТЬNULL для поля Процент. Если для сотрудника не задан тариф в регистре сведений, запрос вернет NULL, что приведет к ошибке при умножении. Замена на 0 решает эту проблему.СрезПоследних очень важен. Обычно берут дату окончания расчетного месяца, чтобы применился именно тот процент, который действовал в этом месяце.В задаче сказано про "Оборотный регистр накопления". Здесь есть два варианта трактовки, в зависимости от того, что именно от вас требуется:
Вариант А: Использовать оборотный регистр только как базу (как мы сделали выше).
В этом случае результат расчета (СуммаЗарплаты) обычно записывается в третий регистр — регистр накопления с видом Остатки (например, ВзаиморасчетыССотудниками). Это логично: начислили — долг фирмы вырос, выплатили — долг уменьшился.
Вариант Б: Использовать оборотный регистр для фиксации факта начисления.
Если задание учебное и преподаватель требует использовать именно оборотный регистр для зарплаты, то вы создаете еще один регистр накопления (Обороты) с именем НачисленияЗарплаты.
В этом случае документ начисления будет делать движения вида:
// Внутри цикла обработки выборки из предыдущего шага:
Движение = Движения.НачисленияЗарплаты.Добавить();
Движение.Период = ПериодРегистрации;
Движение.Сотрудник = Выборка.Сотрудник;
Движение.Сумма = СуммаЗарплаты;
Такой регистр покажет вам аналитику: "Сколько мы начислили денег за период", но он не покажет "Сколько мы сейчас должны сотруднику", так как не учитывает выплаты. Для полноценного учета всегда требуется регистр остатков, но для задачи "посчитать и сохранить результат" оборотного регистра достаточно.
Мы рассмотрели реализацию схемы "Управленческая сдельная зарплата". Давайте подведем итог, почему это решение эффективно для поставленной задачи:
ПланВидовРасчета и РегистрРасчета.РегистрСведений позволяет гибко менять процент. История изменений сохраняется благодаря периодичности.Обороты и СрезПоследних) — это "золотой стандарт" производительности в 1С при получении базы и коэффициентов.Этот подход широко применяется в конфигурациях "Управление торговлей" или "Управление нашей фирмой" для расчета премий менеджеров и бонусов.