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


### Основная причина, почему не меняется год

Год сбрасывается обратно при каждом изменении реквизита **`НомерТекущегоГода`** из-за логического тупика в процедуре `НастроитьПолеКалендаря()`:

1. При изменении поля на форме выставляется новое значение `НомерТекущегоГода` (например, `2027`).
2. Вызывается цепочка: `НомерТекущегоГодаПриИзменении()` $\rightarrow$ `ОбработатьИзменениеГода()` $\rightarrow$ `ЗаполнитьДаннымиТекущегоГода()` $\rightarrow$ **`НастроитьПолеКалендаря()`**.
3. В `НастроитьПолеКалендаря()` первой же строкой выполняется:
```bsl
Если ЗначениеЗаполнено(Объект.Год) Тогда
    НомерТекущегоГода = Объект.Год; // Объект.Год всё еще хранит старый год (2026)!
КонецЕсли;

```


4. Поскольку значение реквизита `Объект.Год` еще не обновлялось, эта строка **мгновенно перезаписывает** значение `НомерТекущегоГода` обратно на старый год.

---

### Логические и функциональные ошибки в коде

#### 1. Затирание прочитанных данных при смене года

В `НомерТекущегоГодаПриИзменении`:

```bsl
ОбработатьИзменениеГода(ЗаписыватьДанныеГрафика); 

Если ЗначениеЗаполнено(Объект.ПроизводственныйКалендарь) Тогда
    ЗаполнитьДаннымиПоУмолчанию(); // Ошибка!
КонецЕсли;

```

* **Проблема:** `ОбработатьИзменениеГода()` считывает реальные данные за выбранный год из регистра и календаря. Сразу после этого вызов `ЗаполнитьДаннымиПоУмолчанию()` полностью стирает эти данные и перезаписывает их базовыми настройками по умолчанию.

#### 2. Ошибка расчёта времени при пустом `ВремяОкончания`

В `ПредставлениеРасписанияДня`:

```bsl
ИначеЕсли Не ЗначениеЗаполнено(СтрокаРасписания.ВремяОкончания) Тогда
    СекундИнтервала = КонецДня(СтрокаРасписания.ВремяОкончания) - СтрокаРасписания.ВремяНачала + 1;

```

* **Проблема:** Если `ВремяОкончания` не заполнено (пустая дата `'0001-01-01 00:00:00'`), функция `КонецДня(СтрокаРасписания.ВремяОкончания)` вернет `'0001-01-01 23:59:59'`. Если у `ВремяНачала` дата отличается, разность в секундах посчитается некорректно или уйдет в минус. Брать конец дня нужно от `ВремяНачала`: `КонецДня(СтрокаРасписания.ВремяНачала)`.

#### 3. Попытка записи в БД незаписанного объекта

В `ОбработатьИзменениеГода`:

```bsl
ЗаписатьДанныеПроизводственногоКалендаряНаСервере(НомерТекущегоГода, РеквизитФормыВЗначение("Объект"));

```

* **Проблема:** Если новый справочник еще ни разу не сохранялся в базе, то у `РеквизитФормыВЗначение("Объект").Ссылка` будет значение `Справочник.ГрафикРаботы.ПустаяСсылка`. Запись в подчиненные регистры/таблицы с пустой ссылкой приведет к ошибке или "битым" записям.

#### 4. Неактуальное чтение при переносах дней

В `ВписатьДатуПереноса`:

```bsl
ИсточникДняДатыНазначения = ПереносыДней.Получить(ДатаНазначения);

```

* **Проблема:** В процедуре используется глобальное `ПереносыДней` (`ФиксированноеСоответствие`), а не локально формируемое `ПереносыДнейСоответствие`. Из-за этого повторные/цепочечные переносы дат считывают старое состояние до фиксации изменений.

#### 5. Отсутствие флага `Модифицированность`

В процедурах `ИзменитьВидыДней()` и `ПеренестиВидДня()` пользователь изменяет состав дней и переносов на форме, но не устанавливается `Модифицированность = Истина;`. В результате платформа не считает форму измененной и не предложит сохранить данные при закрытии.

#### 6. Дублирование кода

Функция `ПолучитьРасписаниеРаботыДня(НомерДня)` полностью дублирует функцию `РасписаниеРаботы(НомерДня)`.

#### 7. Отключенные обработчики событий

В `РабочиеДниДеньВключенВГрафикПриИзменении` и `УчитыватьПраздничныеДниПриИзменении` закомментированы вызовы `ЗаполнитьПоШаблонуНаСервере()`. Из-за этого при переключении флажков интерфейс формы не обновляет расчет дней.

---

### Исправленные ключевые блоки кода

#### Исправление логики года (`НастроитьПолеКалендаря` и `ОбработатьИзменениеГода`)

```bsl
&НаСервере
Процедура НастроитьПолеКалендаря()
	
	Если НомерТекущегоГода = 0 Тогда
		НомерТекущегоГода = ?(ЗначениеЗаполнено(Объект.Год), Объект.Год, Год(ТекущаяДатаСеанса()));
	КонецЕсли;
	
	Объект.Год = НомерТекущегоГода;
	НомерПредыдущегоГода = НомерТекущегоГода;
	
	Элементы.Календарь.НачалоПериодаОтображения	= Дата(НомерТекущегоГода, 1, 1);
	Элементы.Календарь.КонецПериодаОтображения	= Дата(НомерТекущегоГода, 12, 31);
	
	Объект.ДатаНачала = Дата(НомерТекущегоГода, 1, 1);
	Объект.ДатаОкончания = Дата(НомерТекущегоГода, 12, 31);
	
КонецПроцедуры

&НаКлиенте
Процедура НомерТекущегоГодаПриИзменении(Элемент)
	
	ЗаписыватьДанныеГрафика = Ложь; 
	Если Модифицированность Тогда
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Записать измененные данные за %1 год?'"), 
			Формат(НомерПредыдущегоГода, "ЧГ=0")
		);
		Оповещение = Новый ОписаниеОповещения("НомерТекущегоГодаПриИзмененииЗавершение", ЭтотОбъект);
		ПоказатьВопрос(Оповещение, ТекстСообщения, РежимДиалогаВопрос.ДаНет);
		Возврат;
	КонецЕсли;
	
	ОбработатьИзменениеГода(ЗаписыватьДанныеГрафика); 
	
	Модифицированность = Ложь;
	Элементы.Календарь.Обновить(); 
	
КонецПроцедуры  

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

```

#### Исправление функции расчета представления расписания

```bsl
&НаКлиенте
Функция ПредставлениеРасписанияДня(НомерДня)	
	ПредставлениеИнтервалов = "";
	Секунд = 0;
	Для Каждого СтрокаРасписания Из Объект.РасписаниеРаботы Цикл
		Если СтрокаРасписания.НомерДня <> НомерДня Тогда
			Продолжить;
		КонецЕсли;
		
		ПредставлениеИнтервала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			"%1-%2, ", 
			ПредставлениеВремениСуток(СтрокаРасписания.ВремяНачала, ДвенадцатиЧасовойФорматВремени), 
			ПредставлениеВремениСуток(СтрокаРасписания.ВремяОкончания, ДвенадцатиЧасовойФорматВремени)
		);
		ПредставлениеИнтервалов = ПредставлениеИнтервалов + ПредставлениеИнтервала;
		
		Если СтрокаРасписания.ВремяНачала = СтрокаРасписания.ВремяОкончания И ЗначениеЗаполнено(СтрокаРасписания.ВремяНачала) Тогда
			СекундИнтервала = 86400;
		ИначеЕсли СтрокаРасписания.ВремяНачала < СтрокаРасписания.ВремяОкончания Тогда
			СекундИнтервала = СтрокаРасписания.ВремяОкончания - СтрокаРасписания.ВремяНачала;
		ИначеЕсли Не ЗначениеЗаполнено(СтрокаРасписания.ВремяОкончания) Тогда
			// Исправлено: КонецДня берется от ВремяНачала
			СекундИнтервала = КонецДня(СтрокаРасписания.ВремяНачала) - СтрокаРасписания.ВремяНачала + 1;
		Иначе
			ОсновнаяЧасть = КонецДня(СтрокаРасписания.ВремяНачала) - СтрокаРасписания.ВремяНачала + 1;
			ПереходящаяЧасть = СтрокаРасписания.ВремяОкончания - НачалоДня(СтрокаРасписания.ВремяОкончания);
			СекундИнтервала = ОсновнаяЧасть + ПереходящаяЧасть;
		КонецЕсли;
		Секунд = Секунд + СекундИнтервала;
	КонецЦикла;
	
	СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(ПредставлениеИнтервалов, 2);
	
	Если Секунд = 0 Тогда
		Возврат НСтр("ru = 'Заполнить расписание'");
	КонецЕсли;
	
	Часов = Окр(Секунд / 3600, 1);
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 ч. (%2)'"), Часов, ПредставлениеИнтервалов);
	
КонецФункции

```