Загрузка данных


Для идеального выполнения этой задачи мне необходимо детально разобрать исходный код, сверить его с правилами стандартов разработки 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 = 'ДФ=ЧЧ:мм; ДП='"));
	Возврат Формат(ВремяСуток, ФорматВремени);
	
КонецФункции

#КонецОбласти

```