Часто при внедрении 1С:ЗУП на больших проектах внутри холдинга возникает задача реализовать групповой перерасчет документов «Начисление зарплаты». Заказчики хотят иметь возможность выделять сразу несколько документов в списке и их пересчитывать нажатием на одну кнопку. Типовой ЗУП не дает возможности перерасчитывать документы прямо в списке.
1. Групповой перерасчет выбранных в списке документов "Начисление зарплаты и Взносов" в ЗУП 3.1.2
Заказчик хочет следующий функционал:
Решение.
В конфигураторе создаем новую форму списка документа копированием типовой. Задаем префикс в имени формы. Создаем команду формы списка, подменю «ГруппаПересчетДокументов». Устанавливаем флаг «Множественный выбор» в свойствах элемента формы «Список» - чтобы пользователи могли выделять несколько документов при нажатии «Ctrl+Клик мыши».
Спустя некоторое время добавил еще одну кнопку:
Кнопка "Пересчитать (аналог: над таблицей Начисления)" - работает так же, как если бы мы открыли документ и нажали в нем кнопку Пересчитать над табличной частью Начисления (справа от кнопки Очистить), пересчет может потребоваться когда мы вручную меняем Результат начисления по сотруднику и надо по цепочке далее пересчитать зависимые начисления, налоги и взносы.
Кнопка "Пересчитать (аналог: таблица Начисления Сtrl+A --> прав. кнопка мыши Пересчитать сотрудника)" - работает так же, как если бы мы открыли документ, выделили все строки в таблице Начисления (Сtrl+A) и нажали правой кнопкой мыши Пересчитать сотрудника. В этом случае происходит не только пересчет сотрудника, но перезаполнение всех начислений сотрудника (как при первичном нажатии на кнопку Подбор). Это может понадобиться, когда сотрудник в документ есть, но в документе не хватает каких-либо начислений по нему (их ввели немного позже, после первого заполнения документа). Можно не заходя внутрь документа сделать дозаполнение недостающих начислений и сразу перерасчет.
В модуле созданной формы списка пропишем текст процедуры «ПересчитатьСотрудниковВДокументах»
Листинг нетипового функционала модуля формы списка ЗУП 3.1.2
#Область Нетиповая
&НаКлиенте
//Кнопка 1
Процедура ПересчитатьСотрудниковВДокументах(Команда)
//Предупредить пользователя о том, чтобы по выбранным документам не было открытых форм. Формы открыты: Да/Нет.
МассивВыделенныхДокументов = Элементы.Список.ВыделенныеСтроки;
Для Каждого ЭлМасДок из МассивВыделенныхДокументов Цикл
ФормаДокумента = ПолучитьФорму("Документ.НачислениеЗарплаты.Форма.ФормаДокумента", Новый Структура("Ключ",ЭлМасДок), ЭтаФорма);
ИмяТаблицы = "Начисления";
ВедущееПоле = "Сотрудник";
ТипВедущегоПоля = Тип("СправочникСсылка.Сотрудники");
//------------------------------------------------------------------------------------------------------------------------------------------
//1.
ФормаДокумента.СотрудникиКРасчету = СоответствиеСотрудникиКРасчету(ФормаДокумента, ИмяТаблицы);
ФормаДокумента.ПересчитатьДокументНаКлиенте();
//------------------------------------------------------------------------------------------------------------------------------------------
//2.
ФормаДокумента.Записать();
//------------------------------------------------------------------------------------------------------------------------------------------
//3. Закроем окно длительной операции
ОкнаПриложения = ПолучитьОкна();
Для Каждого ОкноПриложения Из ОкнаПриложения Цикл
Если ОкноПриложения.Содержимое.Количество()=0 Тогда Продолжить; КонецЕсли;
Если ОкноПриложения.Содержимое[0].ИмяФормы="ОбщаяФорма.ДлительнаяОперация" и НЕ ОкноПриложения.НачальнаяСтраница и НЕ ОкноПриложения.Основное Тогда
ФормаДлОп = ОкноПриложения.ПолучитьСодержимое();
Если ФормаДлОп.Открыта() Тогда
ФормаДлОп.Закрыть();
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Элементы.Список.Обновить();
ЭтаФорма.ОбновитьОтображениеДанных();
КонецПроцедуры
&НаКлиенте
Функция СоответствиеСотрудникиКРасчету(ФормаДокумента, ИмяТаблицы)
ОписаниеТаблицы = РасчетЗарплатыРасширенныйКлиентСервер.ОписаниеТаблицыРасчета();
ОписаниеТаблицы.ИмяПоляДляВставкиПоказателей = "ДатыНачисления";
ОписаниеТаблицы.СодержитПолеСотрудник = Истина;
ОписаниеТаблицы.ИмяРеквизитаСотрудник = "Сотрудник";
ОписаниеТаблицы.ИмяПоляДляВставкиРаспределенияРезультатов = "НачисленияРезультат";
ОписаниеТаблицы.ОтображатьПоляОписанияВремени = Истина;
ОписаниеТаблицы.ОтображатьПоляНормыВремени = Ложь; //Истина
ОписаниеТаблицы.УправлятьОтображениемПолейОписанияВремени = Ложь; //Истина
ОписаниеТаблицы.ОтменятьВсеИсправления = Ложь;
ОписаниеТаблицы.ПутьКДаннымАдресРаспределенияРезультатовВХранилище = "АдресТаблицыРаспределенияНачислений";
ОписаниеТаблицы.ВставлятьПослеПоля = Истина;
ОписаниеТаблицы.РаспределениеРезультатовЗависимыеТаблицы = "Начисления,Пособия,НДФЛ,Удержания,ПогашениеЗаймов";
ОписаниеТаблицы.СодержитПолеКодВычета = Истина;
ОписаниеТаблицы.ИмяРеквизитаДокументОснование = "ДокументОснование";
ОписаниеТаблицы.ПутьКДаннымАдресРаспределенияПоТерриториямУсловиямТруда = "АдресТаблицыРаспределенияПоТерриториямУсловиямТруда";
ОписаниеТаблицы.Вставить("НачисленияРезультат","");
СписокСотрудников = Новый Соответствие;
Для Каждого ТекСтр Из ФормаДокумента.Объект[ИмяТаблицы] Цикл
ФЛ = ТекСтр.ФизическоеЛицо;
Если СписокСотрудников.Получить(ФЛ) = Неопределено Тогда
СписокСотрудников.Вставить(ФЛ,Истина);
КонецЕсли;
КонецЦикла;
СтруктураНачисления = Новый Структура("ОписаниеТаблицы,СписокСотрудников");
СтруктураНачисления.ОписаниеТаблицы = ОписаниеТаблицы;
СтруктураНачисления.СписокСотрудников = СписокСотрудников;
СотрудникиКРасчету = Новый Соответствие();
СотрудникиКРасчету.Вставить("Начисления", СтруктураНачисления);
Возврат СотрудникиКРасчету;
КонецФункции
&НаКлиенте
//Кнопка 2
Процедура ПерезаполнитьИПересчитатьСотрудника(Команда)
//Предупредить пользователя о том, чтобы по выбранным документам не было открытых форм. Формы открыты: Да/Нет.
МассивВыделенныхДокументов = Элементы.Список.ВыделенныеСтроки;
Для Каждого ЭлМасДок из МассивВыделенныхДокументов Цикл
ФормаДокумента = ПолучитьФорму("Документ.НачислениеЗарплаты.Форма.ФормаДокумента", Новый Структура("Ключ",ЭлМасДок), ЭтаФорма);
ИмяТаблицы = "Начисления";
ВедущееПоле = "Сотрудник";
ТипВедущегоПоля = Тип("СправочникСсылка.Сотрудники");
//------------------------------------------------------------------------------------------------------------------------------------------
//1.
Для каждого Стр Из ФормаДокумента.Объект.Начисления Цикл
ФормаДокумента.Элементы.Начисления.ВыделенныеСтроки.Добавить(Стр.НомерСтроки-1);
КонецЦикла;
ИдентификаторыСтрок = ФормаДокумента.Элементы[ИмяТаблицы].ВыделенныеСтроки;
//РасчетЗарплатыРасширенныйКлиент.ПересчитатьСотрудника(ФормаДокумента, "Начисления", "Сотрудник", Тип("СправочникСсылка.Сотрудники"));
ФормаДокумента.ПересчитатьСотрудника(ИмяТаблицы, ИдентификаторыСтрок, ВедущееПоле, ТипВедущегоПоля);
//------------------------------------------------------------------------------------------------------------------------------------------
//2.
ФормаДокумента.Записать();
//------------------------------------------------------------------------------------------------------------------------------------------
//3. Закроем окно длительной операции
ОкнаПриложения = ПолучитьОкна();
Для Каждого ОкноПриложения Из ОкнаПриложения Цикл
Если ОкноПриложения.Содержимое.Количество()=0 Тогда Продолжить; КонецЕсли;
Если ОкноПриложения.Содержимое[0].ИмяФормы="ОбщаяФорма.ДлительнаяОперация" и НЕ ОкноПриложения.НачальнаяСтраница и НЕ ОкноПриложения.Основное Тогда
ФормаДлОп = ОкноПриложения.ПолучитьСодержимое();
Если ФормаДлОп.Открыта() Тогда
ФормаДлОп.Закрыть();
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Элементы.Список.Обновить();
ЭтаФорма.ОбновитьОтображениеДанных();
КонецПроцедуры
#КонецОбласти
Пример работы реализованного функционала в пользовательском режиме 1С:Предприятие:
Перерасчет выбранных документов работает так же, как и кнопки внутри документа «Пересчитать» или «Пересчитать сотрудника» (если все сотрудники выбраны):
Подводные камни:
1) перед началом перерасчета выделенных документов желательно организовать проверку не открыта ли какая либо из форм одного из выбранных документов сейчас, если открыта - выдавать предупреждение о том, что надо ее закрыть (этого в коде выше нет)
2) в процессе перерасчета начинают отображаться формы длительной операции - нужно позаботиться о закрытии этих форм после перерасчета (в коде выше это есть)
3) после перерасчета выбранных документов иногда приходится обновить список документов вручную, поскольку некоторые документы начинают отображаться как не проведенные, хотя в коде и присутствует строчка
Элементы.Список.Обновить();
4) массовый перерасчет документов может вызывать конфликт блокировок при выполнении транзакции по причине превышении времени ожидания запроса на блокировку.
5) рекомендую изучить механизм утверждения (и расчета) межрасчетных документов в журнале "Начисление зарплаты": когда кадровики вводят документы, затем расчетчики должны эти документы выделить, утвердить и рассчитать. Механизм работы кнопки "Утвердить" содержит типовые алгоритмы перебора выделенных документов и их расчета - очень рекомендую их изучить.
2. Групповой перерасчет выбранных в списке документов "Начисление зарплаты сотрудникам организаций" в ЗУП 2.5.123
Заказчик хочет следующий функционал:
Решение.
В конфигураторе создаем новую форму списка документа копированием типовой. В элемент формы «ДокументСписок» добавляем колонку «Пометка» (без привязки к данным базы данных). Для элемента формы «ДокументСписок» добавляем командную панель с тремя подменю, см. рисунок.
Реализация выделения документов в списке.
Создаем реквизит формы «ТаблицаПометок».
Создаем 3 процедуры для выделения документов в списке:
ДокументСписокПриПолученииДанных(…),ДокументСписокВыбор(…),КоманднаяПанель1СнятьФлажки(…)
Листинг процедур для выделения документов в списке (ЗУП 2.5.123):
Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
Если ТаблицаПометок.Количество()=0 Тогда Возврат; КонецЕсли;
Для Каждого СтрокаТЧ Из ОформленияСтрок Цикл
ДанныеСтроки = СтрокаТЧ.ДанныеСтроки;
Ячейки = СтрокаТЧ.Ячейки;
ЭлТаб = ТаблицаПометок.Найти(ДанныеСтроки.Ссылка,"Ссылка");
Если ЭлТаб=Неопределено Тогда Продолжить; КонецЕсли;
Ячейки.Пометка.УстановитьКартинку( ?(ЭлТаб.Пометка, БиблиотекаКартинок.Утвердить, Новый Картинка) );
СтрокаТЧ.Шрифт = Новый Шрифт (,,ЭлТаб.Пометка);
КонецЦикла;
КонецПроцедуры
Процедура КоманднаяПанель1СнятьФлажки(Кнопка)
Для Каждого ТекСтр Из ТаблицаПометок Цикл
ТекСтр.Пометка = Ложь;
КонецЦикла;
ЭлементыФормы.ДокументСписок.ОбновитьСтроки();
КонецПроцедуры
Процедура ДокументСписокВыбор(Элемент, ВыбраннаяСтрока, Колонка, СтандартнаяОбработка)
Если Колонка.Имя="Пометка" Тогда
СтандартнаяОбработка=Ложь;
ЭлТаб = ТаблицаПометок.Найти(Элемент.ТекущиеДанные.Ссылка,"Ссылка");
Если ЭлТаб=Неопределено Тогда
НовСтр = ТаблицаПометок.Добавить();
НовСтр.Ссылка = Элемент.ТекущиеДанные.Ссылка;
НовСтр.Пометка = Истина;
Иначе
ЭлТаб.Пометка = НЕ ЭлТаб.Пометка;
КонецЕсли;
КонецЕсли;
ЭлементыФормы.ДокументСписок.ОбновитьСтроки();
КонецПроцедуры
Реализация перерасчетов выделенных документов в списке.
Для каждой кнопки подменю добавленной командной панели элемента формы «ДокументСписок» создаем свой обработчик и одну общую процедуру ОбработатьДокументы(ВариантДействий) для всех вариантов перерасчета выбранных документов.
В ЗУП 2.5 в обычных формах мы можем очень просто реализовать расчет в форме списка:
Объект.РассчитатьВсе(); или Объект.РассчитатьНачисления(); или Объект.РассчитатьНДФЛ();
Листинг процедур перерасчета выделенных документов (ЗУП 2.5.123)
////////////////////////////////////////////////////////////////////////////////
//Обработчики кнопок
Процедура КоманднаяПанель1РассчитатьВсе(Кнопка)
ОбработатьДокументы("РассчитатьВсе");
КонецПроцедуры
Процедура КоманднаяПанель1РассчитатьНачисления(Кнопка)
ОбработатьДокументы("РассчитатьНачисления");
КонецПроцедуры
Процедура КоманднаяПанель1РассчитатьНДФЛ(Кнопка)
ОбработатьДокументы("РассчитатьНДФЛ");
КонецПроцедуры
Процедура КоманднаяПанель1РассчитатьУдержания(Кнопка)
ОбработатьДокументы("РассчитатьУдержания");
КонецПроцедуры
//{20140604.Заказчик.Пантелеев Иван(/)}
Процедура ОбработатьДокументы(ВариантДействий)
// Индикация
ФормаИндикации = ПолучитьОбщуюФорму("ХодВыполненияОбработкиДанных");
Если ФормаИндикации.Открыта() Тогда
ФормаИндикации.Закрыть();
КонецЕсли;
ФормаИндикации.НаименованиеОбработкиДанных = "Отображение состояния процесса";
ФормаИндикации.КомментарийОбработкиДанных = "Выполняется обработка отмеченных документов";
ФормаИндикации.Значение = 0;
ФормаИндикации.МаксимальноеЗначение = ТаблицаПометок.Количество();
ФормаИндикации.Открыть();
Попытка
НачатьТранзакцию();
НомПП=0;
Для Каждого ТекСтр Из ТаблицаПометок Цикл
НомПП=НомПП+1;
Если Не ТекСтр.Пометка Тогда Продолжить; КонецЕсли;
Объект = ТекСтр.Ссылка.ПолучитьОбъект();
Если Найти("РассчитатьВсеРассчитатьНачисленияРассчитатьНДФЛРассчитатьУдержания", ВариантДействий)>0 Тогда
Если ВариантДействий="РассчитатьВсе" Тогда
Объект.РассчитатьВсе();
ИначеЕсли ВариантДействий="РассчитатьНачисления" Тогда
Объект.РассчитатьНачисления();
ИначеЕсли ВариантДействий="РассчитатьНДФЛ" Тогда
Объект.РассчитатьНДФЛ();
ИначеЕсли ВариантДействий="РассчитатьУдержания" Тогда
Объект.РассчитатьУдержания();
КонецЕсли;
Если Объект.Проведен Тогда
Объект.Записать(РежимЗаписиДокумента.Проведение);
Иначе
Объект.Записать();
КонецЕсли;
ИначеЕсли Найти("ПровестиОтменаПроведения", ВариантДействий)>0 Тогда
Если ВариантДействий="Провести" Тогда
Объект.Записать(РежимЗаписиДокумента.Проведение);
ИначеЕсли ВариантДействий="ОтменаПроведения" Тогда
Объект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;
ИначеЕсли Найти("ПометитьНаУдалениеСнятьПометкуНаУдаление", ВариантДействий)>0 Тогда
Если ВариантДействий="ПометитьНаУдаление" Тогда
Если НЕ Объект.ПометкаНаУдаление Тогда
Объект.ПометкаНаУдаление = Истина;
Объект.Записать();
КонецЕсли;
ИначеЕсли ВариантДействий="СнятьПометкуНаУдаление" Тогда
Если Объект.ПометкаНаУдаление Тогда
Объект.ПометкаНаУдаление = Ложь;
Объект.Записать();
КонецЕсли;
КонецЕсли;
КонецЕсли;
ОбработкаПрерыванияПользователя();
ЭлементыФормы.ДокументСписок.ОбновитьСтроки();
ФормаИндикации.Значение = НомПП;
ФормаИндикации.КомментарийЗначения = "Обработка документа : "+Строка(ТекСтр.Ссылка);
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
Сообщение = Новый СообщениеПользователю();
ОтменитьТранзакцию();
Сообщение.Текст = ОписаниеОшибки();
Сообщение.УстановитьДанные(Объект);
Сообщение.Сообщить();
КонецПопытки;
// Убираем индикацию
Если ФормаИндикации.Открыта() Тогда
ФормаИндикации.Закрыть();
КонецЕсли;
КонецПроцедуры
Пример работы реализованного функционала в ЗУП 2.5.123:
Ссылки на публикации по теме перерасчетов документов в списке для ЗУП:
Групповой перерасчет отпусков. ЗУП 3.0, ЗУП 3.1 Корп
Групповой перерасчет документов начисления зарплаты. ЗУП 3.0
Рекомендую публикации, посвященные теме внедрений ЗУП на больших проектах:
Отчет "Штатное расписание и расстановка на выбранные даты"
Учет и расчет выплат работникам за время прохождения медосмотров в программе «1С:ЗУП» редакции 2.5
Отчет по состояниям (отклонениям) сотрудников за период.
Отчет «Среднесписочная численность» для ЗУП
Пример создания в КД 2.1 правил обмена данными ЗУП 2.5 -> БП 3.0.
Пример создания в КД 2.1 правил выгрузки данных регистра «Лицевые счета работников» из ЗУП 2.5 в справочник «Банковские счета» БП 3.0
Вопросы, предложения и замечания по статье пишите в комментариях.
Если статья принесла Вам пользу, то поддержите развитие публикации и автора - поставьте звездочку и/или напишите комментарий.
С пожеланием творческих успехов всем посетителям сайта ИС, Пантелеев Иван.