Compare commits

...

6 Commits

Author SHA1 Message Date
tsvetkoff d37dd83b23 Добавление HTTP-сервиса для ввода табелей и регистрация в конфигурации
1) Изменение в
101_ЦМСЧ_ЗиКГУ.ЗагрузкаДанныхИзExcel/src/Configuration/Configuration.mdo:
- добавлена ссылка на новый HTTP-сервис ПС_ВебСервисТабелей

2) Новая функциональность в
101_ЦМСЧ_ЗиКГУ.ЗагрузкаДанныхИзExcel/src/HTTPServices/ПС_ВебСервисТабелей/Module.bsl:
- реализован серверный модуль веб-сервиса с обработчиками маршрутов
- GET /index — возвращает HTML-форму ввода табеля
- GET /me — возвращает JSON с данными текущего пользователя
- GET /departments — возвращает JSON со списком доступных подразделений
- GET /employees — возвращает JSON со списком сотрудников подразделения
- GET /kinds — возвращает список видов использования рабочего времени
- GET /funds — возвращает список источников финансирования

3) Новая функциональность в
101_ЦМСЧ_ЗиКГУ.ЗагрузкаДанныхИзExcel/src/HTTPServices/ПС_ВебСервисТабелей/ПС_ВебСервисТабелей.mdo:
- создан метаданный объект HTTP-сервиса "ПС_ВебСервисТабелей"
- настроены корневой URL /tabel и маршруты для всех обработчиков
2026-09-17 15:53:26 +05:00
tsvetkoff d4661b3677 Перенос общих функций в серверный модуль
Подготовка к переносу работы с табелем в сервис
2026-08-28 16:55:02 +05:00
tsvetkoff 6cb4ff7b78 MVP для отображения уже загруженных табелей 2026-08-27 19:10:28 +05:00
tsvetkoff 1095488c88 Обработка ПС_ЗагрузкаТабеляУчётаРабочегоВремениИзEXCEL.
- Редактируемое поле "Наименование подразделения", привязка OnChange.
- Списки выбора "Подразделение" и "Наименование подразделения" из
  ПС_НастройкиЗагрузкиТабелей с фильтром по организации.
- Автоподстановка наименования подразделения, если в РС для выбранного
  подразделения единственное значение.
- Обратная загрузка: при изменении ключевых реквизитов формы (организация,
  подразделение, наименование подразделения, период регистрации) поиск
  ранее сохранённого табеля через ПС_ЗагруженныеТабеля (последняя
  редакция по дате загрузки) и подтверждение пользователя при наличии
  данных в форме. Заполнение ТЧ — заглушка, открывает найденный табель.
2026-08-16 20:20:15 +05:00
tsvetkoff 691edc541c Отредактировано по замечаниям 1С напарника, исправлены баги. 2026-08-15 17:56:20 +05:00
tsvetkoff bcadc737b7 Функция загрузки табеля отделена для безопасной отработки выхода по
ошибке
2026-08-13 21:37:27 +05:00
13 changed files with 2104 additions and 520 deletions
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:CommonModule xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="f3b01825-0b99-4164-8e92-f4d0535f9033">
<name>ПС_Описание</name>
<name>ПС_ЗагрузкаДанныхИзExcel_Описание</name>
<synonym>
<key>ru</key>
<value>Описание</value>
@@ -0,0 +1,561 @@
// Серверные функции для работы с табелем учёта рабочего времени.
// Перенесены из модуля формы обработки ПС_ЗагрузкаТабеляУчётаРабочегоВремениИзEXCEL.
#Область СлужебныеПроцедурыИФункции
// Поиск элементов справочника ВидыИспользованияРабочегоВремени по наименованию.
// Используется как замена прямого обращения к реквизитам формы обработки.
// Имена элементов зафиксированы в проекте и не подлежат изменению.
Функция ВидВремениЯвкаСГЗ()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Явка (СГЗ)", Истина);
КонецФункции
Функция ВидВремениЯвкаПД()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Явка (ПД)", Истина);
КонецФункции
Функция ВидВремениЯвкаОМС()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Явка (ОМС)", Истина);
КонецФункции
Функция ВидВремениПраздникиСГЗ()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Праздники (СГЗ)", Истина);
КонецФункции
Функция ВидВремениПраздникиПД()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Праздники (ПД)", Истина);
КонецФункции
Функция ВидВремениПраздникиОМС()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Праздники (ОМС)", Истина);
КонецФункции
Функция ВидВремениПраздникиБезПовышеннойОплатыСГЗ()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Праздники без повышенной оплаты (СГЗ)", Истина);
КонецФункции
Функция ВидВремениПраздникиБезПовышеннойОплатыПД()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Праздники без повышенной оплаты (ПД)", Истина);
КонецФункции
Функция ВидВремениПраздникиБезПовышеннойОплатыОМС()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Праздники без повышенной оплаты (ОМС)", Истина);
КонецФункции
Функция ВидВремениРаботаНочныеЧасыСГЗ()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Работа ночные часы (СГЗ)", Истина);
КонецФункции
Функция ВидВремениРаботаНочныеЧасыПД()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Работа ночные часы (ПД)", Истина);
КонецФункции
Функция ВидВремениРаботаНочныеЧасыОМС()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Работа ночные часы (ОМС)", Истина);
КонецФункции
Функция ВидВремениСверхурочныеСГЗ()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Сверхурочные (СГЗ)", Истина);
КонецФункции
Функция ВидВремениСверхурочныеПД()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Сверхурочные (ПД)", Истина);
КонецФункции
Функция ВидВремениСверхурочныеОМС()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Сверхурочные (ОМС)", Истина);
КонецФункции
Функция ВидВремениСверхурочныеБезПовышеннойОплатыСГЗ()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Сверхурочные без повышенной оплаты (СГЗ)", Истина);
КонецФункции
Функция ВидВремениСверхурочныеБезПовышеннойОплатыПД()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Сверхурочные без повышенной оплаты (ПД)", Истина);
КонецФункции
Функция ВидВремениСверхурочныеБезПовышеннойОплатыОМС()
Возврат Справочники.ВидыИспользованияРабочегоВремени.НайтиПоНаименованию("Сверхурочные без повышенной оплаты (ОМС)", Истина);
КонецФункции
// Статьи финансирования — ищем предопределённые элементы.
Функция СтатьяФинансированияСГЗ()
Возврат Справочники.СтатьиФинансированияЗарплата.НайтиПоНаименованию("СГЗ", Истина);
КонецФункции
Функция СтатьяФинансированияПД()
Возврат Справочники.СтатьиФинансированияЗарплата.НайтиПоНаименованию("ПД", Истина);
КонецФункции
Функция СтатьяФинансированияОМС()
Возврат Справочники.СтатьиФинансированияЗарплата.НайтиПоНаименованию("ОМС", Истина);
КонецФункции
#КонецОбласти
#Область ПолучениеВидовВремени
// Возвращает элемент справочника ВидыИспользованияРабочегоВремени для вида «Явка»
// по текущей статье финансирования (СГЗ / ПД / ОМС).
//
// Параметры:
// СтатьяФинансирования - CatalogRef.СтатьиФинансированияЗарплата
//
// Возвращаемое значение:
// CatalogRef.ВидыИспользованияРабочегоВремени
//
Функция ВидВремениЯвка(СтатьяФинансирования) Экспорт
Если СтатьяФинансирования = СтатьяФинансированияСГЗ() Тогда
Возврат ВидВремениЯвкаСГЗ();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияПД() Тогда
Возврат ВидВремениЯвкаПД();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияОМС() Тогда
Возврат ВидВремениЯвкаОМС();
КонецЕсли;
КонецФункции
// Возвращает элемент справочника для вида «Болезнь».
Функция ВидВремениБолезнь() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.Болезнь;
КонецФункции
Функция ВидВремениВыходныеДни() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ВыходныеДни;
КонецФункции
Функция ВидВремениДополнительныйОтпуск() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ДополнительныйОтпуск;
КонецФункции
Функция ВидВремениКомандировка() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.Командировка;
КонецФункции
Функция ВидВремениКормлениеРебенка() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.КормлениеРебенка;
КонецФункции
Функция ВидВремениНеявкиПоНевыясненнымПричинам() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.НеявкиПоНевыясненнымПричинам;
КонецФункции
Функция ВидВремениНеоплачиваемыйОтпускПоРазрешениюРаботодателя() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.НеоплачиваемыйОтпускПоРазрешениюРаботодателя;
КонецФункции
Функция ВидВремениОтстранениеОтРаботыБезОплаты() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОтстранениеОтРаботыБезОплаты;
КонецФункции
Функция ВидВремениОтстранениеОтРаботыСОплатой() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОтстранениеОтРаботыСОплатой;
КонецФункции
Функция ВидВремениОплачиваемыеНерабочиеДни() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОплачиваемыеНерабочиеДни;
КонецФункции
Функция ВидВремениОсновнойОтпуск() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОсновнойОтпуск;
КонецФункции
Функция ВидВремениОтпускНаОбучение() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОтпускНаОбучение;
КонецФункции
Функция ВидВремениОтпускПоБеременностиИРодам() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОтпускПоБеременностиИРодам;
КонецФункции
Функция ВидВремениОтпускПоУходуЗаРебенком() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОтпускПоУходуЗаРебенком;
КонецФункции
// В исходном коде модуля формы эта функция возвращает ОтпускПоУходуЗаРебенком —
// копируем как есть (так зафиксировано в проекте).
Функция ВидВремениДополнительныеВыходныеДниОплачиваемые() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ОтпускПоУходуЗаРебенком;
КонецФункции
Функция ВидВремениПовышениеКвалификации() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.ПовышениеКвалификации;
КонецФункции
Функция ВидВремениПраздники(СтатьяФинансирования) Экспорт
Если СтатьяФинансирования = СтатьяФинансированияСГЗ() Тогда
Возврат ВидВремениПраздникиСГЗ();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияПД() Тогда
Возврат ВидВремениПраздникиПД();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияОМС() Тогда
Возврат ВидВремениПраздникиОМС();
КонецЕсли;
КонецФункции
Функция ВидВремениПраздникиБезПовышеннойОплаты(СтатьяФинансирования) Экспорт
Если СтатьяФинансирования = СтатьяФинансированияСГЗ() Тогда
Возврат ВидВремениПраздникиБезПовышеннойОплатыСГЗ();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияПД() Тогда
Возврат ВидВремениПраздникиБезПовышеннойОплатыПД();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияОМС() Тогда
Возврат ВидВремениПраздникиБезПовышеннойОплатыОМС();
КонецЕсли;
КонецФункции
Функция ВидВремениПрогулы() Экспорт
Возврат Справочники.ВидыИспользованияРабочегоВремени.Прогулы;
КонецФункции
Функция ВидВремениРаботаНочныеЧасы(СтатьяФинансирования) Экспорт
Если СтатьяФинансирования = СтатьяФинансированияСГЗ() Тогда
Возврат ВидВремениРаботаНочныеЧасыСГЗ();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияПД() Тогда
Возврат ВидВремениРаботаНочныеЧасыПД();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияОМС() Тогда
Возврат ВидВремениРаботаНочныеЧасыОМС();
КонецЕсли;
КонецФункции
Функция ВидВремениСверхурочные(СтатьяФинансирования) Экспорт
Если СтатьяФинансирования = СтатьяФинансированияСГЗ() Тогда
Возврат ВидВремениСверхурочныеСГЗ();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияПД() Тогда
Возврат ВидВремениСверхурочныеПД();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияОМС() Тогда
Возврат ВидВремениСверхурочныеОМС();
КонецЕсли;
КонецФункции
Функция ВидВремениСверхурочныеБезПовышеннойОплаты(СтатьяФинансирования) Экспорт
Если СтатьяФинансирования = СтатьяФинансированияСГЗ() Тогда
Возврат ВидВремениСверхурочныеБезПовышеннойОплатыСГЗ();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияПД() Тогда
Возврат ВидВремениСверхурочныеБезПовышеннойОплатыПД();
ИначеЕсли СтатьяФинансирования = СтатьяФинансированияОМС() Тогда
Возврат ВидВремениСверхурочныеБезПовышеннойОплатыОМС();
КонецЕсли;
КонецФункции
#КонецОбласти
#Область КлассификацияВидовВремени
// Возвращает код финансирования ("СГЗ"/"ПД"/"ОМС") для указанного вида времени.
// Для неденежных видов (болезнь, отпуск и т.п.) возвращает Неопределено.
Функция ФинансированиеПоВидуВремени(ВидВремени) Экспорт
Если ВидВремени = ВидВремениЯвкаСГЗ()
ИЛИ ВидВремени = ВидВремениРаботаНочныеЧасыСГЗ()
ИЛИ ВидВремени = ВидВремениПраздникиСГЗ()
ИЛИ ВидВремени = ВидВремениПраздникиБезПовышеннойОплатыСГЗ()
ИЛИ ВидВремени = ВидВремениСверхурочныеСГЗ()
ИЛИ ВидВремени = ВидВремениСверхурочныеБезПовышеннойОплатыСГЗ() Тогда
Возврат "СГЗ";
ИначеЕсли ВидВремени = ВидВремениЯвкаПД()
ИЛИ ВидВремени = ВидВремениРаботаНочныеЧасыПД()
ИЛИ ВидВремени = ВидВремениПраздникиПД()
ИЛИ ВидВремени = ВидВремениПраздникиБезПовышеннойОплатыПД()
ИЛИ ВидВремени = ВидВремениСверхурочныеПД()
ИЛИ ВидВремени = ВидВремениСверхурочныеБезПовышеннойОплатыПД() Тогда
Возврат "ПД";
ИначеЕсли ВидВремени = ВидВремениЯвкаОМС()
ИЛИ ВидВремени = ВидВремениРаботаНочныеЧасыОМС()
ИЛИ ВидВремени = ВидВремениПраздникиОМС()
ИЛИ ВидВремени = ВидВремениПраздникиБезПовышеннойОплатыОМС()
ИЛИ ВидВремени = ВидВремениСверхурочныеОМС()
ИЛИ ВидВремени = ВидВремениСверхурочныеБезПовышеннойОплатыОМС() Тогда
Возврат "ОМС";
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
Функция ВидВремениЯвкаПринадлежитФинансированию(ВидВремени) Экспорт
Возврат ВидВремени = ВидВремениЯвкаСГЗ()
ИЛИ ВидВремени = ВидВремениЯвкаПД()
ИЛИ ВидВремени = ВидВремениЯвкаОМС();
КонецФункции
Функция ВидВремениПраздникиПринадлежит(ВидВремени) Экспорт
Возврат ВидВремени = ВидВремениПраздникиСГЗ()
ИЛИ ВидВремени = ВидВремениПраздникиПД()
ИЛИ ВидВремени = ВидВремениПраздникиОМС()
ИЛИ ВидВремени = ВидВремениПраздникиБезПовышеннойОплатыСГЗ()
ИЛИ ВидВремени = ВидВремениПраздникиБезПовышеннойОплатыПД()
ИЛИ ВидВремени = ВидВремениПраздникиБезПовышеннойОплатыОМС();
КонецФункции
Функция ВидВремениНочныеПринадлежит(ВидВремени) Экспорт
Возврат ВидВремени = ВидВремениРаботаНочныеЧасыСГЗ()
ИЛИ ВидВремени = ВидВремениРаботаНочныеЧасыПД()
ИЛИ ВидВремени = ВидВремениРаботаНочныеЧасыОМС();
КонецФункции
Функция ВидВремениСверхурочныеПринадлежит(ВидВремени) Экспорт
Возврат ВидВремени = ВидВремениСверхурочныеСГЗ()
ИЛИ ВидВремени = ВидВремениСверхурочныеПД()
ИЛИ ВидВремени = ВидВремениСверхурочныеОМС()
ИЛИ ВидВремени = ВидВремениСверхурочныеБезПовышеннойОплатыСГЗ()
ИЛИ ВидВремени = ВидВремениСверхурочныеБезПовышеннойОплатыПД()
ИЛИ ВидВремени = ВидВремениСверхурочныеБезПовышеннойОплатыОМС()
ИЛИ ВидВремени = ВидВремениКормлениеРебенка()
ИЛИ ВидВремени = ВидВремениПовышениеКвалификации();
КонецФункции
// Возвращает буквенное обозначение вида времени (для UI/Excel-формата).
Функция БукваПоВидуВремени(ВидВремени) Экспорт
Если ВидВремени = ВидВремениБолезнь() Тогда
Возврат "Б";
ИначеЕсли ВидВремени = ВидВремениВыходныеДни() Тогда
Возврат "В";
ИначеЕсли ВидВремени = ВидВремениОсновнойОтпуск() Тогда
Возврат "О";
ИначеЕсли ВидВремени = ВидВремениДополнительныйОтпуск() Тогда
Возврат "ОД";
ИначеЕсли ВидВремени = ВидВремениКомандировка() Тогда
Возврат "К";
ИначеЕсли ВидВремени = ВидВремениПрогулы() Тогда
Возврат "П";
ИначеЕсли ВидВремени = ВидВремениНеявкиПоНевыясненнымПричинам() Тогда
Возврат "НН";
ИначеЕсли ВидВремени = ВидВремениОтпускНаОбучение() Тогда
Возврат "ОУ";
ИначеЕсли ВидВремени = ВидВремениОтпускПоБеременностиИРодам() Тогда
Возврат "Р";
ИначеЕсли ВидВремени = ВидВремениОтпускПоУходуЗаРебенком() Тогда
Возврат "ОР";
ИначеЕсли ВидВремени = ВидВремениНеоплачиваемыйОтпускПоРазрешениюРаботодателя() Тогда
Возврат "ОЗ";
ИначеЕсли ВидВремени = ВидВремениОтстранениеОтРаботыБезОплаты() Тогда
Возврат "НБ";
ИначеЕсли ВидВремени = ВидВремениОтстранениеОтРаботыСОплатой() Тогда
Возврат "НО";
Иначе
Возврат "";
КонецЕсли;
КонецФункции
#КонецОбласти
#Область ОбратноеПреобразование
// Классифицирует записи дня для обратной загрузки из табеля в ТЧ формы.
//
// Параметры:
// ЗаписиДня - Массив из Структура (ключи "ВидВремени", "Часы")
//
// Возвращаемое значение:
// Структура с ключами "Основная", "Ночные", "Сверхурочные".
// Каждое значение — Структура("Часы, Буква, ВидВремени") или Неопределено.
//
Функция КлассифицироватьДень(ЗаписиДня) Экспорт
Результат = Новый Структура("Основная, Ночные, Сверхурочные", Неопределено, Неопределено, Неопределено);
ЧасыПраздничных = 0;
ЧасыЯвки = 0;
ЧасыНочных = 0;
ЧасыСверхурочных = 0;
ВидВремениПраздничных = Неопределено;
ВидВремениЯвки = Неопределено;
ВидВремениНочных = Неопределено;
ВидВремениСверхурочных = Неопределено;
ПервыйНеденежный = Неопределено;
Для Каждого Запись Из ЗаписиДня Цикл
ВидВремени = Запись.ВидВремени;
Часы = Запись.Часы;
Если ВидВремениЯвкаПринадлежитФинансированию(ВидВремени) Тогда
ЧасыЯвки = ЧасыЯвки + Часы;
Если ВидВремениЯвки = Неопределено Тогда
ВидВремениЯвки = ВидВремени;
КонецЕсли;
ИначеЕсли ВидВремениПраздникиПринадлежит(ВидВремени) Тогда
ЧасыПраздничных = ЧасыПраздничных + Часы;
Если ВидВремениПраздничных = Неопределено Тогда
ВидВремениПраздничных = ВидВремени;
КонецЕсли;
ИначеЕсли ВидВремениНочныеПринадлежит(ВидВремени) Тогда
ЧасыНочных = ЧасыНочных + Часы;
Если ВидВремениНочных = Неопределено Тогда
ВидВремениНочных = ВидВремени;
КонецЕсли;
ИначеЕсли ВидВремениСверхурочныеПринадлежит(ВидВремени) Тогда
ЧасыСверхурочных = ЧасыСверхурочных + Часы;
Если ВидВремениСверхурочных = Неопределено Тогда
ВидВремениСверхурочных = ВидВремени;
КонецЕсли;
ИначеЕсли ПервыйНеденежный = Неопределено Тогда
ПервыйНеденежный = Новый Структура("Часы, Буква, ВидВремени", Часы, БукваПоВидуВремени(ВидВремени), ВидВремени);
КонецЕсли;
КонецЦикла;
Если ЧасыПраздничных > 0 Тогда
Результат.Основная = Новый Структура("Часы, Буква, ВидВремени", ЧасыПраздничных, "РП", ВидВремениПраздничных);
ИначеЕсли ЧасыЯвки > 0 Тогда
Результат.Основная = Новый Структура("Часы, Буква, ВидВремени", ЧасыЯвки, "Ф", ВидВремениЯвки);
ИначеЕсли ПервыйНеденежный <> Неопределено Тогда
Результат.Основная = ПервыйНеденежный;
КонецЕсли;
Если ЧасыНочных > 0 Тогда
Результат.Ночные = Новый Структура("Часы, Буква, ВидВремени", ЧасыНочных, "Н", ВидВремениНочных);
КонецЕсли;
Если ЧасыСверхурочных > 0 Тогда
Результат.Сверхурочные = Новый Структура("Часы, Буква, ВидВремени", ЧасыСверхурочных, "С", ВидВремениСверхурочных);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает Истина, если во всех 31 колонках ЧасовN строки значение <= 0.
Функция СтрокаПустаяПоЧасам(СтрокаТЧ) Экспорт
Для НомерДня = 1 По 31 Цикл
Если СтрокаТЧ["Часов" + НомерДня] > 0 Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
// Группирует часы по буквенным кодам и формирует строку вида "Я 7, Б 10".
Функция РассчитатьВремяИтог(СтрокаТЧ) Экспорт
ГруппировкаЧасов = Новый Соответствие;
Для НомерДня = 1 По 31 Цикл
Часы = СтрокаТЧ["Часов" + НомерДня];
Если Часы = 0 Тогда
Продолжить;
КонецЕсли;
Буква = СтрокаТЧ["Время" + НомерДня + "Буква"];
Если Буква = "" Тогда
Продолжить;
КонецЕсли;
ТекущаяСумма = ГруппировкаЧасов[Буква];
Если ТекущаяСумма = Неопределено Тогда
ТекущаяСумма = 0;
КонецЕсли;
ГруппировкаЧасов.Вставить(Буква, ТекущаяСумма + Часы);
КонецЦикла;
Результат = "";
Для Каждого КЗ Из ГруппировкаЧасов Цикл
Если Результат <> "" Тогда
Результат = Результат + ", ";
КонецЕсли;
Результат = Результат + КЗ.Ключ + " " + Формат(КЗ.Значение, "ЧРД=.; ЧГ=");
КонецЦикла;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область Валидация
// Проверяет, есть ли в записях дня другие виды времени, отличные от указанного.
Функция ЕстьНесовместимыеВидыВремени(Сотрудник, НомерДня, ТаблицаДня, ВидВремени) Экспорт
НесовместимыеВидыВремениНайдены = Ложь;
СписокНесовместимыхВидовВремени = "";
Для каждого СтрокаТаблицыДня Из ТаблицаДня Цикл
Если СтрокаТаблицыДня.ВидВремени <> ВидВремени Тогда
Если СписокНесовместимыхВидовВремени = "" Тогда
СписокНесовместимыхВидовВремени = Строка(СтрокаТаблицыДня.ВидВремени);
Иначе
СписокНесовместимыхВидовВремени = СписокНесовместимыхВидовВремени + ", " + Строка(СтрокаТаблицыДня.ВидВремени);
КонецЕсли;
НесовместимыеВидыВремениНайдены = Истина;
КонецЕсли;
КонецЦикла;
Возврат НесовместимыеВидыВремениНайдены;
КонецФункции
#КонецОбласти
#Область ПоискСотрудников
// Возвращает табельный номер (поле Код) для указанного сотрудника.
Функция ТабельныйНомерСотрудникаБД(Сотрудник) Экспорт
Возврат Сотрудник.Код;
КонецФункции
// Получает последнюю кадровую историю сотрудника.
Функция КадровыеДанные(Сотрудник, ДатаПолученияКадровыхДанных) Экспорт
СтруктураПоискаКадровыхДанных = Новый Структура("Сотрудник", Сотрудник);
Возврат РегистрыСведений.КадроваяИсторияСотрудников.ПолучитьПоследнее(ДатаПолученияКадровыхДанных, СтруктураПоискаКадровыхДанных);
КонецФункции
// Возвращает пустую структуру данных сотрудника (используется как фабрика).
Функция СтруктураДанныхСотрудника() Экспорт
Возврат Новый Структура("Сотрудник,Должность,НаименованиеДолжностиДляТабеля,ДолжностьПоШтатномуРасписанию,Подразделение,ВидЗанятости,КоличествоСтавок," +
"ПредставлениеСотрудника,ПредставлениеДолжности,ПредставлениеПодразделения,Обработан",
Справочники.Сотрудники.ПустаяСсылка(),
Справочники.Должности.ПустаяСсылка(), "",
Справочники.ШтатноеРасписание.ПустаяСсылка(),
Справочники.ПодразделенияОрганизаций.ПустаяСсылка(),
"",
0,
"", "", "",
Ложь);
КонецФункции
#КонецОбласти
#Область ФильтрацияСотрудников
// Проверяет, есть ли сотрудник в списке совместителей (по физическому лицу).
Функция СотрудникВСпискеСовместителей(Сотрудник, СписокСовместителей) Экспорт
Результат = Ложь;
Попытка
Если СписокСовместителей.Количество() > 0 Тогда
Если Сотрудник.ФизическоеЛицо = СписокСовместителей[0].Сотрудник.ФизическоеЛицо Тогда
Результат = Истина;
КонецЕсли;
КонецЕсли;
Исключение
КонецПопытки;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область ПоискТабеля
// Ищет ссылку на сохранённый табель по ключевым реквизитам через РС ПС_ЗагруженныеТабеля.
// Возвращает последнюю по дате загрузки редакцию.
Функция НайтиСсылкуНаТабель(Организация, Подразделение, НаименованиеПодразделения, ПериодРегистрации) Экспорт
Если НЕ ЗначениеЗаполнено(Организация)
ИЛИ НЕ ЗначениеЗаполнено(Подразделение)
ИЛИ ПустаяСтрока(НаименованиеПодразделения)
ИЛИ НЕ ЗначениеЗаполнено(ПериодРегистрации) Тогда
Возврат Документы.ТабельУчетаРабочегоВремени.ПустаяСсылка();
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПС_ЗагруженныеТабеляСрезПоследних.ТабельУчетаРабочегоВремени КАК ТабельУчетаРабочегоВремени
|ИЗ
| РегистрСведений.ПС_ЗагруженныеТабеля.СрезПоследних(
| &ПериодРегистрации,
| Организация = &Организация
| И НаименованиеПодразделенияПоТабелю = &НаименованиеПодразделения
| И ПериодВводаДанныхОВремени = &ПериодВводаДанныхОВремени
| И СтруктурноеПодразделение = &СтруктурноеПодразделение) КАК ПС_ЗагруженныеТабеляСрезПоследних
|УПОРЯДОЧИТЬ ПО
| ПС_ЗагруженныеТабеляСрезПоследних.ДатаЗагрузки УБЫВ";
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("СтруктурноеПодразделение", Подразделение);
Запрос.УстановитьПараметр("НаименованиеПодразделения", НаименованиеПодразделения);
Запрос.УстановитьПараметр("ПериодВводаДанныхОВремени", Перечисления.ПериодыВводаДанныхОВремени.ТекущийМесяц);
Запрос.УстановитьПараметр("ПериодРегистрации", НачалоМесяца(ПериодРегистрации));
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Возврат Документы.ТабельУчетаРабочегоВремени.ПустаяСсылка();
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Возврат Выборка.ТабельУчетаРабочегоВремени;
КонецФункции
#КонецОбласти
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:CommonModule xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="ce51cd3a-9b22-4c6a-9f49-7b3b1fa0f1aa">
<name>ПС_ТабелиСервер</name>
<server>true</server>
<externalConnection>true</externalConnection>
<clientOrdinaryApplication>true</clientOrdinaryApplication>
<returnValuesReuse>DuringSession</returnValuesReuse>
</mdclass:CommonModule>
@@ -75,8 +75,10 @@
<commonModules>CommonModule.КадровыйУчетВызовСервера</commonModules>
<commonModules>CommonModule.КадровыйУчетБазовый</commonModules>
<commonModules>CommonModule.УчетРабочегоВремениРасширенный</commonModules>
<commonModules>CommonModule.ПС_Описание</commonModules>
<commonModules>CommonModule.ПС_ЗагрузкаДанныхИзExcel_Описание</commonModules>
<commonModules>CommonModule.ПС_КартаДанных</commonModules>
<commonModules>CommonModule.ПС_ТабелиСервер</commonModules>
<httpServices>HTTPService.ПС_ВебСервисТабелей</httpServices>
<catalogs>Catalog.Организации</catalogs>
<catalogs>Catalog.ПодразделенияОрганизаций</catalogs>
<catalogs>Catalog.Пользователи</catalogs>
@@ -499,6 +499,10 @@
<dataPath xsi:type="form:DataPath">
<segments>Объект.Подразделение</segments>
</dataPath>
<handlers>
<event>OnChange</event>
<name>ПодразделениеПриИзменении</name>
</handlers>
<extendedTooltip>
<name>ПодразделениеРасширеннаяПодсказка</name>
<id>493</id>
@@ -579,6 +583,10 @@
<dataPath xsi:type="form:DataPath">
<segments>Объект.НаименованиеПодразделения</segments>
</dataPath>
<handlers>
<event>OnChange</event>
<name>НаименованиеПодразделенияПриИзменении</name>
</handlers>
<extendedTooltip>
<name>НаименованиеПодразделенияРасширеннаяПодсказка</name>
<id>1553</id>
@@ -595,7 +603,6 @@
<autoFill>true</autoFill>
</contextMenu>
<type>InputField</type>
<readOnly>true</readOnly>
<editMode>Enter</editMode>
<showInHeader>true</showInHeader>
<headerHorizontalAlign>Left</headerHorizontalAlign>
@@ -608,18 +615,10 @@
<chooseType>true</chooseType>
<typeDomainEnabled>true</typeDomainEnabled>
<textEdit>true</textEdit>
<textColor xsi:type="core:ColorRef">
<color>Style.SpecialTextColor</color>
</textColor>
<backColor xsi:type="core:ColorRef">
<color>Style.ReportHeaderBackColor</color>
</backColor>
<textSize>Normal</textSize>
<font xsi:type="core:FontRef">
<font>Style.NormalTextFont</font>
<bold>true</bold>
<italic>false</italic>
<underline>false</underline>
<strikeout>false</strikeout>
<scale>100</scale>
</font>
</extInfo>
</items>
<items xsi:type="form:FormField">
@@ -0,0 +1,385 @@
// HTTP-сервис "Веб-сервис табелей".
// Маршруты:
// GET /index — HTML-форма ввода табеля
// GET /me — JSON с данными текущего пользователя
// GET /departments — JSON со списком доступных подразделений
// GET /employees — JSON со списком действующих сотрудников подразделения
#Область ОбработчикиСобытий
Функция ОбработкаГлавной(Запрос)
Возврат ГлавнаяHtml();
КонецФункции
Функция ОбработкаТекущегоПользователя(Запрос)
Данные = ДанныеТекущегоПользователя();
Объект = Новый Соответствие;
Объект.Вставить("name", Данные.Имя);
Объект.Вставить("user", Данные.ИмяПользователя);
Возврат JsonОтвет(200, Объект);
КонецФункции
Функция ОбработкаСпискаПодразделений(Запрос)
Массив = Новый Массив;
Подразделения = ДоступныеПодразделения();
Для Каждого КлючЗначение Из Подразделения Цикл
П = КлючЗначение.Значение;
Элемент = Новый Соответствие;
Элемент.Вставить("ref", XMLСтрока(П.Ссылка));
Элемент.Вставить("name", П.Имя);
Массив.Добавить(Элемент);
КонецЦикла;
Объект = Новый Соответствие;
Объект.Вставить("items", Массив);
Возврат JsonОтвет(200, Объект);
КонецФункции
Функция ОбработкаСпискаСотрудников(Запрос)
СтрокаПодразделения = Запрос.ПараметрыЗапроса.Получить("dep");
Если СтрокаПодразделения = Неопределено Тогда
СтрокаПодразделения = Запрос.ПараметрыURL.Получить("dep");
КонецЕсли;
Если СтрокаПодразделения = Неопределено ИЛИ ПустаяСтрока(СтрокаПодразделения) Тогда
Ошибка = Новый Соответствие;
Ошибка.Вставить("error", "Не передано подразделение (dep)");
Возврат JsonОтвет(400, Ошибка);
КонецЕсли;
Массив = Новый Массив;
СотрудникиСписок = СотрудникиПодразделения(СтрокаПодразделения);
Для Каждого Строка Из СотрудникиСписок Цикл
Элемент = Новый Соответствие;
Элемент.Вставить("ref", XMLСтрока(Строка.Ссылка));
Элемент.Вставить("name", Строка.Имя);
Элемент.Вставить("position", Строка.Должность);
Массив.Добавить(Элемент);
КонецЦикла;
Объект = Новый Соответствие;
Объект.Вставить("items", Массив);
Возврат JsonОтвет(200, Объект);
КонецФункции
Функция ОбработкаСпискаВидовВремени(Запрос)
Массив = Новый Массив;
ВидыСписок = ВидыВремениСписок();
Для Каждого Строка Из ВидыСписок Цикл
Элемент = Новый Соответствие;
Элемент.Вставить("ref", XMLСтрока(Строка.Ссылка));
Элемент.Вставить("letter", Строка.Буква);
Элемент.Вставить("name", Строка.Наименование);
Массив.Добавить(Элемент);
КонецЦикла;
Объект = Новый Соответствие;
Объект.Вставить("items", Массив);
Возврат JsonОтвет(200, Объект);
КонецФункции
Функция ОбработкаСпискаИсточниковФинансирования(Запрос)
Массив = Новый Массив;
Для Каждого Строка Из ИсточникиФинансированияСписок() Цикл
Элемент = Новый Соответствие;
Элемент.Вставить("ref", Строка.Код);
Элемент.Вставить("name", Строка.Наименование);
Массив.Добавить(Элемент);
КонецЦикла;
Объект = Новый Соответствие;
Объект.Вставить("items", Массив);
Возврат JsonОтвет(200, Объект);
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// HTML-страница.
Функция ГлавнаяHtml()
ДанныеПользователя = ДанныеТекущегоПользователя();
Подразделения = ДоступныеПодразделения();
Части = Новый Массив;
Части.Добавить("<!DOCTYPE html>");
Части.Добавить("<html lang=""ru"">");
Части.Добавить("<head>");
Части.Добавить("<meta charset=""utf-8"">");
Части.Добавить("<title>Ввод табеля — MVP</title>");
Части.Добавить("<style>");
Части.Добавить("body { font-family: -apple-system, Segoe UI, sans-serif; margin: 24px; color: #1f2933; background: #f7f9fb; }");
Части.Добавить("h1 { margin: 0 0 4px; font-size: 22px; }");
Части.Добавить(".muted { color: #6b7280; font-size: 13px; }");
Части.Добавить(".card { background: white; border: 1px solid #e1e5eb; border-radius: 6px; padding: 16px; margin-top: 12px; }");
Части.Добавить(".filters { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; }");
Части.Добавить(".filter-cell { display: flex; flex-direction: column; min-width: 180px; }");
Части.Добавить("label { margin-top: 8px; font-size: 13px; }");
Части.Добавить("select, input, button { padding: 6px 10px; font-size: 14px; border: 1px solid #cbd2d9; border-radius: 4px; }");
Части.Добавить("button { background: #2c7be5; color: white; border: 0; cursor: pointer; padding: 8px 16px; }");
Части.Добавить("button:disabled { background: #9aa5b1; cursor: not-allowed; }");
Части.Добавить("table.t { border-collapse: collapse; margin-top: 12px; font-size: 12px; }");
Части.Добавить("table.t th, table.t td { border: 1px solid #e1e5eb; padding: 2px; text-align: center; min-width: 32px; }");
Части.Добавить("table.t th { background: #f0f4f8; }");
Части.Добавить("table.t td.name, table.t th.name { text-align: left; padding-left: 8px; min-width: 220px; background: #fafbfc; position: sticky; left: 0; }");
Части.Добавить("table.t select { width: 100%; border: 0; padding: 2px 4px; font-size: 12px; background: transparent; }");
Части.Добавить(".scroll { overflow-x: auto; max-width: 100%; }");
Части.Добавить("</style>");
Части.Добавить("</head>");
Части.Добавить("<body>");
Части.Добавить("<h1>Ввод табеля учёта рабочего времени</h1>");
Части.Добавить("<div class=""muted"">MVP — проверка концепции.</div>");
Части.Добавить("<div class=""card"">");
Части.Добавить("<div><b>Пользователь:</b> " + ДанныеПользователя.Имя + "</div>");
Части.Добавить("<div><b>Подразделений доступно:</b> " + Формат(Подразделения.Количество(), "ЧГ=0") + "</div>");
Части.Добавить("</div>");
Части.Добавить("<div class=""card"">");
Части.Добавить("<div class=""filters"">");
Части.Добавить("<div class=""filter-cell""><label>Подразделение</label>");
Части.Добавить("<select id=""depSelect""><option value="""">— выберите —</option>" + ОпцииПодразделений(Подразделения) + "</select></div>");
Части.Добавить("<div class=""filter-cell""><label>Период (месяц)</label>");
Части.Добавить("<input type=""month"" id=""period"" value=""" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyy-MM") + """></div>");
Части.Добавить("<div class=""filter-cell""><label>Источник финансирования</label>");
Части.Добавить("<select id=""fundSelect""><option value="""">— выберите —</option></select></div>");
Части.Добавить("<div class=""filter-cell""><label>&nbsp;</label><button id=""load"" disabled>Загрузить табель</button></div>");
Части.Добавить("</div>");
Части.Добавить("<div style=""margin-top: 8px;""><span id=""status"" class=""muted""></span></div>");
Части.Добавить("</div>");
Части.Добавить("<div class=""card"">");
Части.Добавить("<div id=""tableArea""><div class=""muted"">Сотрудники появятся после загрузки.</div></div>");
Части.Добавить("</div>");
Части.Добавить("<script>");
Части.Добавить("var sel = document.getElementById('depSelect');");
Части.Добавить("var period = document.getElementById('period');");
Части.Добавить("var fundSel = document.getElementById('fundSelect');");
Части.Добавить("var btn = document.getElementById('load');");
Части.Добавить("var status = document.getElementById('status');");
Части.Добавить("var tableArea = document.getElementById('tableArea');");
Части.Добавить("var kinds = [];");
Части.Добавить("function ready() { btn.disabled = !(sel.value && period.value && fundSel.value); }");
Части.Добавить("sel.onchange = ready; period.onchange = ready; fundSel.onchange = ready;");
Части.Добавить("function loadKinds(cb) {");
Части.Добавить(" var xhr = new XMLHttpRequest();");
Части.Добавить(" xhr.open('GET', '/8ZikBudg/hs/tabel/kinds', true);");
Части.Добавить(" xhr.onload = function() {");
Части.Добавить(" if (xhr.status === 200) { try { var d = JSON.parse(xhr.responseText); kinds = d.items || []; cb && cb(); }");
Части.Добавить(" catch (e) { status.textContent = 'Ошибка /kinds: ' + e.message; } }");
Части.Добавить(" else { status.textContent = 'Ошибка /kinds: HTTP ' + xhr.status; } };");
Части.Добавить(" xhr.onerror = function() { status.textContent = 'Сбой запроса /kinds.'; };");
Части.Добавить(" xhr.send();");
Части.Добавить("}");
Части.Добавить("function loadFunds() {");
Части.Добавить(" var xhr = new XMLHttpRequest();");
Части.Добавить(" xhr.open('GET', '/8ZikBudg/hs/tabel/funds', true);");
Части.Добавить(" xhr.onload = function() {");
Части.Добавить(" if (xhr.status === 200) { try { var d = JSON.parse(xhr.responseText);");
Части.Добавить(" for (var i = 0; i < d.items.length; i++) {");
Части.Добавить(" var o = document.createElement('option'); o.value = d.items[i].ref; o.textContent = d.items[i].name; fundSel.appendChild(o);");
Части.Добавить(" } ready(); }");
Части.Добавить(" catch (e) { status.textContent = 'Ошибка /funds: ' + e.message; } }");
Части.Добавить(" else { status.textContent = 'Ошибка /funds: HTTP ' + xhr.status; } };");
Части.Добавить(" xhr.onerror = function() { status.textContent = 'Сбой запроса /funds.'; };");
Части.Добавить(" xhr.send();");
Части.Добавить("}");
Части.Добавить("function daysInPeriod(p) {");
Части.Добавить(" var a = p.split('-'); var y = parseInt(a[0], 10); var m = parseInt(a[1], 10);");
Части.Добавить(" return new Date(y, m, 0).getDate();");
Части.Добавить("}");
Части.Добавить("btn.onclick = function() {");
Части.Добавить(" status.textContent = 'Загрузка…'; btn.disabled = true; tableArea.innerHTML = '';");
Части.Добавить(" var days = daysInPeriod(period.value);");
Части.Добавить(" var xhr = new XMLHttpRequest();");
Части.Добавить(" xhr.open('GET', '/8ZikBudg/hs/tabel/employees?dep=' + encodeURIComponent(sel.value), true);");
Части.Добавить(" xhr.onload = function() {");
Части.Добавить(" if (xhr.status === 200) { try {");
Части.Добавить(" var data = JSON.parse(xhr.responseText); renderTable(data.items || [], days);");
Части.Добавить(" status.textContent = 'Готово. Сотрудников: ' + (data.items || []).length + ', дней: ' + days + '.';");
Части.Добавить(" } catch (e) { status.textContent = 'Ошибка разбора: ' + e.message; } }");
Части.Добавить(" else { status.textContent = 'Ошибка /employees: HTTP ' + xhr.status; }");
Части.Добавить(" ready();");
Части.Добавить(" };");
Части.Добавить(" xhr.onerror = function() { status.textContent = 'Сбой запроса /employees.'; ready(); };");
Части.Добавить(" xhr.send();");
Части.Добавить("};");
Части.Добавить("function renderTable(items, days) {");
Части.Добавить(" if (!items.length) { tableArea.innerHTML = '<div class=""muted"">В подразделении нет действующих сотрудников.</div>'; return; }");
Части.Добавить(" var opts = '';");
Части.Добавить(" for (var k = 0; k < kinds.length; k++) { opts += '<option value=""' + kinds[k].letter + '"">' + kinds[k].letter + '</option>'; }");
Части.Добавить(" var html = '<div class=""scroll""><table class=""t""><thead><tr>';");
Части.Добавить(" html += '<th class=""name"">№</th><th class=""name"">Сотрудник</th>';");
Части.Добавить(" for (var d = 1; d <= days; d++) { html += '<th>' + d + '</th>'; }");
Части.Добавить(" html += '</tr></thead><tbody>';");
Части.Добавить(" for (var i = 0; i < items.length; i++) {");
Части.Добавить(" html += '<tr><td class=""name"">' + (i + 1) + '</td><td class=""name"">' + items[i].name + '</td>';");
Части.Добавить(" for (var d = 1; d <= days; d++) { html += '<td><select data-row=""' + i + '"" data-day=""' + d + '""><option value=""""></option>' + opts + '</select></td>'; }");
Части.Добавить(" html += '</tr>';");
Части.Добавить(" }");
Части.Добавить(" html += '</tbody></table></div>';");
Части.Добавить(" tableArea.innerHTML = html;");
Части.Добавить("}");
Части.Добавить("loadFunds(); loadKinds();");
Части.Добавить("</script>");
Части.Добавить("</body></html>");
ТелоHtml = СтрСоединить(Части, Символы.ПС);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "text/html; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(ТелоHtml, КодировкаТекста.UTF8);
Возврат Ответ;
КонецФункции
Функция ОпцииПодразделений(Подразделения)
Части = Новый Массив;
Для Каждого КлючЗначение Из Подразделения Цикл
Ссылка = XMLСтрока(КлючЗначение.Значение.Ссылка);
Имя = КлючЗначение.Значение.Имя;
Части.Добавить("<option value=""" + Ссылка + """>" + Имя + "</option>");
КонецЦикла;
Возврат СтрСоединить(Части, "");
КонецФункции
// Backend.
Функция ДанныеТекущегоПользователя()
ИмяПользователя = "";
Попытка
ИмяПользователя = ИмяПользователя();
Исключение
ИмяПользователя = "Не определён";
КонецПопытки;
Возврат Новый Структура("ИмяПользователя, Имя", ИмяПользователя, ИмяПользователя);
КонецФункции
// Возвращает Соответствие: Ключ = XMLСтрока(ссылки), Значение = Структура{Ссылка, Имя}.
Функция ДоступныеПодразделения()
Результат = Новый Соответствие;
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗРЕШЕННЫЕ Ссылка, Наименование КАК Имя
|ИЗ Справочник.ПодразделенияОрганизаций
|ГДЕ НЕ ПометкаУдаления
|УПОРЯДОЧИТЬ ПО Наименование");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Данные = Новый Структура("Ссылка, Имя", Выборка.Ссылка, СокрЛП(Выборка.Имя));
Результат.Вставить(XMLСтрока(Выборка.Ссылка), Данные);
КонецЦикла;
Возврат Результат;
КонецФункции
// Фиксированный набор источников финансирования для учреждений здравоохранения.
Функция ИсточникиФинансированияСписок()
Результат = Новый Массив;
Результат.Добавить(Новый Структура("Код, Наименование", "СГЗ",
"Субсидии на выполнение государственного задания"));
Результат.Добавить(Новый Структура("Код, Наименование", "ПД",
"Приносящая доход деятельность"));
Результат.Добавить(Новый Структура("Код, Наименование", "ОМС",
"Обязательное медицинское страхование"));
Возврат Результат;
КонецФункции
// Возвращает массив структур {Ссылка, Имя, Должность} — сотрудники, действующие в подразделении.
Функция СотрудникиПодразделения(Знач СтрокаПодразделения)
Результат = Новый Массив;
ПодразделениеСсылка = XMLЗначение(Тип("СправочникСсылка.ПодразделенияОрганизаций"),
СтрокаПодразделения);
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
| КадроваяИстория.Сотрудник КАК Сотрудник
|ИЗ
| РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК КадроваяИстория
|ГДЕ
| КадроваяИстория.Подразделение = &Подразделение
| И КадроваяИстория.ВидСобытия <> ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Увольнение)
| И КадроваяИстория.ДатаНачала <= &ТекущаяДата
| И (КадроваяИстория.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1)
| ИЛИ КадроваяИстория.ДатаОкончания >= &ТекущаяДата)
|УПОРЯДОЧИТЬ ПО
| КадроваяИстория.Сотрудник.Наименование");
Запрос.УстановитьПараметр("Подразделение", ПодразделениеСсылка);
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сотрудник = Выборка.Сотрудник;
Результат.Добавить(Новый Структура(
"Ссылка, Имя, Должность",
Сотрудник,
СокрЛП(Сотрудник.Наименование),
""));
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает массив структур {Ссылка, Буква, Наименование} — предопределённые виды использования рабочего времени.
Функция ВидыВремениСписок()
Результат = Новый Массив;
Запрос = Новый Запрос(
"ВЫБРАТЬ
| ВидыВремени.Ссылка КАК Ссылка,
| ВидыВремени.БуквенныйКод КАК Буква,
| ВидыВремени.Наименование КАК Наименование
|ИЗ
| Справочник.ВидыИспользованияРабочегоВремени КАК ВидыВремени
|ГДЕ
| НЕ ВидыВремени.ПометкаУдаления
| И ВидыВремени.НеИспользуется = ЛОЖЬ
|УПОРЯДОЧИТЬ ПО
| ВидыВремени.Наименование");
УстановитьПривилегированныйРежим(Истина);
Выборка = Запрос.Выполнить().Выбрать();
УстановитьПривилегированныйРежим(Ложь);
Пока Выборка.Следующий() Цикл
Результат.Добавить(Новый Структура(
"Ссылка, Буква, Наименование",
Выборка.Ссылка,
СокрЛП(Выборка.Буква),
СокрЛП(Выборка.Наименование)));
КонецЦикла;
Возврат Результат;
КонецФункции
// Сериализация в JSON.
Функция JsonОтвет(КодСостояния, Объект)
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJsonЗначение(ЗаписьJSON, Объект);
Тело = ЗаписьJSON.Закрыть();
Ответ = Новый HTTPСервисОтвет(КодСостояния);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8);
Возврат Ответ;
КонецФункции
Процедура ЗаписатьJsonЗначение(ЗаписьJSON, Значение)
Если Значение = Неопределено Тогда
ЗаписьJSON.ЗаписатьЗначение(Null);
ИначеЕсли ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Структура") Тогда
ЗаписьJSON.ЗаписатьНачалоОбъекта();
Для Каждого КлючЗначение Из Значение Цикл
ЗаписьJSON.ЗаписатьИмяСвойства(КлючЗначение.Ключ);
ЗаписатьJsonЗначение(ЗаписьJSON, КлючЗначение.Значение);
КонецЦикла;
ЗаписьJSON.ЗаписатьКонецОбъекта();
ИначеЕсли ТипЗнч(Значение) = Тип("Массив") Тогда
ЗаписьJSON.ЗаписатьНачалоМассива();
Для Каждого Элемент Из Значение Цикл
ЗаписатьJsonЗначение(ЗаписьJSON, Элемент);
КонецЦикла;
ЗаписьJSON.ЗаписатьКонецМассива();
Иначе
ЗаписьJSON.ЗаписатьЗначение(Значение);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:HTTPService xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="8fcbeb90-fb46-4f8a-9d9a-da3a1005ea23">
<name>ПС_ВебСервисТабелей</name>
<synonym>
<key>ru</key>
<value>Веб-сервис табелей</value>
</synonym>
<rootURL>tabel</rootURL>
<reuseSessions>AutoUse</reuseSessions>
<sessionMaxAge>20</sessionMaxAge>
<urlTemplates uuid="67247dad-9453-41aa-8e88-2b895a5ca48a">
<name>Корневой</name>
<synonym>
<key>ru</key>
<value>Корневой URL</value>
</synonym>
<template>/index</template>
<methods uuid="dcd0c0b4-ded3-4462-a1d9-84a6a723e0fb">
<name>Главная</name>
<handler>ОбработкаГлавной</handler>
</methods>
</urlTemplates>
<urlTemplates uuid="d1885db9-af3d-4cb3-b90a-e74096076566">
<name>ТекущийПользователь</name>
<synonym>
<key>ru</key>
<value>Текущий пользователь</value>
</synonym>
<template>/me</template>
<methods uuid="692d8ffd-af43-47e0-bf4e-68ca93635e64">
<name>Получить</name>
<synonym>
<key>ru</key>
<value>GET /me</value>
</synonym>
<handler>ОбработкаТекущегоПользователя</handler>
</methods>
</urlTemplates>
<urlTemplates uuid="779b1022-0604-4aa4-85ad-d7c59cdf9146">
<name>Подразделения</name>
<synonym>
<key>ru</key>
<value>Список подразделений</value>
</synonym>
<template>/departments</template>
<methods uuid="f4de8672-285a-416b-8936-c030453f8c3b">
<name>Получить</name>
<synonym>
<key>ru</key>
<value>GET /departments</value>
</synonym>
<handler>ОбработкаСпискаПодразделений</handler>
</methods>
</urlTemplates>
<urlTemplates uuid="a2c66a9e-06b5-4636-bfce-f021e1b348b7">
<name>СотрудникиПодразделения</name>
<synonym>
<key>ru</key>
<value>Сотрудники подразделения</value>
</synonym>
<template>/employees</template>
<methods uuid="d784cad9-e739-4c7e-972f-96466b37c27f">
<name>Получить</name>
<synonym>
<key>ru</key>
<value>GET /employees?dep=...</value>
</synonym>
<handler>ОбработкаСпискаСотрудников</handler>
</methods>
</urlTemplates>
<urlTemplates uuid="7bdbf8ab-d00d-4a52-8f4e-8137aab4e1cd">
<name>ВидыВремени</name>
<synonym>
<key>ru</key>
<value>Виды использования рабочего времени</value>
</synonym>
<template>/kinds</template>
<methods uuid="bb592643-a5c4-4a7c-a2cd-28a91eca8ee9">
<name>Получить</name>
<synonym>
<key>ru</key>
<value>GET /kinds</value>
</synonym>
<handler>ОбработкаСпискаВидовВремени</handler>
</methods>
</urlTemplates>
<urlTemplates uuid="a5ceeefc-14ef-4a89-aa52-21835d58618f">
<name>ИсточникиФинансирования</name>
<synonym>
<key>ru</key>
<value>Источники финансирования</value>
</synonym>
<template>/funds</template>
<methods uuid="8f2dfa7c-1cfe-4a3f-932e-831a52e79a42">
<name>Получить</name>
<synonym>
<key>ru</key>
<value>GET /funds</value>
</synonym>
<handler>ОбработкаСпискаИсточниковФинансирования</handler>
</methods>
</urlTemplates>
</mdclass:HTTPService>
@@ -35,7 +35,7 @@
//
// Общие модули:
// ПС_РаботаСНастройками — программный интерфейс (Сервер)
// ПС_Описание — настоящий модуль документации
// ПС_ПериодическиеНастройки_Описание — настоящий модуль документации
//
// ПРИНЦИП ЗАПИСИ БЕЗ УКАЗАНИЯ ПЕРИОДА
//
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:CommonModule xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="6d9ceeed-89b2-436f-8698-d7314fff223f">
<name>ПС_Описание</name>
<name>ПС_ПериодическиеНастройки_Описание</name>
<synonym>
<key>ru</key>
<value>Описание</value>
@@ -46,7 +46,7 @@
</languages>
<roles>Role.ПС_ЗаписьНастроек</roles>
<roles>Role.ПС_ЧтениеНастроек</roles>
<commonModules>CommonModule.ПС_Описание</commonModules>
<commonModules>CommonModule.ПС_ПериодическиеНастройки_Описание</commonModules>
<commonModules>CommonModule.ПС_РаботаСНастройками</commonModules>
<definedTypes>DefinedType.ПС_ТипыЗначенийНастроек</definedTypes>
<catalogs>Catalog.Пользователи</catalogs>
Submodule Учет родительской платы added at d21b4cc635