В практике разработки на платформе 1С часто возникает задача создания документов для ежемесячного учета показателей. Типичный пример — когда пользователь должен внести данные за каждый день месяца в одну таблицу. Чтобы упростить работу и избежать ошибок ручного ввода, логично заранее подготовить структуру табличной части, чтобы в ней уже содержалось нужное количество строк (от 28 до 31), соответствующих календарным дням.
В этой статье мы подробно разберем, как реализовать механизм автоматического формирования строк табличной части, как обеспечить контроль целостности данных и настроить пользовательский интерфейс для удобной работы.
Рассмотрим ситуацию: нам необходимо, чтобы при создании нового документа или при выборе месяца в табличной части автоматически появлялись строки, пронумерованные от 1 до последнего числа месяца. Пользователю запрещается добавлять новые строки или удалять существующие, он может только редактировать значения в колонках данных.
Для решения этой задачи мы проанализируем следующие этапы:
Для начала выясним, как правильно определить количество дней. Использование жесткой привязки к 31 строке является ошибкой, так как в феврале может быть 28 или 29 дней, а в ряде других месяцев — 30. Проанализируем наиболее эффективный способ с использованием встроенной функции КонецМесяца().
Рассмотрим пример кода, который можно разместить в модуле формы документа. Мы создадим процедуру, которая очищает текущую таблицу и заполняет её заново на основании даты документа:
&НаСервере
Процедура ЗаполнитьТаблицуПоДнямНаСервере()
// Очищаем существующие строки, чтобы избежать дублирования
Объект.ДанныеПоДням.Очистить();
// Определяем дату начала месяца
ДатаНачала = НачалоМесяца(Объект.Дата);
// Получаем количество дней в текущем месяце
ПоследнийДеньМесяца = День(КонецМесяца(Объект.Дата));
// Циклом добавляем строки в табличную часть
Для НомерДня = 1 По ПоследнийДеньМесяца Цикл
НоваяСтрока = Объект.ДанныеПоДням.Добавить();
НоваяСтрока.НомерДня = НомерДня;
// Рекомендуется также хранить полную дату для удобства отчетов
НоваяСтрока.ДатаДня = ДатаНачала + (НомерДня - 1) * 86400; // 86400 секунд в сутках
КонецЦикла;
КонецПроцедуры
В данном примере мы используем переменную Объект.Дата. Важно понимать, что если дата документа не заполнена, функция НачалоМесяца() может вернуть пустую дату, что приведет к ошибке. Поэтому перед выполнением кода следует добавить проверку на заполнение даты.
Чтобы пользователь видел готовую таблицу сразу, разберем, в каких обработчиках событий лучше вызывать процедуру заполнения.
1. При создании на сервере: если это новый документ, мы можем заполнить его данными по умолчанию. Однако, если документ открывается для редактирования, повторно заполнять таблицу нельзя, иначе введенные пользователем данные будут стерты.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Ссылка.Пустая() И ЗначениеЗаполнено(Объект.Дата) Тогда
ЗаполнитьТаблицуПоДнямНаСервере();
КонецЕсли;
КонецПроцедуры
2. При изменении даты: если пользователь решил сменить месяц уже после создания документа, состав строк должен обновиться. Рассмотрим, как реализовать предупреждение, чтобы пользователь случайно не удалил уже введенные данные.
&НаКлиенте
Процедура ДатаПриИзменении(Элемент)
ТекстВопроса = "При изменении даты табличная часть будет перезаполнена. Продолжить?";
ОписаниеОповещения = Новый ОписаниеОповещения("ЗаполнитьПослеПредупреждения", ЭтотОбъект);
ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьПослеПредупреждения(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
ЗаполнитьТаблицуПоДнямНаСервере();
КонецЕсли;
КонецПроцедуры
Чтобы таблица выглядела как статичный бланк, необходимо ограничить стандартные возможности платформы по манипуляции строками. Выясним, какие свойства элементов формы нам помогут в этом.
Проанализируем настройки свойств элемента формы типа Таблица:
Ложь. Это уберет кнопки "Добавить", "Удалить" и "Скопировать", а также отключит горячие клавиши (Ins, Del).Ложь, чтобы пользователь не мог менять порядок дней.Ложь. Это критически важно, так как логика документа завязана на номере строки как на номере дня.Для колонки НомерДня или ДатаДня следует установить свойство ТолькоПросмотр. Пользователь должен вносить данные только в колонки показателей (например, Количество, Сумма и т.д.).
Работа с ежедневными данными станет гораздо удобнее, если мы визуально выделим выходные дни (субботу и воскресенье). Рассмотрим, как это сделать программно через УсловноеОформление формы.
Процедура НастроитьОформлениеВыходных()
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// Выбираем поля, которые будем раскрашивать
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ДанныеПоДням");
// Задаем условие: день недели даты больше 5 (6 - суббота, 7 - воскресенье)
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ДанныеПоДням.ДатаДня");
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Заполнено;
// Для выделения именно выходных можно использовать функционал Производственного календаря
// Или простую проверку ДЕНЬНЕДЕЛИ(ДатаДня) > 5 в языке выражений СКД
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.СветлоРозовый);
КонецПроцедуры
При записи документа важно убедиться, что логика не нарушена. Проанализируем ситуацию: если программист забыл отключить удаление строк, пользователь мог случайно стереть "15-е число". Чтобы этого избежать, добавим проверку в модуль объекта.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
КоличествоДней = День(КонецМесяца(Дата));
Если ДанныеПоДням.Количество() <> КоличествоДней Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Количество строк не соответствует количеству дней в месяце!");
// В зависимости от логики можно либо Отказ = Истина, либо дозаполнить строки
КонецЕсли;
КонецПроцедуры
Мы рассмотрели комплексный подход к созданию "календарной" табличной части. Основные выводы:
КонецМесяца() для динамического определения длины таблицы.Дата для хранения точных значений дат, даже если пользователю показываете только номер дня — это значительно упростит построение отчетов и проведение документа в будущем.РегистраСведений.ПроизводственныйКалендарь.Такой подход делает интерфейс системы предсказуемым для пользователя и минимизирует вероятность ошибок при вводе периодических данных.