Как реализовать автоматическое заполнение табличной части документа по дням месяца

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С часто возникает задача создания документов для ежемесячного учета показателей. Типичный пример — когда пользователь должен внести данные за каждый день месяца в одну таблицу. Чтобы упростить работу и избежать ошибок ручного ввода, логично заранее подготовить структуру табличной части, чтобы в ней уже содержалось нужное количество строк (от 28 до 31), соответствующих календарным дням.

В этой статье мы подробно разберем, как реализовать механизм автоматического формирования строк табличной части, как обеспечить контроль целостности данных и настроить пользовательский интерфейс для удобной работы.

Постановка задачи и выбор подхода

Рассмотрим ситуацию: нам необходимо, чтобы при создании нового документа или при выборе месяца в табличной части автоматически появлялись строки, пронумерованные от 1 до последнего числа месяца. Пользователю запрещается добавлять новые строки или удалять существующие, он может только редактировать значения в колонках данных.

Для решения этой задачи мы проанализируем следующие этапы:

  1. Программное определение количества дней в выбранном месяце.
  2. Алгоритм заполнения табличной части при создании документа.
  3. Обработка изменения даты документа для актуализации состава строк.
  4. Настройка прав и визуального оформления таблицы (блокировка сортировки и удаления).

Алгоритм расчета количества дней и заполнение таблицы

Для начала выясним, как правильно определить количество дней. Использование жесткой привязки к 31 строке является ошибкой, так как в феврале может быть 28 или 29 дней, а в ряде других месяцев — 30. Проанализируем наиболее эффективный способ с использованием встроенной функции КонецМесяца().

Рассмотрим пример кода, который можно разместить в модуле формы документа. Мы создадим процедуру, которая очищает текущую таблицу и заполняет её заново на основании даты документа:


&НаСервере
Процедура ЗаполнитьТаблицуПоДнямНаСервере()
    
    // Очищаем существующие строки, чтобы избежать дублирования
    Объект.ДанныеПоДням.Очистить();
    
    // Определяем дату начала месяца
    ДатаНачала = НачалоМесяца(Объект.Дата);
    
    // Получаем количество дней в текущем месяце
    ПоследнийДеньМесяца = День(КонецМесяца(Объект.Дата));
    
    // Циклом добавляем строки в табличную часть
    Для НомерДня = 1 По ПоследнийДеньМесяца Цикл
        НоваяСтрока = Объект.ДанныеПоДням.Добавить();
        НоваяСтрока.НомерДня = НомерДня;
        
        // Рекомендуется также хранить полную дату для удобства отчетов
        НоваяСтрока.ДатаДня = ДатаНачала + (НомерДня - 1) * 86400; // 86400 секунд в сутках
    КонецЦикла;
    
КонецПроцедуры

В данном примере мы используем переменную Объект.Дата. Важно понимать, что если дата документа не заполнена, функция НачалоМесяца() может вернуть пустую дату, что приведет к ошибке. Поэтому перед выполнением кода следует добавить проверку на заполнение даты.

Обработка события создания и изменения даты

Чтобы пользователь видел готовую таблицу сразу, разберем, в каких обработчиках событий лучше вызывать процедуру заполнения.

1. При создании на сервере: если это новый документ, мы можем заполнить его данными по умолчанию. Однако, если документ открывается для редактирования, повторно заполнять таблицу нельзя, иначе введенные пользователем данные будут стерты.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Объект.Ссылка.Пустая() И ЗначениеЗаполнено(Объект.Дата) Тогда
        ЗаполнитьТаблицуПоДнямНаСервере();
    КонецЕсли;
КонецПроцедуры

2. При изменении даты: если пользователь решил сменить месяц уже после создания документа, состав строк должен обновиться. Рассмотрим, как реализовать предупреждение, чтобы пользователь случайно не удалил уже введенные данные.


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

&НаКлиенте
Процедура ЗаполнитьПослеПредупреждения(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        ЗаполнитьТаблицуПоДнямНаСервере();
    КонецЕсли;
КонецПроцедуры

Настройка пользовательского интерфейса (UX)

Чтобы таблица выглядела как статичный бланк, необходимо ограничить стандартные возможности платформы по манипуляции строками. Выясним, какие свойства элементов формы нам помогут в этом.

Проанализируем настройки свойств элемента формы типа Таблица:

Для колонки НомерДня или ДатаДня следует установить свойство ТолькоПросмотр. Пользователь должен вносить данные только в колонки показателей (например, Количество, Сумма и т.д.).

Использование условного оформления для выделения выходных

Работа с ежедневными данными станет гораздо удобнее, если мы визуально выделим выходные дни (субботу и воскресенье). Рассмотрим, как это сделать программно через УсловноеОформление формы.


Процедура НастроитьОформлениеВыходных()
    ЭлементОформления = УсловноеОформление.Элементы.Добавить();
    
    // Выбираем поля, которые будем раскрашивать
    ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
    ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ДанныеПоДням");
    
    // Задаем условие: день недели даты больше 5 (6 - суббота, 7 - воскресенье)
    ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ДанныеПоДням.ДатаДня");
    ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Заполнено;
    
    // Для выделения именно выходных можно использовать функционал Производственного календаря
    // Или простую проверку ДЕНЬНЕДЕЛИ(ДатаДня) > 5 в языке выражений СКД
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.СветлоРозовый);
КонецПроцедуры

Контроль уникальности и полноты данных

При записи документа важно убедиться, что логика не нарушена. Проанализируем ситуацию: если программист забыл отключить удаление строк, пользователь мог случайно стереть "15-е число". Чтобы этого избежать, добавим проверку в модуль объекта.


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    КоличествоДней = День(КонецМесяца(Дата));
    Если ДанныеПоДням.Количество() <> КоличествоДней Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Количество строк не соответствует количеству дней в месяце!");
        // В зависимости от логики можно либо Отказ = Истина, либо дозаполнить строки
    КонецЕсли;
    
КонецПроцедуры

Резюме

Мы рассмотрели комплексный подход к созданию "календарной" табличной части. Основные выводы:

  1. Всегда используйте функцию КонецМесяца() для динамического определения длины таблицы.
  2. Блокируйте интерактивное изменение состава строк, чтобы сохранить структуру "день = строка".
  3. Используйте скрытые колонки с типом Дата для хранения точных значений дат, даже если пользователю показываете только номер дня — это значительно упростит построение отчетов и проведение документа в будущем.
  4. Для профессионального решения добавляйте визуальные подсказки (выделение выходных и праздников), используя данные из РегистраСведений.ПроизводственныйКалендарь.

Такой подход делает интерфейс системы предсказуемым для пользователя и минимизирует вероятность ошибок при вводе периодических данных.

← На главную