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