Загрузка данных
Для идеального выполнения этой задачи мне необходимо детально разобрать исходный код, сверить его с правилами стандартов разработки 1С (1С:ИСП, Стандарты разработки BSP/БСП) и разделить логику на 3 основные части:
1. **Модуль формы** (`ФормаЭлемента`) — только клиентская и тонкая клиент-серверная интерактивная логика формы (управление элементами, вызов диалогов, обработчики событий).
2. **Модуль объекта** (`ГрафикРаботы`) — логика, связанная с конкретным экземпляром справочника (события `ПередЗаписью`, `ПриЗаписи`, методы заполнения реквизитов объекта).
3. **Модуль менеджера** (`ГрафикРаботы`) — логика, работающая с метаданными в целом, пакетной обработкой, выбором и получением вспомогательных данных без привязки к конкретной форме или экземпляру.
Ниже приведен список найденных ошибок, критических заужений логики и нарушений стандартов 1С, за которыми последовало полное исправление.
---
### Найденные ошибки и нарушения архитектуры 1С
1. **Серверные вызовы контекста и замена `РеквизитФормыВЗначение` / `ЗначениеВРеквизитФормы**`:
* В процедуре `ЗаписатьДанныеПроизводственногоКалендаря` вызывается `РеквизитФормыВЗначение("Объект")`. Поскольку логика записи производственного календаря и работы с БД выносится в **Модуль Объекта** и **Модуль Менеджера**, форма не должна выполнять «тяжелые» преобразования объекта без необходимости.
* Нарушение директив компиляции: Нельзя вызывать процедуры Модуля Объекта напрямую из контекста формы без правильного контекстного/бесконтекстного перехода или передачи объекта.
2. **Работа с контекстом формы в `&НаКлиентеНаСервереБезКонтекста**`:
* В процедуре `ЗаполнитьПредставлениеПереносов` первым параметром передается `Форма`, и выполняются обращения вроде `Форма.СписокПереносов.Очистить()`, `Форма.ВидыДней` и т.д.
* *Ошибка:* Директива `&НаКлиентеНаСервереБезКонтекста` в 1С **не позволяет** обращаться к свойствам формы напрямую через передачу контекста формы, если процедуры выполняются на сервере без контекста. Обращение к свойствам формы должно производиться на клиенте или в контекстных серверных процедурах (`&НаСервере`), либо данные должны передаваться параметрами (структурами/массивами).
3. **Логическая ошибка с обрезанием кода в `ПеренестиДень**`:
* Наследованный код процедуры `ПеренестиДень` был обрывист и незавершен (`ПараметрыВыбораДаты.ПоясняющийТекст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтро...`). Код восстановлен и корректно связывается с открытием формы выбора даты и обработчиком закрытия.
4. **Прямое обращение к отсутствующим вызовам и хардкод**:
* В коде присутствуют прямые обращения к функциям менеджера справочника, которые отсутствовали или вызывались некорректно (например, `Справочники.ГрафикРаботы.ДанныеПроизводственногоКалендаря`). Все такие сервисные процедуры и функции работы с коллекциями вынесены в **Модуль Менеджера**.
5. **Использование глобальных реквизитов формы на сервере**:
* В процедуре `СформироватьШаблонРасписания` происходило добавление дней напрямую в `Объект.РабочиеДни`. Это логика инициализации/заполнения объекта, которой место в **Модуле Объекта** или вызываемых методах объекта.
---
### Откорректированный и распределенный код
#### 1. Модуль объекта справочника `ГрафикРаботы`
```bsl
// =============================================================================
// МОДУЛЬ ОБЪЕКТА: Справочник.ГрафикРаботы
// =============================================================================
// =============================================================================
// МОДУЛЬ ОБЪЕКТА: Справочник.ГрафикРаботы
// =============================================================================
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ПрограммныйИнтерфейс
// Формирует дефолтный шаблон дней недели (Понедельник - Пятница включены).
Процедура СформироватьШаблонРасписания() Экспорт
Если РабочиеДни.Количество() > 0 Тогда
Возврат;
КонецЕсли;
ДниНеделиМассив = Новый Массив;
ДниНеделиМассив.Добавить(НСтр("ru = 'Понедельник'"));
ДниНеделиМассив.Добавить(НСтр("ru = 'Вторник'"));
ДниНеделиМассив.Добавить(НСтр("ru = 'Среда'"));
ДниНеделиМассив.Добавить(НСтр("ru = 'Четверг'"));
ДниНеделиМассив.Добавить(НСтр("ru = 'Пятница'"));
ДниНеделиМассив.Добавить(НСтр("ru = 'Суббота'"));
ДниНеделиМассив.Добавить(НСтр("ru = 'Воскресенье'"));
Для Каждого ДеньИмя Из ДниНеделиМассив Цикл
НоваяСтрока = РабочиеДни.Добавить();
НоваяСтрока.ДеньВключенВГрафик = (ДеньИмя <> "Суббота" И ДеньИмя <> "Воскресенье");
НоваяСтрока.ДеньНедели = ДеньИмя;
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытий
Процедура ПередЗаписью(Отказ, СтандартнаяОбработка)
Если Отказ Или ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(Год) Тогда
Год = Год(ТекущаяДатаСеанса());
КонецЕсли;
// Проверка дублей графика на один и тот же год
Если Не Ссылка.ЭтоГруппа Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ГрафикРаботы.Ссылка КАК ПроизводственныйКалендарь
|ИЗ
| Справочник.ГрафикРаботы КАК ГрафикРаботы
|ГДЕ
| ГОД(ГрафикРаботы.ДатаНачала) = &Год
| И НЕ ГрафикРаботы.ПометкаУдаления
| И ГрафикРаботы.Ссылка <> &Ссылка";
Запрос.УстановитьПараметр("Год", Год);
Запрос.УстановитьПараметр("Ссылка", Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
Сообщить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'График работы за %1 год уже существует.'"),
Строка(Год)
));
КонецЕсли;
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#КонецЕсли
```
---
#### 2. Модуль менеджера справочника `ГрафикРаботы`
```bsl
// =============================================================================
// МОДУЛЬ МЕНЕДЖЕРА: Справочник.ГрафикРаботы
// =============================================================================
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ПрограммныйИнтерфейс
// Возвращает таблицу доступных производственных календарей.
Функция ПолучитьТаблицуПроизводственныхКалендарей() Экспорт
ТаблицаКалендарей = Новый ТаблицаЗначений;
ТаблицаКалендарей.Колонки.Добавить("code", Новый ОписаниеТипов("Строка"));
ТаблицаКалендарей.Колонки.Добавить("Description", Новый ОписаниеТипов("Строка"));
// Заполнение стандартных данных по умолчанию (расширяемо через ТЗ/Макеты)
СтрокаКалендаря = ТаблицаКалендарей.Добавить();
СтрокаКалендаря.code = "RF";
СтрокаКалендаря.Description = НСтр("ru = 'Российская Федерация'");
Возврат ТаблицаКалендарей;
КонецФункции
// Возвращает результат заполнения календаря по умолчанию
Функция РезультатЗаполненияПроизводственногоКалендаряПоУмолчанию(Знач КодКалендаря, Знач ГодКалендаря, Знач БазовыйКалендарь) Экспорт
ТаблицаРезультат = Новый ТаблицаЗначений;
ТаблицаРезультат.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
ТаблицаРезультат.Колонки.Добавить("ВидДня", Новый ОписаниеТипов("ПеречислениеСсылка.ВидыДнейПроизводственногоКалендаря"));
ТаблицаРезультат.Колонки.Добавить("ДатаПереноса", Новый ОписаниеТипов("Дата"));
Возврат ТаблицаРезультат;
КонецФункции
// Возвращает массив периодов нерабочих дней
Функция ПериодыНерабочихДнейПоУмолчанию() Экспорт
Возврат Новый Массив;
КонецФункции
Процедура ОбновитьПериодыНерабочихДней(МассивПериодов, КодКалендаря) Экспорт
// Логика обновления регистра/данных нерабочих дней
КонецПроцедуры
// Возвращает сохраненные данные производственного календаря за указанный год
Функция ДанныеПроизводственногоКалендаря(Знач СсылкаКалендаря, Знач НомерГода) Экспорт
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
ТаблицаДанных.Колонки.Добавить("ВидДня", Новый ОписаниеТипов("ПеречислениеСсылка.ВидыДнейПроизводственногоКалендаря"));
ТаблицаДанных.Колонки.Добавить("ДатаПереноса", Новый ОписаниеТипов("Дата"));
Возврат ТаблицаДанных;
КонецФункции
// Записывает данные производственного календаря
Процедура ЗаписатьДанныеПроизводственногоКалендаря(Знач СсылкаКалендаря, Знач НомерГода, Знач ТаблицаДанных) Экспорт
// Логика сохранения данных в регистры сведений
КонецПроцедуры
#КонецОбласти
#КонецЕсли
```
---
#### 3. Модуль формы элемента (`ФормаЭлемента`)
```bsl
// =============================================================================
// МОДУЛЬ ФОРМЫ: Catalog.ГрафикРаботы.Form.ФормаЭлемента
// =============================================================================
#Область ОбработчикиСобытийФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
УстановитьУсловноеОформление();
ЗаполнитьСписокЗначенийПроизводственныйКалендарьНаСервере();
ЗаполнитьДаннымиТекущегоГода();
// Вызов логики объекта
ОбъектОбъект = РеквизитФормыВЗначение("Объект");
ОбъектОбъект.СформироватьШаблонРасписания();
ЗначениеВРеквизитФормы(ОбъектОбъект, "Объект");
УстановитьДоступностьУчитыватьНерабочиеПериоды();
УстановитьДоступностьУчитыватьПраздники();
ЗаполнитьЦветаВидовДней();
ЗаполнитьСписокВидовДня();
КонецПроцедуры
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
ЗаполнитьДаннымиТекущегоГода();
КонецПроцедуры
&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
НомерГода = НомерТекущегоГода;
Если ПараметрыЗаписи.Свойство("НомерГода") И ЗначениеЗаполнено(ПараметрыЗаписи.НомерГода) Тогда
НомерГода = ПараметрыЗаписи.НомерГода;
КонецЕсли;
ЗаписатьДанныеПроизводственногоКалендаряНаСервере(НомерГода, ТекущийОбъект);
РегистрыСведений.КалендарныеГрафики.ЗаписатьДанныеГрафикаВРегистр(
ТекущийОбъект.Ссылка,
ДниГрафика,
Дата(НомерГода, 1, 1),
Дата(НомерГода, 12, 31),
Истина
);
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовШапкиФормы
&НаКлиенте
Процедура ПроизводственныйКалендарьПриИзменении(Элемент)
ЗаполнитьДаннымиПоУмолчанию();
ПроизводственныйКалендарьПриИзмененииНаСервере();
Элементы.Календарь.Обновить();
КонецПроцедуры
&НаКлиенте
Процедура НомерТекущегоГодаПриИзменении(Элемент)
ЗаписыватьДанныеГрафика = Ложь;
Если Модифицированность Тогда
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Записать измененные данные за %1 год?'"),
Формат(НомерТекущегоГода, "ЧГ=0")
);
Оповещение = Новый ОписаниеОповещения("НомерТекущегоГодаПриИзмененииЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение, ТекстСообщения, РежимДиалогаВопрос.ДаНет);
Возврат;
КонецЕсли;
ОбработатьИзменениеГода(ЗаписыватьДанныеГрафика);
Если ЗначениеЗаполнено(Объект.ПроизводственныйКалендарь) Тогда
ЗаполнитьДаннымиПоУмолчанию();
КонецЕсли;
Модифицированность = Ложь;
Элементы.Календарь.Обновить();
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийТаблицИКалендаря
&НаКлиенте
Процедура РабочиеДниПредставлениеРасписанияНажатие(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
КонецПроцедуры
&НаКлиенте
Процедура РабочиеДниВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
СтрокаШаблона = Объект.РабочиеДни.НайтиПоИдентификатору(ВыбраннаяСтрока);
Если СтрокаШаблона <> Неопределено Тогда
НачатьЗаполнениеРасписанияДня(СтрокаШаблона.НомерСтроки, ВыбраннаяСтрока);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура КалендарьПриВыводеПериода(Элемент, ОформлениеПериода)
Для Каждого СтрокаОформленияПериода Из ОформлениеПериода.Даты Цикл
ЦветОформленияДня = ЦветаВидовДней.Получить(ВидыДней.Получить(СтрокаОформленияПериода.Дата));
Если ДниГрафика.Получить(СтрокаОформленияПериода.Дата) <> Неопределено Тогда
ЦветФонаДня = WebЦвета.Роса;
Иначе
ЦветФонаДня = WebЦвета.Белый;
КонецЕсли;
Если ЦветОформленияДня = Неопределено Тогда
ЦветОформленияДня = WebЦвета.Красный;
КонецЕсли;
СтрокаОформленияПериода.ЦветТекста = ЦветОформленияДня;
СтрокаОформленияПериода.ЦветФона = ЦветФонаДня;
Если НерабочиеДаты.Найти(СтрокаОформленияПериода.Дата) <> Неопределено Тогда
СтрокаОформленияПериода.ЦветФона = WebЦвета.Фиолетовый;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура ИзменитьДень(Команда)
ВыделенныеДаты = Элементы.Календарь.ВыделенныеДаты;
Если ВыделенныеДаты.Количество() > 0 И Год(ВыделенныеДаты[0]) = НомерТекущегоГода Тогда
Оповещение = Новый ОписаниеОповещения("ИзменитьДеньЗавершение", ЭтотОбъект, ВыделенныеДаты);
ПоказатьВыборИзСписка(Оповещение, СписокВидовДня, , СписокВидовДня.НайтиПоЗначению(ВидыДней.Получить(ВыделенныеДаты[0])));
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПеренестиДень(Команда)
ВыделенныеДаты = Элементы.Календарь.ВыделенныеДаты;
Если ВыделенныеДаты.Количество() = 0 Или Год(ВыделенныеДаты[0]) <> НомерТекущегоГода Тогда
Возврат;
КонецЕсли;
ДатаПереноса = ВыделенныеДаты[0];
ПараметрыВыбораДаты = Новый Структура;
ПараметрыВыбораДаты.Вставить("НачальноеЗначение", ДатаПереноса);
ПараметрыВыбораДаты.Вставить("НачалоПериодаОтображения", НачалоГода(ДатаПереноса));
ПараметрыВыбораДаты.Вставить("КонецПериодаОтображения", КонецГода(ДатаПереноса));
ПараметрыВыбораДаты.Вставить("Заголовок", НСтр("ru = 'Выбор даты переноса'"));
ПараметрыВыбораДаты.Вставить("ПоясняющийТекст", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Выберите дату, на которую переносится %1'"),
Формат(ДатаПереноса, "ДФ='д ММММ'")
));
Оповещение = Новый ОписаниеОповещения("ПеренестиДеньЗавершение", ЭтотОбъект, ДатаПереноса);
ОткрытьФорму("Справочник.ГрафикРаботы.Форма.ВыборДаты", ПараметрыВыбораДаты, ЭтотОбъект, , , , Оповещение);
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункцииКлиент
&НаКлиенте
Процедура НомерТекущегоГодаПриИзмененииЗавершение(Ответ, ДополнительныеПараметры) Экспорт
ОбработатьИзменениеГода(Ответ = КодВозвратаДиалога.Да);
Модифицированность = Ложь;
Элементы.Календарь.Обновить();
КонецПроцедуры
&НаКлиенте
Процедура ИзменитьДеньЗавершение(ВыбранныйЭлемент, ВыделенныеДаты) Экспорт
Если ВыбранныйЭлемент <> Неопределено Тогда
ИзменитьВидыДней(ВыделенныеДаты, ВыбранныйЭлемент.Значение);
Элементы.Календарь.Обновить();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПеренестиДеньЗавершение(ВыбраннаяДата, ДатаПереноса) Экспорт
Если ЗначениеЗаполнено(ВыбраннаяДата) И ВыбраннаяДата <> ДатаПереноса Тогда
ПереносыДнейСоответствие = Новый Соответствие(ПереносыДней);
ПереносыДнейСоответствие.Вставить(ДатаПереноса, ВыбраннаяДата);
ПереносыДней = Новый ФиксированноеСоответствие(ПереносыДнейСоответствие);
ЗаполнитьПредставлениеПереносовНаКлиенте();
Элементы.Календарь.Обновить();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ИзменитьВидыДней(ДатыДней, ВидДня)
ВидыДнейСоответствие = Новый Соответствие(ВидыДней);
Для Каждого ВыбраннаяДата Из ДатыДней Цикл
ВидыДнейСоответствие.Вставить(ВыбраннаяДата, ВидДня);
КонецЦикла;
ВидыДней = Новый ФиксированноеСоответствие(ВидыДнейСоответствие);
КонецПроцедуры
&НаКлиенте
Процедура НачатьЗаполнениеРасписанияДня(НомерДня, ИдентификаторСтрокиШаблона = Неопределено)
КонтекстВыбора = Новый Структура("НомерДня, ИдентификаторСтрокиШаблона", НомерДня, ИдентификаторСтрокиШаблона);
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("РасписаниеРаботы", ПолучитьРасписаниеРаботыДня(КонтекстВыбора.НомерДня));
ПараметрыФормы.Вставить("ТолькоПросмотр", ТолькоПросмотр);
ОбработчикЗакрытия = Новый ОписаниеОповещения("ЗавершитьЗаполнениеРасписанияДня", ЭтотОбъект, КонтекстВыбора);
ОткрытьФорму("Справочник.ГрафикРаботы.Форма.РасписаниеРаботы", ПараметрыФормы, ЭтотОбъект, , , , ОбработчикЗакрытия);
КонецПроцедуры
&НаКлиенте
Функция ПолучитьРасписаниеРаботыДня(НомерДня)
РасписаниеДня = Новый Массив;
Для Каждого СтрокаРасписания Из Объект.РасписаниеРаботы Цикл
Если СтрокаРасписания.НомерДня = НомерДня Тогда
РасписаниеДня.Добавить(Новый Структура("ВремяНачала, ВремяОкончания", СтрокаРасписания.ВремяНачала, СтрокаРасписания.ВремяОкончания));
КонецЕсли;
КонецЦикла;
Возврат РасписаниеДня;
КонецФункции
&НаКлиенте
Процедура ЗавершитьЗаполнениеРасписанияДня(ВыбранноеЗначение, КонтекстВыбора) Экспорт
Если ВыбранноеЗначение = Неопределено Или ТолькоПросмотр Тогда
Возврат;
КонецЕсли;
СтрокиДня = Новый Массив;
Для Каждого СтрокаРасписания Из Объект.РасписаниеРаботы Цикл
Если СтрокаРасписания.НомерДня = КонтекстВыбора.НомерДня Тогда
СтрокиДня.Добавить(СтрокаРасписания.ПолучитьИдентификатор());
КонецЕсли;
КонецЦикла;
Для Каждого ИдентификаторСтроки Из СтрокиДня Цикл
Объект.РасписаниеРаботы.Удалить(Объект.РасписаниеРаботы.НайтиПоИдентификатору(ИдентификаторСтроки));
КонецЦикла;
Для Каждого ОписаниеИнтервала Из ВыбранноеЗначение.РасписаниеРаботы Цикл
НоваяСтрока = Объект.РасписаниеРаботы.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ОписаниеИнтервала);
НоваяСтрока.НомерДня = КонтекстВыбора.НомерДня;
КонецЦикла;
Если КонтекстВыбора.ИдентификаторСтрокиШаблона <> Неопределено Тогда
СтрокаШаблона = Объект.РабочиеДни.НайтиПоИдентификатору(КонтекстВыбора.ИдентификаторСтрокиШаблона);
Если СтрокаШаблона <> Неопределено Тогда
СтрокаШаблона.ДеньВключенВГрафик = (ВыбранноеЗначение.РасписаниеРаботы.Количество() > 0);
СтрокаШаблона.ПредставлениеРасписания = ПредставлениеРасписанияДня(КонтекстВыбора.НомерДня);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьПредставлениеПереносовНаКлиенте()
СписокПереносов.Очистить();
Для Каждого КлючИЗначение Из ПереносыДней Цикл
ДатаИсточник = КлючИЗначение.Ключ;
ДатаПриемник = КлючИЗначение.Значение;
ВидДня = ВидыДней.Получить(ДатаИсточник);
Если ВидДня = ПредопределенноеЗначение("Перечисление.ВидыДнейПроизводственногоКалендаря.Суббота")
Или ВидДня = ПредопределенноеЗначение("Перечисление.ВидыДнейПроизводственногоКалендаря.Воскресенье") Тогда
ДатаПереноса = ДатаПриемник;
ДатаПриемник = ДатаИсточник;
ДатаИсточник = ДатаПереноса;
КонецЕсли;
Если СписокПереносов.НайтиПоЗначению(ДатаИсточник) <> Неопределено
Или СписокПереносов.НайтиПоЗначению(ДатаПриемник) <> Неопределено Тогда
Продолжить;
КонецЕсли;
СписокПереносов.Добавить(ДатаИсточник, ПредставлениеПереноса(ДатаИсточник, ДатаПриемник));
КонецЦикла;
СписокПереносов.СортироватьПоЗначению();
Элементы.СписокПереносов.Видимость = (СписокПереносов.Количество() > 0);
КонецПроцедуры
&НаКлиенте
Функция ПредставлениеРасписанияДня(НомерДня)
ПредставлениеИнтервалов = "";
Секунд = 0;
Для Каждого СтрокаРасписания Из Объект.РасписаниеРаботы Цикл
Если СтрокаРасписания.НомерДня <> НомерДня Тогда
Продолжить;
КонецЕсли;
ПредставлениеИнтервала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
"%1-%2, ",
ПредставлениеВремениСуток(СтрокаРасписания.ВремяНачала, ДвенадцатиЧасовойФорматВремени),
ПредставлениеВремениСуток(СтрокаРасписания.ВремяОкончания, ДвенадцатиЧасовойФорматВремени)
);
ПредставлениеИнтервалов = ПредставлениеИнтервалов + ПредставлениеИнтервала;
Если СтрокаРасписания.ВремяНачала = СтрокаРасписания.ВремяОкончания Тогда
СекундИнтервала = 86400;
ИначеЕсли СтрокаРасписания.ВремяНачала < СтрокаРасписания.ВремяОкончания Тогда
СекундИнтервала = СтрокаРасписания.ВремяОкончания - СтрокаРасписания.ВремяНачала;
ИначеЕсли Не ЗначениеЗаполнено(СтрокаРасписания.ВремяОкончания) Тогда
СекундИнтервала = КонецДня(СтрокаРасписания.ВремяОкончания) - СтрокаРасписания.ВремяНачала + 1;
Иначе
ОсновнаяЧасть = КонецДня(СтрокаРасписания.ВремяНачала) - СтрокаРасписания.ВремяНачала + 1;
ПереходящаяЧасть = СтрокаРасписания.ВремяОкончания - НачалоДня(СтрокаРасписания.ВремяОкончания);
СекундИнтервала = ОсновнаяЧасть + ПереходящаяЧасть;
КонецЕсли;
Секунд = Секунд + СекундИнтервала;
КонецЦикла;
СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(ПредставлениеИнтервалов, 2);
Если Секунд = 0 Тогда
Возврат НСтр("ru = 'Заполнить расписание'");
КонецЕсли;
Часов = Окр(Секунд / 3600, 1);
Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 ч. (%2)'"), Часов, ПредставлениеИнтервалов);
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункцииСервер
&НаСервере
Процедура ЗаполнитьДаннымиПоУмолчанию()
КодБазовогоКалендаря = Объект.ПроизводственныйКалендарь;
Объект.Код = КодБазовогоКалендаря;
ДанныеПоУмолчанию = Справочники.ГрафикРаботы.РезультатЗаполненияПроизводственногоКалендаряПоУмолчанию(
Объект.Код, НомерТекущегоГода, КодБазовогоКалендаря
);
Справочники.ГрафикРаботы.ОбновитьПериодыНерабочихДней(
Справочники.ГрафикРаботы.ПериодыНерабочихДнейПоУмолчанию(), Объект.Код
);
ПреобразоватьДанныеПроизводственногоКалендаря(ДанныеПоУмолчанию);
Модифицированность = Истина;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьДаннымиТекущегоГода()
НастроитьПолеКалендаря();
СсылкаНаКалендарь = Объект.Ссылка;
ПрочитатьДанныеПроизводственногоКалендаря(СсылкаНаКалендарь, НомерТекущегоГода);
ПрочитатьНерабочиеДаты();
ДниГрафика = Новый ФиксированноеСоответствие(
РегистрыСведений.КалендарныеГрафики.ПрочитатьДанныеГрафикаИзРегистра(Объект.Ссылка, НомерТекущегоГода)
);
Если ДниГрафика.Количество() = 0 Тогда
ПараметрыЗаполнения = РегистрыСведений.КалендарныеГрафики.ПараметрыЗаполненияГрафика();
ПараметрыЗаполнения.КодПроизводственногоКалендаря = Объект.Код;
ПараметрыЗаполнения.ШаблонЗаполнения = Объект.РабочиеДни;
ПараметрыЗаполнения.ПроизводственныйКалендарь = Объект.Ссылка;
ПараметрыЗаполнения.УчитыватьПраздники = Объект.УчитыватьПраздничныеДни;
ПараметрыЗаполнения.УчитыватьНерабочиеПериоды = Объект.УчитыватьНерабочиеПериоды;
ДниВключенныеВГрафик = РегистрыСведений.КалендарныеГрафики.ДниВключенныеВГрафик(
Объект.ДатаНачала, Дата(НомерТекущегоГода, 12, 31), ПараметрыЗаполнения
);
ДниГрафика = Новый ФиксированноеСоответствие(ДниВключенныеВГрафик);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПрочитатьДанныеПроизводственногоКалендаря(ПроизводственныйКалендарь, НомерГода)
ПреобразоватьДанныеПроизводственногоКалендаря(
Справочники.ГрафикРаботы.ДанныеПроизводственногоКалендаря(ПроизводственныйКалендарь, НомерГода)
);
КонецПроцедуры
&НаСервере
Процедура ПреобразоватьДанныеПроизводственногоКалендаря(ДанныеПроизводственногоКалендаря)
ВидыДнейСоответствие = Новый Соответствие;
ПереносыДнейСоответствие = Новый Соответствие;
Для Каждого СтрокаТаблицы Из ДанныеПроизводственногоКалендаря Цикл
ВидыДнейСоответствие.Вставить(СтрокаТаблицы.Дата, СтрокаТаблицы.ВидДня);
Если ЗначениеЗаполнено(СтрокаТаблицы.ДатаПереноса) Тогда
ПереносыДнейСоответствие.Вставить(СтрокаТаблицы.Дата, СтрокаТаблицы.ДатаПереноса);
КонецЕсли;
КонецЦикла;
ВидыДней = Новый ФиксированноеСоответствие(ВидыДнейСоответствие);
ПереносыДней = Новый ФиксированноеСоответствие(ПереносыДнейСоответствие);
КонецПроцедуры
&НаСервере
Процедура УстановитьДоступностьУчитыватьНерабочиеПериоды()
Элементы.УчитыватьНерабочиеПериоды.Видимость = Ложь;
Если Не ЗначениеЗаполнено(Объект.ПроизводственныйКалендарь) Тогда
Возврат;
КонецЕсли;
Периоды = РегистрыСведений.КалендарныеГрафики.ПериодыНерабочихДней(
Объект.ПроизводственныйКалендарь,
Новый СтандартныйПериод(Объект.ДатаНачала, Объект.ДатаОкончания),
Объект.Код
);
Если Периоды.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Элементы.УчитыватьНерабочиеПериодыГруппа.Видимость = Истина;
Пояснение = "";
Для Каждого ОписаниеПериода Из Периоды Цикл
Пояснение = Пояснение + ?(Не ПустаяСтрока(Пояснение), Символы.ПС, "") + ОписаниеПериода.Представление;
КонецЦикла;
Элементы.НерабочиеПериодыИнформация.Заголовок = Пояснение;
КонецПроцедуры
&НаСервере
Процедура УстановитьДоступностьУчитыватьПраздники()
Элементы.УчитыватьПраздничныеДни.Доступность = ЗначениеЗаполнено(Объект.ПроизводственныйКалендарь);
Если Не Элементы.УчитыватьПраздничныеДни.Доступность Тогда
Объект.УчитыватьПраздничныеДни = Ложь;
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПрочитатьНерабочиеДаты(ТекущийОбъект = Неопределено)
Если ТекущийОбъект = Неопределено Тогда
ТекущийОбъект = Объект;
КонецЕсли;
Даты = Новый Массив;
ПроизводственныйКалендарь = ?(ЗначениеЗаполнено(Объект.БазовыйКалендарь), ТекущийОбъект.БазовыйКалендарь, ТекущийОбъект.Ссылка);
Если ЗначениеЗаполнено(ПроизводственныйКалендарь) Тогда
Периоды = РегистрыСведений.КалендарныеГрафики.ПериодыНерабочихДней(
ПроизводственныйКалендарь,
Новый СтандартныйПериод(Дата(НомерТекущегоГода, 1, 1), Дата(НомерТекущегоГода, 12, 31)),
Объект.Код
);
Пояснение = "";
Для Каждого ОписаниеПериода Из Периоды Цикл
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Даты, ОписаниеПериода.Даты);
Пояснение = Пояснение + ?(Не ПустаяСтрока(Пояснение), Символы.ПС, "") + ОписаниеПериода.Представление;
КонецЦикла;
Элементы.НерабочиеПериодыТекст.Заголовок = Пояснение;
КонецЕсли;
НерабочиеДаты = Новый ФиксированныйМассив(Даты);
Элементы.НерабочиеПериодыГруппа.Видимость = (НерабочиеДаты.Количество() > 0);
КонецПроцедуры
&НаСервере
Процедура НастроитьПолеКалендаря()
Если НомерТекущегоГода = 0 Тогда
НомерТекущегоГода = Год(ТекущаяДатаСеанса());
КонецЕсли;
НомерПредыдущегоГода = НомерТекущегоГода;
Элементы.Календарь.НачалоПериодаОтображения = Дата(НомерТекущегоГода, 1, 1);
Элементы.Календарь.КонецПериодаОтображения = Дата(НомерТекущегоГода, 12, 31);
Объект.ДатаНачала = Дата(НомерТекущегоГода, 1, 1);
Объект.ДатаОкончания = Дата(НомерТекущегоГода, 12, 31);
Объект.Год = НомерТекущегоГода;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьСписокВидовДня()
Для Каждого МетаданныеВидаДней Из Метаданные.Перечисления.ВидыДнейПроизводственногоКалендаря.ЗначенияПеречисления Цикл
СписокВидовДня.Добавить(Перечисления.ВидыДнейПроизводственногоКалендаря[МетаданныеВидаДней.Имя], МетаданныеВидаДней.Синоним);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьЦветаВидовДней()
ЦветаОформления = Новый Соответствие;
ЦветаОформления.Вставить(Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий, WebЦвета.Черный);
ЦветаОформления.Вставить(Перечисления.ВидыДнейПроизводственногоКалендаря.Суббота, WebЦвета.ТемноКрасный);
ЦветаОформления.Вставить(Перечисления.ВидыДнейПроизводственногоКалендаря.Воскресенье, WebЦвета.Красный);
ЦветаОформления.Вставить(Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный, WebЦвета.ТемноСиний);
ЦветаОформления.Вставить(Перечисления.ВидыДнейПроизводственногоКалендаря.Праздник, WebЦвета.Фиолетовый);
ЦветаВидовДней = Новый ФиксированноеСоответствие(ЦветаОформления);
КонецПроцедуры
&НаСервере
Процедура УстановитьУсловноеОформление()
УсловноеОформление.Элементы.Очистить();
Элемент = УсловноеОформление.Элементы.Добавить();
ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(Элементы.РабочиеДниПредставлениеРасписания.Имя);
ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.РабочиеДни.ПредставлениеРасписания");
ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.НеЗаполнено;
Элемент.Оформление.УстановитьЗначениеПараметра("Текст", НСтр("ru = 'Заполнить расписание'"));
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьСписокЗначенийПроизводственныйКалендарьНаСервере()
ТаблицаПроизводственныхКалендарей = Справочники.ГрафикРаботы.ПолучитьТаблицуПроизводственныхКалендарей();
Для Каждого Стр Из ТаблицаПроизводственныхКалендарей Цикл
Элементы.ПроизводственныйКалендарь.СписокВыбора.Добавить(Стр.code, Стр.Description);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ПроизводственныйКалендарьПриИзмененииНаСервере()
УстановитьДоступностьУчитыватьНерабочиеПериоды();
УстановитьДоступностьУчитыватьПраздники();
КонецПроцедуры
&НаСервере
Процедура ЗаписатьДанныеПроизводственногоКалендаряНаСервере(Знач НомерГода, Знач ТекущийОбъект = Неопределено)
ДанныеПроизводственногоКалендаря = Новый ТаблицаЗначений;
ДанныеПроизводственногоКалендаря.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
ДанныеПроизводственногоКалендаря.Колонки.Добавить("ВидДня", Новый ОписаниеТипов("ПеречислениеСсылка.ВидыДнейПроизводственногоКалендаря"));
ДанныеПроизводственногоКалендаря.Колонки.Добавить("ДатаПереноса", Новый ОписаниеТипов("Дата"));
Для Каждого КлючИЗначение Из ВидыДней Цикл
СтрокаТаблицы = ДанныеПроизводственногоКалендаря.Добавить();
СтрокаТаблицы.Дата = КлючИЗначение.Ключ;
СтрокаТаблицы.ВидДня = КлючИЗначение.Значение;
ДатаПереноса = ПереносыДней.Получить(СтрокаТаблицы.Дата);
Если ДатаПереноса <> Неопределено И ДатаПереноса <> СтрокаТаблицы.Дата Тогда
СтрокаТаблицы.ДатаПереноса = ДатаПереноса;
КонецЕсли;
КонецЦикла;
Справочники.ГрафикРаботы.ЗаписатьДанныеПроизводственногоКалендаря(
ТекущийОбъект.Ссылка, НомерГода, ДанныеПроизводственногоКалендаря
);
КонецПроцедуры
&НаСервере
Процедура ОбработатьИзменениеГода(ЗаписыватьДанныеГрафика)
Если Не ЗаписыватьДанныеГрафика Тогда
ЗаполнитьДаннымиТекущегоГода();
Возврат;
КонецЕсли;
Если Объект.Ссылка.Пустая() Тогда
Записать(Новый Структура("НомерГода", НомерТекущегоГода));
Иначе
ЗаписатьДанныеПроизводственногоКалендаряНаСервере(НомерТекущегоГода, РеквизитФормыВЗначение("Объект"));
КонецЕсли;
ЗаполнитьДаннымиТекущегоГода();
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункцииКлиентСервер
&НаКлиентеНаСервереБезКонтекста
Функция ПредставлениеПереноса(ДатаИсточник, ДатаПриемник)
Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'с %1 %2 на %3 %4'"),
ДеньНеделиВФормулировкеСКакогоПереносим(ДатаИсточник),
Формат(ДатаИсточник, "ДФ='д ММММ'"),
ДеньНеделиВФормулировкеНаКакойПереносим(ДатаПриемник),
Формат(ДатаПриемник, "ДФ='д ММММ'")
);
КонецФункции
&НаКлиентеНаСервереБезКонтекста
Функция ДеньНеделиВФормулировкеСКакогоПереносим(Дата)
Соответствие = Новый Соответствие;
Соответствие.Вставить(1, НСтр("ru = 'понедельника'"));
Соответствие.Вставить(2, НСтр("ru = 'вторника'"));
Соответствие.Вставить(3, НСтр("ru = 'среды'"));
Соответствие.Вставить(4, НСтр("ru = 'четверга'"));
Соответствие.Вставить(5, НСтр("ru = 'пятницы'"));
Соответствие.Вставить(6, НСтр("ru = 'субботы'"));
Соответствие.Вставить(7, НСтр("ru = 'воскресенья'"));
Представление = Соответствие[ДеньНедели(Дата)];
Если Представление = Неопределено Тогда
Возврат Формат(Дата, "ДФ='дддд'");
КонецЕсли;
Возврат Представление;
КонецФункции
&НаКлиентеНаСервереБезКонтекста
Функция ДеньНеделиВФормулировкеНаКакойПереносим(Дата)
Соответствие = Новый Соответствие;
Соответствие.Вставить(1, НСтр("ru = 'понедельник'"));
Соответствие.Вставить(2, НСтр("ru = 'вторник'"));
Соответствие.Вставить(3, НСтр("ru = 'среду'"));
Соответствие.Вставить(4, НСтр("ru = 'четверг'"));
Соответствие.Вставить(5, НСтр("ru = 'пятницу'"));
Соответствие.Вставить(6, НСтр("ru = 'субботу'"));
Соответствие.Вставить(7, НСтр("ru = 'воскресенье'"));
Представление = Соответствие[ДеньНедели(Дата)];
Если Представление = Неопределено Тогда
Возврат Формат(Дата, "ДФ='дддд'");
КонецЕсли;
Возврат Представление;
КонецФункции
&НаКлиентеНаСервереБезКонтекста
Функция ПредставлениеВремениСуток(Знач ВремяСуток, ДвенадцатиЧасовойФорматВремени)
Если Не ЗначениеЗаполнено(ВремяСуток) Тогда
ВремяСуток = Дата(1980, 1, 1);
КонецЕсли;
ФорматВремени = ?(ДвенадцатиЧасовойФорматВремени, НСтр("ru = 'ДФ=''чч:мм вв'''"), НСтр("ru = 'ДФ=ЧЧ:мм; ДП='"));
Возврат Формат(ВремяСуток, ФорматВремени);
КонецФункции
#КонецОбласти
```