МОДУЛЬ ФОРМЫ СПИСКА ЖУРНАЛА КАДРОВЫХ ПРИКАЗОВ
Разместим в нем предопределенную процедуру ПриОткрытии, в которой, во-первых, определим стандартный список действий для кнопки Действия диалога формы и, во-вторых, установим интервал журнала, характеризуемый двумя датами: начала интервала и конца интервала.
Список действий разместим в переменной сДейст типа СписокЗначений, а с кнопкой Действия диалога формы списка свяжем на закладке Дополнительно в поле формула вызов процедуры глобального модуля глДействия(ТекущийДокумент, сДейст).
Начало интервала положим равным дате первого документа ПриказОПриеме, а конец - текущей дате. Если документов ПриказОПриеме в журнале кадровых приказов нет, то дату начала интервала определим по первому приказу об изменении окладов. Если нет и таковых, то дату начала установим равной текущей дате.
перем сДейст; // Список действий по документу
// Формирует список действий и устанавливает интервал журнала, отображающий // все введенные документы видов ПриказОПриеме и ИзменениеОклада процедура ПриОткрытии()
перем дНач; // Дата начала интервала журнала кадровых приказов
перем флаг, док;
// Определяем список действий для кнопки Действия сДейст.ДобавитьЗначение("Структура подчиненности"); сДейст.ДобавитьЗначение("Ввести на основании"); сДейст.ДобавитьЗначение("Движения документа");
флаг = 1; // Равен единице, если удалось создать док
попытка
док = СоздатьОбъект("Документ.ПриказОПриеме");
исключение
попытка
док = СоздатьОбъект("Документ.ИзменениеОклада"); исключение флаг = 0; конецПопытки; конецПопытки;
// Если создан либо документ ПриказОПриеме, либо документ ИзменениеОклада если флаг = 1 тогда
// Находим документ с наименьшей датой. По умолчанию документы располагаются // в выборке по возрастанию их дат док. ВыбратьДокументы (); если док.ПолучитьДокумент() = 1 тогда дНач = док.ДатаДок; иначе
дНач = ТекущаяДата(); конецЕсли;
иначе // Искомых документов нет
дНач = ТекущаяДата(); конецЕсли;
УстановитьИнтервал(дНач, ТекущаяДата()); конецПроцедуры // ПриОткрытии
// В основной программе модуля всего один оператор сДейст = СоздатьОбъект("СписокЗначений");
5.8.4. ПРИКАЗ ОБ ИЗМЕНЕНИИ ОКЛАДА
5.8.4.1. ПОРЯДОК РАБОТЫ С ДОКУМЕНТОМ
Этот приказ интересен тем, что имеет табличную часть, поскольку в общем случае затрагивает группу сотрудников. Поэтому диалог формы Приказа об изменении оклада может иметь следующий вид:
Номер |НомерДок Дата [датаДок [п] Дата вступлетия в силу |ДзтаНоеОкл|?|
Подбор
Сотрудник
Прежний оклад
O^KTHTb
Удалить
Эм РЫТЬ
Рис. 5.42. Диалог формы документа Приказ об изменении оклада
Заданные для документа идентификаторы реквизитов (кроме номера и даты документа), а также идентификаторы самого документа и его журнала отображены на рис. 5.43.
Журнал I ПриказыКеоровые *
Идентификатор: |И зменениеО к пааа
комментарий: (Можно выпустить для группы со Синоним |Приказ о новом окладе
Реквизиты шапки
ДатаНовОклааа
Реквизиты табличной части
ПрежнийОклаа
Новыми к лад
Рис. 5.43. Идентификаторы документа, его реквизитов и журнала
Полный перечень реквизитов создаваемого документа и имя самого документа перечислены в табл. 5.4.
Таблица 5.4
Реквизиты Приказа об изменении оклада |
Реквизит |
Тип/разновидность типа |
Длина.Точность |
ДатаДок (задан по умолчанию) |
Дата |
- |
НомерДок (задан по умолчанию) |
Числовой |
5.0 |
ДатаНовОклада |
Дата |
- |
Сотрудник |
Справочник.Сотрудники_2 |
- |
ПрежнийОклад |
Числовой |
10.2 |
НовыйОклад |
Числовой |
10.2 |
|
Замечание. Для нового и прежнего окладов заданы свойства Разделять триады и Неотрицательный. |
Порядок работы с документом таков:
1. Реквизит НомерДок сделаем, как и ранее, недоступным для редактирования.
2. Запретим редактирование и графы ПрежнийОклад.
3. При вводе нового документа имеющиеся в нем даты устанавливаются по умолчанию равными рабочей дате.
4. Кнопка Подбор открывает форму списка справочника Сотрудники_2 для множественного выбора, в результате выполнения которого добавляются данные в две первые графы таблицы; ранее перенесенные в таблицу данные сохраняются.
5. Кнопки Очистить, Удалить и ОК доступны только при наличии в табличной части хотя бы одной строки.
6. Графы Сотрудник и Прежний оклад табличной части документа заполняем после выбора сотрудника из справочника Сотрудники_2. Для этого употребим процедуру ВыборОдного, задав на закладке Дополнительные в окне свойств графы Сотрудник формулу ВыборОдного( ), и процедуру Подбор, связанную с одноименной кнопкой диалога и позволяющую делать множественный выбор данных.
7. Выбранная в справочнике Сотрудники_2 запись не может переноситься в табличную часть документа более одного раза; проверка уникальности записи в табличной части документа выполняется, если осуществляется множественный выбор, в процедуре ОбработкаПодбора или в предопределенной процедуре модуля формы документа ПриОкончанииРедактированияСтроки, если выбор выполняется из табличной части документа.
8. Проведение документа не выполняется, если действующий и новый оклады имеют одинаковые значения.
9. При редактировании проведенного документа, когда удаляется запись из его табличной части, в справочнике Сотрудники_2 удаляется соответствующая ему запись периодического реквизита Оклад. Это достигается за счет того, что значение периодического реквизита Оклад в справочнике Сотрудники_2 устанавливается с привязкой к документу.
10. При замене в табличной части проведенного документа одного сотрудника на иного удаляются проводка, связанная с заменяемым сотрудником. Это также достигается за счет того, что значение периодического реквизита Оклад устанавливается с привязкой к документу.
11. При удалении документа удаляются все выполненные им проводки.
Читатель, имеющий опыт программирования в 1С, реализует приведенный механизм управления документом без особого труда. Нам же придется приложить некоторые усилия, но не напрасные, а продвигающие к следующему уровню освоения системы.
Итак, добавим в конфигурацию документ, употребляя уже имеющиеся навыки, и приведем его форму к виду, изображенному на рис. 5.42.
Чтобы регулировать доступность кнопок Очистить, Удалить и ОК, дадим им идентификаторы, совпадающие с названиями кнопок (рис. 5.44).
 |
Рис. 5.44. Задание идентификатора кнопки Очистить |
Добавим соответствующий пункт в колонку Документы меню интерфейса Ученик, установив для команды открытия документа акселератор Alt+7. С кнопками диалога и с графой Сотрудник Приказа об изменении оклада через их свойство Формула свяжем перечисленные в табл. 5.5 процедуры и команды.
Таблица. 5.5
Процедуры и команды, связанные в элементами диалога документа |
Кнопка |
Процедура/команда |
Сотрудник |
ВыборОдного() |
Подбор |
Подбор() |
Очистить |
ОчиститьТабл() |
Удалить |
УдалитьСтрокуТабл() |
ОК |
#Записать? Провести? Закрыть |
Закрыть |
#3акрыть |
|
5.8.4.2. МОДУЛЬ ФОРМЫ ДОКУМЕНТА
Содержит следующие процедуры:
процедура ВводНового( ) // Задает начальные значения дат при вводе
ДатаДок = РабочаяДата(); // нового документа
ДатаНовОклада = РабочаяДата();
// При вводе нового документа табличная часть пуста, поэтому делаем кнопки // Очистить, Удалить и ОК недоступными форма.Очистить.Доступность(0); форма.Удалить.Доступность(0); форма.ОК.Доступность(0); конецПроцедуры // ВводНового
процедура ПриОткрытии()
Очистить0кно Сообщений();
ПриЗаписиПерепроводить(1); конецПроцедуры // ПриОткрытии
// Связана графой Сотрудник табличной части документа // Открывает подбор элемента из справочника Сотрудники_2 // После выбора заполняются поля Сотрудник и Прежний оклад // Добавление строки происходит при нажатии на клавишу клавиатуры Ins процедура ВыборОдного()
перем сСотр_2, контПодбора;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Дата для периодического реквизита Оклад справочника Сотрудники_2 сСотр_2.ИспользоватьДату(РабочаяДата());
// Сотрудник и ПрежнийОклад - реквизиты табличной части // диалога формы рассматриваемого документа если сСотр_2.НайтиЭлемент(Сотрудник) = 1 тогда ПрежнийОклад = сСотр_2.Оклад; конецЕсли;
// При добавлении хотя бы одной строки следующие кнопки делаем доступными если КоличествоСтрок() > 0 тогда форма.Очистить.Доступность(1); форма.Удалить.Доступность(1); форма.ОК.Доступность(1); конецЕсли;
конецПроцедуры // ВыборОдного
процедура ПриОкончанииРедактированияСтроки() перем старСтрока, сотр;
// Проверяет введенную запись на уникальность // Если она нарушена, введенная запись удаляется
старСтрока = НомерСтроки; // Запоминаем номер введенной строки
сотр = Сотрудник; // и значение графы Сотрудник
ВыбратьСтроки( ); пока ПолучитьСтроку() > 0 цикл
если (Сотрудник = сотр) и (НомерСтроки о старСтрока) тогда Предупреждение("Сотрудник уже выбран.");
УдалитьСтроку();
конецЕсли;
конецЦикла // пока
КОнецПроцедуры // ПриОкончанииРедактированияСтроки
// Связана с кнопкой Подбор диалога формы документа
// Открывает множественный подбор из справочника Сотрудники_2
// Каждый выбор элемента добавляет строку в табличную часть документа,
// заполняя в ней поля Сотрудник и Прежний оклад // Добавление строки осуществляется предопределенной процедурой // ОбработкаПодбора модуля формы процедура Подбора( )
перем сСотр_2, контПодбора;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Дата для периодического реквизита Оклад справочника Сотрудники_2 сСотр_2. ИспользоватьДату(РабочаяДата());
// Указываем явно имя основной формы списка для метода ОткрытьПодбор ОткрытьПодбор("Справочник.Сотрудники_2", "ФормаСписка", контПодбора); форма.Очистить.Доступность(1); форма.Удалить. Доступность(1); форма.ОК.Доступность(1); конецПроцедуры // Подбор
// Добавляет строку в табличную часть документа, определяя в ней значения // полей Сотрудник и Прежний оклад процедура ОбработкаПодбора(текЭл, конт)
// Проверяем, есть ли выбранная запись в табличной части документа ВыбратьСтроки(); пока ПолучитьСтроку() > 0 цикл если Сотрудник = текЭл тогда
Предупреждение("Сотрудник уже выбран."); возврат; конецЕсли; конецЦикла; // пока
НоваяСтрока(); // Добавляем строку в табличную часть документа
Сотрудник = текЭл;
ПрежнийОклад - конт.Оклад; // конт - контекст формы списка справочника конецПроцедуры // ОбработкаПодбора
// Удаляет все строки табличной части. Связана с кнопкой Очистить диалога формы приказа процедура ОчиститьТабл()
если КоличествоСтрок() = 0 тогда
Предупреждение("Нет строк для удаления."); возврат; конецЕсли;
если Вопрос("Очистить таблицу документа?", "Да+Нет") = "Да" тогда УдалитьСтроки();
// Поскольку в приказе нет сотрудников, следующие кнопки делаем недоступными форма.Очистить.Доступность(0); форма.Удалить.Доступность(0); форма.ОК.Доступность(0); конецЕсли;
конецПроцедуры // ОчиститьТабл
// Удаляет текущую строку табличной части документа // Связана с кнопкой Очистить диалога формы приказа процедура УдалитьСтрокуТабл()
если КоличествоСтрок() = 0 тогда
Предупреждение("Нет строк для удаления."); возврат; конецЕсли;
если Вопрос("Удалить текущую строку?", "Да+Нет") = "Да" тогда УдалитьСтроку(); если КоличествоСтрок() = 0 тогда
// Поскольку в приказе не осталось сотрудников,
// следующие кнопки делаем недоступными форма.Очистить.Доступность(0); форма.Удалить.Доступность(0); форма.ОК.Доступность(0); конецЕсли; конецЕсли;
конецПроцедуры // УдалитьСтрокуТабл
// Предопределенная процедура. Осуществляет контроль введенных данных процедура ПриЗаписи( )
если (ПустоеЗначение(ДатаНовОклада) = 1) тогда
Предупреждение("Определите дату нового оклада.");
СтатусВозврата(0); // Не записываем данные
// Перемещаемся на элемент диалога ДатаНовОклада Активизировать("ДатаНовОклада", 1); возврат; конецЕсли;
если КоличествоСтрок() = 0 тогда
Предупреждение("Список сотрудников пуст.");
СтатусВозврата(0); // Запрещаем запись документа
возврат; конецЕсли;
// Проверим, для всех ли сотрудников задан оклад // и отличается ли он от прежнего оклада ВыбратьСтроки(); пока ПолучитьСтроку() > 0 цикл если НовыйОклад = 0 тогда
Предупреждение("Сотруднику " + Сотрудник + " не установлен оклад."); СтатусВозврата(0); // Запрещаем запись документа
возврат; конецЕсли;
если НовыйОклад = ПрежнийОклад тогда
Предупреждение("Новый и прежний оклады сотрудника " + РазделительСтрок + Сотрудник +" одинаковы.");
СтатусВозврата(0); // Запрещаем запись документа
возврат; конецЕсли; конецЦикла; // пока конецПроцедуры // ПриЗаписи
Содержит предопределенную процедуру ОбработкаПроведения. Проведение или перепроведение проведенного документа выполняется каждый раз при его записи.
Процедура ОбработкаУдаленияПроведения может быть опущена, так как при удалении документа порожденные им новые оклады также будут удаляться. Это обусловлено тем, что они устанавливаются в справочнике Сотрудники_2 с привязкой к док ументу.
// Устанавливает значения периодического атрибута Оклад для всех попавших в приказ // сотрудников, а также значение реквизита справочника ПриказОклад процедура ОбработкаПроведения() перем сСотр_2;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Дата для периодического реквизита Оклад справочника Сотрудники_2 сСотр_2.ИспользоватьДату(РабочаяДата());
ВыбратьСтроки();
пока ПолучитьСтроку() > 0 цикл
если сСотр_2.НайтиЭлемент(Сотрудник) = 0 тогда
Предупреждение("Сотрудник " + Сотрудник + РазделительСтрок +
" в справочнике Сотрудники_2 не найден."); продолжить; конецЕсли;
// Устанавливаем связь документа с записью справочника Сотрудники_2 сСотр_2.ПриказОклад = ТекущийДокумент(); сСотр_2.3аписать(); // Сохраняем изменения
// Записываем периодический реквизит Оклад с привязкой к документу УстановитьРеквизитСправочника(Сотрудник, "Оклад", НовыйОклад, ДатаНовОклада); конецЦикла; // пока
// Ограничиваем время показа окна с предупреждением тремя секундами // См. также замечание 1 к процедурам ОбработкаПроведения // и ОбработкаУдаленияПроведения в разд. 5.8.2.3
если Проведен() = 0 тогда // Если документ проводится впервые
Предупреждение("Документ проведен.", 3); иначе
Предупреждение("Документ перепроведен.", 3); конецЕсли;
конецПроцедуры // ОбработкаПроведения
5.9. ОТБОР И ФИЛЬТРАЦИЯ ДАННЫХ СПРАВОЧНИКА
Применяется для вывода в форме списка справочника данных, удовлетворяющих некоторым условиям.
5.9.1. ОТБОР ПО РЕКВИЗИТУ СПРАВОЧНИКА
Позволяет, например, в справочнике Сотрудники_2 отобразить только сотрудников, имеющих, скажем, высшее образование. Эта возможность предоставляется благодаря тому, что для реквизита Образование заданы свойства Сортировка и Отбор по реквизиту (рис. 5.29, б). Причем такие свойства можно задать только для непериодического реквизита. Отбор по реквизиту, не имеющему таких свойств, невозможен.
Отбор данных по реквизиту может быть реализован либо интерактивно, либо про-. граммно. В первом случае следует использовать иконки " ° ^
панели инстру
ментов формы списка справочника. Выбор иконки
в котором задается значение (критерий) отбора и запускается или отключается отбор.
 |
Рис. 5.45. Отбор по реквизиту Образование |
Список существующих значений реквизита Образование заполняется данными из справочника Образование_2. Он же является источником данных для поля Значение отбора. Заполнив эти список и поле (или что-нибудь одно) и нажав на кнопку Установить отбор, устанавливающую отбор по заданному значению, мы вместо полного списка сотрудников получим отфильтрованный приведенный на рис. 5.46 список (выводится без существующей иерархии данных).
 |
Рис. 5.46. Сотрудники с высшим образованием
После нескольких отборов по разным значениям реквизита (или нескольких ре кви- I зитов) мы имеем возможность установить отбор по списку, выводимому при выборе j иконки ^ отображающей историю отборов (рис. 5.47). |
отображаются на панели инструментов формы списка спра
 |
Рис. 5.47. Установка отбора в списке окна История отборов |
Замечания:
1. Иконки ІІІІІІ
вочника при наличии в нем реквизитов, имеющих свойство Отоор по реквизиту.
2. История отборов запоминается со справочником и не может быть отредактирована.
5.9.1.2. ЗАДАНИЕ ОТБОРА В ПРОГРАММЕ
Открывая форму списка справочника в программе, используем для задания критерия отбора метод УстановитьОтбор, который может быть вызван только в модуле формы списка справочника, например в его предопределенной процедуре ПриОткры-тии. Также в ней можно задать и закладки отбора, например:
// Создана для формы списка справочники Сотрудники_2 // Устанавливает закладки отбора по реквизиту Образование процедура ПриОткрытии() перем обр;
обр = СоздатьО6ъекг("Справочник.О6разование_2");
// Ищем начальное образование
если обр.НайтиПоНаименованиюС'Н'', 0) = 1 тогда
// Второй параметр метода ЗакладкиОтбора должен иметь разновидность типа // Справочник.Образование_2
ЗакладкиОтбора("Образование", обр.ТекущийЭлементО); ИерархическийСписок(0, 1); // Можно менять режим отображения
иначе
Предупреждение
("В справочнике Образование_2 нет записи, начинающейся с буквы Н."); конецЕсли;
конецПроцедуры // ПриОткрытии
Диалог формы,списка справочника С6трудники_2 с закладками отбора по реквизиту Образование приведен на рис. 5.48.
<Пустое значе»*»е> | Высшее Нача/ьное | Неоконченное высшее | Среднее |
Наименование
Д Сотрудники 2
ЛППЛНМИ
Начальное
Нача/ъное
Коспча О/ьга В ладимироен;
Рис. 5.48. Закладки отбора по реквизиту Образование
Замечания:
1. Список закладок отбора по реквизиту, если справочник отображается без учета иерархии (не по группам), содержит все существующие значения реквизита (рис. 5.48), включая пустое, и редактированию не подлежит. Так, из него нельзя удалить закладку <Пустое значение> или добавить закладку Все сотрудники.
2. При выводе иерархического списка сотрудников отображаются только закладки, позволяющие отобразить непустой список. Так, если в подразделении 01/1 есть сотрудники только с высшим и средним образованием, то диалог формы списка примет приведенный на рис. 5.49 вид.
Высшее Среднее |
а _1| Сотрудники_2 а CJ 01 Цех оі /1 С] 01 /2 |
|
Щод IНаименование_I |
Оклад |
Образование |
|
|
01 Цех |
|
|
_jl |
rill |
01 /1 |
|
|
ffc~ |
112 |
Добрецое Борис Юрьевич |
2.300 00 |
Среднее |
|
Рис. 5.49. Закладки отбора для подразделения 01/1 при выводе данных с учетом иерархии |
Закладки отбора исчезнут из диалога, если метод ЗакладкиОтбора вызвать следующим образом:
ЗакладкиОтбора(""); // Убираем закладки отбора
Таким образом, чтобы отображать диалог с закладками отбора или без них, мы должны иметь возможность в модуле списка справочника вызывать метод Закладки-Отбора с аргументами, устанавливающими или убирающими закладки. Чтобы эту возможность реализовать, введем в диалог формы списка справочника Сотрудники_2 флажок Закладки отбора по образованию (рис. 5.50), дадим ему имя закл и свяжем с ним формулу (процедуру) ПоказатьЗакладки, которую, так же как и предопределенную процедуру ПриОткрытии, разместим в модуле формы списка справочника.
<Пустое значение) | Высшее Начальное | Неоконченное
1.850.001 Начальное
Васильева Елена Иваное
!09| Костина Ольга Владимир
Ы Закладки отбора по образованию
Рис. 5.50. Диалог формы списка справочника Сотрудники_2 с флажком Закладки отбора по образованию
Код процедуры ПоказатьЗакладки прост:
// Показывает/убирает закладки отбора по образованию процедура ПоказатьЗакладки( ) перем значОтбора;
если закл = 1 тогда // Показать закладки
значОтбора = ?(ЭтоГруппа() = 0, Образование, ""); ЗакладкиОтбора("Образование", значОтбора);
иначе // Убрать закладки
ЗакладкиОтбора(""); конецЕсли;
конецПроцедуры // ПоказатьЗакладки
Замечание. Вместо процедуры ПоказатьЗакладки с флажком закл можно связать формулу
?(закл = 0, ЗакладкиОтбора(""),
ЗакладкиОтбора("Образование", ?(ЭтоГруппа() = 0, Образование, "")))
разместив ее в поле Формула окна задания свойств флажка.
Код предопределенной процедуры ПриОткрытии можно дополнить следующими операторами:
закл = 1; // Добавляются в процедуру ПриОткрытии
ЗакладкиОтбора("Образование",""); конецПроцедуры // ПриОткрытии
Также напомним, что модуль формы списка справочника Сотрудники_2 содержит приведенную в разд. 5.8.2.4 предопределенную процедуру ПриНачалеРедактирования-Строки.
Помимо рассмотренного метода ЗакладкиОтбора для организации отбора могут быть также употреблены методы УстановитьОтбор, ПолучитьОтбор и ВидыОтбора. Они, так же как и метод ЗакладкиОтбора, могут появляться только в модуле формы списка справочника. Описание методов см. в разд. 5.12.5.
5.9.2. ФИЛЬТРАЦИЯ ДАННЫХ
Осуществляется методом ИспользоватьСписокЭлементов, принимающим в качестве параметра список элементов справочника, которые следует отобразить в форме его списка. Заносимые в список значения должны иметь тип Справочник. В случае пустого списка выводятся все данные справочника.
Пример. В форме списка справочника Сотрудники_2 отображаются только сотрудники, оклад которых больше или равен 2500 руб.
// Содержится в модуле формы списка справочника Сотрудники_2 процедура ПриОткрытии() перем сЗнач, сСотр_2; сЗнач = СоздатьОбъект("СписокЗначений"); сСотр_2 = СоздатьОбьект("СправочникСотрудники_2");
// Дата для периодического реквизита Оклад сСотр_2.ИспользоватьДату(РабочаяДата());
// Позиционируемся на первой записи справочника Сотрудники_2 сСотр_2.ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл если сСотр_2.0клад >= 2500 тогда
// Добавляем в список элемент справочника сЗнач.ДобавитьЗначение(сСотр_2.ТекущийЭлемент()); конецЕсли;
конецЦикла; // пока сСотр_2 = 0;
// Задаем фильтр для справочника Сотрудники_2 ИспользоватьСписокЭлементов(сЗнач); конецПроцедуры // ПриОткрытии
Замечание. Не удается одновременно применить и отбор и фильтрацию данных.
5.10. АТРИБУТ ВЛАДЕЛЕЦ
5.10.1. СПРАВОЧНИК ДЕТИ
Добавим в конфигурацию справочник Дети и назначим ему в качестве владельца справочник Сотрудники_2. В справочнике будем хранить данные о детях, возраст которых не более 18 лет.
В новом справочнике для наших учебных целей достаточно иметь 3 реквизита (не считая двух, Код и Наименование, заданных по умолчанию): Имя, ДатаРождения и Возраст (рис. 5.51).
 |
Рис. 5.51. Свойства и реквизиты справочника Дети |
Длину символьных реквизитов Имя и Возраст установим соответственно равной 30 и 10 символам. Реквизит ДатаРождения, понятно, имеет тип Дата. Реквизит Возраст может содержать, например, такие значения: 5 месяцев, 8 лет и т. п.
Реквизит Наименование использовать не будем, поэтому сократим его длину до нуля (заданный по умолчанию реквизит удаляется). Длину кода установим равной трем, что вполне достаточно для кода, задаваемого в пределах подчинения (дети любого сотрудника будут представляться под номерами 1, 2 и т. д.).
Для отображения данных справочника используем форму списка, представленную на рис. 5.52. |
 |
Рис. 5.52. Форма списка справочника Дети |
На самом деле для каждого ребенка вводится только дата рождения, а возраст вычисляется. Причем такие вычисления будем выполнять при каждом открытии справочника, обновляя значения реквизита Возраст. Если в процессе вычислений обнаружится, что ребенок существенно повзрослел (его возраст превысил 18 лет), то соответствующая запись в справочнике Дети помечается для удаления без предупреждений.
При вводе и редактировании данных используем диалог, представленный на рис. 5.53.
 |
Рис. 5.53. Диалог формы элемента справочника Дети |
Причем поле Возраст сделаем доступным только для чтения. Вычисление возраста будем производить функцией НайтиВозраст, которую свяжем на закладке Дополнительно с полем ДатаРождения. Тогда эта функция будет вызываться каждый раз после смены даты. Добавим в диалог поле дТ, также доступное только для чтения, установив его равным текущей дате, возвращаемой встроенной функцией Текущая-Дата( ). Это поле предназначено для визуального контроля установленной в компьютере текущей даты, от значения которой, в частности, зависит и результат, возвращаемый функцией НайтиВозраст.
Теперь ясно, какими процедурами следует снабдить модули форм элемента и списка.
5.10.2. МОДУЛЬ ФОРМЫ ЭЛЕМЕНТА СПРАВОЧНИКА ДЕТИ
Содержит функцию НайтиВозраст и предопределенные процедуры ПриОткрытии и ПриЗаписи. Первая устанавливает значение элемента диалога дТ, вторая контролирует заданные в диалоге значения.
процедура ПриОткрытии() дТ = ТекущаяДата(); конецПроцедуры // ПриОткрытии
// Возвращает возраст ребенка
// Результат имеет вид, например, 4 года или 5 лет, если возраст больше одного года,
// или, например, 8 месяцев - в противном случае
функция НайтиВозраст()
перем нгр, нгт, нмр, нмт, числоЛет, числоМес, возр; если ПустоеЗначение(ДатаРождения) = 1 тогда Предупреждение("Введите дату рождения."); возврат""; конецЕсли;
нгр = ДатаГод(ДатаРождения); // Возвращает год рождения
нгт = ДатаГод(дТ); числоЛет = нгт - нгр; если числоЛет > 18 тогда
Предупреждение("Возраст ребенка не должен быть более 18 лет."); возврат""; конецЕсли;
если числоЛет < 0 тогда
Предупреждение("Неверная дата рождения."); возврат '”'; конецЕсли;
если числоЛет = 0 тогда
нмр = ДатаМесяц(ДатаРождения); нмт = ДатаМесяц(дТ); числоМес = нмт - нмр; если числоМес < 0 тогда
Предупреждение("Неверная дата рождения."); возврат ""; конецЕсли;
если числоМес = 1 тогда возр = "1 месяц"
иначеЕсли (числоМес = 2) или (числоМес = 3) или (числоМес = 4) тогда // Например, 3 месяца возр = строка(числоМес) + " месяца";
иначе // числоМес > 4 или числоМес = О
// Например, 7 месяцев возр = строка(числоМес) + " месяцев"; конецЕсли;
иначе // числоЛет > 1
если числоЛет = 1 тогда возр = "1 год"
иначеЕсли (числоЛет = 2) или (числоЛет = 3) или (числоЛет = 4) тогда // Например, 3 года возр = строка(числоЛет) + " года"; иначе // числоЛет > 4
// Например, 7 лет возр = строка(числоЛет) + " лет"; конецЕсли; конецЕсли;
Возраст = возр; возврат возр;
конецФункции // НайтиВозраст
процедура ПриЗаписи( ) // Предопределенная процедура
если ПустоеЗначение(Возраст) = 1 тогда
Предупреждение("Не определен возраст.");
СтатусВозврата(0); // Запрещаем запись данных
возврат; конецЕсли;
если ПустоеЗначение(Имя) = 1 тогда Предупреждение("Введите имя.");
СтатусВозврата(0); // Запрещаем запись данных
форма.Активизировать(Имя); // Устанавливаем курсор на поле Имя возврат; конецЕсли;
если (ПустоеЗначение(Имя) = 1) или (ПустоеЗначение(ДатаРождения) = 1) тогда Предупреждение("Введите дату рождения.");
// Устанавливаем курсор на поле ДатаРождения форма.Активизировать(ДатаРождения);
СтатусВозврата(0); // Запрещаем запись данных
конецЕсли;
конецПроцедуры // ПриЗаписи
5.10.3. МОДУЛЬ ФОРМЫ СПИСКА СПРАВОЧНИКА ДЕТИ
Содержит предопределенную процедуру ПриОткрытии, вычисляющую и обновляющую в результате вызова процедуры ИзменитьВозраст значение реквизита Возраст всех записей справочника Дети. Запись о ребенке старше 18 лет помечается для удаления. Если форма списка справочника Дети открывается не из справочника-владельца, а, например, встроенной функций ОткрытьФорму, то в качестве владельца формы устанавливается последний сотрудник из справочника Сотрудники_2, имеющий данные о детях в справочнике Дети.
процедура ИзменитьВозраст(Дети, дТ) далее
// Обновляет, вызывая процедуру ИзменитьВозраст,
// значение реквизита Возраст в справочнике Дети роцедура ПриОткрытии()
перем сСотр_2, Дети, послВлад, дТ; дТ = ТекущаяДата();
// Создаем объект Дети. Он необходим, поскольку открываемый справочник Дети
// не может быть перепозиционирован
Дети = СоздатьОбъект("Справочник.Дети");
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Перемещаемся на первый элемент справочника Сотрудники_2 сСотр_2.ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл если сСотр_2.ЭтоГруппа() = 1 тогда
продолжить; // Пропускаем группы справочника Сотрудники_2
конецЕсли;
Дети.ИспользоватьВладельца(сСотр_2.ТекущийЭлемент());
// или проще: Дети.ИспользоватьВладельца(сСотр_2);
// Встаем на первой, относящейся к элементу-владельцу записи справочника Дети ,
если Дети.ВыбратьЭлементы( ) = 1 тогда
// Используем переменную послВлад при автономном открытии // формы списка справочника Дети послВлад = сСотр_2.ТекущийЭлемент(); конецЕсли;
ИзменитьВозраст(Дети, дТ); конецЦикла; // пока сСотр_2.ПолучитьЭлемент() = 1 // Если справочник Дети открывается автономно, например, так: //ОткрытьФормуС'Справочник.Дети'');
// то владелец отсутствует. Установим в качестве такового // элемент послВлад справочника Сотрудники_2
// Метод формы списка справочника ИспользоватьВладельца, возвращает текущий // элемент-владелец формы списка справочника Дети. Если владельца нет если ПустоеЗначение(ИспользоватьВладельца()) = 1 тогда ИспользоватьВладельца(послВлад); конецЕсли;
Дети = 0; сСотр_2 = 0;
конецПроцедуры // ПриОткрытии
// Вычисляет и обновляет значение реквизита Возраст для записей справочника Дети,
// подчиненных ранее заданному владельцу процедура ИзменитьВозраст(Дети, дТ)
перем нгр, нгт, нмр, нмт, числоЛет, числоМес;
// Выбор элементов справочника Дети, связанных с элементом-владельцем пока Дети.ПолучитьЭлемент() = 1 цикл нгр = ДатаГод(Дети.ДатаРождения); нгт = ДатаГод(дТ); числоЛет = нгт - нгр; если числоЛет > 18 тогда
// Проставляем пометку удаления без предупреждения Дети.Удалить(0); конецЕсли;
если числоЛет = 0 тогда
нмр = ДатаМесяц(Дети.ДатаРождения); нмт = ДатаМесяц(дТ); числоМес = нмт - нмр; если числоМес = 1 тогда Дети.Возраст = "1 месяц"
иначеЕсли (числоМес = 2) или (числоМес = 3) или (числоМес = 4) тогда // Например, 3 месяца
Дети.Возраст = строка(числоМес) + " месяца"; иначе // числоМес > 4 или числоМес = 0 // Например, 7 месяцев
Дети.Возраст = строка(числоМес) + " месяцев"; конецЕсли;
иначе // числоЛет > 1
если числоЛет = 1 тогда Дети.Возраст = "1 год"
иначеЕсли (числоЛет = 2) или (числоЛет = 3) или (числоЛет = 4) тогда // Например, 3 года
Дети.Возраст = строка(числоЛет) + " года"; иначе // числоЛет > 4 // Например, 7 лет
Дети.Возраст = строка(числоЛет) + " лет"; конецЕсли; конецЕсли;
Дети.3аписать( ); // Не забываем сохранить данные
конецЦикла; // пока Дети.ПолучитьЭлемент() = 1 конецПроцедуры // ИзменитьВозраст
Вычисление и обновление реквизита Возраст можно было бы выполнять только для конкретного владельца в предопределенной процедуре ПриВыбореВладельца. Тогда в предопределенной процедуре ПриОткрытии подчиненного справочника достаточно модифицировать реквизит Дети.Возраст только для записей, подчиненных элемен-ту-владельцу, который возвращается методом ИспользоватьВладельца. При таком подходе модуль формы списка справочника будет иметь следующий код:
процедура ИзменитьВозраст(Дети, дТ) далее процедура ПриВыбореВладельца(влад) далее
процедура ПриОткрытии() перем влад;
влад = ИспользоватьВладельца(); // Получаем владельца при открытии
// Вычисляем и обновляем значение реквизита Возраст для записей справочника Дети,
// подчиненных владельцу влад ПриВыбореВладельца(влад); конецПроцедуры // ПриОткрытии
// Вызывает процедуру ИзменитьВозраст, которая вычисляет и обновляет // значение реквизита Возраст для записей справочника Дети, подчиненных владельцу влад процедура ПриВыбореВладельца(влад) // Предопределенная процедура
перем Дети, дТ; // Запускается при смене элемента-владельца
дТ = ТекущаяДата();
// Создаем объект Дети. Он необходим, поскольку открываемый справочник Дети // не может быть перепозиционирован Дети = СоздатьОбъект("Справочник.Дети");
Дети. ИспользоватьВладельца(влад);
// Встаем на первой, относящейся к элементу-владельцу записи справочника Дети если Дети.ВыбратьЭлементы() = 1 тогда ИзменитьВозраст(Дети, дТ); конецЕсли;
Дети = 0;
конецПроцедуры // ПриВыбореВладельца
процедура ИзменитьВозраст(Дети, дТ)
// Текст процедуры см. выше конецПроцедуры // ИзменитьВозраст
5.10.4. ЗАПОЛНЕНИЕ СПРАВОЧНИКА ДЕТИ
Введем несколько значений в справочник Дети в интерактивном режиме. Для этого откроем справочник Сотрудники 2, которому справочник Дети подчинен, выберем сотрудника, например Горюнову Ульяну, и воспользуемся иконкой ^ , позволяющей отобразить форму списка справочника Дети. Вызвав дважды форму элемента этого справочника (рис. 5.54), введем данные о детях (рис. 5.55).
 |
Рис. 5.54. Заполненный диалог формы элемента справочника Дети |
Из рис. 5.55 видно, что в подчиненном справочнике Дети отображаются только строки, содержащие данные о детях сотрудника, выбранного в справочнике-владельце Сотрудники_2.
 |
Рис. 5.55. Ульяна Горюнова и ее дети |
В информационной базе для справочника Дети будет создан файл, возможно SC4233.DBF, имеющий структуру, представленную в табл. 5.6.
Таблица 5.6
Структура DBF-файла справочника Дети |
Id |
Code |
Descr |
Parentext |
Ismark |
VerStamp |
Sp4237 |
Sp4236 |
Sp4235 |
1 |
1 |
|
A |
|
|
Васильева Лена |
09/21/1999 |
2 года |
2 |
1 |
|
1Q |
|
|
Горюнов Алеша |
06/12/2001 |
5 месяцев |
3 |
2 |
|
1Q |
|
|
Горюнова Маша |
11/12/1998 |
3 года |
|
Справочник Дети связан со справочником-владельцем (справочником Сотрудни-ки_2) через атрибут Владелец; связь между записью владельца и записями подчиненного справочника фиксируется соответственно в полях Id и Parentext их DBF-таблиц. В частности, значения поля Id Горюновой Ульяны Валерьевны в справочнике Сотруд-ники_2 и полей Parentext ее детей в справочники Дети совпадают и равны 1Q. |
5.10.5. ВЫБОР ДАННЫХ ПОДЧИНЕННОГО СПРАВОЧНИКА
При выборе данных из справочника Дети предварительно надо указать, сославшись на справочник Сотрудники_2, сотрудника, детей которого мы хотим выбрать. Такая привязка к сотруднику осуществляется методом ИспользоватьВладельца.
Пример. Обработкой Проба выводятся сообщения о детях Горюновой Ульяны.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, Дети, род;
ОчиститьОкноСообщенийО;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// 2010 - код Горюновой Ульяны. Выполняем поиск во всем справочнике если сСотр_2.НайтиПоКоду(2010, 0) = 0 тогда Предупреждение(''Сотрудник не найден."); возврат; конецЕсли;
род = сСотр_2; // Родитель
// или род = сСотр_2.ТекущийЭлемент();
Дети = СоздатьОбъект("Справочник.Дети");
// Фиксируем сотрудника, для которого выводятся данные о его детях Дети.ИспользоватьВладельца(род);
Дети.ВыбратьЭлементы(); // Перемещаемся на начало справочника Дети // Заголовок таблицы результатов Сообщить(сСотр_2.Наименование + ". Ее дети:");
// Метод ПолучитьЭлемент выбирает очередной элемент справочника,
// связанный с записью-владельцем пока Дети.ПолучитьЭлемент() = 1 цикл
Сообщить(Дети.Имя + СимволТабуляции + Дети.Возраст); конецЦикла // пока конецПроцедуры // Выполнить
Результат:
Горюнова Ульяна Валерьевна. Ее дети:
Горюнов Алеша 5 месяцев
Горюнова Маша 3 года
5.11. ПРОСТОЙ ОТЧЕТ ДЛЯ СПРАВОЧНИКА
5.11.1. ДИАЛОГ И ТАБЛИЦА ОТЧЕТА
Сформируем отчет, содержащий данные о сотрудниках справочника Сотруд-ники_2, имеющих заданное образование обр и оклад, не меньший заданной величины окл. Вывод осуществим с разбивкой по цехам и их подразделениям. В пределах каждого подразделения данные отобразим в алфавитном порядке фамилий сотрудников.
Для задания значений переменных обр и окл диалог обработки Проба приведем к представленному на рис. 5.56 виду.
'ДОгчт-т по справочник Сотрудники |
Образов»»* |обр |
У Пуп. |
Мк#*»налы«>й оклад |окп |
Закрыть 1 |
Рис. 5.56. Диалог отчета по справочнику Сотрудники _2
Переменная обр имеет разновидность типа Справочник.Образование_2, а переменная окл - числовой тип формата 10.2.
В таблице отчета будем выводить отображенные на рис. 5.57 сведения.
? Внешний отч |
ет(обработ?а) - Проба ert |
_ ___________ щ |
|
|
Lll_? |
I з I_4_7 » Г « |
заг |
1 |
I «Сотрудники, имеющие [обр] образование и оклад, не неныиий [окл| руб.> |
|
2 |
|
|
|
3 |
Сотрудник |
Код Дата трудоустройства Оклад |
|
4 |
|
юдр |
5 |
«Подразделение [подр]> |
сотр |
* |
I «сотр» _ |
«код» <дП» «ставка» |
АвтаОтч |
7 |
| «Дата отчета [ТекущаяДатаО> |
|
Ш |
|
«1 |
|
|
I . |
|
YCJДиалог / 1 Моочль і іитсаиие > Лісотоищнмкм .
Рис. 5.57. Макет отчета о сотрудниках
ГАІКоистаить-ч” |
В секциях заг, подр и датаОтч тип выводимых сообщений - шаблон, в секции сотр - выражение. Читателям, испытывающим затруднения при построении таблиц отчета, рекомендуем вновь обратиться к разд. 1.9, в котором конструируется отчет о непериодических константах.
5.11.2. МОДУЛЬ ОТЧЕТА
Модуль отчета, как это уже повелось, содержит связанную с кнопкой Пуск процедуру Выполнить, извлекающую на этот раз данные о сотрудниках и направляющую их в только что построенную таблицу Сотрудники_2. Кроме процедуры Выполнить, включим в модуль отчета предопределенную процедуру ПриОткрытии, устанавливающую начальные значения переменных диалога обр и окл. Вывод секции подр будем осуществлять, если в подразделении есть хотя бы один сотрудник, удовлетворяющий условиям, заданным переменными обр и окл. Для сокращения кода разместим его часть в функции ЕслиПродолжить.
Алгоритм формирования отчета:
1. Начало.
2. Создать объект сСотр_2, имеющий разновидность типа Справочник.Сотрудники_2.
3. Установить дату для периодического реквизита Оклад.
4. Открыть выборку из справочника Сотрудникик_2.
5. Если текущий элемент - это группа, то найти, нужно ли выводить секцию подр. Критерий прост: если в группе есть хотя бы один сотрудник, удовлетворяющий условиям, заданным переменными обр и окл, то ее имя выводится в секции подр. Ответ на вопрос, нужно ли выводить имя группы (подразделения), возвращает функция НайтиФлагПодр. Предварительно, когда найдено первое подразделение (числоПодр = 1), создается объект табл, имеющий тип Таблица, и выводится заголовок отчета - секция заг.
6. Если текущий элемент - это сотрудник, то вывести секцию сотр, если сотрудник удовлетворяет заданным условиям, или перейти на начало цикла - в противном случае.
7. После завершения выборки, если в отчете есть данные о сотрудниках (числоПодр > 0), вывести дату отчета и показать отчет, иначе вывести предупреждение о том, что отчет пуст.
8. Конец.
// Установим начальные значения переменных диалога обр и окл процедура ПриОткрытии() перем видОбр;
ОчиститьОкноСообщений();
видОбр = СоздатьОбъект(''Справочник.Образование_2''); видОбр .ВыбратьЭлементы(); видОбр. ПолучитьЭлемент();
// Используем в качестве начального значения переменной обр // первый элемент справочника Образование_2 обр = видОбр.ТекущийЭлемент(); окл = 2000.0 // руб.
конецПроцедуры // ПриОткрытии
функция ЕслиПродолжить(сСотр_2) далее функция НайтиФлагПодр(кодПодр) далее
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, сотр, код, дП, ставка, подр, текПодр; перем табл, числоПодр;
// Создаем объекты сСотр2 и табл
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Дата для периодического реквизита Оклад справочника Сотрудники_2 сСотр_2.ИспользоватьДату(РабочаяДата());
// Позиционируемся на первой записи справочника Сотрудники_2 сСотр_2.ВыбратьЭлементы(1); // Задаем выборку с учетом иерархии
числоПодр = 0; // Число выбранных подразделений
// Включаем в выборку все подчиненные элементы пока сСотр_2.ПолучитьЭлемент(1)= 1 цикл если сСотр_2.ЭтоГруппа() = 1 тогда
// Найдем, нужно ли выводить секцию подр если НайтиФлагПодр(сСотр_2.Код) = 0 тогда
продолжить; // В этом подразделении нет сотрудников,
иначе // удовлетворяющих условиям обр и окл
числоПодр = числоПодр + 1;
// Если есть хотя бы один сотрудник, удовлетворяющий заданным условиям,
// то начинаем формировать тотчет
если числоПодр = 1 тогда
табл = СоздатьОбъект("Таблица");
// Свяжем переменную табл с таблицей Сотрудники_2,
// содержащей макет отчета табл.ИсходнаяТ аблица(" Сотрудники_2");
// При выводе применяем заданные по умолчанию параметры таблицы;
// для их изменения следует обратиться к методу Опции табл.ВывестиСекцию("заг"); // Выводим секцию заг конецЕсли;
подр = сСотр_2.Наименование; табл.ВывестиСекцию("подр"); продолжить; конецЕсли; конецЕсли;
если ЕслиПродолжить(сСотр_2) = 1 тогда
продолжить; // Переход на начало цикла
конецЕсли;
сотр = сСотр_2.Наименование; код = сСотр_2.Код;
если ПустоеЗначение(сСотр_2.ПриказПрием) = 0 тогда
// Дату трудоустройства берем из соответствующего приказа о приеме на работу дП = сСотр_2.ПриказПрием.ДатаПриема; иначе
дП = "-"; конецЕсли;
ставка = сСотр_2.0клад;
// Вывод очередной строки в отчет табл.ВывестиСекцию("сотр"); конецЦикла; // пока если числоПодр = 0 тогда
Предупреждение("Сотрудников, отвечающих заданным условиям, нет."); иначе // В отчете есть сотрудники
табл.ВывестиСекцию("датаОтч"); // Дата отчета // Запрещаем редактирование результирующей таблицы табл .ТолькоПросмотр(1);
// Задаем в методе Показать заголовок окна с результирующей таблицей табл.Показать("Выборка из справочника Сотрудники_2"); конецЕсли;
конецПроцедуры // Выполнить. Результат приведен в табл. 5.7
// Возвращает 1, если сотрудник не удовлетворяет требованиям обр и окл функция ЕслиПродолжить(сСотр_2)
если (сСотр_2.Оклад < окл) или (сСотр_2.Образование <> обр) тогда
возврат 1; // Условия, заданные в диалоге, не выполняются
иначе
возврат 0; // Цикл не прерывается
конецЕсли;
конецФункции // ЕслиПродолжить
// Функция НайтиФлагПодр вернет 1, если в подразделении есть // хотя бы один сотрудник, удовлетворяющий условиям,
// заданным переменными обр и окл, или 0 -в противном случае Функция НайтиФлагПодр(кодПодр) перем сСотр_2а;
сСотр_2а = СоздатьОбъект("Справочник.Сотрудиики_2");
// Дата для периодического реквизита Оклад справочника Сотрудники_2 сСотр_2а.ИспользоватьДату(РабочаяДата());
// Найдем группу. Ищем во всем справочнике сСотр_2а. НайтиПоКоду(кодПодр, 0);
// Задаем родителя, в пределах которого будет осуществляться последующая выборка сСотр_2а.ИсполкюватъРодителя(сСотр_2а.ТекущийЭлемент());
// или проще: сСотр_2а.ИспользоватьРодителя(сСотр_2а);
сСотр_2а.ВыбратьЭлементы(1); // Задаем выборку с учетом иерархии
// Включаем в выборку все подчиненные элементы пока сСотр_2а.ПолучитьЭлемент(1) = 1 цикл если ЕслиПродолжить(сСотр_2а) = 0 тогда
возврат 1; // Сотрудник, подходящий под условия
конецЕсли; // обр и окл, найден
конецЦикла;
возврат 0; // Нет нужного сотрудника конецФункции // НайтиФлагПодр
Таблица 5.7
Сотрудники, имеющие высшее образование и оклад, не меньший 2000 руб. |
Сотрудник |
Код |
Дата трудоустройства |
Оклад |
Подразделение 01 Цех |
|
|
|
Подразделение 01/1 |
|
|
|
Агальцов Юрий Алексеевич |
111 |
- |
2900 |
Подразделение 01 / 2 |
|
|
|
Кузьмина Раиса Николаевна |
122 |
- |
2700 |
Подразделение 02 Цех |
|
|
|
Абрамова Лариса Сергеевна |
201 |
- |
2000 |
Горюнова Ульяна Валерьевна |
2010 |
20.11.01 |
2700 |
Дата отчета 29.11.01 |
|
- |
|
|
5.11.3. МОДУЛЬ ОТЧЕТА С ЗАПРОСОМ
Длинный код по выбору данных принято заменять запросами к файлам базы данных. В СУБД общего назначения, например FoxPro, запросы не только компактнее по коду, но и эффективнее по быстродействию. В 1С последнее качество запросов не столь очевидно.
Результатом выполнения запроса является таблица, содержащая отобранные запросом данные. На основе этой таблицы можно, например, создать отчет, выполнить требуемые вычисления или иные предусмотренные алгоритмом действия.
Запрос 1С - это объект, например запС, появляющийся в программе в результате присваивания
запС = СоздатьОбъект("Запрос");
Содержание запроса оформляется в 1С, как правило, в виде длинной, расположенной на нескольких строчках символьной именованной константы, например текст-ЗапС, которая затем употребляется в качестве параметра метода Выполнить:
флаг = запС.Выполнить(текстЗапС);
Метод Выполнить вернет 1 при успешном выполнении запроса или 0 -в случае неудачи.
Оставим диалог обработки Проба без изменений, но удалим из ее модуля ранее внесенный в него код (кроме процедуры ПриОткрытии) и заменим его на нижеприводимые процедуры и функции. Первая, имеющая имя ЗапрСотр, выполняет запрос к справочнику Сотрудники_2, выбирая в результате данные, удовлетворяющие перечисленным в разд. 5.11.1 критериям. Процедура ВывТабСотр формирует, используя макет таблицы Сотрудники_2 (см. рис. 5.57) обработки Проба, отчет. Разумеется, если в диалоге (см. рис. 5.56) для переменной обр задано значение Высшее, а для переменной окл - 2000, то итоговый отчет полностью совпадет с результатом, содержащимся в табл. 5.7.
Назначение иных программных компонентов модуля обработки Проба будет поясняться сопровождающим их комментарием.
// Установим начальные значения переменных диалога обр и окл процедура ПриОткрытии() перем видОбр;
ОчиститьОкноСообщенийО;
видОбр = СоздатьОбъект("Справочник.Образование_2"); видОбр .ВыбратьЭлементы (); видОбр.ПолучитьЭлементО;
// Используем в качестве начального значения переменной обр // первый элемент справочника Образование_2 обр = видОбр.ТекущийЭлемент(); окл = 2000.0 // руб.
конецПроцедуры // ПриОткрытии
// Формируем и выполняем запрос по сотрудникам,
// имеющим образование обр и оклад, не меньший окл // Функция принимает и возвращает параметр запС типа Запрос
функция ЗапрСотр(запС) |
|
|
Перем текстЗапС; //
перем рабДат; рабДат = РабочаяДата(); текстЗапС = " |
|
Содержание запроса |
| период с рабДат по рабДат;
// Переменные запроса |
// |
Дата для периодического реквизита Оклад |
| род = Справочник.Сотрудники_2.ТекущийЭлемент.Родитель; | имяСотр = Справочник.Сотрудники_2.Наименование;
| код = Справочник.Сотрудники_2.Код;
| образование = Справочник.Сотрудники_2.Образование;
| оклад = Справочник.Сотрудники_2.Оклад;
// Задаем порядок выборки данных | группировка род;
| группировка имяСотр;
| условие ((образование = обр) и (оклад >= окл));";
// Выполняем запрос и возвращаем 1 в случае удачи, или 0, если есть проблемы возврат запС.Выполнить(текстЗапС); конецФункции // ЗапрСотр
функция НайтиДП(сСотр 2, код) далее
// Выводит данные в таблицу Сотрудники_2 обработки Проба процедура ВывТабСотр(запС) перем табл;
// Создаем объекты сСотр_2 и табл
// Объект сСотр_2 создается для функции НайтиДП, осуществляющей поиск
// даты приема на работу сотрудника
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
табл = СоздатьОбъект("Таблица");
// Свяжем переменную табл с таблицей Сотрудники_2, содержащей макет отчета табл.ИсходнаяТ аблица("Сотрудники_2");
// При выводе применяем заданные по умолчанию параметры таблицы;
// для их изменения следует обратиться к методу Опции табл.ВывестиСекцию("заг"); // Выводим секцию заг
// Вывод запроса в таблицу Сотрудники_2 пока запС.Группировка("род") = 1 цикл подр = запС.Род; табл.ВывестиСекцию("подр"); пока запС.Группировка("имяСотр") = 1 цикл сотр = запС.ИмяСотр; код = запС.Код; дП = НайтиДП(сСотр_2, код); ставка = запС.Оклад;
// Вывод очередной строки в отчет табл.ВывестиСекцию("сотр"); конецЦикла; // пока конецЦикла; // пока
табл.ВывестиСекцию("датаОтч"); // Дата отчета
// Запрещаем редактирование результирующей таблицы табл.ТолькоПросмотр(1);
// Задаем в методе Показать заголовок окна с результирующей таблицей табл.Показать("Выборка из справочника Сотрудники_2"); конецПроцедуры // ВывТабСотр
// Находит, если есть ссылка на приказ о приеме на работу, дату трудоустройства сотрудника функция НайтиДП(сСотр 2, код)
сСотр_2.НайтиПоКоду(код, 0); // Ищем во всем справочнике
// Вернем либо дату приказа о приеме на работу, либо символ -, если // в рассматриваемой записи справочника Сотрудники_2 нет ссылки на приказ возврат ?(ПустоеЗначение(сСотр_2.ПриказПрием) = 0, сСотр_2.ПриказПрием.ДатаПриема,"-"); конецФункции // НайтиДП
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем запС, тЗнач;
// Создаем объекты запС и тЗнач запС = СоздатьОбъекг("Запрос"); если ЗапрСотр(запС) = 0 тогда
возврат; // Запрос не выполнен
конецЕсли;
// Если в отчете нет сведений о сотрудниках если запС.Группировка("род") = 0 тогда
Предупреждение("Сотрудников, отвечающих заданным условиям, нет."); возврат; иначе
запС. ВНачалоВыборки(); конецЕсли;
// Создаем объект тЗнач для промежуточной демонстрации выборки запроса тЗнач = СоздатьОбъект("ТаблицаЗначений");
// Выгружаем все переменные запроса в таблицу значений тЗнач // для его предварительного просмотра запС.Выгрузшъ(тЗнач, 1);
// Просмотр таблицы значений (результатов запроса) тЗнач.ВыбратьСтроку(, "Запрос в таблице значений");
// Выводим выборку запроса в таблицу Сотрудники_2 ВывТабСотр(запС); конецПроцедуры // Выполнитъ
Результат приведен в табл. 5.7.
Сделаем некоторые пояснения.
Результатом запроса является выборка, являющаяся последовательностью записей. Фактически выборка является таблицей, в столбцах которой расположены значения заданных в тексте запроса переменных - в нашем случае переменных род
г имяСотр, код, образование и оклад. В общем случае выборка состоит из нескольких групп, задаваемых в тексте запроса оператором Группировка.
Быстрый просмотр выборки запроса можно организовать, выполнив два следующих метода:
// Выгружаем все переменные запроса в таблицу значений тЗнач запС.Выгрузить(тЗнач, 1);
// Просмотр таблицы значений
тЗнач.ВыбратьСтроку(, "Запрос в таблице значений");
Результат см. на рис. 5.58.
Запрос в таблице значений
Р«« I имяСотр
0 |
|
0.00 |
111 |
Высшее |
2900.00 |
111 |
Высшее |
290000 |
122 |
Высшее |
270000 |
122 |
Высшее |
270000 |
201 |
Высшее |
2000 00 |
201 |
Высшее |
2000.00 |
2010 |
Высшее |
2700.00 |
01 Цех 01/1
01/1 Агальцов Юрий Алексеевич 01 /2
01/2 Куэькчна Раиса Николаевна
02 Цех
02 Цех Абрамова Л вриса Сергеевна 02 Цех Горюнова Уль«ыа Валерьевна
Просмотр таблицы показывает, что в ней расположены все нужные нам данные (кроме даты приказа о приеме на работу), причем сгруппированные и упорядоченные надлежащим образом. Объем выбираемых данных, способ группировки и их порядок определяется текстом запроса.
Текст запроса текстЗапС содержит, во-первых, дату, задаваемую строкой "период с рабДат по рабДат". Дата в этом запросе нужна только для определения значения периодического реквизита Оклад и играет ту же роль, что и метод ИспользоватьДату при простой выборке из справочника. Далее перечисляются реквизиты, значения которых необходимо разместить в запросе (в результирующей таблице), и порядок выборки, устанавливаемый операторами Группировка. Критерий выбора данных задается оператором Условие.
Последовательность операторов Группировка, например | группировка род;
| группировка имяСотр;
приводит к созданию вложенных групп данных. Так, в нашем случае употребленные группировки отображают имеющуюся в справочнике Сотрудники_2 иерархию данных.
В тексте запроса можно размещать внешние по отношению к запросу переменные, но только те, к которым есть доступ в программном компоненте, содержащем команду выполнения запроса
// Должны быть видны имеющиеся в тексте запроса переменные рабДат, обр и окл запС.Выполнить(текстЗапС);
Поскольку в тексте запроса нельзя разместить строку "дП = Справочник.Сотрудники_2.ПриказПрием.ДатаПриема;"
задающую выборку (эти ограничения накладывает 1С), то для получения даты приема сотрудника на работу в код введена функция НайтиДП, работающая со специально созданным для нее объектом сСотр І, имеющим разновидность типа Справочни-ки.Сотрудники_2.
Так как текст запроса является символьной переменной, то для его формирования можно использовать несколько строк, объединяя их при помощи употребляемой со строками операцией конкатенации (сложения). Например:
// Дата для периодического реквизита Оклад датаЗапр = "период с рабДат по рабДат;";
перемЗапр = " // Переменные запроса
| род = Справочник. Сотрулники_2.ТекущийЭлеменг.Родигель;
| имяСотр = Справочник.Сотрудники_2.Наименование;
| код = Справочник.Сотрудники_2.Код;
| образование = Справочник.Сотрудники_2.Образование;
| оклад = Справочник.Сотрудники_2.Оклад;''; групЗапр = "группировка род; // Группы запроса
| группировка имяСотр;"; услЗапр = " // Условие выборки
| условие ((образование = обр) и (оклад >= окл));";
// Формируем текст запроса
текстЗапС = датаЗапр + перемЗапр + групЗапр + услЗапр;
Для получения отчета, отображенного в табл. 5.7, можно, поскольку мы выгрузили запрос в таблицу значений тЗнач, было бы употребить следующий код:
// Позиционируемся перед первой строкой таблицы значений тЗнач тЗнач. ВыбратьСгрокиО;
// Перебор строк таблицы значений начинается с ее первой строки пока тЗнач.ПолучитьСтрокуО = 1 цикл подр = тЗнач.Род;
// Ничего не вводим
Переход на начало цикла
// Строка содержит имя подразделения Строка содержит данные о сотруднике
если ПустоеЗначение(подр) = 1 тогда продолжить; //
конецЕсли;
сотр = тЗнач.ИмяСотр;
// Вывод очередной строки в отчет если ПустоеЗначение(сотр) = 1 тогда табл.ВывестиСекцию("подр"); иначе //
код = тЗнач.Код; дП = НайтиДП(сСотр_2, код); ставка = тЗнач.Оклад; табл.ВывестиСекцию("сотр"); конецЕсли; конецЦикла; // пока
Однако для перебора элементов выборки, созданной запросом, в большинстве случаев удобнее пользоваться методом Группировка, принимающим имя группы и получающим очередное значение выборки в заданной группе. Поскольку сразу после выполнения запроса он позиционируется перед первой своей записью, то первое употребление метода Группировка с именем старшей группы, например
запС.Группировка("род");
обеспечит перемещение на первую запись выборки.
Перебор записей начинается с первой старшей группы. После ее выбора можно перебрать принадлежащие ей записи, вновь употребив метод Группировка, но передав ему в качестве параметра имя группы, расположенной на следующем уровне иерархии выборки. Метод Группировка вернет 0, если либо выбрана запись другого уровня иерархии выборки, либо выборка исчерпана. В противном случае Группировка возвращает число 1. Понятно, что для перебора более всего подходит управляющая конструкция - цикл Пока, которую мы и применили в вышеприведенной процедуре Выполнить.
Поскольку наш запрос имеет две вложенные группы, род и имяСотр, то для перебора их записей пришлось использовать вложенные конструкции Пока. Если нужно вывести только значения старшей группы, то достаточно одного цикла, например такого:
пока запС.Группировка("род”) = 1 цикл подр = запС.Род; табл.ВывестиСекцию("подр"); конецЦикла; // пока
Нам уже понятно, что доступ к отдельному компоненту записи выборки запроса осуществляется по известной схеме - <имя запроса>.<имя переменной запроса>, например
Сообщить(запС.ИмяСотр); // Печатаем имя сотрудника
Содержание раздела