Регистры расчёта для начинающих

06.07.26

Разработка - Механизмы платформы 1С

Описание механизма периодических расчётов в платформе 1С.

Бесплатные

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Узнавайте о новых бесплатных решениях в нашей телеграм-группе Инфостарт БЕСПЛАТНО

Наименование Скачано Бесплатно
Регистры расчёта для начинающих
.zip 696,54Kb
3 Скачать бесплатно

Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

Регистр расчёта имеет славу экзотического объекта конфигурации, назначение и приёмы работы с которым не могут быть описаны в двух словах.

Если понимание работы прочих регистров не вызывает затруднения (регистры сведений хранят постоянные и периодические сведения, регистры накопления и бухгалтерии фиксируют приходные и расходные движения), то само назначение регистра расчёта — сложные периодические расчёты — кажется замысловатым.

В силу этого во время подготовки (которая ещё продолжается) к экзамену на специалиста по платформе возникла мысль о сочинении некоего учебного материала, который может послужить дополнительным источником при освоении темы.

 

Оглавление
1. Простой регистр расчёта
2. Использование периода действия
2.1 Период действия
2.2 График
2.3 Вытеснение
2.4 Настройка использования периода действия
2.5 Таблицы
2.6 Расчёт записей регистра
2.7 Использование разных способов расчёта
3. Зависимость от базы
3.1 Настройка использования зависимости от базы
3.2 Получение базы
3.3 Использование разных планов видов расчёта
3.4 Свойство Период действия базовый
3.5 Расчёт записей регистра
4. Сторно
5. Перерасчёт
6. Файлы публикации

 

1. Простой регистр расчёта

 

Регистр расчёта — это таблица, которая хранит сведения о факте действия / наличия данного вида расчёта в данном периоде (называющемся периодом регистрации).

Период записи соответствует периодичности регистра расчёта (день, месяц, квартал, год) — почти такая же как у регистра сведений, кроме секунды.

Вид расчёта — это предопределённое измерение регистра (как Счёт для регистра бухгалтерии) типа План видов расчёта: назначается в свойствах регистра. В контексте расчёта заработной платы под видом расчёта можно понимать то или иное начисление сотруднику (оклад, премия и т.п.).

Состав полей регистра зависит от его настройки. В самом простом варианте при записи в него обязательны поля Период регистрации и Вид расчёта.

Помимо таких полей как Активность, Регистратор, Номер строки, у записи есть поле Сторно (что бы это пока ни значило).

Также запись может содержать необходимые измерения (сотрудник), ресурсы (сумма) и реквизиты (из сказанного следует, что регистр может быть вообще без измерений, ресурсов и реквизитов).

Например, запись может быть такой: В январе 2026 г. (Период регистрации) сотруднику Петрову (Сотрудник) начислен оклад (Вид расчёта) в размере 100 тыс. (сумма).

Создадим объекты конфигурации:

  • Справочники ФизическиеЛица, Организации, Сотрудники
  • План видов расчёта ОсновнойРасчет
  • Регистр расчёта ОсновнойРасчет (измерения — Сотрудник, ресурсы — Результат, реквизиты — Организация)
  • Документ НачислениеЗарплаты

Как принято, справочник Сотрудники привяжем к справочникам ФизическиеЛица и Организации, чтобы одно физическое лицо могло быть сотрудником разных организаций.

Укажем план видов расчёта в свойстве регистра расчёта. Программно следующее выражение возвращает истина:

Метаданные.РегистрыРасчета.ОсновнойРасчет.ПланВидовРасчета = Метаданные.ПланыВидовРасчета.ОсновнойРасчет

Периодичность регистра — Месяц:

Метаданные.РегистрыРасчета.ОсновнойРасчет.Периодичность = Метаданные.СвойстваОбъектов.ПериодичностьРегистраРасчета.Месяц

Измерение будет одно — Сотрудник: поскольку у справочника есть реквизит Организация, дублировать его в измерениях регистра не будем, но включим в состав реквизитов. Ресурс назовём, как это принято в конфигурации ЗУП, Результат.

Регистр расчёта в элементарном варианте настройки

 

 

Создадим в режиме предприятия вид расчёта Работа. Создадим экземпляр документа НачислениеЗарплаты, добавим в табличную часть 2 одинаковые строки и проведём его.

Вид расчёта и документ НачислениеЗарплаты

 

 

Обработка проведения документа НачислениеЗарплаты

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

	НЗ.Записать();

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

 

Обратим внимание на созданные таблицы базы данных (тут может пригодиться информация с ИТС — Размещение данных 1С:Предприятия. Таблицы и поля).

План видов расчёта ОсновнойРасчет

Имя таблицы Имя таблицы хранения Назначение

ПланВидовРасчета.ОсновнойРасчет

CKinds214 Основная
ПланВидовРасчета.ОсновнойРасчет.ВедущиеВидыРасчета CKinds214.LeadingCK ТабличнаяЧасть

 

 

 

 

 

Табличная часть ВедущиеВидыРасчета — пустая. При текущей настройке плана вида расчётов она не имеет смысла.

Регистр расчёта ОсновнойРасчет

Имя таблицы Имя таблицы хранения Назначение

РегистрРасчета.ОсновнойРасчет

CRg215 Основная

 

 

 

 

В регистр расчёта были записаны 2 одинаковые строки документа, и отличаются они только номером строки. Между тем у регистра расчёта нет прихода в регистр, нет расхода из регистра, нет оборота по регистру — есть только факт наличия записи. Поэтому данный (искусственный) пример следует понимать не как то, что было произведено начисление по виду расчета Работа на 200, а как то, что  было произведено начисление на 100 с номером строки 1 и начисление на 100 с номером строки 2. Разумеется, проще ввести одну строку на 200, но при наличии двух строк каждая из них уникальна и самостоятельна чуть более, чем в привычном смысле.

Период записи (то есть период регистрации) приводится к началу календарного периода, соответствующего периодичности регистра: так, в период регистрации передаётся дата документа — конец месяца, а записывается — начало.

Таким образом, период регистрации это и поле таблицы регистра расчёта, и календарный период — период расчёта.

При текущей настройке регистра у него одна физическая таблица (максимум — их две) и нет виртуальных. Обоснованно полагать, что возможностей у регистра расчёта больше, чем у простой таблицы.

 

2. Использование периода действия

 

2.1 Период действия

Введённые ранее записи характеризовались только фактом наличия в данном периоде регистрации. Помимо периода регистрации, у записи регистра может быть обозначен интервал действия. Даты начала и окончания этого интервала должны лежать внутри одного периода, ограниченного периодичностью регистра. Этот период (по аналогии с периодом регистрации) называется периодом действия.

Поля регистра

Поле

Описание

ПериодРегистрации

Всегда равен началу периода, кратного периодичности регистра.

ПериодДействия

Всегда равен началу периода, кратного периодичности регистра.

ПериодДействияНачало

Произвольная дата внутри периода действия.

ПериодДействияКонец

Произвольная дата внутри периода действия.

 

Например, периодичность регистра — месяц, период регистрации — 01.01.2016, он же январь 2016, дата начала действия — 16.01.2016, дата окончания действия — 27.01.2016, период действия — 01.01.2016, он же январь 2016.

Под периодом действия, как и под периодом регистрации, мы понимаем дату начала и саму календарную единицу времени — период, соответствующий периодичности регистра (день, месяц и т.п.). Сам же календарный отрезок, во избежание разночтения, можно называть интервалом.

Помимо обозначенного при записи интервала действия, существует фактический (что бы это пока ни значило), который (в конфигураторе и литературе) называется фактическим периодом действия и может отличаться от первого. Поскольку «фактический период действия» — это официальный термин, можем использовать его наравне с выражением «фактический интервал действия». Интервал между датой начала и датой окончания действия записи регистра можем называть «плановый период действия» или «плановый интервал действия».

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

Период действия может не совпадать с периодом регистрации.

Использование периода действия расширяет возможности регистра.

 

2.2 График

Во-первых, разумно считать, что интервал действия записи регистра определяет его (действия) удельный вес относительно периода действия.

Вес каждого дня указывается (как произвольное число в ресурсе) в регистре сведений (именуемом графиком), с которым связывается регистр расчёта. Чтобы получить вес дня, необходимо сопоставить значения полей регистра расчёта полям регистра сведений.

У регистра сведений должно быть минимум одно измерение типа Дата (день) и один ресурс типа Число (вес). При наличии прочих измерений регистра сведений устанавливается их соответствие полям (измерениям и реквизитам) регистра расчёта.

Типичный пример использования такого регистра сведений (с говорящим названием)— это хранение в нём нормативного времени графиков работы.

На рисунке продемонстрирован регистр с измерениями Дата и График (ссылка на справочник) и ресурсом Значение (признак рабочего дня). У записи регистра расчёта указан интервал действия и график (реквизит регистра — ссылка на справочник).

Сумма ресурса Значение за интервал действия 01.01.2016-16.01.2016 равна 5. Сумма ресурса за период действия (01.01.2016) равна 15. Удельный вес интервала в периоде действия равен 5/15 = 1/3.

Использование графика

 

 

У регистра-графика может быть больше одного ресурса, по каждому из которых может быть рассчитан удельный вес.

Для расчёта данных графика может быть использована одноимённая виртуальная таблица.

 

2.3 Вытеснение

Во-вторых, одни виды расчёта могут «вытеснять» другие на интервале действия.

На рисунке показаны 2 записи регистра расчёта с пересекающимися интервалами. При этом вид расчёта Неработа вытесняет вид расчёта Работа. В результате вытеснения у записи регистра появляется, помимо указанного при записи, фактический интервал действия (или фактический период действия).

На рисунке записи с видом расчёта Работа соответствуют 2 фактических интервала.

Фактические интервалы рассчитываются при записи в регистр и хранятся в отдельной физической таблице, доступ к которой осуществляется через виртуальную.

Чтобы вытеснение произошло, помимо пересечения интервалов, необходимы одинаковые значения измерений регистра (реквизиты в вытеснении не участвуют).

Вытеснение работает только в рамка одного плана видов расчёта (нельзя указать в качестве вытесняющего вид расчёта из другого ПВР).

Фактический интервал действия

 

 

2.4 Настройка использования периода действия

Создадим справочник ГрафикиРаботы, регистр сведений ГрафикиРаботы, создадим элемент справочника ГрафикиРаботы «Основной», заполним регистр сведений ГрафикиРаботы (за период Январь 2026, график работы — Основной, Значение равно 1, если это рабочий день).

Графики работы

 

 

Добавим в табличную часть документа НачислениеЗарплаты реквизиты График, ПериодДействияНач, ПериодДействияКон.

Реквизит Результат переименуем в Значение (или Размер), чтобы отличать эту цифру от ресурса регистра Результат, который может отличаться от планового значения (например, из-за того, что фактический интервал действия оказался меньше планового).

Документ НачислениеЗарплаты

 

 

У плана видов расчёта установим флаг использования периода действия.

Программно следующее выражение возвращает истина:

Метаданные.ПланыВидовРасчета.ОсновнойРасчет.ИспользованиеПериодаДействия = Истина

ПВР ОсновнойРасчет

 

 

У регистра расчёта установим флаг использования периода действия.

Добавим реквизиты Значение, График.

Укажем свойство График — регистр сведений ГрафикиРаботы, дату графика, значение графика.

Для реквизита График укажем связь с графиком — измерение регистра сведений.

Программно следующие выражения возвращают истина:

Метаданные.РегистрыРасчета.ОсновнойРасчет.ПериодДействия = Истина
Метаданные.РегистрыРасчета.ОсновнойРасчет.График = Метаданные.РегистрыСведений.ГрафикиРаботы
Метаданные.РегистрыРасчета.ОсновнойРасчет.ЗначениеГрафика = Метаданные.РегистрыСведений.ГрафикиРаботы.Ресурсы.Значение
Метаданные.РегистрыРасчета.ОсновнойРасчет.ДатаГрафика = Метаданные.РегистрыСведений.ГрафикиРаботы.Измерения.Дата
Метаданные.РегистрыРасчета.ОсновнойРасчет.Реквизиты.График.СвязьСГрафиком = Метаданные.РегистрыСведений.ГрафикиРаботы.Измерения.График

РР ОсновнойРасчет

 

 

Доработаем обработку проведения документа НачислениеЗарплаты.

Обработка проведения документа НачислениеЗарплаты

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

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

 

Создадим новый вид расчёта Неработа и настроим вытеснение.

Настройка вытеснения вида расчёта

 

 

Заполним и проведём документ НачислениеЗарплаты.

Документ НачислениеЗарплаты

 

 

Движения документа НачислениеЗарплаты

 

 

2.5 Таблицы

У плана видов расчёта ОсновнойРасчет появились 2 новые таблицы. Одна из них соответствует предопределённой табличной части ВытесняющиеВидыРасчета. Другая таблица с назначением

ПорядокВытеснения не имеет соответствия в конфигураторе.

План видов расчёта ОсновнойРасчет

Имя таблицы Имя таблицы хранения Назначение

ПланВидовРасчета.ОсновнойРасчет.ВытесняющиеВидыРасчета

CKinds214.DisplacedCK ТабличнаяЧасть
  CKindsDN240 ПорядокВытеснения

 

 

 

 

При настройке вытеснения платформа контролирует порядок вытеснения видов расчётов. На рисунке у вида расчёта Неработа значение поля _DisplNumber равно 1, у вида расчёта Работа — 2.

Таблица ПорядокВытеснения

 

 

Таблица ВытесняющиеВидыРасчета

 

У регистра расчёта ОсновнойРасчет появилась 1 новая таблица с назначением ПериодыДействия, которая не имеет соответствия в конфигураторе.

Регистр расчёта ОсновнойРасчет

Имя таблицы Имя таблицы хранения Назначение
  CRgActP242 ПериодыДействия

 

 

 

У основной таблицы регистра появились дополнительные поля _ActionPeriod, _APDateFrom, _APDateTill, которые соответствуют полям ПериодДействия, ПериодДействияНачало, ПериодДействияКонец.

Основная таблица РР ОсновнойРасчет

 

 

Для получения данных физической таблицы ПериодыДействия используется виртуальная таблица ФактическийПериодДействия.

У таблицы один параметр типа Условие.

Записи таблицы не являются безымянными, но соответствуют записям регистратора: есть Регистратор и номер строки. В данном случае запись документа с номером строки 1 фигурирует дважды: до и после интервала пересечения.

Состав физической таблицы ПериодыДействия скромен: помимо регистратора и номера строки, есть 2 поля _APDateFrom и _APDateTill. При формировании виртуальной таблицы используется соединение основной таблицы регистра с таблицей ПериодыДействия.

Таблица ПериодыДействия РР ОсновнойРасчет

 

 

Виртуальная таблица ФактическийПериодДействия РР ОсновнойРасчет

 

Чтобы сымитировать в консоли запросов запрос, формирующийся на стороне СУБД, используем данные виртуальной таблицы как физическую, создав временную таблицу.

 
 Запрос к виртуальной таблице ФактическийПериодДействия РР ОсновнойРасчет на стороне СУБД
SELECT
T1.Period_,
T1.RecorderRRef,
T1.LineNo_,
T1.CalcKindRRef,
T1.ActionPeriod_,
T1.APDateFrom_,
T1.APDateTill_,
T1.Active_,
T1.Storno_,
T1.Fld216RRef,
T1.Fld217_,
T1.Fld219RRef,
T1.Fld258_,
T1.Fld245RRef
FROM (SELECT
T2._Period AS Period_,
T2._RecorderRRef AS RecorderRRef,
T2._LineNo AS LineNo_,
T2._CalcKindRRef AS CalcKindRRef,
T2._ActionPeriod AS ActionPeriod_,
CASE WHEN T3._APDateFrom IS NULL THEN T2._APDateFrom ELSE T3._APDateFrom END AS APDateFrom_,
CASE WHEN T3._APDateTill IS NULL THEN T2._APDateTill ELSE T3._APDateTill END AS APDateTill_,
T2._Active AS Active_,
T2._Storno AS Storno_,
T2._Fld216RRef AS Fld216RRef,
T2._Fld217 AS Fld217_,
T2._Fld219RRef AS Fld219RRef,
T2._Fld258 AS Fld258_,
T2._Fld245RRef AS Fld245RRef
FROM dbo._CRg215 T2
LEFT OUTER JOIN dbo._CRgActP242 T3
ON T2._RecorderRRef = T3._RecorderRRef AND T2._LineNo = T3._LineNo
WHERE (T3._APDateFrom <> @P1 OR T3._APDateFrom IS NULL)) T1

 

 
 Имитация запроса к виртуальной таблице ФактическийПериодДействия РР ОсновнойРасчет на стороне СУБД
ВЫБРАТЬ
	*
ПОМЕСТИТЬ ПериодыДействия
ИЗ
	РегистрРасчета.ОсновнойРасчет.ФактическийПериодДействия КАК Таблица
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T1.Period_ КАК Period_,
	T1.RecorderRRef КАК RecorderRRef,
	T1.LineNo_ КАК LineNo_,
	T1.CalcKindRRef КАК CalcKindRRef,
	T1.ActionPeriod_ КАК ActionPeriod_,
	T1.APDateFrom_ КАК APDateFrom_,
	T1.APDateTill_ КАК APDateTill_,
	T1.Active_ КАК Active_,
	T1.Storno_ КАК Storno_,
	T1.Fld216RRef КАК Fld216RRef,
	T1.Fld217_ КАК Fld217_,
	T1.Fld219RRef КАК Fld219RRef,
	T1.Fld258_ КАК Fld258_,
	T1.Fld245RRef КАК Fld245RRef
ИЗ
	(ВЫБРАТЬ
		T2.ПериодРегистрации КАК Period_,
		T2.Регистратор КАК RecorderRRef,
		T2.НомерСтроки КАК LineNo_,
		T2.ВидРасчета КАК CalcKindRRef,
		T2.ПериодДействия КАК ActionPeriod_,
		ВЫБОР
			КОГДА T3.ПериодДействияНачало ЕСТЬ NULL
				ТОГДА T2.ПериодДействияНачало
			ИНАЧЕ T3.ПериодДействияНачало
		КОНЕЦ КАК APDateFrom_,
		ВЫБОР
			КОГДА T3.ПериодДействияКонец ЕСТЬ NULL
				ТОГДА T2.ПериодДействияКонец
			ИНАЧЕ T3.ПериодДействияКонец
		КОНЕЦ КАК APDateTill_,
		T2.Активность КАК Active_,
		T2.Сторно КАК Storno_,
		T2.Сотрудник КАК Fld216RRef,
		T2.Результат КАК Fld217_,
		T2.Организация КАК Fld219RRef,
		T2.Значение КАК Fld258_,
		T2.График КАК Fld245RRef
	ИЗ
		РегистрРасчета.ОсновнойРасчет КАК T2
			ЛЕВОЕ СОЕДИНЕНИЕ ПериодыДействия КАК T3
			ПО T2.Регистратор = T3.Регистратор
				И T2.НомерСтроки = T3.НомерСтроки
	ГДЕ
		(T3.ПериодДействияНачало <> ДАТАВРЕМЯ(1, 1, 1)
				ИЛИ T3.ПериодДействияНачало ЕСТЬ NULL)) КАК T1

 

 

Следующая таблица — виртуальная таблица ДанныеГрафика.

У таблицы один параметр типа Условие.

Опять же, записи таблицы связаны с уникальными номерами строк движений регистратора по регистру ОсновнойРасчет.

Каждый ресурс регистра сведений множится на 3 поля: <ИмяРесурса>ПериодДействия, <ИмяРесурса>ФактическийПериодДействия, <ИмяРесурса>ПериодРегистрации.

В данном случае в графике число рабочих дней за Январь 2016 составляет 15, за фактический период действия по виду расчёта Работа число рабочих дней составляет 12, так как интервал действия записи был вытеснен видом расчёта Неработа.

Выше мы говорили, что реквизиты регистра расчёта не участвуют в вытеснении. Если бы график по виду расчёта Неработа был также равен Основной, это не повлияло бы на вытеснение, но фактическое значение ресурса графика по виду расчёта Неработа в результате запроса было бы равно 3.

Заметим, что в тексте запроса присутствует реквизит регистра расчёта Значение, которое не связано с ресурсом регистра сведений — просто у них одинаковые имена (реквизит регистра расчёта можно было назвать Размер, а ресурс регистра сведений — Дней).

Виртуальная таблица ДанныеГрафика РР ОсновнойРасчет

 

В несложном тексте запроса состоит выгода использования виртуальной таблицы. Реальный запрос намного витиеватей.

 
 Имитация запроса к виртуальной таблице ДанныеГрафика РР ОсновнойРасчет на стороне СУБД

 

ВЫБРАТЬ
	*
ПОМЕСТИТЬ ПериодыДействия
ИЗ
	РегистрРасчета.ОсновнойРасчет.ФактическийПериодДействия КАК Таблица
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T1.DATEFROM_ КАК _DATEFROM,
	T1.DATETILL_ КАК _DATETILL,
	T1.Fld245RRef КАК _Fld245RRef,
	ВЫРАЗИТЬ(СУММА(T3.Значение) КАК ЧИСЛО(16, 0)) КАК _Fld63AAP
ПОМЕСТИТЬ tt3
ИЗ
	(ВЫБРАТЬ РАЗЛИЧНЫЕ
		T2.ПериодДействия КАК DATEFROM_,
		ДОБАВИТЬКДАТЕ(T2.ПериодДействия, МЕСЯЦ, 1) КАК DATETILL_,
		T2.График КАК Fld245RRef
	ИЗ
		РегистрРасчета.ОсновнойРасчет КАК T2) КАК T1
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикиРаботы КАК T3
		ПО (T3.Дата >= T1.DATEFROM_)
			И (T3.Дата < T1.DATETILL_)
			И T1.Fld245RRef = T3.График
ГДЕ
	T3.Дата ЕСТЬ НЕ NULL 

СГРУППИРОВАТЬ ПО
	T1.DATEFROM_,
	T1.DATETILL_,
	T1.Fld245RRef
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T4.DATEFROM_ КАК _DATEFROM,
	T4.DATETILL_ КАК _DATETILL,
	T4.Fld245RRef КАК _Fld245RRef,
	ВЫРАЗИТЬ(СУММА(T7.Значение) КАК ЧИСЛО(16, 0)) КАК _Fld63RP
ПОМЕСТИТЬ tt5
ИЗ
	(ВЫБРАТЬ РАЗЛИЧНЫЕ
		ВЫБОР
			КОГДА T6.ПериодДействияНачало ЕСТЬ NULL
				ТОГДА T5.ПериодДействияНачало
			ИНАЧЕ T6.ПериодДействияНачало
		КОНЕЦ КАК DATEFROM_,
		ВЫБОР
			КОГДА T6.ПериодДействияКонец ЕСТЬ NULL
				ТОГДА T5.ПериодДействияКонец
			ИНАЧЕ T6.ПериодДействияКонец
		КОНЕЦ КАК DATETILL_,
		T5.График КАК Fld245RRef
	ИЗ
		РегистрРасчета.ОсновнойРасчет КАК T5
			ЛЕВОЕ СОЕДИНЕНИЕ ПериодыДействия КАК T6
			ПО T5.Регистратор = T6.Регистратор
				И T5.НомерСтроки = T6.НомерСтроки) КАК T4
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикиРаботы КАК T7
		ПО (T7.Дата >= T4.DATEFROM_)
			И (T7.Дата <= T4.DATETILL_)
			И T4.Fld245RRef = T7.График
ГДЕ
	T7.Дата ЕСТЬ НЕ NULL 

СГРУППИРОВАТЬ ПО
	T4.DATEFROM_,
	T4.DATETILL_,
	T4.Fld245RRef
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВЫРАЗИТЬ(СУММА(T10._Fld63RP) КАК ЧИСЛО(22, 0)) КАК _Fld63AAP,
	T8.Регистратор КАК _RecorderRRef,
	T8.НомерСтроки КАК _LineNo
ПОМЕСТИТЬ tt4
ИЗ
	РегистрРасчета.ОсновнойРасчет КАК T8
		ЛЕВОЕ СОЕДИНЕНИЕ ПериодыДействия КАК T9
		ПО T8.Регистратор = T9.Регистратор
			И T8.НомерСтроки = T9.НомерСтроки
		ЛЕВОЕ СОЕДИНЕНИЕ tt5 КАК T10
		ПО (T10._DATEFROM = ВЫБОР
				КОГДА T9.ПериодДействияНачало ЕСТЬ NULL
					ТОГДА T8.ПериодДействияНачало
				ИНАЧЕ T9.ПериодДействияНачало
			КОНЕЦ)
			И (T10._DATETILL = ВЫБОР
				КОГДА T9.ПериодДействияКонец ЕСТЬ NULL
					ТОГДА T8.ПериодДействияКонец
				ИНАЧЕ T9.ПериодДействияКонец
			КОНЕЦ)
			И T8.График = T10._Fld245RRef

СГРУППИРОВАТЬ ПО
	T8.Регистратор,
	T8.НомерСтроки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T11.DATEFROM_ КАК _DATEFROM,
	T11.DATETILL_ КАК _DATETILL,
	T11.Fld245RRef КАК _Fld245RRef,
	ВЫРАЗИТЬ(СУММА(T13.Значение) КАК ЧИСЛО(16, 0)) КАК _Fld63AP
ПОМЕСТИТЬ tt2
ИЗ
	(ВЫБРАТЬ РАЗЛИЧНЫЕ
		T12.ПериодРегистрации КАК DATEFROM_,
		ДОБАВИТЬКДАТЕ(T12.ПериодРегистрации, МЕСЯЦ, 1) КАК DATETILL_,
		T12.График КАК Fld245RRef
	ИЗ
		РегистрРасчета.ОсновнойРасчет КАК T12) КАК T11
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикиРаботы КАК T13
		ПО (T13.Дата >= T11.DATEFROM_)
			И (T13.Дата < T11.DATETILL_)
			И T11.Fld245RRef = T13.График
ГДЕ
	T13.Дата ЕСТЬ НЕ NULL 

СГРУППИРОВАТЬ ПО
	T11.DATEFROM_,
	T11.DATETILL_,
	T11.Fld245RRef
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T15._Fld63AP КАК _Fld63RP,
	T14.Регистратор КАК _RecorderRRef,
	T14.НомерСтроки КАК _LineNo
ПОМЕСТИТЬ tt6
ИЗ
	РегистрРасчета.ОсновнойРасчет КАК T14
		ЛЕВОЕ СОЕДИНЕНИЕ tt2 КАК T15
		ПО (T15._DATEFROM = T14.ПериодРегистрации)
			И (T15._DATETILL = ДОБАВИТЬКДАТЕ(T14.ПериодРегистрации, МЕСЯЦ, 1))
			И T14.График = T15._Fld245RRef
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T1.Period_ КАК Period_,
	T1.RecorderRRef КАК RecorderRRef,
	T1.LineNo_ КАК LineNo_,
	T1.CalcKindRRef КАК CalcKindRRef,
	T1.ActionPeriod_ КАК ActionPeriod_,
	T1.APDateFrom_ КАК APDateFrom_,
	T1.APDateTill_ КАК APDateTill_,
	T1.Active_ КАК Active_,
	T1.Storno_ КАК Storno_,
	T1.Fld216RRef КАК Fld216RRef,
	T1.Fld217_ КАК Fld217_,
	T1.Fld219RRef КАК Fld219RRef,
	T1.Fld258_ КАК Fld258_,
	T1.Fld245RRef КАК Fld245RRef,
	T1.Fld63AP_ КАК Fld63AP_,
	T1.Fld63AAP_ КАК Fld63AAP_,
	T1.Fld63RP_ КАК Fld63RP_
ИЗ
	(ВЫБРАТЬ
		T2.Period_ КАК Period_,
		T2.RecorderRRef КАК RecorderRRef,
		T2.LineNo_ КАК LineNo_,
		T2.CalcKindRRef КАК CalcKindRRef,
		T2.ActionPeriod_ КАК ActionPeriod_,
		T2.APDateFrom_ КАК APDateFrom_,
		T2.APDateTill_ КАК APDateTill_,
		T2.Active_ КАК Active_,
		T2.Storno_ КАК Storno_,
		T2.Fld216RRef КАК Fld216RRef,
		T2.Fld217_ КАК Fld217_,
		T2.Fld219RRef КАК Fld219RRef,
		T2.Fld258_ КАК Fld258_,
		T2.Fld245RRef КАК Fld245RRef,
		T2.Fld63AP_ КАК Fld63AP_,
		T5._Fld63AAP КАК Fld63AAP_,
		T6._Fld63RP КАК Fld63RP_
	ИЗ
		(ВЫБРАТЬ
			T3.ПериодРегистрации КАК Period_,
			T3.Регистратор КАК RecorderRRef,
			T3.НомерСтроки КАК LineNo_,
			T3.ВидРасчета КАК CalcKindRRef,
			T3.ПериодДействия КАК ActionPeriod_,
			T3.ПериодДействияНачало КАК APDateFrom_,
			T3.ПериодДействияКонец КАК APDateTill_,
			T3.Активность КАК Active_,
			T3.Сторно КАК Storno_,
			T3.Сотрудник КАК Fld216RRef,
			T3.Результат КАК Fld217_,
			T3.Организация КАК Fld219RRef,
			T3.Значение КАК Fld258_,
			T3.График КАК Fld245RRef,
			T4._Fld63AAP КАК Fld63AP_
		ИЗ
			РегистрРасчета.ОсновнойРасчет КАК T3
				ЛЕВОЕ СОЕДИНЕНИЕ tt3 КАК T4
				ПО (T4._DATEFROM = T3.ПериодДействия)
					И (T4._DATETILL = ДОБАВИТЬКДАТЕ(T3.ПериодДействия, МЕСЯЦ, 1))
					И T3.График = T4._Fld245RRef) КАК T2
			ЛЕВОЕ СОЕДИНЕНИЕ tt4 КАК T5
			ПО T2.RecorderRRef = T5._RecorderRRef
				И T2.LineNo_ = T5._LineNo
			ЛЕВОЕ СОЕДИНЕНИЕ tt6 КАК T6
			ПО T2.RecorderRRef = T6._RecorderRRef
				И T2.LineNo_ = T6._LineNo) КАК T1

 

 

2.6 Расчёт записей регистра

Текущий вариант обработки проведения документа записал в регистр значение реквизита Значение и оставил ресурс Результат незаполненным.

На момент проведения вычислить удельный вес фактического интервала действия записи нельзя, так как платформой ещё не рассчитан фактический период действия, и не записаны данные в таблицу ПериодыДействия.

Поэтому после первой записи в регистр рассчитаем ресурс Результат и выполним повторную запись.

При повторной записи второй параметр метода Записать ТолькоЗапись передадим со значением Истина.

В этом случае производится только запись набора (см. Синтакс-помощник).
Обработка проведения документа НачислениеЗарплаты

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

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

 

Запрос по расчёту ресурса Результат по данным графика

 

Движения документа НачислениеЗарплаты

 

 

2.7 Использование разных способов расчёта

Использование периода действия у регистра расчёта не подразумевает то, что каждый вид расчёта связан с графиком и вытеснением. График и вытеснение — это дополнительные возможности регистра, и их применение для произвольного вида расчёта не обязательно.

Разнообразим состав видов расчёта и способов расчёта.

Создадим перечисление СпособыРасчетаЗарплаты, в план видов расчёта добавим реквизит СпособРасчета.

Реквизит СпособРасчета

 

 

Создадим регистр сведений СтавкиВознаграждения и добавим строчку.

РС СтавкиВознаграждения

 

 

Создадим нового сотрудника, дополним табличную часть документа НачислениеЗарплаты.

Документ НачислениеЗарплаты

 

 

Перепишем проведение документа.

Обработка проведения документа НачислениеЗарплаты

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

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

 

Запрос по расчёту ресурса Результат

 

 

Движения документа НачислениеЗарплаты

 

 

Хотя мы не использовали график и вытеснение для видов расчётов Почасовка и Поощрение, тем не менее, мы записали в регистр даты начала и окончания периода действия — как даты начала и окончания месяца. С одной стороны, мы обязаны передать туда какие-то значения, с другой — можно подразумевать, что сдельная оплата труда специалиста и его поощрение осуществлены на основании работы за месяц. В то же время мы могли установить дату начала и окончания периода действия как дату начала и конца дня периода регистрации или вообще использовать план видов расчёта без использования периода действия. Данный пассаж имеет целью подчеркнуть, что настройка расчёта производится не столько с учётом каких-то методических требований, сколько в контексте возможностей платформы.

 

3. Зависимость от базы

 

3.1 Настройка использования зависимости от базы

Для расчёта некоторых величин используются значения других, которые являются базой для первых. Например, сумма начисленного оклада может выступить базой для расчёта премии за текущий месяц способом умножения на некий коэффициент.

Настройка зависимости от базы выполняется с помощью свойства плана видов расчёта  ЗависимостьОтВидовРасчета и свойства регистра расчёта БазовыйПериод.
Программно выражение

Метаданные.ПланыВидовРасчета.<ИмяПВР>.ЗависимостьОтВидовРасчета

может быть следующих значений:

Метаданные.СвойстваОбъектов.ИспользованиеБазыПланаВидовРасчета.НеИспользовать / ПоПериодуДействия / ПоПериодуРегистрации.

Программно выражение

Метаданные.РегистрыРасчета.<ИмяРР>.БазовыйПериод

может быть следующих значений: Истина или Ложь.

Установим у ПВР ОсновнойРасчет зависимость по периоду действия и включим свойство БазовыйПериод у одноимённого РР. В табличной части документа НачислениеЗарплаты добавим реквизиты БазовыйПериодНач и БазовыйПериодКон.

Настройка зависимости от базы

 

 

При включении зависимости от базы у плана видов расчёта появляется предопределённая табличная часть БазовыеВидыРасчета. Создадим новый вид расчёта и добавим туда базовые виды расчёта.

Вид расчёта Премия

 

 

Добавим новые строки в документ НачислениеЗарплаты.

Документ НачислениеЗарплаты

 

 

Доработаем обработку проведения документа.

Обработка проведения документа НачислениеЗарплаты

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
	
//...
			
			Если ОбъектМетаданныхРегистр.БазовыйПериод Тогда
				Если ЗначениеЗаполнено(СтрокаТЧ.БазовыйПериодНач) Тогда
					НовСтр.БазовыйПериодНачало = СтрокаТЧ.БазовыйПериодНач;
				КонецЕсли;
				Если ЗначениеЗаполнено(СтрокаТЧ.БазовыйПериодКон) Тогда
					НовСтр.БазовыйПериодКонец = КонецДня(СтрокаТЧ.БазовыйПериодКон);
				КонецЕсли;
			КонецЕсли;
			
//...
	
КонецПроцедуры

 

Как уже было сказано, при включении зависимости от базы у плана видов расчёта появляется таблица БазовыеВидыРасчета.

План видов расчёта ОсновнойРасчет

Имя таблицы Имя таблицы хранения Назначение
ПланВидовРасчета.ОсновнойРасчет.БазовыеВидыРасчета CKinds214.BaseCK ТабличнаяЧасть

 

 

 

 

У плана видов расчёта появляется реквизит ПериодДействияБазовый.

Основная таблица ПВР

 

 

У регистра расчёта появились поля _BPDateFrom и _BPDateTill, которые соответствуют полям БазовыйПериодНачало и БазовыйПериодКонец.

Таблица регистра расчёта

 

 

3.2 Получение базы

В платформе существует приём получения базы с помощью виртуальной таблицы.

Виртуальных таблиц для получения базы существует столько, сколько возможно комбинаций из "основного" (зависимого) и "базового" регистра расчёта.

Конструкция обращения к таблице формируется так:

РегистрРасчета.<ИмяОсновногоРегистра>.База<ИмяБазовогоРегистра>

Здесь мы назвали основным регистр, в котором наличествуют записи с видами расчёта, которые зависят от базы, а базовым — с базовыми видами расчёта.

В нашем примере ПВР ОсновнойРасчет (имена регистров и планов видов расчёта у нас одинаковые) зависит от базы сам от себя, и виртуальная таблица формируется так:

РегистрРасчета.ОсновнойРасчет.БазаОсновнойРасчет

Получение базы предусматривает:

  • наличие в регистре расчёта записей с зависимыми видами расчёта (у нас это Премия)
  • наличие записей с базовыми видами расчёта (Работа, Почасовка)
  • указание даты начала и окончания базового периода (01.01.2016-15.01.2016)
  • способ зависимости от базы (в нашем случае это зависимость по периоду действия)

Если с первыми двумя пунктами всё понятно, то третий и четвёртый вызывают вопросы. Чем отличается зависимость по периоду действия и периоду регистрации и что мы хотели сказать, обозначив базовый период половиной месяца.

Скажем так, что зависимость по периоду действия предполагает, что базовый вид расчёта использует период действия, а при зависимости по периоду регистрации важен только факт наличия записи.

Базовый период в первом случае должен пересекаться с периодом действия, во втором — с периодом регистрации.

Вид расчёта Работа в нашем примере явно использует период действия, так как при записи ему назначен график. Вид расчёта Почасовка, мы можем сказать,  по своему замыслу период действия не использует, хотя технически находится в том же регистре.

Базовый период задан как первая половина месяца, чтобы полученная база отличалась от полного результата записи и можно было делать какие-то выводы.

Виртуальная таблица базы имеет 4 параметра.

Первые 2 параметра обязательны: ИзмеренияОсновногоРегистра и ИзмеренияБазовогоРегистра.

В этих параметрах указывается массив имён измерений и реквизитов, в рамках которых происходит получение базы. 

Наличие этих параметров преследует цели сопоставления полей основного и базового регистров (в одном регистре измерение/реквизит может именоваться Сотрудник, в другом — Работник) и обозначения контура получения базы (например, с учётом или без учёта разнообразных измерений и реквизитов — Организации, Подразделения и т.п.).

Остальные параметры разберём позже, а сейчас выполним запрос к виртуальной таблице базы, используя измерение Сотрудник.

Наименование поля базы формируется как <ИмяРесурса>База. Их может быть столько, сколько ресурсов у регистра расчёта.

Как полагается, установим свойство Базовое у измерения регистра Сотрудник. См. Свойство Базовое измерения регистра расчета.

Программное следующее выражение возвращает Истина:

Метаданные.РегистрыРасчета.ОсновнойРасчет.Измерения.Сотрудник.БазовоеИзмерение

Установка свойства никак не влияет на приёмы работы в 1С, но изменяет структуру индексов.

Свойство БазовоеИзмерение измерения регистр расчёта

 

Запрос к виртуальной таблице базы регистра расчёта

 

Чтобы (примерно) понять, что делает платформа, полезно исследовать запрос, выполняющийся на стороне СУБД.

 
 Имитация запроса к виртуальной таблице базы регистра расчёта на стороне СУБД

 

ВЫБРАТЬ
	*
ПОМЕСТИТЬ ПериодыДействия
ИЗ
	РегистрРасчета.ОсновнойРасчет.ФактическийПериодДействия КАК Таблица
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	T2.Регистратор КАК _RecorderRRef,
	T2.ВидРасчета КАК _CalcKindRRef,
	T2.НомерСтроки КАК _LineNo,
	T2.ПериодДействия КАК _ActionPeriod,
	T2.Сотрудник КАК _Fld216RRef,
	T2.Результат КАК _Fld217,
	T2.График КАК _Fld245RRef,
	ВЫБОР
		КОГДА T3.ПериодДействияНачало ЕСТЬ NULL
			ТОГДА T2.ПериодДействияНачало
		ИНАЧЕ T3.ПериодДействияНачало
	КОНЕЦ КАК _DATEFROM,
	ВЫБОР
		КОГДА T3.ПериодДействияКонец ЕСТЬ NULL
			ТОГДА T2.ПериодДействияКонец
		ИНАЧЕ T3.ПериодДействияКонец
	КОНЕЦ КАК _DATETILL
ПОМЕСТИТЬ tt2
ИЗ
	РегистрРасчета.ОсновнойРасчет КАК T1
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.ОсновнойРасчет КАК T2
		ПО (T2.ПериодРегистрации < ДОБАВИТЬКДАТЕ(T1.ПериодРегистрации, МЕСЯЦ, 1)
				ИЛИ T2.ПериодРегистрации <= T1.БазовыйПериодКонец)
			И (T2.Активность = ИСТИНА)
			И T1.Сотрудник = T2.Сотрудник
			И (ДОБАВИТЬКДАТЕ(T2.ПериодДействия, МЕСЯЦ, 1) > T1.БазовыйПериодНачало)
			И (T2.ПериодДействия <= T1.БазовыйПериодКонец)
			И (ДОБАВИТЬКДАТЕ(T2.ПериодДействия, МЕСЯЦ, 1) > T1.БазовыйПериодНачало
					И T2.ПериодДействия < T1.БазовыйПериодНачало
				ИЛИ T2.ПериодДействия <= T1.БазовыйПериодКонец
					И ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(T2.ПериодДействия, МЕСЯЦ, 1), ДЕНЬ, -1) > T1.БазовыйПериодКонец)
		ЛЕВОЕ СОЕДИНЕНИЕ ПериодыДействия КАК T3
		ПО (T2.Регистратор = T3.Регистратор)
			И (T2.НомерСтроки = T3.НомерСтроки)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПланВидовРасчета.ОсновнойРасчет.БазовыеВидыРасчета КАК T4
		ПО (T4.ВидРасчета = T2.ВидРасчета)
			И (T4.Ссылка = T1.ВидРасчета)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T5._RecorderRRef КАК _RecorderRRef,
	T5._LineNo КАК _LineNo,
	T5._CalcKindRRef КАК _CalcKindRRef,
	T5._ActionPeriod КАК _ActionPeriod,
	T5._Fld216RRef КАК _Fld216RRef,
	T5._Fld217 КАК _Fld217,
	T5._Fld245RRef КАК _Fld245RRef,
	T5._DATEFROM КАК _DATEFROM,
	T5._DATETILL КАК _DATETILL,
	ВЫРАЗИТЬ(СУММА(ВЫБОР
				КОГДА T6.Значение ЕСТЬ NULL
					ТОГДА 0
				ИНАЧЕ T6.Значение
			КОНЕЦ) КАК ЧИСЛО(16, 0)) КАК _CALEND
ПОМЕСТИТЬ tt3
ИЗ
	tt2 КАК T5
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикиРаботы КАК T6
		ПО (T6.Дата >= T5._DATEFROM)
			И (T6.Дата <= T5._DATETILL)
			И T5._Fld245RRef = T6.График

СГРУППИРОВАТЬ ПО
	T5._RecorderRRef,
	T5._LineNo,
	T5._CalcKindRRef,
	T5._ActionPeriod,
	T5._Fld216RRef,
	T5._Fld217,
	T5._Fld245RRef,
	T5._DATEFROM,
	T5._DATETILL
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	T1.RecorderRRef КАК RecorderRRef,
	T1.LineNo_ КАК LineNo_,
	T1.CalcKindRRef КАК CalcKindRRef,
	T1.Fld217Base_ КАК Fld217Base_
ИЗ
	(ВЫБРАТЬ
		T2.RecorderRRef КАК RecorderRRef,
		T2.LineNo_ КАК LineNo_,
		T2.CalcKindRRef КАК CalcKindRRef,
		ВЫРАЗИТЬ(СУММА(T2.Fld217Base_) КАК ЧИСЛО(38, 8)) КАК Fld217Base_
	ИЗ
		(ВЫБРАТЬ
			T3.RecorderRRef КАК RecorderRRef,
			T3.LineNo_ КАК LineNo_,
			T3.CalcKindRRef КАК CalcKindRRef,
			ВЫБОР
				КОГДА T3.CALEND_ ЕСТЬ NULL
					ТОГДА T3.Fld217Base_
				КОГДА T3.CALEND_ <> 0
					ТОГДА (ВЫРАЗИТЬ(T3.Fld217Base_ КАК ЧИСЛО(17, 2)))
					* (ВЫРАЗИТЬ((ВЫРАЗИТЬ(ВЫРАЗИТЬ(СУММА(ЕСТЬNULL(T9.Значение, 0)) КАК ЧИСЛО(16, 0)) КАК ЧИСЛО(24, 8)))
					/ T3.CALEND_ КАК ЧИСЛО(22, 8)))
				ИНАЧЕ ВЫБОР
						КОГДА T3.DATEFROM_MIN_ = T3.DATEFROM_
							ТОГДА T3.Fld217Base_
						ИНАЧЕ 0
					КОНЕЦ
			КОНЕЦ КАК Fld217Base_
		ИЗ
			(ВЫБРАТЬ
				T4.Регистратор КАК RecorderRRef,
				T4.НомерСтроки КАК LineNo_,
				T4.ВидРасчета КАК CalcKindRRef,
				ВЫРАЗИТЬ(СУММА(T5._Fld217) КАК ЧИСЛО(21, 2)) КАК Fld217Base_,
				T7.CALEND_ КАК CALEND_,
				T7.DATEFROM_MIN_ КАК DATEFROM_MIN_,
				T5._Fld245RRef КАК Fld245IRRRef,
				ВЫБОР
					КОГДА T4.БазовыйПериодНачало > T5._DATEFROM
						ТОГДА T4.БазовыйПериодНачало
					ИНАЧЕ T5._DATEFROM
				КОНЕЦ КАК DATEFROM_,
				ВЫБОР
					КОГДА T4.БазовыйПериодКонец < T5._DATETILL
						ТОГДА T4.БазовыйПериодКонец
					ИНАЧЕ T5._DATETILL
				КОНЕЦ КАК DATETILL_
			ИЗ
				РегистрРасчета.ОсновнойРасчет КАК T4
					ЛЕВОЕ СОЕДИНЕНИЕ tt3 КАК T5
					ПО T4.Сотрудник = T5._Fld216RRef
						И (T5._DATEFROM <= T4.БазовыйПериодКонец)
						И (T5._DATETILL >= T4.БазовыйПериодНачало)
						И (ДОБАВИТЬКДАТЕ(T5._ActionPeriod, МЕСЯЦ, 1) > T4.БазовыйПериодНачало
								И T5._ActionPeriod < T4.БазовыйПериодНачало
							ИЛИ T5._ActionPeriod <= T4.БазовыйПериодКонец
								И ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(T5._ActionPeriod, МЕСЯЦ, 1), ДЕНЬ, -1) > T4.БазовыйПериодКонец)
					ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПланВидовРасчета.ОсновнойРасчет.БазовыеВидыРасчета КАК T6
					ПО (T6.ВидРасчета = T5._CalcKindRRef)
						И (T6.Ссылка = T4.ВидРасчета)
					ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
						T8._RecorderRRef КАК RecorderRRef,
						T8._LineNo КАК LineNo_,
						ВЫРАЗИТЬ(СУММА(T8._CALEND) КАК ЧИСЛО(22, 0)) КАК CALEND_,
						МИНИМУМ(T8._DATEFROM) КАК DATEFROM_MIN_
					ИЗ
						tt3 КАК T8
					
					СГРУППИРОВАТЬ ПО
						T8._RecorderRRef,
						T8._LineNo) КАК T7
					ПО (T7.RecorderRRef = T5._RecorderRRef)
						И (T7.LineNo_ = T5._LineNo)
			
			СГРУППИРОВАТЬ ПО
				T4.Регистратор,
				T4.НомерСтроки,
				T4.ВидРасчета,
				T7.CALEND_,
				T7.DATEFROM_MIN_,
				T5._Fld245RRef,
				T4.БазовыйПериодНачало,
				T4.БазовыйПериодКонец,
				T5._DATEFROM,
				T5._DATETILL) КАК T3
				ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикиРаботы КАК T9
				ПО (T9.Дата >= T3.DATEFROM_)
					И (T9.Дата <= T3.DATETILL_)
					И T3.Fld245IRRRef = T9.График
		
		СГРУППИРОВАТЬ ПО
			T3.RecorderRRef,
			T3.LineNo_,
			T3.CalcKindRRef,
			T3.Fld217Base_,
			T3.CALEND_,
			T3.DATEFROM_MIN_,
			T3.DATEFROM_,
			T3.DATETILL_
		
		ОБЪЕДИНИТЬ ВСЕ
		
		ВЫБРАТЬ
			T10.Регистратор,
			T10.НомерСтроки,
			T10.ВидРасчета,
			ВЫРАЗИТЬ(ВЫРАЗИТЬ(СУММА(T11.Результат) КАК ЧИСЛО(21, 2)) КАК ЧИСЛО(38, 8))
		ИЗ
			РегистрРасчета.ОсновнойРасчет КАК T10
				ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.ОсновнойРасчет КАК T11
				ПО (T11.ПериодРегистрации < ДОБАВИТЬКДАТЕ(T10.ПериодРегистрации, МЕСЯЦ, 1)
						ИЛИ T11.ПериодРегистрации <= T10.БазовыйПериодКонец)
					И (T11.Активность = ИСТИНА)
					И T10.Сотрудник = T11.Сотрудник
					И (ДОБАВИТЬКДАТЕ(T11.ПериодДействия, МЕСЯЦ, 1) > T10.БазовыйПериодНачало)
					И (T11.ПериодДействия <= T10.БазовыйПериодКонец)
					И (НЕ(ДОБАВИТЬКДАТЕ(T11.ПериодДействия, МЕСЯЦ, 1) > T10.БазовыйПериодНачало
								И T11.ПериодДействия < T10.БазовыйПериодНачало
							ИЛИ T11.ПериодДействия <= T10.БазовыйПериодКонец
								И ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(T11.ПериодДействия, МЕСЯЦ, 1), ДЕНЬ, -1) > T10.БазовыйПериодКонец))
				ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПланВидовРасчета.ОсновнойРасчет.БазовыеВидыРасчета КАК T12
				ПО (T12.ВидРасчета = T11.ВидРасчета)
					И (T12.Ссылка = T10.ВидРасчета)
		
		СГРУППИРОВАТЬ ПО
			T10.Регистратор,
			T10.НомерСтроки,
			T10.ВидРасчета) КАК T2
	
	СГРУППИРОВАТЬ ПО
		T2.RecorderRRef,
		T2.LineNo_,
		T2.CalcKindRRef) КАК T1

 

 

Этот запрос можно упростить, вынеся некоторые вложенные запросы во временные таблицы. Не будем погружаться в него, но сделаем вывод.

По виду расчёта Работа запрос посчитал количество рабочих дней (сумму поля Значение графика) в базовом периоде (это 2 рабочих дня с учётом того, что период 14.01-15.01 не считается в результате вытеснения), количество рабочих дней в периоде действия (12), получил удельный вес и умножил его на результат: 2/12 * 80 000 = 13,333.

По виду расчёта Почасовка запрос взял результат целиком — 136000. Можно сказать, что в этом случае фактический вид зависимости получился как зависимость по периоду регистрации.

По нашему небольшому опыту заметим, что получение базы может быть не всегда однозначным.

Третий параметр виртуальной таблицы называется Разрезы и также представляет массив строк — имён измерений и реквизитов, в разрезах которых получается база.

Укажем массив значений НомерСтроки и ВидРасчета. Наименования полей разреза формируются как <ИмяПоля>Разрез.
 

Запрос к виртуальной таблице базы регистра расчёта

 

Реквизиты регистра, наряду с измерениями, участвуют в получении базы.

Предположим, у регистра расчёта есть реквизит Подразделение. Добавим в табличную часть реквизит Подразделение и запишем в регистр.

Документ НачислениеЗарплаты

 

Если добавить реквизит Подразделение в параметры Измерения, то, так как подразделения по сотруднику Специалист для видов расчётов Почасовка и Премия отличаются, база будет отсутствовать.

Если убрать Подразделение из параметров, то результат вернётся к прежнему значению.

Запрос к виртуальной таблице базы регистра расчёта

 

Четвёртый параметр таблицы — Условие.

 

3.3 Использование разных планов видов расчёта

Поскольку для плана вида расчётов может быть установлена зависимость от базы по периоду действия или по периоду регистрации и, кроме того, план видов расчёта может использовать или не использовать период действия, итого можно создать 4 вида плана видов расчёта и 16 вариантов зависимости их друг от друга, которые мы реализовали в демонстрационной конфигурации (как говорится — чтобы этого не делали вы).

Сейчас мы отвлечёмся от основных объектов метаданных и сосредоточимся на серии вспомогательных.

Планы видов расчёта

 

Виды расчёта

 

Базовые виды расчёта

 

Таким образом, мы настроили 16 вариантов зависимости от видов расчёта. Конкретно в каждом ПВР есть основной вид расчёта — Работа и 2 зависимых вида расчёта, один из которых зависит от видов расчёта, использующих период действия, а другой — от не использующих.

Для каждого ПВР был создан отдельный одноимённый регистр расчёта.

Документ НачислениеЗарплаты

 

В результате исполнения различных запросов получилась следующая таблица формул получения базы.

Варианты получения базы

 

Таблица читается слева направо. Цвета означают похожий текст запроса на стороне СУБД (это всё заняло длительное время, и в таблице возможны неточности).

Здесь ФЗ это фактическое значение, ПЗ — плановое значение, БП — базовый период, ПД — период действия, Результат — знакомый нам ресурс регистра расчёта.

Формула не обязательно должна быть верной. Например, если взять вариант ОсновнойПоДст.БазаОсновнойПоДст, то, как мы выяснили до того, база может быть равна и целому значению результата: пример, когда Премия по Почасовке равна целому результату без всякого удельного веса. Формула, скорее, отображает основной алгоритм получения базы. Тут мы не можем однозначно говорить о том, что в какой-то ячейке нет иных вариантов расчёта.

Особый интерес представляет формула, когда основной план видов расчёта зависит по периоду регистрации от плана видов расчёта, использующего период действия. Это формула «ФЗ-БП / ПЗ-ПД * Результат». Читается как фактическое значение в базовом периоде делить на плановое значение в периоде действия умножить на результат.

Например, если бы мы рассчитывали таким образом наш вид расчёта Премии от вида расчёта Работа, то формула была бы не 2/12 * 80000, а 2/15 * 80000, так как плановое значение рабочих дней равно 15, а 12 их становится в результате вытеснения видом расчёта Неработа.

Вместе с тем при таком варианте зависимости имеет значение пересечение базового периода с периодом действия. В целом, можно получить и нулевой результат, и целый результат, и результат, вычисленный по упомянутой формуле.

Разумеется, если существуют необычные случаи получения базы, это не отменяет того, что есть проверенные и предсказуемые варианты.

 

3.4 Свойство Период действия базовый

У плана видов расчёта есть свойство ПериодДействияБазовый —_BaseAsAct.

Истинное значение реквизита указывает на то, что базовый период задаётся не напрямую с помощью полей регистра БазовыйПериодНачало и БазовыйПериодКонец, а соответствует фактическому периоду действия записи.

Например, если бы в примере выше мы для вида расчёта взвели флаг ПериодДействияБазовый, то база рассчиталась бы за полный месяц, так как период действия указан как начало и конец месяца, и базовый период был бы равен 01.01-31.01, а не 01.01-15.01. Правда, этот пример не совсем блестящий, так как у Премии нет вытесняющих видов расчёта.

Реквизит ПериодДействияБазовый полезно использовать тогда, когда фактический период действия записи заранее не известен и формируется в результате вытеснения. Рассчитанный фактический период действия и будет выступать как базовый период.

 

3.5 Расчёт записей регистра

Создадим новое значение перечисления СпособыРасчетаЗарплаты ПроцентОтБазы.

Способ расчёта вида расчёта Премия

 

Добавим для разнообразия новую строку (номер 3) в документ Начисление зарплаты. Процент по виду расчёта Премия установим 100. Также установим для него период действия 01.01-15.01: это ни на что не влияет, так как база получается по базовому периоду (флаг ПериодДействияБазовый равен Ложь), но выглядит логичней. Более того, вид расчёта Премия можно было бы разместить в отдельном плане виде расчёта без использования периода действия. Тогда период действия можно было бы вообще не указывать — только базовый период.

Документ НачислениеЗарплаты

 

База вида расчёта Премия по сотруднику Специалист и виду расчёта Работа будет 4/15 * 60000 = 16 000, так как число рабочих дней в базовом периоде 01.01-15.01 по графику равно 4 (вытеснения тут нет).

Запрос к виртуальной таблице базы регистра расчёта

 

Поскольку код проведения был написан с неким притязанием на универсальность, придётся выдержать его в том же стиле. Причина этого в том, что архитектура конфигурации постоянно менялась и имеет учебный характер.

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

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

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

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

 

 

Запрос по получению результата при проведении документа

 

Движения документа НачислениеЗарплаты

 

4. Сторно

 

Создадим новый вид расчёта Командировка со способом расчёта Значение и добавим его в список вытесняющих вида расчёта Работа.

Вид расчёта Командировка

 

Создадим документ Начисление зарплаты за февраль. Добавим туда строчку по виду расчёта Работа за февраль и по виду расчёта Командировка за 3 дня января. Выше мы говорили, что период регистрации может не совпадать с периодом действия.

Документ НачислениеЗарплаты

 

Движения документа НачислениеЗарплаты

 

Документ рассчитался ожидаемо: вид расчёта Работа — по графику, Командировка — по значению.
Между тем, вид расчёта Командировка вытесняет вид расчёта Работа, а в нашем случае —  запись за январь, и предполагается, что мы как-то должны учесть это.

Поведение платформы таково, что вид расчёта с более поздним периодом регистрации не может вытеснить вид расчёта с более ранним периодом регистрации.
Сформируем запрос к виртуальной таблице фактического периода действия с отбором по данному регистратору.

Запрос к фактическому периоду действия

 

В результате запроса отсутствует запись по виду расчёта Командировка, ибо она не смогла вытеснить вид расчёта Работа за январь.

Это произошло потому, что при записи в регистр платформа обновила таблицу ПериодыДействия, установив нулевой интервал действия для записи с видом расчёта Командировка. Можно вспомнить, что при формировании запроса к виртуальной таблице на стороне СУБД было условие ПериодДействияНачало <> ДАТАВРЕМЯ(1, 1, 1).

Таблица ПериодыДействия

 

Чтобы у вида расчёта Командировка появился фактический период действия необходимо сформировать «сторнирующую» запись по виду расчёта Работа за период действия вида расчёта Командировка. При этом у вида расчёта Командировка появится фактический период действия (который нам вообще-то не нужен, ибо там всё посчитано при проведении способом расчёта Значение), а по виду расчёта Работа появится запись, которая позволит уменьшить начисленный оклад за январь.

Сторнирующую запись можно ввести точно таким же способом как и остальные записи, установив необходимые значения полей и флаг Сторно, но легче воспользоваться методом, предоставляемым платформой.

После формирования набора записей из табличной части вызовем метод набора записей регистра накопления ПолучитьДополнение.

Метод ПолучитьДополнение

 

Для записей с флагом Сторно инвертируем Результат.

Учёт сторно при расчёте записей регистра

 

Обработка проведения документа НачислениеЗарплаты

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

 

В результате получили, что хотели — сторнировали начисление по виду расчёта Работа за январь за период вида расчёта Командировка.

Движения документа НачислениеЗарплаты

 

5. Перерасчёт

 

Перепишем проведение документа. Процедуры расчёта записей регистра вынесем в общий модуль. Дополнительно предусмотрим отбор, если расчёт необходимо производить по списку видов расчётов и сотрудников.

 
 Обработка проведения документа НачислениеЗарплаты

 

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

 

 

 
 Общий модуль РасчетЗарплаты

 

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

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

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

 

 

Изменим состав документов за январь, разделив их по видам расчёта. Также есть один документ за февраль. Проведём их по порядку.

Документы НачислениеЗарплаты

 

Создадим в конфигурации объект метаданных Перерасчет.

Перерасчет

 

Укажем у вида расчёта Премия ведущие виды расчёта.

Ведущие виды расчёта

 

Назначение объекта метаданных Перерасчет состоит в отслеживании факта записи по видам расчёта (ведущих видов расчёта), которые могут влиять на результаты по другим видам расчёта.

При этом если вид расчёта вытесняется другим, то ведущий вид расчёта указывать не обязательно.

Например, вид расчёта Работа вытесняется видом расчёта Неработа, но указывать у вида расчёта Работа в списке ведущих вид расчёта Неработа не обязательно, хотя можно. Мы намеренно не будет его включать в список ведущих.

Если вид расчёта зависит от базы, то ведущий вид расчёта указывать нужно. Для вида расчёта Премия мы продублировали базовые виды расчёта в списке ведущих.

Повторно проведём документ Начисление зарплаты №2,  где зарегистрирован вид расчёта Неработа.

Среди таблиц базы данных появилась таблица перерасчета, к которой мы можем сформировать запрос.

Запрос к таблице перерасчета

 

ОбъектПерерасчета и ВидРасчета это обязательные поля таблицы, поле Сотрудник мы указали в конфигураторе при настройке объекта метаданных.

В данном случае платформа предлагает перерассчитать документ №1. Если бы мы указали вид расчёта Неработа как ведущий по отношению к виду расчёта Премия, то в результате запроса появился бы также документ №3.

Если мы перепроведём документ №1, то результат запроса изменится.

Запрос к таблице перерасчета

 

Если мы перепроведём документы №№3-4, то в таблице перерасчета уже не будет записей. Перерасчет выполнил свою работу.

Теперь озаботимся таким вопросом как перерасчёт записей регистра по данным таблицы перерасчёта без проведения документа. Для этого мы процедуры расчёта вынесли в общий модуль.

Создадим незамысловатую обработку Перерасчет.
Проведём документ №2.

Обработка Перерасчет

 

В процедуре перерасчёта напишем следующее.

 
Процедура перерасчёта версия 1

 

Если выполнить эту процедуру, то записи регистра перерассчитаются, но запись в таблице перерасчёта останется. Перепишем процедуру перерасчёта: добавим удаление записи из таблицы перерасчёта.

 
 Процедура перерасчёта версия 2

 

Процедура ВыполнитьПерерасчет(ОбъектПерерасчета)
	
//...
	
	НаборЗаписейПерерасчет = РегистрыРасчета.ОсновнойРасчет.Перерасчеты.Основной.СоздатьНаборЗаписей();
	НаборЗаписейПерерасчет.Отбор.ОбъектПерерасчета.Установить(ОбъектПерерасчета);
	НаборЗаписейПерерасчет.Записать();
	
КонецПроцедуры

 

 

Документ будет перерассчитан, запись из таблицы перерасчёта исчезнет, но в ней не появятся записи по документам №№3-4: не будет рекомендовано перерассчитать документ, где есть вид расчёта Премия (зависит от вида расчёта Работа), документ, где задним числом вводится запись по виду расчёта Командировка (тут, наверно, перерасчёт может повлиять на сторно по виду расчёта Работа).

Перепишем процедуру перерасчёта: уберём удаление из таблицы перерасчёта, но записывать в регистр расчёта будем с записью перерасчётов (третий параметр метода). 

 
 Процедура перерасчёта версия 3

 

Процедура ВыполнитьПерерасчет(ОбъектПерерасчета)
	
//...
	
	РасчетЗарплаты.РассчитатьЗаписиРегистраПоСпособуРасчета(РеквизитыОбъекта, "ОсновнойРасчет", НЗ, Отбор);
	НЗ.Записать(,, Ложь, Истина);
	
	ИменаБазовыхРегистров = РасчетЗарплаты.ИменаБазовыхРегистров("ОсновнойРасчет");
	Если ИменаБазовыхРегистров.Количество() > 0 Тогда
		РасчетЗарплаты.РассчитатьЗаписиРегистраПоБазе(РеквизитыОбъекта, "ОсновнойРасчет", ИменаБазовыхРегистров, НЗ, Отбор);
		НЗ.Записать(,, Ложь, Истина);
	КонецЕсли;
	
КонецПроцедуры

 

 

Теперь после перерасчёта документа №1, появляется сведение о необходимости перерасчёта документа №3, но не документа №4.

Вновь перепишем перерасчёт

 
 Процедура перерасчёта версия 4

 

Процедура ВыполнитьПерерасчет(ОбъектПерерасчета)
	
//...
	
	РасчетЗарплаты.РассчитатьЗаписиРегистраПоСпособуРасчета(РеквизитыОбъекта, "ОсновнойРасчет", НЗ, Отбор);;
	НЗ.Записать();
	
	ИменаБазовыхРегистров = РасчетЗарплаты.ИменаБазовыхРегистров("ОсновнойРасчет");
	Если ИменаБазовыхРегистров.Количество() > 0 Тогда
		РасчетЗарплаты.РассчитатьЗаписиРегистраПоБазе(РеквизитыОбъекта, "ОсновнойРасчет", ИменаБазовыхРегистров, НЗ, Отбор);
		НЗ.Записать();
	КонецЕсли;	
	
КонецПроцедуры

 

 

Теперь наш перерасчёт работает так как хотелось бы, но для этого нам пришлось перезаписать наборы записей регистра с параметрами по умолчанию, с пересчётом фактического периода действия и записью перерасчётов. Возможно, организовать перерасчёт можно было бы по другому.

 

6. Файлы публикации

Архив содержит 3 файла:

— конфигурация

— файл выгрузки с данными, который можно загрузить в информационную базу с помощью обработки Универсальный обмен данными в формате XML

— расширение для работы с запросами (собственная разработка, которую можно найти среди публикаций)

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Механизмы платформы 1С Программист Бесплатно (free)

Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?

16.07.2025    35352    TitanLuchs    109    

150

Механизмы платформы 1С Работа с интерфейсом Программист Стажер 1С:Предприятие 8 Бесплатно (free)

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    19401    bayselonarrend    127    

68

Механизмы платформы 1С Программист 1С:Предприятие 8 Бесплатно (free)

В этой статье подробно рассматривается работа с JSON в XDTO в 1С:Предприятие. Вы узнаете, как сериализовать и десериализовать объекты XDTO в JSON, интегрировать 1С с веб-сервисами и API, а также корректно обрабатывать данные при обмене. Разбираются особенности работы с коллекциями, использование функций восстановления и частые ошибки при работе с JSON и XDTO.

30.01.2025    24979    user2122906    10    

66

Механизмы платформы 1С Файловый обмен (TXT, XML, DBF), FTP Программист 1С:Предприятие 8 Бесплатно (free)

Этот материал познакомит вас с механизмом XDTO (XML Data Transfer Objects) в 1С и научит эффективно использовать его возможности. Мы разберёмся, как работать с XML-схемами, создавать модели данных, манипулировать объектами XDTO, а также сериализовать и десериализовать их в XML. Вы узнаете, как использовать XDTO для интеграции с внешними системами, избегать типичных ошибок и оптимизировать код. К концу вы будете уверенно применять XDTO для решения сложных задач обмена данными и автоматизации процессов.

17.01.2025    43637    user2122906    12    

63

Механизмы платформы 1С WEB-интеграция Программист 1С:Предприятие 8 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    36392    dsdred    106    

152

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    31620    bayselonarrend    22    

178

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    17034    dsdred    22    

89
Для отправки сообщения требуется регистрация/авторизация