Добрый день!

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

Поставили задачу: в документе начисление ЗП при заполнении делать проверку на наличие табеля у человека в месяце расчета зарплаты, иначе выводить список сотрудников, но без расчета ЗП или вообще не выводить, а писать сообщение "нет табеля".

Как я вижу, при подготовке данных для заполнения можно отредактировать запрос сотрудников, исключив тех, у кого нет табеля. Но как сообщить пользователю, что что-то идет не так? Ведь мы находимся в "эфире, на сервере, вне контекста формы. Если же делать на форме, то как, чтобы это более-менее оптимально, а не в стиле "рассчитаем всю зп - вернемся на форму - сообщим пользователю, что пошло не так - нужно рассчитать еще раз" + запретим проведение...

Посоветуйте, каким способом лучше решить задачу =)
---
Хотелось бы по минимуму, конечно. С расширениями в этом проекте не работаем.

Кстати, на данный момент решила вопрос так: написала функцию ЕстьСотрудникиБезТабеляВМесяцеРасчета()

```1c
    &НаСервере
    Функция ЕстьСотрудникиБезТабеляВМесяцеРасчета()

    ЕстьСотрудникиБезТабеля = Истина;

    ПараметрыПолученияСотрудников = КадровыйУчет.ПараметрыПолученияСотрудниковОрганизацийПоСпискуФизическихЛи­ц();
    ПараметрыПолученияСотрудников.Организация = Объект.Организация;
    ПараметрыПолученияСотрудников.Подразделение = Объект.Подразделение;
    ПараметрыПолученияСотрудников.НачалоПериода = Объект.МесяцНачисления;
    ПараметрыПолученияСотрудников.ОкончаниеПериода = КонецМесяца(Объект.МесяцНачисления);
    ПараметрыПолученияСотрудников.ПодработкиРаботниковПоТрудовымДоговорам = ПолучитьФункциональнуюОпцию("ИспользоватьПодработки");
    ПараметрыПолученияСотрудников.РаботникиПоДоговорамГПХ = Ложь; // не проверяем табель для гпхшников

    МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
    КадровыйУчет.СоздатьВТСотрудникиОрганизации(МенеджерВременныхТаблиц, Истина, ПараметрыПолученияСотрудников, "ВТВсеСотрудникиОрганизации");

    //получим сотрудников, у которых есть табель
    Запрос = Новый Запрос;
    Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
    Запрос.Текст =
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    | ТабельУчетаРабочегоВремениДанныеОВремени.Сотрудник КАК Сотрудник
    |ПОМЕСТИТЬ ВТСотрудникиСТабелем
    |ИЗ
    | Документ.ТабельУчетаРабочегоВремени.ДанныеОВремени КАК ТабельУчетаРабочегоВремениДанныеОВремени
    | ЛЕВОЕ СОЕДИНЕНИЕ Документ.ТабельУчетаРабочегоВремени КАК ТабельУчетаРабочегоВремени
    | ПО (ТабельУчетаРабочегоВремениДанныеОВремени.Ссылка = ТабельУчетаРабочегоВремени.Ссылка)
    |ГДЕ
    | ТабельУчетаРабочегоВремени.ДатаНачалаПериода >= &ДатаНачалаПериода
    | И ТабельУчетаРабочегоВремени.ДатаОкончанияПериода <= &ДатаОкончанияПериода
    | И ТабельУчетаРабочегоВремени.Организация = &Организация";
    Запрос.УстановитьПараметр("ДатаНачалаПериода", Объект.МесяцНачисления);
    Запрос.УстановитьПараметр("ДатаОкончанияПериода", КонецМесяца(Объект.МесяцНачисления));
    Запрос.УстановитьПараметр("Организация", Объект.Организация);
    Запрос.Выполнить();

    //получим отработавших в периоде сотрудников, у которых нет табеля
    Запрос = Новый Запрос;
    Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
    Запрос.Текст =
    "ВЫБРАТЬ
    | ВТВсеСотрудникиОрганизации.Сотрудник КАК Сотрудник
    |ИЗ
    | ВТВсеСотрудникиОрганизации КАК ВТВсеСотрудникиОрганизации
    | ЛЕВОЕ СОЕДИНЕНИЕ ВТСотрудникиСТабелем КАК ВТСотрудникиСТабелем
    | ПО ВТВсеСотрудникиОрганизации.Сотрудник = ВТСотрудникиСТабелем.Сотрудник
    |ГДЕ
    | ВТСотрудникиСТабелем.Сотрудник ЕСТЬ NULL";
    РезультатЗапроса = Запрос.Выполнить();

    Если РезультатЗапроса.Пустой() Тогда
    ЕстьСотрудникиБезТабеля = Ложь;
    КонецЕсли;

    Возврат ЕстьСотрудникиБезТабеля;

    КонецФункции
```

и в команды Заполнить и Подбор в модуле формы документа добавила:

```1c
    Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() = Истина Тогда
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Документ не может быть рассчитан! У некоторых сотрудников отсутствует табель");
    Возврат;
    КонецЕсли;
```
---
Добрый день, типовая зуп с задачей по минимуму доработок? Или в конфигурации будете изменять модуль?
---
Хотелось бы по минимуму, конечно. С расширениями в этом проекте не работаем.

Кстати, на данный момент решила вопрос так: написала функцию ЕстьСотрудникиБезТабеляВМесяцеРасчета()

```1c
    &НаСервере
    Функция ЕстьСотрудникиБезТабеляВМесяцеРасчета()

    ЕстьСотрудникиБезТабеля = Истина;

    ПараметрыПолученияСотрудников = КадровыйУчет.ПараметрыПолученияСотрудниковОрганизацийПоСпискуФизическихЛи­ц();
    ПараметрыПолученияСотрудников.Организация = Объект.Организация;
    ПараметрыПолученияСотрудников.Подразделение = Объект.Подразделение;
    ПараметрыПолученияСотрудников.НачалоПериода = Объект.МесяцНачисления;
    ПараметрыПолученияСотрудников.ОкончаниеПериода = КонецМесяца(Объект.МесяцНачисления);
    ПараметрыПолученияСотрудников.ПодработкиРаботниковПоТрудовымДоговорам = ПолучитьФункциональнуюОпцию("ИспользоватьПодработки");
    ПараметрыПолученияСотрудников.РаботникиПоДоговорамГПХ = Ложь; // не проверяем табель для гпхшников

    МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
    КадровыйУчет.СоздатьВТСотрудникиОрганизации(МенеджерВременныхТаблиц, Истина, ПараметрыПолученияСотрудников, "ВТВсеСотрудникиОрганизации");

    //получим сотрудников, у которых есть табель
    Запрос = Новый Запрос;
    Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
    Запрос.Текст =
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    | ТабельУчетаРабочегоВремениДанныеОВремени.Сотрудник КАК Сотрудник
    |ПОМЕСТИТЬ ВТСотрудникиСТабелем
    |ИЗ
    | Документ.ТабельУчетаРабочегоВремени.ДанныеОВремени КАК ТабельУчетаРабочегоВремениДанныеОВремени
    | ЛЕВОЕ СОЕДИНЕНИЕ Документ.ТабельУчетаРабочегоВремени КАК ТабельУчетаРабочегоВремени
    | ПО (ТабельУчетаРабочегоВремениДанныеОВремени.Ссылка = ТабельУчетаРабочегоВремени.Ссылка)
    |ГДЕ
    | ТабельУчетаРабочегоВремени.ДатаНачалаПериода >= &ДатаНачалаПериода
    | И ТабельУчетаРабочегоВремени.ДатаОкончанияПериода <= &ДатаОкончанияПериода
    | И ТабельУчетаРабочегоВремени.Организация = &Организация";
    Запрос.УстановитьПараметр("ДатаНачалаПериода", Объект.МесяцНачисления);
    Запрос.УстановитьПараметр("ДатаОкончанияПериода", КонецМесяца(Объект.МесяцНачисления));
    Запрос.УстановитьПараметр("Организация", Объект.Организация);
    Запрос.Выполнить();

    //получим отработавших в периоде сотрудников, у которых нет табеля
    Запрос = Новый Запрос;
    Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
    Запрос.Текст =
    "ВЫБРАТЬ
    | ВТВсеСотрудникиОрганизации.Сотрудник КАК Сотрудник
    |ИЗ
    | ВТВсеСотрудникиОрганизации КАК ВТВсеСотрудникиОрганизации
    | ЛЕВОЕ СОЕДИНЕНИЕ ВТСотрудникиСТабелем КАК ВТСотрудникиСТабелем
    | ПО ВТВсеСотрудникиОрганизации.Сотрудник = ВТСотрудникиСТабелем.Сотрудник
    |ГДЕ
    | ВТСотрудникиСТабелем.Сотрудник ЕСТЬ NULL";
    РезультатЗапроса = Запрос.Выполнить();

    Если РезультатЗапроса.Пустой() Тогда
    ЕстьСотрудникиБезТабеля = Ложь;
    КонецЕсли;

    Возврат ЕстьСотрудникиБезТабеля;

    КонецФункции
```

и в команды Заполнить и Подбор в модуле формы документа добавила:

```1c
    Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() = Истина Тогда
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Документ не может быть рассчитан! У некоторых сотрудников отсутствует табель");
    Возврат;
    КонецЕсли;
```
---
Есть два варианта быстро решить эту проблему. Если против внесения изменений в конфу просто написать внешнюю обработку по заполнению табличной части. Пробегаться по таблице, находить ненужные строки, складывать их массив и удалять потом из таблицы.
Второй вариант я бы не использовал...это дописать проверку на заполнение контрагентов в том же месте где они собираются. Единственно нужно учитывать что это будет общий модуль и не факт что везде где будет встречаться вызов этой процедуры из модуля по логике будет правильно отрезать контрагентов. Поэтому тут нужно будет добавить проверку на тип документа.
---
нет, внешняя не подойдет, потому что она должна запускаться многократно и постоянно пользователем... умным пользователем =) Мы наоборот пишем защиту от дурака, которая должна отрабатывать всегда.

А насчет доработки общего модуля согласна, хотела бы этого избежать. Ну, в-общем-то, это удалось =)
---
внешние обработки можно открывать программно.
---
тогда это должно быть какое-то задание? которое должно отлавливать событие нажатия на кнопку Заполнить/Подбор или событие расчета ЗП? и запускать обработку? такого я еще не реализовывала, очень интересно
---
У нас это реализовано так. Пишется обработка которая выполняет необходимые действия. И прицепляется к конфигурации как внешняя. Она не имеет формы и открывается программно. Но у нас задача была из одной внешней обработки открывать другую.

Если ЗначениеЗаполнено(ВнешОтчет) Тогда
     ДвоичныеДанные = ВнешОтчет.ХранилищеВнешнейОбработки.Получить();
     ИмяФайла = ПолучитьИмяВременногоФайла();
     ДвоичныеДанные.Записать(ИмяФайла);
     ОбработкаПечати = ВнешниеОбработки.Создать(ИмяФайла);
 Иначе
  Предупреждение("Не найдена внешняя обработка печатных форм!");
  Возврат;
 КонецЕсли;

Можно подумать в этом направлении...повесить на обработчик какой - нибудь...там уже смотрите сами. Просто говорю что это возможно.
---
спасибо!
---
Конечно можно и так) но так , много писать....
---
ха, кстати, свежим взглядом нашла у себя тавтологию в коде =)))
```1c
    Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() = Истина Тогда
```
 можно просто
```1c
    Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() Тогда
```
---
Просто я когда дорабатываю любую типовую конфигурацию придерживаюсь одного правила "Минимум кода максимум комментариев". Иначе при обновлении конфигурации будет очень все плохо