Механизм периодических сведений не включен в БСП, но тем не менее используется в большинстве типовых решений 1С, прежде всего в ЗУП, и реже - в остальных (УТ, КА и т.д.). Он может быть полезен при добавлении своих "периодических" реквизитов в конфигурацию. В его состав входит всего четыре модуля:
- РедактированиеПериодическихСведений
- РедактированиеПериодическихСведенийВызовСервера
- РедактированиеПериодическихСведенийКлиент
- РедактированиеПериодическихСведенийКлиентСервер
На небольшом примере покажем, как добавить "периодический" реквизит в типовую конфигурацию. Предположим, мы ведем учет автомобилей в справочнике "Автомобили" и у этого справочника есть реквизит "Пробег", в котором фиксируется история пробега.
Начнем с регистра. Регистр будет иметь наименование ПробегАвтомобилей (оно произвольное). У регистра одно измерение Автомобиль с типом СправочникСсылка.Автомобили, ведущее. И ресурс Пробег, тип - числовой. Естественно, регистр периодический.
Далее, к регистру добавляем форму набора записей с наименованием РедактированиеИстории. Наименование должно быть именно таким, так как именно такая форма нужна типовому коду. У реквизита НаборЗаписей снимаем признак Основной реквизит, это нужно для работы отбора и добавляем следующий реквизит:
- ОбъектВладелец с типом СправочникСсылка.Автомобили
На форму этот реквизит выносить не нужно, он используется в работе механизма для отбора.
Примерный вид формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Параметры.Свойство("ВедущийОбъект", ОбъектВладелец);
Если Не ЗначениеЗаполнено(ОбъектВладелец) Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Для Каждого ЗаписьНабора Из Параметры.МассивЗаписей Цикл
ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), ЗаписьНабора);
КонецЦикла;
НаборЗаписей.Сортировать("Период");
КонецПроцедуры
&НаКлиенте
Процедура КомандаОК(Команда)
РедактированиеПериодическихСведенийКлиент.ОповеститьОЗавершении(ЭтаФорма, "ПробегАвтомобилей", ОбъектВладелец);
КонецПроцедуры
&НаКлиенте
Процедура КомандаОтмена(Команда)
Закрыть();
КонецПроцедуры
&НаКлиенте
Процедура НаборЗаписейПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
Если Не НоваяСтрока Тогда
Возврат;
КонецЕсли;
Если Элемент.ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Элемент.ТекущиеДанные.Автомобиль = ОбъектВладелец;
НовыйПериод = НачалоМесяца(ОбщегоНазначенияКлиент.ДатаСеанса());
Если НаборЗаписей.Количество() > 1 Тогда
ПоследнийПериод = НаборЗаписей.Получить(НаборЗаписей.Количество() - 2).Период;
Иначе
ПоследнийПериод = '00010101000000';
КонецЕсли;
Если НовыйПериод <= ПоследнийПериод Тогда
НовыйПериод = КонецМесяца(ПоследнийПериод) + 1;
КонецЕсли;
Элемент.ТекущиеДанные.Период = НовыйПериод;
КонецПроцедуры
&НаКлиенте
Процедура НаборЗаписейПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
Если ОтменаРедактирования Тогда
Возврат;
КонецЕсли;
Если Элемент.ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(Элемент.ТекущиеДанные.Период) Тогда
СообщениеОбОшибке = НСтр("ru = 'Необходимо указать дату сведений'");
ОбщегоНазначенияКлиент.СообщитьПользователю(СообщениеОбОшибке, , "НаборЗаписей.Период", , Отказ);
Иначе
НайденныеСтроки = НаборЗаписей.НайтиСтроки(Новый Структура("Период", Элемент.ТекущиеДанные.Период));
Для Каждого НайденнаяСтрока Из НайденныеСтроки Цикл
Если НайденнаяСтрока <> Элемент.ТекущиеДанные Тогда
СообщениеОбОшибке = НСтр("ru = 'Уже есть запись с указанной датой сведений'");
ОбщегоНазначенияКлиент.СообщитьПользователю(СообщениеОбОшибке, , "НаборЗаписей.Период", , Отказ);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура НаборЗаписейПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)
Если ОтменаРедактирования Тогда
Возврат;
КонецЕсли;
РедактированиеПериодическихСведенийКлиент.УпорядочитьНаборЗаписейВФорме(ЭтаФорма);
КонецПроцедуры
Код несложный, оставлю только несколько пояснений:
- ПриСозданииНаСервере, заполняем набор записей из переданных в форму при создании параметров, там уже будет отбор по владельцу, т.е. будут сведения о пробеге только целевого автомобиля.
- НаборЗаписейПриНачалеРедактирования, заполняем владельца записи набора регистра, т.е. автомобиль, заполняем период по-умолчанию.
- НаборЗаписейПередОкончаниемРедактирования, предупреждаем пользователя, если он некорректно заполнил новую запись.
- НаборЗаписейПриОкончанииРедактирования, упорядочеваем записи по дате при окончании редактирования.
- КомандаОК, вызываем типовое оповещение о закрытии.
К слову сказать, форма совершенно шаблонная и, например, в ЗУП-е таких, почти одинаковых форм, 30 (тридцать). Т.е. если в других ЯП используется наследование, у нас используется копи-паст.
Перейдем к адаптации справочника-владельца "периодического" реквизита. Форме элемента справочника Автомобили добавляем пять реквизитов:
- ПробегАвтомобилей с типом РегистрСведенийМенеджерЗаписи.ПробегАвтомобилей
- ПробегАвтомобилейНаборЗаписей с типом РегистрСведенийНаборЗаписей.ПробегАвтомобилей
- ПробегАвтомобилейНаборЗаписейПрочитан с типом булево
- ПробегАвтомобилейНоваяЗапись с типом булево
- ПробегАвтомобилейПрежняя с типом Произвольный
Обратите внимание, все добавленные реквизиты имеют префикс ПробегАвтомобилей, он должен совпадать с наименованием регистра сведений, в котором хранится история "периодического" реквизита.
Больше всего здесь нас интересует реквизит ПробегАвтомобилей, именно он несет в себе полезную нагрузку. Выводим реквизит ПробегАвтомобилей.Пробег на форму, остальные реквизиты - служебные, они используются в работе механизма и на форме не отображаются.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
РедактированиеПериодическихСведений.ПрочитатьЗаписьДляРедактированияВФорме(ЭтаФорма, "ПробегАвтомобилей", Объект.Ссылка);
РедактированиеПериодическихСведенийКлиентСервер.ОбновитьНаборЗаписейИстории(ЭтаФорма, "ПробегАвтомобилей", Объект.Ссылка);
КонецПроцедуры
&НаКлиенте
Процедура ПробегИстория(Команда)
РедактированиеПериодическихСведенийКлиент.ОткрытьИсторию("ПробегАвтомобилей", Объект.Ссылка, ЭтотОбъект, Истина);
КонецПроцедуры
&НаСервере
Процедура ПрочитатьНаборЗаписейПериодическихСведений(ИмяРегистра, ВедущийОбъект) Экспорт
РедактированиеПериодическихСведений.ПрочитатьНаборЗаписей(ЭтотОбъект, ИмяРегистра, ВедущийОбъект);
КонецПроцедуры
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ОтредактированаИстория" И Источник = Объект.Ссылка Тогда
РедактированиеПериодическихСведенийКлиент.ОбработкаОповещения(
ЭтотОбъект,
Объект.Ссылка,
ИмяСобытия,
Параметр,
Источник);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
РедактированиеПериодическихСведений.ЗаписатьЗаписьПослеРедактированияВФорме(ЭтотОбъект, "ПробегАвтомобилей", Объект.Ссылка);
КонецПроцедуры
Небольшие пояснения:
- ПриСозданииНаСервере, читаем историю реквизита из регистра
- ОбработкаОповещения, обновляем реквизит на форме
- ПередЗаписьюНаСервере, записываем данные в регистр
- ПробегИстория, открытие формы истории реквизита
В результате, получаем долгожданный "периодический" реквизит:
По задумке разработчиков, в 8-й версии в форме элемента всегда редактируется последняя запись. В 7-й версии при редактировании значения периодического реквизита, новое значение добавлялось в историю автоматически с текущей датой. Чтобы воспроизвести такое поведение, можно поступить примерно так:
&НаКлиенте
Процедура ПробегАвтомобилейПробегПриИзменении(Элемент)
ПробегАвтомобилейПриИзмененииНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПробегАвтомобилейПриИзмененииНаСервере()
Если ПробегАвтомобилейПрежняя.Пробег <> ПробегАвтомобилей.Пробег Тогда
ПробегАвтомобилей.Период = ТекущаяДатаСеанса();
НоваяЗапись = ПробегАвтомобилейНаборЗаписей.Добавить();
ЗаполнитьЗначенияСвойств(НоваяЗапись, ПробегАвтомобилей);
ПробегАвтомобилейНоваяЗапись = Истина;
КонецЕсли;
КонецПроцедуры
Т.е., если значение поменялось, добавляем новую запись с текущей датой и выставляем признак новой записи в истину.
Спасибо, что дочитали до конца, если вы работали в семерке, уверен, на вашем лице улыбка.