ВЫВОДЫ
|
Пример вызова |
Результат |
Тип |
|
str(5.234) |
5 |
” |
|
str(5.234, 5) |
5 |
” |
|
str(5.234, 6, 4) |
5.2340 |
” |
|
substr("Небосклон", 3, 3) |
бос |
” |
|
substr("Hебосклон", 5) |
склон |
” |
|
иррегСНебосклон'') |
НЕБОСКЛОН |
” |
|
va1("Небосклон") |
0 |
Числовой |
|
val(”-1.23") |
-1.23 |
” |
|
val(,,+432”) |
432 |
” |
|
val(”1.3e+2”) |
130 |
” |
9.4. ВЫВОДЫ
1. Объект XBase подсоединяется к DBF-файлу в режиме монопольного доступа.
2. Чтобы индексный файл соответствовал своему DBF-файлу, необходимо открывать первый вместе с DBF-файлом. Тогда изменения в DBF-файле автоматически вызовут необходимые изменения индексного файла.
3. Если какое-то время DBF-файл редактировался при закрытом индексном файле, то, открывая последний, следует выполнить его переиндексацию.
4. Атрибут Ключ объекта XBase используется для задания операндов индексного выражения.
5. Для поиска по составному ключу следует использовать метод НайтиПоКлючу взамен метода Найти.
6. Для просмотра находящихся в работе DBF-файлов полезно иметь процедуру, переносящую записи файла в таблицу значений. Вывод таблицы значений можно осуществить как в одноименный элемент диалога, так и в окно, открываемое методом ВыбратьСтроку.
ПРИЛОЖЕНИЕ 1. ПРИМЕРЫ СТРУКТУР МЕТАДАННЫХ
Структура метаданных отображается в текстовом файле, если, находясь в конфигурации, в колонке Конфигурация выбрать пункт Описание структуры метаданных. Появляющийся в результате текст будет весьма обширным, но для пояснения его устройства вполне достаточно привести несколько фрагментов.
Так, для созданной нами константы к5 файл будет содержать следующую информацию:
- Константа
- Идентификатор
- Синоним
- Комментарий
- Тип -Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады -Периодический
- ОбластьРаспространения |
"к5"
"Коэффициент к5"
"Для вычисления премии 1234" "Число"
"5"
"2"
"0"
"0"
"1"
"ВсеИнформационныеБазы" |
Если бы константа имела агрегатный тип специального назначения (разд. 3.1), то для нее было бы определено значение компонента Вид. Например, константа ГлБухгалтер имеет разновидность типа Справочник.Сотрудники_2, то есть ее компонент Вид равен Сотрудники_2.
Способ доступа к компонентам константы посредством объекта метаданные рассмотрен в разд. 1.7.3.
Справочник Сотрудники_2 имеет следующую структуру метаданных:
- Справочник
"Сотрудники_2"
Сотрудники"
Простой справочник"
3"
5"
"30"
’ВПределахПодчинения"
Числовой"
'ВВидеНаименования"
1"
2"
1"
ОбоимиСпособами"
"0"
- Идентификатор
- Синоним
- Комментарий
- Владелец
- КоличествоУровней
- ДлинаКода
- ДлинаНаименования
- СерииКодов
- ТипКода
- ОсновноеПредставление
- КонтрольУникальности
- АвтоНумерация
- ГруппыВпереди
- СпособРедактирования
- ЕдинаяФормаЭлемента
ОсновнаяФорма
"Справочник.Сотрудники_2.ФормаСписка.ФормаСписка"
ОсновнаяФормаДляВыбора
"Справочник.Сотрудники_2.ФормаСписка.ФормаДляВыбора' ОбластьРаспространения "ВсеИнформационныеБазы"
АвтоРегистрация
Дополнительные КодыИБ
Реквизит |
" 1" |
- Идентификатор
- Синоним
- Комментарий
- Тип
- Вид |
"Оклад"
"Оклад сотрудника"
"Меняется документом ИзменениеОклада" "Число" |
-Длина
- Точность
- Неотрицательный -РазделятьТриады
- Периодический
- Сортировка
- Отбор
- РучноеИзменение
- ИзменяетсяДокументами
- Использование
Реквизит |
"10"
"2"
"1"
"1"
"1"
"0"
"0"
"1"
"1"
"ДляЭлемента" |
- Идентификатор
- Синоним
- Комментарий
- Тип
- Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- Периодический -Сортировка -Отбор
- РучноеИзменение
- ИзменяетсяДокументами
- Использование
Реквизит |
"Образование"
"Образование"
"Выбирается из справочника Образование "Справочник"
"Образование_2"
"0"
"0"
"0"
"0"
"0"
"1"
"1"
"1"
"0"
"ДляЭлемента" |
- Идентификатор
- Синоним
- Комментарий
- Тип
- Вид -Длина
- Точность
- Неотрицательный
- РазделятьТриады
- Периодический |
"ПриказОклад"
"Приказ об изменении оклада"
"Ссылка на документ о новом окладе" "Документ"
"ИзменениеОклада"
"0"
"0"
"0"
"0"
"0" |
"0"
- Сортировка
- Отбор
- РучноеИзменение
- ИзменяетсяДокументами
- Использование -Реквизит
- Идентификатор
- Синоним
- Комментарий
- Тип
- Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- Периодический
- Сортировка
- Отбор
-РучноеИзменение
- ИзменяетсяДокументами
- Использование
- Реквизит
- Идентификатор
- Синоним
- Комментарий
- Тип -Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- Периодический
- Сортировка
- Отбор
-РучноеИзменение
- ИзменяетсяДокументами
- Использование
- ФормаСписка
- Идентификатор
- Синоним
- Комментарий
- ФормаСписка
- Идентификатор
- Синоним
- Комментарий
"0"
1"
"0"
"ДляЭлемента"
’ПриказПрием"
'Приказ о зачислении в штат"
Ссылка на документ ПриказОПриеме" "Документ"
ПриказОПриеме"
"0"
"0"
"0"
"0"
"0"
"0"
"0"
1"
"0"
"ДляЭлемента"
"Календарь"
"Календарь"
"Ссылка на объект типа Календарь" "Календарь"
"0"
"0"
"0"
"0"
"0"
"0"
"0"
1"
"0"
"ДляЭлемента"
"ФормаСписка"
"В форме запрещен выбор групп"
"ФормаДляВыбора"
"Форма для выбора"
"В форме разрешен выбор групп"
Все компоненты структуры объекта Справочник. Сотрудники_2 можно прочитать, употребив объект Метаданные, например так, как это выполнено в разд. 9.3.1.2.
Документ
- Идентификатор
- Синоним
- Комментарий
- Журнал
- ПериодичностьНомера
- ДлинаНомера
- ТипНомера
- АвтоНумерация
- КонтрольУникальности
- Нумератор |
"ИзменениеОклада"
"Приказ о новом окладе"
"Можно выпустить для группы сотрудников' "Журнал. ПриказыКадровые"
"Все"
"5"
"Числовой"
"2"
"1" |
- ОперативныйУчет -Расчет
- БухгалтерскийУчет
- СоздаватьОперацию |
"0"
"1"
"0" |
- АвтоНумерацияСтрок
- АвтоудалениеДвижений
- РедактированиеОпераций
- РазрешитьПроведение
- ВводимыеНаОснованииДокументы |
"1"
"1"
"0"
"1" |
- ОснованиеДляЛюбогоДокумента
- ОбластьРаспространения
- АвтоРегистрация
- ДополнительныеКодыИБ
- РеквизитШапки |
"0"
"ВсеИнформационныеБазы"
" 1" |
- Идентификатор
- Синоним
- Комментарий
- Тип -Вид |
"ДатаНовОклада"
"Дата нового оклада"
"Дата, с которой вступает в силу новый оклад" "Дата" |
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- РеквизитТабличнойЧасти |
о о о о |
- Идентификатор
- Синоним
- Комментарий
- Тип
- Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- ИтогПоКолонке
- РеквизитТабличнойЧасти |
"Сотрудник"
"Сотрудник"
"Ссылка на справочник Сотрудники_2" "Справочник"
"Сотрудники_2"
"0"
"0"
"0"
"0"
"0" |
- Идентификатор
- Синоним |
"ПрежнийОклад"
"Действующий оклад" |
"Носит осведомительный характер”
- Комментарий
- Тип -Вид -Длина
- Точность
- Неотрицательный
- РазделятьТриады
- ИтогПоКолонке
- РеквизитТабличнойЧасти
- Идентификатор
- Синоним
- Комментарий
- Тип -Вид -Длина
- Точность -Неотрицательный
- РазделятьТриады
- ИтогПоКолонке
Число"
”10”
’2”
1”
1”
”0”
''НовыйОклад''
Новый оклад”
'Оклад, назначенный настоящим приказом” Число”
”10”
”2”
1”
” 1”
”0”
Журналы документов характеризуются следующими данными (на примере журнала Табель):
- Журнал
- Идентификатор
- Синоним
- Комментарий
- ТипЖурнала
- Состав
- ОсновнаяФорма
- ОсновнаяФормаДляВыбора
- ДляЖурналаПодчиненныхДокументов
- ДляПолногоЖурнала
- ФормаСписка
- Идентификатор
- Синоним
- Комментарий
”Табель”
”Табель”
”Журнал документов учета рабочего времени” ”Обычный”
"Журнал.Табель. Форма. ФормаСписка” "Журнал.Табель. Форма. ФормаСписка”
”0”
”0”
”ФормаСписка”
Содержит графы Дата, Время, Документ и Номер
Структуру метаданных перечислений представим на примере введенного нами
в разд. 7.3.3 перечисления ВР2:
- Перечисление
- Идентификатор
- Синоним
- Комментарий
- Значение
- Идентификатор
- Комментарий
- Представление
- Значение
- Идентификатор
- Комментарий
- Представление
”ВР_2”
”Выбор расчета”
”Документы, вводящие расчеты с разными ВР” ”НачСальдо”
"Расчеты с ВР НачСальдо_2”
”Начальное сальдо”
”Табель”
"Расчеты с ВР Оклад_2, НДФЛ2 и ВБанк_2” "Расчеты Оклад/Тариф, НДФЛ и ВБанк”
- Значение
- Идентификатор "Премия"
- Комментарий "ПремияКоэф_2, ПремияСум_2 и Премия 1234_2"
-Представление "Премия коэффициентом, суммой и 1234"
Метаданные для журнала Зарплата_2:
- ЖурналРасчетов
- Идентификатор
- Синоним
- Комментарий
- ОсновнойСправочник
- ОсновнаяФорма
- ОсновнаяФормаДляВыбора
- РазмерПериода
- ДатаОтсчета
- ДлинаРезультата
- ТочностьРезультата
- ТипГрафОтбора
- Реквизит
- Идентификатор
- Синоним
- Комментарий
- Тип -Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- Реквизит
- Идентификатор
- Синоним
- Комментарий
- Тип
- Вид
- Длина
- Точность
- Неотрицательный
- РазделятьТриады
- Реквизит
- Идентификатор
- Синоним
- Комментарий
- Тип -Вид
. -Длина
- Точность
- Неотрицательный
- РазделятьТриады
- ФормаСписка
- Идентификатор
- Синоним
- Комментарий
"Зарплата_2"
Журнал заработной платы"
'Расчеты сотрудников из справочника Сотрудники_2" "Справочник. Сотрудники_2"
"ЖурналРасчетов.Зарплата_2. Форма.ФормаСписка" "ЖурналРасчетов.Зар плата_2. Форма. ФормаСписка" Месяц"
"20010101"
"10"
"2"
НаКонецПериода"
"всегоЧасов"
Отработанные часы"
'Число часов, отработанных сотрудником в РП"
"Число"
’5"
1"
1"
"0"
"хозОп"
"Хозоперация"
"Введена для бухучета зарплаты"
"Справочник"
"ХозяйственнаяОперация"
"0"
"0"
"0"
"0"
"строкаДок"
"Номер строки документа"
’Номер строки документа, породившего расчет" "Число"
"5"
"0"
"0"
"0"
"ФормаСписка"
’Данные расчета помещаются в одной строке"
Относительно правил перерасчета метаданные сообщают следующее (на примере правила перерасчета Премия 12342):
- ПравилоПерерасчета
- Идентификатор -Синоним
- Комментарий
- ТипПравила
- КоличествоПериодов
- ВедушийВидРасчета
- ПодчиненныйВидРасчета
"Премия1234_2"
"Правило перерасчета Премия 1234_2" "Правило для премии 1234" "СледующийПериод"
" 1"
"ВидРасчета.Оклад_2"
"ВидРасчета. ПремияКоэф_2" "ВидРасчета. ПремияСум_2"
"ВидРасчета.Премия1234_2"
Виды расчетов представляются следующими метаданными:
- ВидРасчета
- Идентификатор
- Синоним
- Комментарий
- Очередность
- ВытесняетВидРасчета
- ВытесняетсяВидомРасчета
- ГруппаРасчетов
Группы ВР описываются так:
- ГруппаРасчетов
- Идентификатор
- Синоним
- Комментарий
- ВидРасчета
'ПремияКоэф_2"
'Премия коэффициентом"
"Премия, зависящая от отработанного времени" "5"
"ВидРасчета. ПремияКоэф_2"
"ВидРасчета. ПремияКоэф_2" "ВидРасчета.ПремияСум_2"
"ГруппаРасчетов.ВсеНачисления_2"
'ВсеНачисления_2"
'Все начисления"
"Для сотрудников из справочника Сотрудники_2"
ВидРасчета.Оклад_2"
'ВидРасчета.ПремияКоэф_2"
'ВидРасчета.ПремияСум_2"
'ВидРасчета.Премия1234_2"
Распечатки подобного рода лицу, сопровождающему систему, полезно иметь в пределах досягаемости, например для анализа структур объектов с целью их последующего усовершенствования.
Используя приведенные сведения, вы сможете прочитать и употребить по назначению необходимые значения свойств объектов. Изменить значения подавляющего большинства метаданных можно, лишь находясь в конфигурации, в интерактивном режиме. Исключение составляют правила перерасчета: отражаемые в метаданных свойства правил можно редактировать соответствующими методами (разд. 7.16).
ПРИЛОЖЕНИЕ 2. ИНСТРУКЦИЯ ПО РАБОТЕ С ДИСКЕТОЙ
Прилагаемая к пособию дискета содержит архивный файл lSConfig.zip, включающий файлы информационной базы и файлы внешних обработок в папке ExtForms.
Кроме того, в папке DBF вы найдете файлы bal.dbf и bal.cdx, которые мы использовали для загрузки начального сальдо (разд. 7.4.6.), а также файлы employee.dbf, employee.cdx и salary.dbf, salary.cdx, в которые мы сбросили данные справочника Со-трудники_2 (разд. 9.3.1).
Папка ТХТ содержит текстовые файлы, загружаемые из модулей созданных нами объектов: обработок, справочников, журналов и документов. Для загрузки в модуле объекта используется, например, такая команда (разд. 1.11):
#ЗагрузитьИзФайла d:\l с?77\Тс8І\ТХТ\измОклМ
При необходимости код из текстовых файлов можно перенести в модули соответствующих объектов.
В папку BMP помещен файл p.bmp, содержащий последовательность пиктограмм для таблицы значений (см. пример 8 из разд. 3.4.4).
В директорию USRDEF записаны сведения о зарегистрированных пользователях (разд. 1.3).
Порядок использования дискеты таков:
1) в папке 1CV77, содержащей систему 1С:Предприятие версии 7.7, создайте директорию Test;
2) скопируйте с дискеты файл lSConfig.zip и извлеките из него имеющиеся в нем данные, используя опции архиватора WinZip, представленные на рис. П-2.1.
 |
|
Рис. П-2.1. Извлекаем архивные файлы |
3) убедитесь, что в папке Test есть директории ExtForms, DBF, TXT, BMP и USRDEF; при отсутствии повторите процедуру разархивации;
4) загружая 1С, зарегистрируйте информационную базу (рис. П-2.2);

Рис. П-2.2. Первая загрузка 1С с новой информационной базой
5) при авторизации доступа выбирается имя пользователя Ученик; пароль отсутствует;
6) в загруженной системе доступны все представленные в книге объекты.
В пособии примеры, сопровождающие новый материал, запускались из обработки Проба, которая модифицировалась в соответствии с решаемой задачей. Читателю, начинающему изучение языка, полезно самостоятельно выполнить необходимые для запуска примеров действия. В то же время для оперативного запуска примеров в папке ExtForms читатель найдет обработки, содержащие эти примеры. При этом программы, не использующие переменные диалога (за исключением указанных ниже процедур), размещены в обработке Проба. Все программы, кроме одной, предназначенной для исполнения, должны быть закомментированы. (Напомним, что для управления комментарием в 1С имеются иконки // и //Х, которые работают с выделенным текстом.)
Каждая программа модуля обработки Проба начинается текстом, содержащим ссылку на раздел, откуда программа взята, например такую:
// Пример из разд. 1.4.2. ПЕРВАЯ ПРОГРАММА
В разд. 1.11 указано, что переход от одной программы к другой быстрее выполнить, если все программы разместить в текстовом файле, загружаемом в обработку командой
#ЗагрузитьИзФайла d:\lcv77\Test\TXT\npoбa.txt
Эта возможность реализована в обработке Проба. Поэтому нет необходимости открывать ее в конфигураторе, а достаточно выполнить надлежащие изменения в файле пpoбa.txt, открыв его в 1 С: Предприятии. Напомним, что .изменения возымеют эффект после их записи на диск и повторного вызова обработки, для чего у нас есть соответствующий пункт меню или ускоритель Alt+1.
В файл Пробам не включен ряд программ, изменяющих состояние системы. Например, в нем нет процедуры из разд. 7.2, выполняющей смену расчетного периода, процедур из разд. 7.4.5 удаления записей ЖЗ и мягкой смены расчетного периода, процедур и функций из разд. 7.4.6, выполняющих загрузку начального сальдо из DBF-файла, и т. д.
Замечание. Из-за большого числа строк в файле пpoбa.txt его компиляция может занять продолжительное время. Его можно уменьшить либо разбив файл на несколько частей, либо удалив не представляющий интереса код.
Отдельно в обработке Проба_1.ег1; размещена процедура Выполнить из разд. 5.12.2, Демонстрирующая общие методы справочников.
Примеры, использующие помимо кнопок Пуск и Закрыть иные элементы диалога, демонстрируются обработками, список которых представлен в табл. П-2.1.
Таблица П-2.1
|
Обработки для примеров пособия |
Имя
обработки |
Что демонстрирует |
|
Проба.ет! |
Большинство программ, не использующих переменные диалога.
Запускает из меню интерфейса Ученик в результате выбора Проба -Пуск или Alt+1 |
|
Проба_1.ет1 |
Общие методы справочников (процедура Выполнить из разд. 5.12.2) |
|
Проба_2.м1 |
Пример из разд. 1.5. Диалог с числовым полем приведен на рис. 1.20 |
|
Проба_3.ет1 |
Список непериодических констант в таблице значений (пример из разд. 1.8) |
|
Проба_4.м1 |
Отчет со списком непериодических констант (пример из разд. 1.9) |
|
Открыть.м! |
Пример из разд. 1.12. Запускает из меню интерфейса Ученик в результате выбора Проба - Открыть или Alt+5 |
Открыть_2.сг1,
Проба_5.ет1 |
Контекст обработки Проба_5, загружаемой из обработки Открыть_2. Модифицированный пример из разд. 1.13 |
|
Проба_6.eгt |
Список значений как элемент диалога (пример из разд. 3.3.4) |
|
Проба_7хЛ |
Редактирование таблицы значений в диалоге (пример из разд. 3.4.2) |
|
Проба_8.сг1 |
Использование пиктограмм в таблице значений (пример 8 из разд. 3.4.4) |
|
Проба_9.eгt |
Отчет о сотрудниках по справочнику Сотрудники_2 (пример из разд. 5.11.1) |
|
Проба_10.eгt |
Тот же отчет, что и в npo6a_9.ert, но с запросом (пример из разд. 5.11.2) |
|
Проба_11.eгt |
Данные запроса о суммарных результатах по хозяйственным операциям (программа из разд. 7.17.4.) |
|
Проба_12.eгt |
То же, но с выводом данных о составе групп (программа из разд. 7.17.4) |
|
Проба_13.eгt |
Данные о суммарных результатах по хозяйственным операциям возвращаются не запросом, а функцией сумХозОп2 (программа из разд. 7.17.4) |
|
Проба_14.eгt |
Процедуры и функции из разд. 9.3.1.2 переноса данных 1С а DBF-файлы |
|
Проба_15.ет1 |
Вывод произвольного DBF-файла в таблицу значений (пример 6 из разд. 9.3.2.2) |
|
|
Замечания: |
1. Обработку из табл. П-2.1 будет проще открыть, если в меню интерфейса Ученик выбрать Проба - Открыть или использовать Al1+5 и затем работать с приведенным на рис. П-2.3 диалогом.
 |
|
Рис. П-2.3. Диалог формы, открывающей обработку |
2. В некоторых примерах есть ссылки на удаленные объекты (например, в примере из разд. 2.5 есть ссылка на справочник Сотрудники, который затем был заменен на справочник Сотрудники_2; это связано с тем, что написание этих примеров предшествовало устранению объектов из конфигурации - такова логика создания пособия). Чтобы восстановить работоспособность программ, в ссылках на справочник имя Сотрудники заменяется на имя Сотрудники_2, имя Зарплата - на Зар-плата_2 и т. д.
ЛИТЕРАТУРА
1. 1С:Предприятие 7.7. Описание встроенного языка: В 2 ч. Номер издания 77.001.03, 1999.909 с.
2. Агафонова М. Ю. и др. Большой экономический словарь / Под ред. А. Н. Азрилияна. М.: Институт новой экономики, 1997. 864 с.
3. Бартеньев О. В. Современный Фортран. М.: Диалог-МИФИ, 2000. 448 с.
4. Он же. Фортран для профессионалов. Математическая библиотека IMSL: Ч. 1. М.: Диалог-МИФИ, 2000. 448 с.
5. Майерс Г. Искусство тестирования программ. М.: Финансы и статистика, 1982.176 с.
6. Ленгсам Й., Огенстайн М., Тененбаум А. Структуры данных д ля персональных ЭВМ. М.: Мир, 1989. 568 с.
7. Любимский Э. 3., Мартынюк В. В., Трифонов Н. П. Программирование. М.: Наука, 1980. 608 с.
8. Microsoft Visual FoxPro. Developer's Guide. Microsoft Corporation, 1995. 496 p.
Бартеньев О. В. - 1С Предприятие программирование для всех
Рассматриваются элементы встроенного языка.программирования 1С:Предприятие и методы написания программ на этом языке. Также на примере компонента Расчеты демонстрируется технология построения заказных, использующих модели 1С оптимальных систем. В качестве критериев оптимизации выступают быстродействие, надежность программ, уровень защищенности данных и др. Дополнительно приводятся справочные сведения об использованных в пособии объектах 1С и их методах. Включенные в пособие примеры программ и компоненты предложенной облегченной версии системы размещены на дискете, которую можно приобрести в издательстве. Этот же материал находится в Интернете на сервере издательства (.
Предназначено для всех лиц, желающих освоить или усовершенствовать технику разработки программ на основе моделей 1С:Предприятие, а также для руководящих работников, имеющих потребность расширить свои знания относительно характера и способов построения систем автоматизации деятельности административно-хозяйственных подразделений организаций различного профиля.
Учебно-справочное издание Бартеньев Олег Васильевич
1С:Предприятие: программирование для всех
Базовые объекты и расчеты на одной дискете
ПРЕДИСЛОВИЕ
Широкое распространение системы 1 С: Предприятие (далее вместо длинного названия "Система 1С:Предприятие" будем, где это возможно, употреблять более короткие названия 1С и система) вызывает к жизни разнообразную литературу, освещающую различные стороны программы. Имеющаяся на прилавках магазинов литература содержит преимущественно сведения для пользователей системы - работников бухгалтерии, отделов снабжения, сбыта и иных административно-хозяйственных подразделений предприятия.
Однако для функционирования системы одних пользователей недостаточно: с системой должен постоянно работать ее сопровождающий специалист, имеющий обширный круг обязанностей как по администрированию программы, так и по ее усовершенствованию.
Возможно, вы хотите приобрести такие навыки - тогда эта книга для вас. Возможно, вы озабочены поиском такого специалиста, тогда в этой книге есть ответ на вопрос, какими профессиональными навыками должен обладать подбираемый вами работник. Если же вы реализуете средствами 1С некоторый проект, вам тоже полезна эта книга, поскольку всегда не будет лишним сопоставить различные подходы и постараться выбрать в результате наилучший.
В книге решаются, по сути, три задачи. Первая - оснастить лиц, желающих научиться писать программы в 1С, необходимыми приемами и сведениями. Вторая - рассмотреть оптимизационный подход к построению или модификации системы и, реализуя его, решать первую задачу. И третья - снабдить ответственных лиц информацией об объеме и характере проблем, которые приходится улаживать при настройке системы и ее сопровождении.
Характер изложения таков, что после описания базовых понятий раскрываются этапы реализации облегченной системы расчета зарплаты на основе моделей 1С (другие задачи, например бухгалтерии, строятся на аналогичных моделях). Далее обсуждаются вопросы эффективности системы и комплекс мер по ее повышению. Попутно излагаются справочные сведения о встроенном языке программирования системы 1С:Предприятие 7.7.
На вопрос, зачем взамен поставляемых фирмой средств разрабатывать альтернативы, ответ известен. Практически на любом предприятии при внедрении системы стоят задачи ее адаптации и оптимизации, собственно для решения которых и приспособлен встроенный язык программирования 1С.
Как правило, предприятие, внедряющее систему, по причине недостаточной подготовки персонала возлагает решение этих задач на сторонних лиц и организации -так называемые франчайзи* (партнеры) 1С. Иногда это экономически обременительно (час работы представителя партнера оценивается в 20-30 у. е.). Поэтому зачастую шаги
Франчайз, или франшиза, - это право на создание коммерческого предприятия и на торговлю продукцией старшего партнера. Франчайзи, или франшизы, - это лицо или организация, покупающие франчайз (франшизу).
по настройке программы являются половинчатыми и система не выходит на соответствующий ее возможностям уровень функционирования.
Согласитесь, что во многих случаях выгоднее иметь в штате специалиста (или двух), сопровождающего систему, знающего ее особенности и понимающего задачи ее развития, чем полагаться на структуры массового обслуживания. С выходом этой книги подготовка таких специалистов упростится, а их число увеличится. По существу, при надлежащем прилежании им может стать любой имеющий склонность к программированию сотрудник предприятия, привлекаемый руководством к внедрению и сопровождению системы.
Включенные в пособие примеры программ и компоненты предложенной облегченной версии системы размещены на дискете, которую можно приобрести в издательстве. Этот же материал находится в Интернете на сервере издательства . Эта дискета позволит вам посмотреть в работе представленные в пособии объекты, отдельные обработки, а также реализованную облегченную версию конфигурации системы. Это станет возможным (если вам доступна программа 1С:Предприятие версии 7.7) сразу после выполнения изложенных в прил. 2 инструкций.
1. НАЧАЛЬНЫЕ СВЕДЕНИЯ
1.1. ВВЕДЕНИЕ
Система 1С:Предприятие, версии 7.7 эксплуатируется на большом числе российских предприятий. Комплексная поставка включает следующие компоненты: Бухгалтерия, Торговля, Склад, Заработная плата, Кадры, Услуги и Производство. Субъекты хозяйственной деятельности (предприятия, фирмы и др.) нередко используют часть возможностей системы, например подсистему Бухгалтерия, или Торговля и Склад, или Зарплата и Кадры. Такие подсистемы в 1С называются конфигурациями.
Приспособление системы к потребностям предприятия осуществляется средствами встроенного языка программирования, первые шаги по освоению которого делаются в этой главе.
Встроенный язык программирования 1С оперирует большим числом сложных объектов (около 30), предлагая для них исчерпывающий набор методов и предопределенных процедур. По существу, освоение языка и состоит в изучении этих объектов и приобретении навыков их употребления в алгоритмах и реализующих их программах. Однако подойти к этой цели мы сможем, лишь пройдя необходимые этапы освоения языка.
На первом этапе мы научимся запускать тривиальные программы. На втором. -вкладывать в эти программы некоторый смысл. На третьем - оснащать их базовыми конструкциями языка, с пониманием строить числовые, символьные, логические выражения и выражения с датами, употребляя в них имеющиеся в языке операции и встроенные функции. И так далее.
И тогда любой имеющий тягу к программированию пользователь познает язык системы, что пойдет на благо как ему самому, так и организации, в которой он служит.
Для освоения материала читателю не требуется иметь специальных навыков программирования, а достаточно обладать знаниями в пределах школьного курса информатики или первого курса высшего учебного заведения. Это обусловлено тем, что изложение предмета носит, как правило, неформальный характер, строится по принципу от простого к сложному и иллюстрируется большим числом примеров.
1.2. ИНТЕРФЕЙС УЧЕНИК
Создадим для учебных целей простой, не обремененный избыточными кнопками и пунктами меню пользовательский интерфейс, дав ему имя Ученик. Запустим для этого систему в режиме Конфигуратор и выберем некоторую информационную базу, например Расчет зарплаты и кадровый учет (рис. 1.1), или любую иную.
Запуск 1C: Предприятия
Отмена
& 1 С:Предлриягис
^конфигурация Іная комФигурацГ
Пометить
Отладчик
ф Монитор
Добавить
комплексная конфигурация [демо) Конфигурация 'Т оргоеля+Склад" КонФи-урация "Т ортов ля» Склад" Демо ПроизеооствотУслуги+Бухгалгерия . Произесиство+УслчгитБчхгалгерия [демс
Удалить
Помощь
D:\1Cv77\Test\
Рис. 1.1. Запуск системы
Откроем после запуска системы ее конфигурацию, выбрав пункты меню Конфигурация - Открыть конфигурацию (рис. 1.2).
 |
|
Рис. 1.2. Открываем конфигурацию системы |
В отобразившемся окне выберем закладку Интерфейсы. Ударим по правой кнопке мыши и в появившемся меню выберем пункт Новый интерфейс (рис. 1.3).
 |
|
Рис. 1.3. Ввод нового интерфейса |
В окне Свойства пользовательского интерфейса в поле Название введем слово Ученик и отключим меню Операции (рис. 1.4).
 |
|
Рис. 1.4. Задание основных свойств интерфейса |
Нажав на кнопку ОК, получим окно, содержащее интерфейс Ученик (рис. 1.5).
ej Конфигурация *
Настройка
П олный
^Метаданные 1 ? Интерфейсы Права I
Рис. 1.5. Закладка с интерфейсом Ученик
Добавим теперь в меню интерфейса Ученик колонку Проба. Разместим для этого на элементе Ученик курсор, нажмем правую кнопку мыши или дважды ударим по ее левой кнопке и выберем в появившемся списке возможностей пункт Редактировать меню. В появившемся окне разместим курсор на элементе Ученик, задействуем правую кнопку мыши и в раскрывшемся списке выберем пункт Свойства (рис. 1.6, а). В окне задания свойств в поле Название введем имя Проба (рис. 1.6, б) и нажмем на кнопку ОК.
 |
|
Рис. 1.6. Изменение имени колонки меню: а - вызов окна ввода свойств колонки меню; б - общие свойства колонки |
Вставим далее в колонку Проба меню интерфейса Ученик пункт Пуск. Ударим для этого мышью по крестику, расположенному перед элементом Проба, разместим курсор на пункте <новый...> и вновь приведем в действие правую кнопку мыши. В появившемся списке выберем пункт Свойства (рис. 1.7, а) и в поля окна задания свойств введем указанные на рис. 1.7, б значения.
I воиства элемента меню
Удалить is; конструктор..
Проба
uUl* I
Акселератор
Параметры
< новая колонка . >
Івст...
I Комета
аэеани?
шт
)k Вырезать
Овьжт.
Отчеты
Щ ^помнить
|0т
Открытье ИММИЙ
era
;алип
I Открывает учебную обребегг
I. ос сказка
[ ЁОЙС П I
а б
Рис. 1.7. Добавление пункта Пуск:
а - вызов окна ввода свойств элемента меню; б - общие свойства элемента
Замечание. Для задания объекта Отчет достаточно разместить курсор на поле Объект и нажать на клавиатуре на русскую букву О (строчную или прописную).
На следующем шаге выберем закладку Акселератор, нажмем на кнопку Выбрать акселератор и задействуем сочетание клавиш, например Alt+1, которое затем будем использовать для вызова связанного с пунктом меню Пуск файла.
После нажатия на кнопку ОК просмотрим созданное меню, нажав на правую кнопки мыши и выбрав пункт Тест. Результат тестирования приведем на рис. 1.8.
 |
|
Рис. 1.8. Просмотр меню интерфейса Ученик |
Замечание. На самом деле в соответствии с рис. 1.4 колонка Операции при использовании интерфейса Ученик в 1С:Предприятии будет отсутствовать.
Имя файла, который будет связан с пунктом меню Пуск, зададим несколько позже.
1.3. ПОЛЬЗОВАТЕЛЬ ПО ИМЕНИ УЧЕНИК
Чтобы создать такого пользователя, выберем пункты меню Администрирование -Пользователь и в появившемся окне (рис. 1.9), нажав на правую клавишу мыши, выберем пункт Новый и зададим в окне свойств атрибуты (рис. 1.10, а) И роль (рис. 1.10, б) пользователя.
- Атрибуты]] Роль I Имя;
Полное имя Еебочий каталог
Атрибуты Роль I Права. [ПолныеПрава
Интерфейс; [Ученик
Г” Отключить контроль прав

[Учёнйі
[Николаев Н А [DAI Cv77\T esf
3]
31
|
I #'» Пользователи |
|
J а т t |
fil (? Н: !й |
|
|
Имя |
1 Полное |
1 Роль (Праве. Интерфейс! |
|
1 fa Адкмшс’-ратзр |
Адмпкютратор |
ПолныеПрава, Полный |
|
|
Рис. 1.9. Список пользователей |
а б
Рис. 1.10. Характеристики пользователя Ученик: а - атрибуты; б - роль Замечания:
1. В поле Рабочий каталог рис. 1.10, а установлен путь к папке, содержащей информационную базу данных системы.
2. Вопросы задания прав доступа пользователей рассматриваются в разд. 8,5. Пока что установим пользователю Ученик полные права (рис. 1.10, б).
При необходимости для пользователя Ученик в окне, изображенном на рис. 1.9, можно установить пароль, который придется вводить при входе в систему. Для задания или смены пароля воспользуйтесь иконкой с изображением замка -it
или нажмите
на правую кнопку мыши и выверите пункт изменить пароль. Введенные данные, разумеется, надо сохранить.
Теперь при входе в систему нам нужно будет выбирать пользователя с именем Ученик и вводить пароль, если он задан (рис. 1.11).
 |
Рис. 1.11. Вход в систему
Добавим, что при желании на закладке Права интерфейса Ученик (см. рис. 1.5) можно в набор прав включить новый элемент, например права Ученика, и задать соответствующие права, отличающиеся от установленных нами, а затем установить эти права нашему пользователю на закладке Роль, приведенной на рис. 1.10, б. |
1.4. ОБРАБОТКА ПО ИМЕНИ ПРОБА
1.4.1. ДИАЛОГ ОБРАБОТКИ
Обработкой называется программа, запускаемая в результате ее вызова из некоторой экранной формы.
Под формой в общем случае понимается совокупность следующих компонентов:
• диалога формы;
• модуля формы;
• таблиц формы (по умолчанию в форме задана одна таблица);
• описания формы.
Доступ к компонентам формы осуществляется в результате выбора соответствующей закладки в окне создания и редактирования формы (рис. 1.12).
 |
|
Рис. 1.12. Закладки окна создания и редактирования формы |
Для наших учебных целей мы создадим внешнюю обработку, назвав ее Проба, и будем размещать в ней наши программы. Доступ к обработке обеспечим из пункте .меню Пуск (рис. 1.8). Также обработка может быть вызвана в результате набора сочетания клавиш Alt+1, если для пункта меню Пуск задан такой акселератор (механизм задания акселератора описан выше).
Создание обработки выполним в конфигураторе, выбрав пункт меню Новый отчет колонки Конструкторы (специального конструктора обработок в 1С не предусмотрено). Затем активизируем кнопку Внешний отчет и зададим имя файла обработки, использовав расширение ERT (рис. 1.13).
 |
|
Рис. 1.13. Задание внешней обработки |
Заметим, что внешние отчеты и обработки система предлагает сохранить в папке ExtForms (внешние формы).
Нажмем, не производя иных действий, дважды на кнопку Далее и в конце на кнопку Готово. В появившемся окне Внешний отчет (обработка) - npoбa.ert, оставаясь на закладке Диалог, во-первых, полностью раскроем окно, во-вторых, захватив мышью нижний правый угол диалога, уменьшим его размеры и, в-третьих, перенесем кнопки Сформировать и Закрыть в центр преобразованного диалога (рис. 1.14, а).


а
б
Рис. 1.14. Диалог обработки Проба:
а - заданные по умолчанию кнопки; б - кнопки диалога после их редактирования
Для выполнения последних действий следует нажать левую кнопку мыши и заключить при помощи мыши, не отпуская кнопку, названные элементы диалога в прямоугольную область. Затем отпустить нажатую кнопку мыши, переместить мышь в некоторую точку выделенной области и вновь, задействовав левую кнопку мыши, переместить теперь уже выделенную область в требуемое место.
Произведем теперь действия, которые, в общем-то, не нужны для запуска обработки, но полезны для приобретения навыков по редактирования диалогов.
Присвоим левой кнопке диалога имя Пуск, установив на ней мышь, ударив вслед по ее правой кнопке, выбрав в появившемся меню пункт Свойства и введя в поле Заголовок текст Пуск (рис. 1.15, а).
Общие I Дополжтельно | Команда | Картинка | Огнсани 0вшив [Допо*ыгвльно| Каната | Карттіа | Описате | Заголовок; |Пусж Уденгифкжаггор: Г
Формула |Вьполнить()
Г Пропускать три вводе
Г Сделать нецоступтан П Сделать ввеищаими
Г Затреплъ р'ДЭ'гпі'.ееч.і?
а б
Рис. 1.15. Задание свойств элемента диалога: а - общих; б - дополнительных
Откроем затем закладку Дополнительно и в поле Формула взамен текста Сформировать ) разместим текст Выполнить( ) (рис. 1.15, б). Это изменение означает, что после нажатия на кнопку Пуск будет запускаться процедура обработки под именем Выполнить (если таковая определена в модуле обработки). На закладке Описание введем текст Запуск учебной программы. Чтобы использовать этот текст в качестве подсказки, проставим флажок Использовать описание (рис. 1.16) и сохраним, нажав наОК, изменения.
Общие I Допо/амтельно | Команда | Картажа Огмсамне
 |
Подсказке- f" ^слользомтъ описание) Р7
Рис. 1.16. Описание и подсказ.л элемента диалога |
, расположенную на панели
Приведем диалог к виду, представленному т. рис. 1.14. б, употребив для центрирования по горизонтали кнопок Пуск и Закрыть иконку *Ф*, инструментов Редактор диалога (рис. 1.17).
іі: :ііт7іі!Ф4-’1ні|мх®1в'
!|''з «
Рис. 1.17. Панель инструментов Редактор диалога
Для просмотра диалога можно нажать Ctrl+R или выбрать иконку 'Э на вышепри веденной панели инструментов.
Замечания:
1. Перечень имеющихся в системе панелей инструментов выводится в окне рис. 1.18, а, отображаемом после выбора пункта меню Панели инструментов в колонке Сервис.
|
Пам<м имстр^ноктое I МшиФжация 1 Доі»л«ге<ы«>ів |
Панели инструментов Модификация 1 Дополнительные |
|
Панели инструментов |
Р Показ подсказок Р Плоские КИОЖН |
|
Категории |
Киогки —- |
|
|
? Стандартная
Редактор таб/чі у Т «кетовый редактор |
|
Стандартная
Редактор твбг?щ
Т екстоеый редактор |
? Я ГШ Ф + ИIHIfflв |
|
|
у Редактор диалогов у Элементы диалога у Конфигурация уАдг*+«4стрированис |
|
|
Э леменгы диалога
Конфигурация
Администримвание |
S в |
|
|
|
|
|
Комстр^сгоры |
|
а б
Рис. 1.18. Панели инструментов: а - выбор отображаемых панелей; б - настройка панелей
2. Рассматривая компоненты системы, мы не будем без необходимости подробно останавливаться на всех их возможностях. Так, в случае панели инструментов Редактор диалога мы обратили внимание на две его иконки: Ф и та. ных иконок этой панели легко понять, испытав их воздействие на выделенные элементы диалога и их группы или обратившись к закладке Модификация окна управления панелями инструментов (рис. 1.18,6).
Не забудем связать файл Пробам с пунктом меню Пуск колонки Проба из меню интерфейса Ученик. Для этого откроем конфигурацию, выберем закладку Интерфейсы, в ней перейдем на интерфейс Ученик, вызовем редактор меню, дойдем до элемента Пуск и дважды ударим по нему мышью. Выберем в появившемся окне закладку Параметры и определим в ней полное имя файла, связанного с пунктом меню Пуск (рис. 1.19). Заметим, что имя файла можно задать, указав в нем путь относительно каталога с базами данных.
|
Общие Параметры | Акселератор | |
|
|
Введите имя файла: |
|
|
1D :\1 Cv77 VTest \Е xtFotmsUl роба ert |
? |
|
Р Открывать Форму модально |
|
|
|
Рис. 1.19. Ввод имени файла |
Сохраним измененную конфигурацию. При этом система 1C: Предприятие должна быть закрыта.
1.4.2. ПЕРВАЯ ПРОГРАММА
Перейдем на закладку Модуль (см. рис. 1.12). На этой закладке располагаются программы, выполняющие обработку.
В нашей первой программе мы объявим одну числовую переменную, присвоим ей некоторое значение и выведем его в окно сообщений.
Здесь следует отметить, что программы (диалоги, таблицы) создаются в конфигураторе системы, запустить их на выполнение в конфигураторе нет возможности (можно, правда, проверить программу на наличие синтаксических ошибок, выбирая иконку
на панели инструментов Текстовый редактор). Для запуска обработки потребуется вызвать 1С:Предприятие, нажав, например, на иконку или клавишу F11.
Итак, перейдя на закладку Модуль, мы обнаружим там следующую заготовку:
процедура Сформировать( ) конецПроцедуры
Поскольку в диалоге на закладке Дополнительно текст Сформировать( ) был заменен на текст Выполнить( ), то те же изменения произведем и в имеющейся заготовке, затем добавим код, выполняющий ранее намеченные действия. Все пояснения будем размещать в создаваемом коде в виде комментария, который располагается после символов //.
процедура Выполнить( ) // Выполнить - имя процедуры
перем а; // Объявляем локальную переменную с именем а
а = 5.1; // = - знак оператора присваивания
Сообщить(а); // Выводим значение переменной а в окно сообщений
конецПроцедуры // Выполнить (комментарий с именем законченной процедуры)
Замечание. Запись
а= 5.1;
является оператором присваивания. В результате его выполнения переменная а получит значение 5.1. В общем случае оператор присваивания имеет следующий вид:
имяПеременной = выражение; // Завершаем оператор присваивания точкой с запятой
Также операторами в приведенной процедуре являются неисполняемый оператор объявления переменной а:
перем а; // Объявляем локальную переменную с именем а
и исполняемый оператор вызова встроенной процедуры:
Сообщить(а); // Выводим значение переменной а в окно сообщений
Операторы, если они не являются составными элементами конструкции, например конструкции "если - то - иначе", завершаются точкой с запятой.
Выполним проверку синтаксиса программы и, убедившись в ее корректности, сох-храним обработку, нажав Ctrl+S или воспользовавшись пунктом меню Сохранить колонки Файл.
Откроем описанным выше способом 1С:Предприятие и в появившемся меню найдем колонку Проба и ее пункт Пуск или воспользуемся для вызова обработки Проба сочетанием клавиш Alt +1. Нажмем на кнопку Пуск и просмотрим окно сообщени В нем выведено число 5.1.
Закроем обработку Ученик.
Замечание. Имена переменных, процедур и функций в программах 1С могут с держать буквы русского и английского алфавитов (строчные и прописные), символ подчеркивания и символы цифр, например _новоеИмя_23. Имя не может начинать с цифры и содержать пробелы.
1.4.3. ОБСУЖДЕНИЕ ПЕРВОЙ ПРОГРАММЫ
Программа состоит из одной пользовательской процедуры, имеющей имя Выполнить и размещенной в модуле формы обработки. Напомним, что процедура - это выполняющий некоторые действия программный компонент, который обменивается данными с другими компонентами через свои параметры. Также в процедурах 1С могут использоваться переменные модуля, диалога и глобальные объекты данных. (В нашем случае, правда, процедура параметров не имеет и работает только с одной локальной переменной а.)
В процедуре Выполнить использована встроенная процедура Сообщить. Она выводит значение своего аргумента в окно сообщений системы. Заметим, что более информативен следующий вывод значения переменной а:
Сообщить("а =" + а);
Процедура Сообщить сработает следующим образом. Прежде числовое представление переменной а будет преобразовано в символьное (число 5.1 будет преобразовано в строку ”5.1”). Затем строка "а = " объединится со строкой "5.1" и в окне сообщений отобразится текст
а = 5.1
Отметим общие для всех программ моменты:
1. При написании программы регистр букв не имеет значения. Так, имя процедуры не изменится, если его написать прописными буквами; имена А и а задают одну и ту же переменную.
2. После каждого оператора необходимо проставлять точку с запятой.
3. В процедурах и функциях 1С можно не объявлять явно оператором Перем скалярные переменные (не массивы), а вводить переменные и определять их тип по мере необходимости. То есть оператор
перем а;
в приведенной процедуре Выполнить может быть опущен; числовая переменная а будет введена в результате выполнения оператора присваивания
а = 5.1;
4. Поскольку программы пишутся в конфигураторе, а запускаются в 1С:Предприятии, то для ускорения процесса их отладки следует держать открытыми как конфигуратор, так и 1С:Предприятие; если в 1С:Предприятии открыта старая версия программы (в нашем случае обработки), то после внесения и сохранения исправлений (это выполняется в конфигураторе) старую версию нужно закрыть и загрузить затем обновленный файл. В нашем случае для этого достаточно набрать Alt+1. (О мероприятиях по ускорению отладки см. также разд. 1.11.)
Замечание. Созданная обработка Проба находится в файле Проба.ert, и если файл по какой-либо причине закрыт, то для его загрузки в конфигураторе следует выполнить стандартные действия по открытию файла, например выбрать из списка недавно открытых файлов, имеющегося в колонке Файл меню конфигуратора.
1.4.4. МОДУЛЬ ОБРАБОТКИ ПРОБА
Процедура Выполнить принадлежит модулю обработки. Модуль обработки в общем случае может содержать следующие компоненты:
• объявления переменных модуля, которые доступны в любом его программном компоненте;
• процедуры, в том числе и предопределенные, и функции, созданные пользователем;
• операторы основной программы модуля, следующие за его процедурами и функциями; основная программа выполняется один раз при загрузке модуля.
Запишем в качестве примера в модуле обработки код, содержащий объявление переменной модуля а, пользовательскую процедуру Выполнить и основную программу из одного оператора.
// Объявляем переменную модуля обработки
// Она может быть использована в любой процедуре (функции) модуля // и его основной программе перем а;
Сообщить("Сумма а и б равна " + (а + конецПроцедуры // Выполнить
Выполнить - имя процедуры Локальная переменная процедуры Выполнить Выводим значение переменной а в окно сообщений Определяем значение локальной переменной б б));
// Основная программа модуля состоит из одного оператора
а = 5.1; // Определяем значение переменной модуля
После загрузки и запуска обработки в 1С: Предприятие в окне сообщений выведутся две следующие строки: а=5.1
Сумма а и б равна 9.3
Замечания:
1. Нельзя изменить использованный порядок следования компонентов модуля То есть ошибочен, например, код
Объявляем переменную модуля
//
перем а;
// Основная программа модуля; такое ее расположение в модуле ошибочно а = 5.1; // Определяем значение переменной модуля
Сообщить("Сумма а и б равна " конецПроцедуры // Выполнить
Связана с кнопкой Пуск обработки Проба Локальная переменная процедуры Выполнить Выводим значение переменной а в окно сообщений Определяем значение локальной переменной б + (а + б));
2. Если употребить вызов
Сообщшъ("Сумма а и б равна " + а + б); // а + б без круглых скобок
то в окне сообщений появится текст
а=5.1
Сумма а и б равна 5.14.2
То есть без круглых скобок в символьное представление преобразовываются по отдельности переменные а и б, а не их сумма.
3. Если убрать объявление переменной модуля а, то переменная а основной программы станет локальной (область ее действия будет распространяться только на основную программу) и, следовательно, недоступной в процедуре Выполнить, написанная программа окажется неработоспособной.
Процедура Выполнить вызывается при нажатии кнопки Пуск диалога обработки Проба (см. рис. 1.14, б). В общем случае процедура модуля может быть вызвана как из диалога, так и из иного программного компонента модуля, в том числе и из его основной программы. Например, после загрузки обработки, в модуле которой содержится код
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
б = 4.2; // Определяем значение локальной переменной б
Сообщить("б = " + б); конецПроцедуры // Выполнить
// Основная программа модуля
ОчиститьОкноСообщений( ); // Очищаем окно сообщений
а = 5.1; // Определяем значение локальной переменной а
Сообщить("а = " + а);
// Процедура Выполнить будет вызвана из основной программы при загрузке обработки Проба Выполнить(); // Конец основной программы
сразу будет исполнен код основной программы и, следовательно, процедуры Выполнить, в результате чего в окне сообщений появится текст
а = 5.1 б = 4.2
Последующие нажатия на кнопку Пуск также будут приводить к вызову процедуры Выполнить и, следовательно, добавлять в окно сообщений строку
б = 4.2
Код основной программы модуля для исполнения более недоступен.
Заметим, что допускаются рекурсивные вызовы процедур, то есть вызовы, в которых процедура вызывает сама себя.
Приведем теперь пример пользовательской функции модуля. Напомним, что функция - это программный компонент, возвращающий значение и вызываемый из выражения, которое это значение использует. Например, в операторе
у = 2 * Лог(3.4); // Лог - встроенная функция
использована встроенная функция Лог, имеющая в качестве входного параметра положительное число и возвращающая в качестве результата числовое значение, равное натуральному логарифму параметра. Функция вызывается из выражения 2 * Лог(3.4). Разместим в модуле нашей обработки следующий код:
функция ВычислитьУ(х) // х - формальный параметр функции ВычислитьУ
у = 2 * Лог(х); // Лог - встроенная функция
// Вернем в выражение, из которого вызывается функция ВычислитьУ, значение у возврат у;
конецФункции // ВычислитьУ
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
б = ВычислитьУ(3.0); // Функция ВычислитьУ вернет 21п(3)
ОчиститьОкноСообщений(); // Очищаем окно сообщений Сообщить("б = " + б); конецПроцедуры // Выполнить
После исполнения набранного кода (для этого измененную обработку надо открыл в 1С:Предприятии и нажать на кнопку Пуск) в окне сообщений появится строка
б = 2.1972245773362
Замечание. Нельзя в теле функции объявлять ее формальные параметры. Так, ошибочен код
функция ВычислитьУ (х) // х- формальный параметр функции ВычислитьУ перем х; // Это объявление недопустимо
Функция ВычислитьУ должна быть размещена в модуле до процедуры Выполнить, из которой функция вызывается. Если вы хотите записать код функции ВычислитьУ после процедуры Выполнить, то в Начале модуля надо привести предварителъ нов описание функции ВычислитьУ, завершив его словом Далее, например:
|
функция ВычислитьУ(х) далее |
// |
Предварительное описание функции ВычислитьУ |
|
процедура Выполнить() |
// |
Код процедуры Выполнить |
|
конецПроцедуры // Выполнить |
функция ВычислитьУ (х)
конецФункции // ВычислитьУ
Замечания: |
// |
Код функции ВычислитьУ |
1. В общем случае предварительное описание определенных в модуле процедур и функций можно размещать как в начале модуля после объявления его переменных, так и между его любыми программными компонентами.
1.5. ПЕРЕМЕННЫЕ ДИАЛОГА
Переменные модуля и локальные переменные его программных компонентов объявлялись и определялись, то есть получали значения, в самом модуле. Переменные модуля доступны во всех его программных компонентах, локальные - только в том компоненте, где они были объявлены явно или неявно, появившись в левой части оператора присваивания. Кроме таких переменных, в модуле можно оперировать и переменными диалога, которые объявляются в диалоге как идентификаторы его элементов. Область действия переменных диалога распространяется на все программные компоненты модуля, то есть они имеют такой же статус, как и переменные модуля.
Замечание. У переменных диалога есть другие названия - реквизиты формы и идентификаторы элементов диалога.
Рассмотрим пример использования переменных диалога. Приведем диалог, отображенный на рис. 1.14, б, к виду, представленному на рис. 1.20, добавив в него два элемента - текст и числовое поле для ввода и редактирования данных.
 |
|
Рис. 1.20. Диалог с числовым полем |
Текст добавляется после выбора мышью иконки Г панели инструментов Элементы диалога (рис. 1.21) и позиционирования курсора на диалоговом окне в точке начала размещения текста.
 |
|
Рис. 1.21. Панель инструментов Элементы диалога |
После позиционирования курсора появится окно задания свойств текста, в котором его общие свойства определим в соответствии с рис. 1.22.
 |
|
Рис. 1.22. Общие свойства текста |
Поле ввода и редактирования данных попадет в диалог после выбора иконки панели инструментов Элементы диалога. Общие свойства поля и его тип зададим в соответствии с рис. 1.23.
т^ I Дополнительно | Описание |
I-
jyo'/OПО>С
Идентификатор: |дЧ
Обшие !
Ttfl || Допогмиге/ъно | Описание |
[<<Число>>
Г Сделать нваостугьым Г Сделать иееиоимым Г Запретить редактирование Р Сохранить при сохранен* настрой*
Ік#і
Д/*иа
Холостъ:
[б ^ Г Разделять триады
І2 ~Н Г Неотрицательный
Рис. 1.23. Свойства поля ввода и редактирования данных: а - общие свойства; б - тип поля
После вставки элементов отрегулируем их размеры и положение (для этого предварительно элемент выделяется одним ударом мыши, а затем вновь мышью модифицируются его геометрические характеристики). Для выравнивания новых элементе по левой границе предварительно выполним их выделение, а затем используем икот
і(«
!¦>* панели инструментов Редактор диалога (рис. 1.17).
С полем ввода и редактирования данных мы связали его идентификатор, которы как мы уже говорили, интерпретируется в программных компонентах модуля как переменная.
Сохраним обработку и продолжим ее редактирование. Напишем в модуле обработки код, меняющий значения переменной дЧ, добавим код процедуры ПриОткрытии и проследим поведение диалога после выполнения этой процедуры, а затем после неоднократного нажатия на кнопку Пуск.
перем а; // Переменная модуля
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
// Встроенное процедура Предупреждение выводит текст,
// переданный процедуре в качестве параметра, в окно с кнопкой ОК Предупреждение("3начение числового поля будет увеличено в 2 раза."); дЧ = дЧ * а; // Результат после загрузки и двух нажатий
конецПроцедуры // на кнопку Пуск см. на рис. 1.24
процедура ПриОткрытии()
ОчиститьОкноСообщений(); // а = 2.0; //
дЧ = 5.23; //
конецПроцедуры // ПриОткрытии
Очищаем окно сообщений
Начальное значение переменной модуля а
Начальное значение переменной диалога дЧ
 |
|
Рис. 1.24. Поле дЧ диалога обработки Проба: а - после открытия диалога; б - после двукратного нажатия на кнопку Пуск |
Замечание. Имеющаяся в коде процедура ПриОткрытии является предопределенной и выполняется, как это следует из ее названия, в момент открытия диалога. При необходимости процедуру можно вызвать и из иного программного компонента модуля, например из процедуры Выполнить. Для этого, однако, потребуется либо добавить перед процедурой Выполнить оператор предварительного описания
процедура ПриОткрытииО далее
либо разместить процедуру ПриОткрытии перед процедурой Выполнить. С диалогом обработки связаны и другие предопределенные процедуры, например ПриЗакрытии или ПриВыбореЗакладки.
Переменная диалога дЧ станет недоступной во всех программных компонентах модуля, если в модуле обработки объявить переменную модуля дЧ:
перем дЧ; // Объявляем переменную модуля
Если же такое объявление сделать в каком-нибудь программном компоненте модуля, например в процедуре Выполнить, то переменная диалога дЧ станет недоступной в этом программном компоненте. В таких случаях говорят: "Локальная переменная закрывает глобальную переменную". Таким же образом можно закрыть в процедуре или функции модуля его любую переменную. Каких-либо предупреждений о закрытии переменных компилятором не выдается.
Избежать непредвиденных закрытий переменных будет легче, если придумывать имена переменным, опираясь на некоторую систему, например начинать переменные диалога с буквы д или использовать так называемую венгерскую нотацию. В соответствии с ней имя объекта снабжается префиксом из строчных букв, указывающих его тип. Последующая часть имени раскрывает его смысл. Причем каждая часть имени, отражающая отдельный смысловой компонент, начинается с прописной буквы. Например, имя переменной сНазваниеПодразделения говорит нам не только о том, что в ней хранится, но и о том, что тип переменной является символьным.
1.6. ГЛОБАЛЬНЫЕ ИМЕНА
Имена объектов (переменных, процедур и функций), определенных в модуле обработки, доступны только в самом модуле (в модуле, например, другой обработки эти имена недоступны). Причем области действия переменных модуля и локальных переменных его программных компонентов различны, а область действия имени процедуры (функции) модуля - это программные компоненты, расположенные в модуле вслед за рассматриваемой процедурой (функцией). Чтобы распространить область действия имени процедуры (функции) на весь модуль или его часть, нужно в соответствующем месте дать предварительное описание этой процедуры (функции).
В то же время в системе существуют по-настоящему глобальные имена - это:
• имена встроенных процедур, функций, атрибутов и методов. Так, функция Текущее-
Время вернет символьное представление времени, которое показывают часы вашего
компьютера. Например:
Сообщить(ТекущееВремя()); // Вернет, например, 17:14:37
• имена системных констант, например имя РазделительСтрок;
• имена объектов, определенных в глобальном модуле системы и снабженных атрибутом Экспорт, например:
// Глобальная переменная глобального модуля;
// объявлена до начала кода процедур и функций глобального модуля Перем Вычеты Экспорт;
Функция глНомерРелиза() Экспорт // Функция глобального модуля возврат "7.70.028";
КонецФункции // глНомерРелиза
• имена метаданных, то есть имена объектов, входящих в. конфигурацию системы, например имена справочников или видов расчетов и их групп.
Замечания:
1. Чтобы просмотреть глобальный модуль, прежде, находясь в конфигураторе, следует открыть конфигурацию (Конфигурация - Открыть конфигурацию), а затем в появившейся в меню колонке Действия выбрать пункт Глобальный модуль.
2. Метаданные - это определенные в конфигурации системы данные со сложной структурой, позволяющие управлять другими, более низкого уровня данными. Например, тип Справочник.Сотрудники имеет более 20 компонентов, такие, как Идентификатор, Синоним и др., причем некоторые из компонентов типа также обладают сложной структурой. С объектами, тип которых описан в метаданных, связаны методы - процедуры и функции, позволяющие выполнять некоторые действия с объектами или его компонентами. Например:
// Создаем переменную типа Справочник.Сотрудники сСотр = СоздатьОбъект("Справочник.Сотрудники");
// Перемещаемся на элемент справочника, в котором значение реквизита // Наименование начинается с буквы А. Для позиционирования // используем метод НайтиПоНаименованию сСотр.НайтиПоНаименованию("А", 0);
// Выводим значение реквизита Наименование найденного элемента справочника // Возможный результат: Абасова Татьяна Анатольевна Сообщить(сСотр.Наименование);
Пример использования имени, определенного в глобальном модуле. Вывести в окне сообщений регистрационный номер системы.
Напишем в модуле обработки Проба простой код (взамен существующего):
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
Сообщить(глНомерРелиза( )); // Выведет сообщение, например 7.70.028
конецПроцедуры // Выполнить
сохраним изменения, загрузим обработку в 1С: Предприятие (Alt+1) и нажмем на кнопку Пуск.
Работу с метаданными продолжим в следующем разделе, рассматривая объект Константы.
1.7. КОНСТАНТЫ
1.7.1. ДОСТУП К КОНСТАНТАМ
Определяемые в конфигурации 1С константы хранят неизменяемые при расчетах и формировании документов данные, например размер минимальной заработной платы (в процессе эксплуатации системы значения подобных констант, разумеется, могут редактироваться). Значения констант располагаются в файле 1SCONST.DBF. Для внешнего представления данных с каждой записью файла связываются атрибуты и идентификатор (имя) некоторой константы, значения которых записаны в файле 1CV7.MD, хранящем конфигурацию системы. При отображении констант предусмотренным в 1С способом (команда Константы.Открыть; может быть выполнена только в главном меню системы) используются ее атрибуты Синоним и Комментарий, а также значения поля Value файла 1SCONST.DBF.
Замечание. Файл 1 SCONST.DBF содержит не только константы системы, но и другие данные, например значения периодических атрибутов справочников.
Чтобы иметь возможность просматривать и редактировать константы, добавим, находясь в конфигураторе, в меню интерфейса Ученик колонку Справочники, а в этой колонке создадим пункт Константы, имеющий приведенные на рис. 1.25 общие свойства.
 |
|
Рис. 1.25. Общие свойства пункта меню Константы Загрузим далее 1С:Предприятие и откроем список констант (рис. 1.26). |
 |
|
Рис. 1.26. Фрагмент списка констант |
Для изменения значения кэнстанты необходимо дважды ударить мышью по соответствующему полю последнего столбца, ввести данные и нажать на Enter либо
на иконку ^ в левом верхнем углу окна со списком констант (рис. 1.26).
Замечание. Имена первых двух столбцов списка констант не соответствуют именам атрибутов, значения которых в этих столбцах отображаются. Так, в столбце Код представляется синоним константы, а в столбце Наименование - ее комментарий. Для согласования имен столбцов в приведенном на рис. 1.26 списке и имен атрибутов необходимо изменить встроенную в 1С процедуру открытия списка констант, вызываемую командой Константы. Открыть.
Отображаемые после открытия атрибуты Синоним и Комментарий для редактирования в этом списке закрыты, но могут быть изменены в конфигураторе. Там же можно добавить новую или удалить существующую константу. Последовательность, например, добавления константы такова: находясь в конфигураторе, откройте конфигурацию, оставаясь на закладке Метаданные (рис. 1.27), откройте список констант, ударив мышью по пункту Константы, или просто выделите пункт Константы, нажмите на правую кнопку мыши и выберите пункт Новая Константа.
 |
|
Рис. 1.27. Закладка Метаданные |
В появившемся окне (рис. 1.28) определите значения всех полей, понимая, что значение, занесенное в поле Идентификатор, используется для доступа к константе в программах. Поэтому имя идентификатора образуется по тем же правилам, что и имя переменной.
 |
|
Рис. 1.28. Общие свойства константы Название организации |
Замечание. В конфигурации системы объекта Справочники.Константы нет. Доступ к полю Значение (см. рис. 1.26) обеспечивается либо за счет использования идентификатора константы (для непериодических констант), либо в результате применения разработанных для констант методов.
1.7.2. НЕПЕРИОДИЧЕСКИЕ И ПЕРИОДИЧЕСКИЕ КОНСТАНТЫ
Константы разделяются на непериодические и периодические. К последним относятся константы, старые значения которых нужно сохранять при вводе изменений. Примером может послужить константа ЕдиновременнаяВыплатаНаРебенка, содержащая значение единовременного пособия при рождении ребенка. Это пособие может меняться, возможно даже увеличиваться, в течение, скажем, года несколько раз. Однако на эту константу могут быть ссылки в документах или в отчетах, например в отчете о выплатах упомянутого пособия за год. Поэтому, выполняя изменение размера пособия, необходимо сохранять значения константы и период их действия. Это выполняется в 1С, если компонент константы Периодический имеет значение 1.
Константа ЕдиновременнаяВыплатаНаРебенка является периодической. Поэтому если изменяется ее значение, то в файле 1 SCONST.DBF в отношении этой константы появится новая запись и сохранятся существующие. Это иллюстрирует табл. 1.1.
Таблица 1.1
|
Фрагмент файла 1SCONST.DBF с записями о константе ЕдиновременнаяВыплатаНаРебенка |
|
Date |
Id |
Value |
|
15.04.00 |
EV |
1000 |
|
01.01.01 |
EV |
1500 |
|
25.08.01 |
EV |
2500 |
|
В приведенном фрагменте отображается состояние константы ЕдиновременнаяВыплатаНаРебенка на 3 разные даты. (О том, что записи относятся к одной и той же константе, говорят совпадающие значения поля Id.)
Значения, которые ранее имела периодическая константа, можно просмотреть, на
жав на иконку с названием История, расположенную в окне со списком констант (см. рис. 1.26).
С периодическими константами употребляются методы Получить и Установить, соответственно возвращающие и устанавливающие значение константы на заданную дату. Применив для взятой в качестве примера константы вызовы
Сообщить(Константа.ЕциновременнаяВыппатаНаРебенкаПолучшъ('21.05.00')); Сообщить(Константа. ЕдиновременнаяВыплатаНаРебенка. Получить('21.07.01')); Сообщить(Константа. ЕдиновременнаяВыплатаНаРебенка. Получить('21.09.01'));
получим следующие сообщения:
1000
1500
3500
Также с периодическими константами применяются методы объекта Периодический, рассматриваемые в гл. 6. В частности, л разд. 6.1 приводится код вывода значений определенных в конфигурации непериодических констант.
Замечания:
1. В списке констант, наблюдаемом в конфигурации, рядом с именем периодической константы стоит иконка ^, а непериодической - иконка -I
2. Хотя в 1С и есть тип Константа (по крайней мере об этом говорится в документации), объектов с таким типом нет. Так, если написать процедуру
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
Сообщить(ТипЗначенияСтр(Констата.НазваниеОрганизации)); Сообщить(ТипЗначенияСтр(Констата)); конецПроцедуры // Выполнить
то после ее запуска получим сообщения
Строка
НеизвестныйОбъект
1.7.3. ПРИМЕРЫ РАБОТЫ С НЕПЕРИОДИЧЕСКИМИ КОНСТАНТАМИ
Значение непериодической константы можно получать и изменять, обращаясь к ней по имени Константа.ИдентификаторКонстанты или употребляя методы Полу-читьАтрибут и УстановитьАтрибут.
Пример 1. Вывести название организации.
процедура Выполнить() // Связана с кнопкой Пуск
Сообщить(Константа.НазваниеОрганизации); // Напечатает, например, АО ТрансМаш // То же сообщение выведет вызов
Сообщить(Константа.ПолучитъАтрибут(''НазваниеОрганизации'')); конецПроцедуры // Выполнить
Пример 2. Создать код, изменяющий значение непериодической константы Назва-ниеОрганизации с прежнего на АО Простор, а затем восстанавливающий старое название.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем новоеНазвание, староеНазвание, ответ; новоеНазвание = "АО Простор"; староеНазвание = Константа. НазваниеОрганизации;
ОчиститьОкноСообщенийО;
Сообщить("Прежнее название организации:" + староеНазвание);
ответ = Вопрос("Изменить название организации на " + новоеНазвание +"?", "Да+Нет"); если ответ = "Да" тогда // Нажата кнопка Да
Константа.НазваниеОрганизации = новоеНазвание;
Сообщить("Название организации после изменения: " +
Константа. НазваниеОрганизации);
// Восстановим старое название константы Предупреждение(”Название организации будет восстановлено.”); Константа.НазваниеОрганизации = староеНазвание; иначе // Выбрана кнопка Нет
Предупреждение("Название организации осталось без изменений."); конецЕсли;
конецПроцедуры // Выполнить Замечания:
1 • Вместо присваивания
Константа.НазваниеОрганизации = новоеНазвание; можно использовать метод
Константа.УстановитьАтрибут("НазваниеОрганизации", новоеНазвание);
2- Встроенная функция Вопрос выведет при исполнении программы окно с кнопкам! Да и Нет (рис. 1.29).
 |
|
Рис. 1.29. Окно, порождаемое встроенной функцией Вопрос |
Имена кнопок определяются вторым параметром функции, заданным в виде строки "Да+Нет". Функция Вопрос вернет строку со значением, совпадающим с именем нажатой кнопки.
3. В случае громоздких операторов или выражений их следует размещать на нескольких строчках. Символы переноса при этом не употребляются. Например:
Сообщить("Название организации после изменения:" +
Константа. НазваниеОрганизации);
4. Пример показывает, что нужно крайне аккуратно работать со справочниками вообще и с константами в частности. Достаточно несколько строк небрежного кода, чтобы исказить данные и сделать в результате неработоспособной всю систему.
В нашем примере мы избежали негативных последствий, добавив код, восстанавливающий прежнее значение измененной константы.
Пример 3. Выводится список непериодических констант, имеющих синоним, в окно сообщений.
Просмотр списка констант можно организовать, написав программу, выводящую, например, в окно сообщений идентификатор, синоним константы и ее значение. Разместим этот код, как всегда, в процедуре Выполнить модуля обработки Проба:
// Процедура вывода списка непериодических, определенных в конфигурации констант процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем всего Констант; // Число констант в конфигурации
перем идеи, син, значен;
ОчистшъОкноСообщенийО; // Очищаем окно сообщений
всегоКонстант = Метаданные.КонстантаО; для ин = 1 по всегоКонстант цикл
если Метацанные.Константа(ин).Периодический = 1 тогда
продолжить; // Значения периодических констант не выводятся
конецЕсли;
син = Метаданные.Константа(ии). Синоним;
// Выводим сообщения о константах, для которых задан синоним если ПустоеЗначение(син) = 0 тогда
идеи = Метаданные.Константа(ин).Идентификатор; значен = Константа.ПолучитьАтрибут(иден);
Сообщить(иден + " - " + син + " - " + значен); конецЕсли; конецЦикла; // для • конецПроцедуры // Выполнить
Замечание. Встроенная функция ПустоеЗначение(параметр) вернет нуль, если параметр определен (имеет значение), и единицу - в противном случае.
Эта программа - пример работы с метаданными, в котором использован метод Ме-таданные.Константа, возвращающий при работе с константами следующие величины:
• если не задан параметр, число констант в конфигурации;
• константу, расположенную в конфигурации под номером ин, если параметром метода является целочисленная переменная ин, например Метаданные.Константа(ин);
константу, имеющую идентификатор идеи, если параметром метода является символьная переменная идеи, содержащая значение идентификатора, например:
перем идеи, конст;
идеи = 'ТлБухгалтер'';
конст = Метаданные.Константа(иден);
Сообщить(конст); // Вернет значение синонима, например Главный бухгалтер
Вызывая этот метод, можно получить следующие сведения о константе:
• идентификатор, например АдресГНИ;
• синоним, например Адрес ГНИ;
• комментарий, например Адрес ГНИ;
• тип, например Строка;
• вид, например ДаНет, если тип константы - Перечисление;
• длина, например 240;
• точность, например 0;
• неотрицательный, например 0;
• разделятьТриады, например 0;
• периодический, например 0;
• областьРаспространения, например ВсеИнформационныеБазы.
Пример. Процедура
Сообщшъ(Метаданные.Константа(1).Длина); // Вернет, например, 240 выведет в окне сообщений данные о длине первой константы.
1.7.4. МЕТОДЫ КОНСТАНТ
Здесь и далее мы не будем, дублируя документацию и материал, имеющийся в справке, приводить подробные сведения о методах, применяемых с объектами 1С, поскольку наша цель - приобщение к методам программирования на языке 1С - достигается в результате решения разнообразных практических задач и анализа используемых при составлении программ приемов. В то же время полезно дать читателю как можно более полную информацию о возможностях системы. Понимая это, мы будем приводить необходимые справочные данные. Первую порцию таких данных разместим в табл. 1.2-1.4.
Таблица 1.2
Методы констант |
|
Метод |
Вид |
Описание |
|
Метод непериодических и периодических констант |
|
НазначитьТип |
Процедура |
Назначает тип значению константы, для которого в конфигураторе задан неопределенный тип |
|
Методы непериодических констант |
|
УстановитьАтрибут |
Процедура |
Устанавливает значение константы по имени ее идентификатора |
|
ПолучитьАтрибут |
Функция |
Возвращает значение константы по имени ее идентификатора |
|
|
Метод |
Вид |
Описание |
|
Методы периодических констант |
|
Получить |
Функция |
Возвращает значение периодической константы на заданную дату |
|
Установить |
Процедура |
Устанавливает значение периодической константы |
|
|
Таблица 1.3 |
Синтаксис вызова метода
Непериодические и периодические константы
Константа.НазначитьТип(идентификатор, тип, [длина, точность]);
Непериодические константы
Константа.УстановитьАтрибут(идентификатор, значение);
значение = Констата.ПолучтьАтрнбут(идентификатор);
Периодические константы
значение = Константа.ИдентификаторКонстанты.Получить(дата);
Константа .ИдентификаторКонстанты.Установть(дата, значение);
Замечания:
1. Здесь и далее при описании синтаксиса необязательные параметры процедур, функций и методов заключаются в квадратные скобки.
2. Наличие в имени метода текста (ИдентифшаторКонстанты), записанного курсивом, означает, что в программах этот текст должен быть заменен на соответствующее значение. Например:
// Меняем значение периодической константы с идентификатором Кассир Константа.Кассир.Установить(ТекущаяДатаО, "Ремизова Нина Дмитриевна");
3. Параметрами методов являются выражения, тип и смысл которых описан в табл. 1.4.
Таблица 1.4
Описание параметров методов |
|
Параметр |
Смысл |
Тип |
|
дата |
Дата, на которую устанавливается или возвращается значение периодической константы |
Дата |
|
длина |
Размер поля, отводимого для представления константы, имеющей тип Число или Строка |
Число |
|
значение |
Значение константы |
Строка, число или дата |
|
идентификатор |
Символьное представление идентификатора константы, например "НазваниеОрганизации" |
Строка |
|
тип |
Символьное представление типа, используемого при определении значения константы, например "Число", "Строка", "Дата", "Справочник.Сотрудники" |
|
|
точность |
Число знаков после десятичной точки в представлении числовой константы |
|
|
1.8. ОТОБРАЖЕНИЕ СПИСКА КОНСТАНТ В ДИАЛОГОВОМ ОКНЕ
Просмотр констант в списке, появляющемся в окне сообщений после запуска приведенной в разд. 1.7.3 процедуры, весьма затруднителен. Более высокое качество отображения перечня констант (и других представляемых в виде таблицы объектов) обеспечивает элемент диалога Таблица значений. Продемонстрируем способ его употребления на примере вывода информации о константах системы. Как и ранее, будем выводить данные только о непериодических константах, отображая их идентификаторы, синонимы и значения.
Изменения обработки Проба выполним в следующем порядке. Первоначально увеличим размер диалогового окна, переместим кнопки Пуски Закрыть, добавим в него текст
Список непериодических констант, вставим, используя иконку ІН находящуюся на панели инструментов Элементы диалога (см. рис. 1.21), элемент Таблица значений, дав ему в качестве идентификатора имя тЗнач (для подобных элементов с 1С предусмотрен тип ТаблицаЗначений), и изменим его размеры, ориентируясь на рис. 1.30.

Затем напишем в модуле нашей обработки следующий код, использующий методы, применяемые с переменными типа ТаблицаЗначений:
процедура СоздатьТаблЗнач() далее // Предварительное описание процедур процедура ЗаполнитьТаблЗнач() далее
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
ОчиститьОкноСообщений();
Сообщить("Переменная тЗнач имеет тип ТаблицаЗначений."); конецПроцедуры // Выполнить
процедура ПриОткрытии() // Процедура выполняется перед открытием формы
// Создаем в таблице тЗнач три столбца
СоздатьТаблЗнач(); // Вызов ранее описанной процедуры
// Заполняем таблицу тЗнач данными о непериодических константах ЗаполнитьТаблЗнач(); // Эта процедура также описана ранее
конецПроцедуры // Выполнить
// Процедура создает незаполненную таблицу значений процедура СоздатьТаблЗнач()
// Задаем при вызовах метода НоваяКолонка следующие параметры:
// идентификатор столбца;
// тип данных, заносимых в столбец;
// далее пропускаем два параметра - длину и точность представления данных;
// заголовок столбца
//Помним, что область действия переменной диалога тЗнач - все // программные компоненты модуля; тип переменной тЗнач - ТаблицаЗначений тЗнач.НоваяКолонка("иден", "Строка",,, "Идентификатор"); тЗнач.НоваяКолонка("син", "Строка",,, "Синоним"); тЗнач.НоваяКолонка("значен", "Строка",,, "Значение"); конецПроцедуры // СоздатьТаблЗнач
// Процедура заполняет таблицу значений данными о непериодических константах процедура ЗаполнитьТаблЗнач() перем ин, син, идеи, значен; для ин = 1 по Метаданные.Константа() цикл
если Метаданные.Константа(ин).Периодический = 1 тогда
продолжить; // Значения периодических констант не выводятся
конецЕсли;
син = Метаданные.Константа(ин). Синоним;
// Выводим сообщения о константах, для которых задан синоним если ПустоеЗначение(син) = 0 тогда
идеи = Метаданные.Константа(ин).Идентификатор; значен = Константа. ПолучитьАтрибут(иден);
// Используем для добавления новой строки в таблицу тЗнач метод НоваяСтрока тЗнач.НоваяСтрока(); // Добавляем новую строку в таблицу значений тЗнач.иден = идеи; // При занесении данных в ячейку столбца тЗнач.син = син; // пользуемся его идентификатором тЗнач.значен = сокрЛ(значен); конецЕсли; конецЦикла; // для
конецПроцедуры // ЗаполнитьТаблЗнач Замечания:
1. Переменная тЗнач имеет тип ТаблицаЗначений, если (что справедливо для нашего случая) она определена в диалоге как идентификатор одноименного элемента диалога или если она создана в программе в результате выполнения оператора
тЗнач = СоздатьОбьект('ТаблицаЗначений)";
2. Встроенная функция СокрЛ(строка) возвращает значение параметра строка без ведущих пробелов. Например:
стр = СокрЛ(" Сводка "); // Вернет строку "Сводка "
Сохраним данные, загрузим обработку в 1С:Предприятие и получим, даже не нажимая на кнопку Пуск, приведенный на рис. 1.31 результат.

1.9. ФОРМИРОВАНИЕ ОТЧЕТА СО СПИСКОМ
КОНСТАНТ
При необходимости список констант можно распечатать. Для этого, однако, его предварительно нужно представить либо в виде табличного отчета, либо в виде текстового документа, расположив информацию в отчете (документе) в удобном для прочтения виде.
Расширим обработку Проба, которую мы до сих пор использовали для отладки и запуска учебных программ, до внешнего отчета 1С, использовав в ней вывод данных в таблицу, созданную на закладке Таблица (рис. 1.32).
 |
|
Рис. 1.32. Начальный вид закладки Таблица |
Первоначально, если не пользоваться помощником создания отчета, в таблице нет заполненных ячеек.
Если поставить курсор на имя закладки Таблица и нажать на правую кнопку мыши, то раскроется список действий, которые можно предпринять (рис. 1.33).
 |
|
Рис. 1.33. Меню операций для таблицы |
Из списка видно, что форма может в общем случае содержать более одной таблицы. Воспользуемся пунктом Задать имя таблицы и присвоим ей имя Константы, которое затем и будем использовать в программе.
Поставим задачу получить отчет со списком констант в виде табл. 1.5.
Таблица 1.5
Список непериодических констант, 02.10.01 |
|
Идентификатор |
Синоним |
Значение |
|
АдресГНИ |
Адрес ГНИ |
Некоторый адрес |
|
АдресОрганизации |
Адрес Организации |
Некоторый адрес |
|
Архиватор |
|
Нет |
|
ОграничиватьПосмотрСписка |
Ограничивать просмотр списка |
Нет |
|
|
Всего непериодических констант: 94 |
Для ее решения потребуется в отчете Проба на закладке Константы (новое имя закладки Таблица) сформировать макет отчета по образцу, приведенному на рис. 1.34, а затем написать программу вывода данных в таблицу Константы.
|
|
|
Т| І Г 3 I 4 |
|
Заголовок |
1
2 |
<Список непериодических констант, [ТекущаяДата( )]> |
|
3 |
Идентификатор Синоним Значение |
|
|
4 |
|
|
(оКоистант |
5 |
|<иден> |<син> |<значен> |
|
|
S |
|
|
|Всего |
7 |
«Всего непериодических констант |числоКонст|> |
|
|
С-ІДиапм' у _] Мсодл» у Огысатие у А) Константы / |
Рис. 1.34. Образец для отчета Список непериодических констант
Проделаем эту работу в следующем порядке. Перейдем на закладку Константы, выделим ячейки 2, 3 и 4 первой строки и выполним их объединение, нажав на иконку
і-а-»
панели инструментов Редактор таблиц (рис. 1.35) или выбрав пункт Объединить Колонки Таблицы меню конфигуратора.
 |
|
Рис. 1.35. Панель инструментов Редактор таблиц Занесем в объединенные ячейки шаблон следующего вида: Список непериодических констант, [ТекущаяДата()], введя его на закладке Текст в окне Свойства ячейки, которое появляется после позиционирования курсора на ячейке, удара по правой клавише мыши и выбора пункта Свойства (рис. 1.36). (В квадратных скобках содержится выражение, вычисляемое при использовании шаблона. В нашем случае выражение - это встроенная функция, возвращающая установленную в вашем компьютере текущую дату.) |
|
IСвойства ячейки |
КЗІ |
|
! "Текст }| Положение | Шрифт | Рамке | Узор | |
хЫ |
|
Ьп |Шаблон Контроль]Авто _»] |
|
|
JСписок непериодических констант. [ТекушаяДата{)] |
|
|
d |
ок |
|
Расшифровал |~ |
Отмена |
|
Р Защита |
Обновитъ | |
Рис. 1.36. Задание свойства Текст ячейки таблицы Константы
Используя закладки Положение и Шрифт, расположим текст по центру ячеек 2-4, сделаем его полужирным и увеличим его размер до 12.
Проведя аналогичные действия, сформируем в ячейках 2, 3 и 4 строки 3 заголовки будущей таблицы со списком констант, а затем увеличим, оперируя мышью, ширину каждого столбца с заголовками. При этом на закладке Текст окна Свойства ячейки в поле Тип установим значение не Шаблон, а Текст. Высоту шрифта и его толщину можно изменить сразу для всех заголовков, выделив их и вызвав затем окно Свойства ячейки. Кроме изменения параметров шрифта, зададим, перейдя на закладку Рамка, разделяющие ячейки вертикальные и горизонтальные линии. _
Просмотрим промежуточный вариант макета отчета, выбрав на стандартной панели инструментов конфигуратора иконку или пункт Просмотр колонки системного меню Файл.
Замечание. Чтобы изменить размер столбца таблицы, нужно захватить мышью, нажав на ее левую кнопку, разделяющую номера столбцов линию и переместить ее в нужном направлении.
В строке 5 формируемого макета отчета в ячейку второго столбца (эта ячейка имеет номер R5C2) занесем текст иден, задав для него в поле Тип значение Выражение (рис. 1.37).
' Текст і| Положетме | Шри<рг | Рамса | Узор |
Тип I Выражение J*] Контроль jАето |
ицен
jJ
Рис. 1.37. Свойства ячейки R5C2
В нашем случае выражение иден - это имя переменной в программе, которой в процессе чтения информации об очередной константе присваивается значение ее идентификатора.
Далее аналогичным образом зададим в ячейках 3 и 4 строки 5 выражения син и значен, являющиеся в нашем случае именами переменных, получающими соответственно синоним и значение константы. Затем, выделив три ячейки с выражениями, на закладке Рамка зададим разделяющие их вертикальные линии.
Замечание. Можно организовать перенос длинных имен, не умещающихся в заданных для них ячейках таблицы. Для этого в поле Контроль (рис. 1.37) следует установить значение Переносить.
В строке 7 после объединения столбцов 3 и 4 зададим шаблон Всего непериодических констант: [числоКонст], в котором выражение числоКонст - это переменная, получающая в процессе вычислений значение, равное количеству непериодических констант.
Перейдем к формированию секций. Объединим в секцию первые 3 строки табли
л цы. Для этого выполним их выделение, проведя мышью, у которой нажата левая кнопка, по номерам строк 1-3, выберем иконку С. (см. рис. 1.35) и присвоим идентификатору секции значение Заголовок. Аналогичным образом создадим секции оКонстанте и Всего.
Макет отчета готов. Направим в него данные и отобразим результат, использовав в отчете Проба следующий снабженный обширным комментарием код:
// Процедура формирования отчета, содержащего список непериодических констант процедура Выполнить() // Связана с кнопкой Пуск обработки (отчета) Проба
перем ин, числоКонст, син, иден, значен; перем табл;
ОчиститьОкноСообщений(); табл = СоздатьОбъект("Таблица");
// Свяжем переменную табл с таблицей Константы, содержащей макет отчета табл.ИсходнаяТаблица("Константы");
// При выводе применяем заданные по умолчанию параметры таблицы;
// для их изменения следует обратиться к методу Опции
// Выводим, используя шаблон Список непериодических констант, [ТекущаяДата()],
// секцию Заголовок табл.ВывестиСекцию(''Заголовок'');
числоКонст = 0; // Число непериодических констант
для ин = 1 по Метаданные.Константа() цикл
если Метацанные.Константа(ин).Периодический = 1 тогда
продолжить; // Значения периодических констант не выводятся
конецЕсли;
числоКонст = числоКонст + 1; // Еще одна константа
// Определяем значения переменных идеи, син и значен
// Эти значения будут использованы при выводе секции оКонстанте
идеи = Метаданные.Константа(ин).Идентификатор;
син = Метаданные.Константа(ин). Синоним;
значен = сокрЛ(Константа.ПолучитьАтрибут(иден));
// Вывод очередной строки в отчет табл.ВывестиСекцию(''оКонстанте''); конецЦикла; // для
табл.ВывестиСекцию("Всего"); // Вывод данных о числе непериодических констант
// Запрещаем редактирование результирующей таблицы
табл.ТолькоПросмотр(1);
// Задаем в методе Показать заголовок окна с результирующей таблицей табл.Показать("Отчет о константах"); конецПроцедуры // Выполнить.
Результат приведен в табл. 1.5.
ВЫВОД СПИСКА КОНСТАНТ В ТЕКСТОВЫЙ ФАЙЛ
Текстовые файлы часто используют для обмена данными между программами, например для передачи из 1С платежных поручений в банк, где они воспринимаются установленной там процедурой. Механизм вывода данных в текстовый документ с последующим его сохранением в файле продемонстрируем на уже решенной нами задаче формирования списка констант, направляя его на этот раз не в таблицу значений (разд. 1.8) или в табличный отчет (разд. 1.9), а в текстовый файл.
Наша задача довольно проста, и мы после создания объекта Текст обойдемся небольшим числом методов, применяемых в 1С для объектов такого типа, - методами ДобавитьСтроку, ТолькоПросмотр, Показать и Записать. Для форматирования и преобразования данных используем встроенные функции Формат и Строка. Необходимые пояснения впервые использованных методов и функций дадим в нижеприводимом тексте программы.
// Процедура формирования текстового файла с данными о непериодических константах процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем ин, числоКонст, син, идеи, значен; перем текст, имяФайла; имяФайла = "Koнстакты.txt"; текст = СоздатьОбъект("Текст");
// Формируем текст с данными о константах; системная константа // РазделительСтрок обеспечит вставку пустой строки между // заголовком списка и заголовками столбцов
текст.ДобавитьСтроку("Список непериодических констант" + РазделительСтрок);
// Вывод заголовков столбцов
// Как и ранее, выведем в каждой строке 3 поля: идентификатор, синоним // и значение константы, задав длину каждого поля, равной 20 символам текст.ДобавитьСтроку(Формат("Идентификатор", "С20") + " " +
ФорматС'Синоним", "С20") + + Формат("Значение", "С20") + РазделительСтрок);
числоКонст = 0; // Число непериодических констант
для ин = 1 по Метаданные.Константа() цикл
если Метаданные.Константа(ин).Периодический = 1 тогда
продолжить; // Значения периодических констант не выводятся
конецЕсли;
числоКонст = числоКонст + 1;
// Определяем значения переменных идеи, син и значен идеи = Метаданные.Константа(ин).Идентификатор; син = Метаданные.Константа(ин).Синоним; значен = сокрЛ(Константа.ПолучитьАтрибут(иден));
// Вывод очередной строки в формируемый текст // Встроенная функция Формат(пар, "С20") вернет значение // параметра пар в виде строки длиной в 20 символов текст.ДобавитьСтроку(Формат(иден, "С20") + " " +
Формат(син, "С20") + " " + Формат(значен, "С20"));
конецЦикла; / / для
текст.ДобавитьСтроку(""); // Выводим пустую строку // Функция Строка преобразовывает значение переменной числоКонст // в символьное представление
текст.ДобавитьСтроку("Всего непериодических констант " + Строка(числоКонст));
// Вывод данных о числе непериодических констант // Запрещаем редактирование результирующего текста текст.Т олькоПросмотр(1);
// Покажем текст, в окне, имеющем заголовок Список непериодических констант текст.Показать("Список непериодических констант");
текст.Записать(имяФайла); // Запишем текст в файл Константы-txt нецПроцедуры // Выполнить.
Результат приведен на рис. 1.38.
 |
Рис. 1.38. Текст отображается с применением равномерного шрифта Замечания:
1. Поля с данными будут расположены равномерно, если применить шрифт с фиксированной шириной символа, например Fixedsys. Переход от пропорционального шрифта к равномерному в результирующем тексте осуществляется в 1С:Пред-приятии в результате выбора пунктов меню Текст - Текст модуля. Колонка меню Текст появляется при просмотре текста. |
2. Метод Записать, если не задан путь, разместит файл в директории с базами данных системы. Если файл записывается впервые, то метод Записать создаст этот файл. При записи в существующий файл и при его создании метод Записать, если он употребляется совместно с методом Показать, предварительно осведомится, нужно ли записывать данные в указанный файл.
1.11. ЗАГРУЗКА ТЕКСТА МОДУЛЯ ИЗ ФАЙЛА
До сих пор мы редактировали диалог или таблицу формы или набирали код модуля, находясь в конфигураторе, затем выполняли его синтаксический контроль, сохраняли, устранив ошибки, файл обработки (отчета), переходили в 1С:Предприятие, загружали там обновленную обработку и выполняли ее запуск.
Если же диалог и таблица в процессе работы над формой не изменяются, а модифицируется только код программных компонентов модуля, то процесс запуска измененной программы можно несколько ускорить. Для этого следует воспользоваться командой
#ЗагрузитьИзФайла ИмяФайла
Эта команда должна быть размещена в первой строке модуля и начинаться с ее первой позиции. ИмяФайла - это указанное без кавычек имя файла, в котором размещается текст редактируемого модуля, например Проба.ей.
При наличии в модуле такой команды весь расположенный вслед за ней код игнорируется. Редактирование данных должно выполняться в файле ИмяФайла. При этом файл загружается не в конфигураторе, а в 1С:Предприятии (Файл - Открыть). Чтобы появившийся текст представлялся как программа, то есть с использованием заданных для текста программ шрифта, цветов и размера табуляции, необходимо после открытия файла выбрать в меню пункты Текст - Текст модуля.
После внесения изменений необходимо сохранить файл (Ctrl+S), закрыть файл формы (обработки), если она открыта, и открыть его заново. В загруженной форме будет использован обновленный в файле ИмяФайла код модуля.
Выполним только что приведенные рекомендации. Добавим, во-первых, в код модуля обработки Пробаей, открытой в конфигурации, команду (в вашем случае путь, разумеется, может быть иным)
// Команда размещена в первой строке модуля #ЗагрузитьИзФайла Д\1ст7ДТей\ІХІ\Прс)баМ
Затем создадим, например в папке ТХТ, текстовый файл Пробам, откроем его в 1С:Предприятии, скопируем в него код модуля обработки Проба.ей, выберем пункты меню Текст - Текст модуля, внесем в текст файла изменения, добавив, например, в процедуру выполнить оператор
Сообщить("Код модуля загружен из файла Пробам");
Сохраним файл Проба.Ш, откроем и запустим обновленную обработку (файл Проба.М закрывать не нужно).
Еще одна рекомендация. При работе с кодом модуля не забывайте о возможностях колонки меню Текст и панели инструментов Текстовый редактор (рис. 1.39).
 |
|
Рис. 1.39. Панель инструментов Текстовый редактор |
Напомним, что действия с блоком (вторая группа кнопок на рис. 1.39) становятся возможными после выделения одной или нескольких строк текста.
Отметим, что если программа модифицируется в 1С:Предприятии, а не в конфигураторе, то на панели инструментов Текстовый редактор отсутствуют иконки
и , то есть мы не имеем возможности просмотреть список процедур и функций модуля и осуществить синтаксический контроль кода без загрузки обработки в систему.
1.12. КАК ОТКРЫТЬ ОТЧЕТ ИЛИ ОБРАБОТКУ В ПРОГРАММЕ
Запуск обработки Проба мы до сих пор выполняли из созданного нами меню, либо выбирая в нем Проба - Пуск, либо нажимая Alt+1. Кроме того, мы могли открыть обработку, использовав пункты Открыть колонки меню Файл. При необходимости, однако, отчет или обработку можно открыть из любой другой формы или программы глобального модуля. Для этой цели употребляется функция ОткрытьФорму.
Чтобы привести примеры обращения к функции и методу, открывающим отчет (обработку), создадим еще одну обработку, дав ей имя Открыть.ert, и разместим ее там же, где и обработка Проба. Формируя новую обработку, не забудем вставить команду ее вызова в меню Ученик, ответив утвердительно на соответствующее предложение помощника создания обработки. Диалог обработки может иметь приведенный на рис. 1.40 вид.
 |
|
Рис. 1.40. Диалог обработки Открыть |
С кнопкой Открыть обработки свяжем процедуру Открыть, разместив в ней следующий код:
Процедура Открыть() // Открывает обработку Проба
перем контОбрПроба; // Контекст обработки Проба
ОткрытьФорму("Отчет", контОбрПроба, "d:\lCv77\Test\ExtForms\npoбa.ert"); КонецПроцедуры // Открыть
Теперь, если верно указано полное имя файла обработки Проба, после нажатия на кнопку Открыть диалога, приведенного на рис. 1.40, мы откроем обработку Проба.
Имя файла можно получить, применив метод ВыбратьФайл агрегатного типа ФС. Тогда код процедуры Открыть будет таким:
процедура Открыть() // Открывает обработку Проба
перем контОбрПроба; перем флаг, имяФайла;
// Третий параметр метода ВыбратьФайл опущен флаг = ФС.ВыбратьФайл(0, имяФайла,,
"Находим файл Проба^гТ, "Отчет и обработки | *.ert''); если флаг = 1 тогда // Если файл обработки выбран
если ОткрытьФорму("Отчет", контОбрПроба, имяФайла) = 0 тогда Предупреждение(''Не удается открыть обработку " + имяФайла); возврат; конецЕсли; иначе
Предупреждение("Файл обработки не выбран."); конецЕсли;
конецПроцедуры // Открыть
Метод ВыбратьФайл, если его первый параметр равен нулю, открывает диалог типа Открыть (рис. 1.41) и возвращает, если файл выбран, во второй параметр имя файла.
 |
|
Рис. 1.41. Выбор файла, содержащего обработку Проба |
Четвертый параметр (третий опущен) задает заголовок диалога, а пятый - сообщение, выводимое в поле Тип файлов, и после разделительной черты - маску, определяющую вид отображаемых в диалоге файлов. Заданная нами маска оставит в диалоге только файлы с расширением ERT.
Замечания:
1. Функция ОткрытьФорму имеет более широкое назначение. Она употребляется для открытия форм справочников, документов, различных журналов и др.
2. Чтобы открыть отчет (обработку), встроенный в конфигурацию, можно из модуля некоторой формы вместо функции ОткрытьФорму употребить метод ОткрытьПодбор.
1.13. КОНТЕКСТ ОБРАБОТКИ ПРОБА
Вторым параметром использованной в предшествующем разделе функции От-крытьФорму является контекст формы обработки Проба, под которым понимается совокупность ее реквизитов (переменных диалога) й методов формы обработки. Этот параметр является выходным.
Проиллюстрируем методы работы с контекстом на примере обработки, диалог которой содержит два поля (рис. 1.42): одно числового типа (дЧ), другое типа Перечисление (пер).
 |
|
Рис. 1.42. Обработка Проба с полями ДЧ и пер |
Определяя тип второго поля на закладке Тип в диалоге задания его свойств, выберем перечисление ТипПлатежа (рис. 1.43).
 |
|
Рис. 1.43. Выбор вида перечисления для поля пер |
Это перечисление определено в конфигурации и содержит следующие идентификаторы значений:
• ВсеДолгиПоЗарплате;
• Зарплата;
• Аванс;
• МежрасчВыплата;
• ВыплатыНаДетей;
• Дивиденды;
• ЕдиновременныеПособия.
В модуле модифицированной обработки Проба запишем предопределенную процедуру ПриОткрытии с двумя операторами присваивания:
процедура ПриОткрытии()
// Начальные значения переменных диалога дЧ и пер дЧ = 5.55;
пер = Перечисление.ТипПлатежа.ЗначениеПоНомеру(2); // Зарплата конецПроцедуры // ПриОткрытии
В обработке Открыть (см. рис. 1.40), из которой в результате применения функции ОткрытьФорму вызывается обработка Проба, создадим процедуру НовыйКонтекст, изменяющую значения переменных дЧ и пер диалога обработки Проба и обновляющую ее диалог. В качестве результата выведем состояние диалога обработки Проба до и после изменения значения переменных дЧ и пер.
Чтобы вместе с обработкой Открыть закрывалась и обработка Проба, в предопределенной процедуре ПриЗакрытии первой обработки выполним оператор
контОбрПроба.Форма.Закрыть();
Таким образом, модуль обработки Открыть будет содержать следующий код: перем контОбрПроба; // Переменная модуля обработки Открыть
// Изменяет значения переменных дЧи пер и обновляет диалог обработки Проба процедура НовыйКонтекст(контОбр Проба)
Сообщить(контОбрПроба.Дч); // 5.55
Сообщить(контОбрПроба.пер); // Зарплата
Предупреждение("Сейчас будут изменены переменные дЧ и пер обработки Проба.");
// Изменяем переменные диалога дЧ и пер обработки Проба
// и смотрим на ее диалог; результаты наблюдений приведены на рис. 1.44
контОбрПроба.Дч = 7.98;
контОбрПроба.пер =
Перечисление.ТипПлатежа.ЗначениеПоНомеру(З); // Аванс // Обновляем диалог обработки Проба контОбрПроба.Форма.Обновить(); конецПроцедуры // НовыйКонтекст
процедура Открыть() // Открывает обработку Проба
перем флаг, имяФайла; флаг = ФС.ВыбратьФайл(0, имяФайла,
"Находим файл Проба.еіі, "Отчет и обработки | *.ert"); если флаг = 1 тогда // Если файл обработки выбран
если ОткрытьФорму("Отчет", контОбрПроба, имяФайла) = 0 тогда Предупреждение("Не удается открыть обработку " + имяФайла); возврат; иначе
НовыйКонтекст(контОбрПроба); // Изменяем значения переменных дЧ и пер конецЕсли; // и обновляем окно формы обработки Проба
иначе
Предупреждение("Файл обработки не выбран."); конецЕсли;
конецПроцедуры // Открыть
// Закрывает открытую обработку Проба, используя для доступа к методу Закрыть // переменную модуля контОбрПроба процедура ПриЗакрытии()
если ПустоеЗначение(контОбрПроба) = 0 тогда контОбрПроба.Форма.Закрыть(); конецЕсли;
конецПроцедуры // ПриЗакрытии
 |
|
Рис. 1.44. Диалог обработки Проба: а - до обновления; б - после него |
Структура контекста говорит о том, что он является объектом агрегированного типа, включающего компоненты (в нашем случае реквизиты формы) и методы, употребляемые с обработкой. Приведем еще один пример управления формой обработки Проба через ее контекст. Так, если в процедуру перед вызовом
контОбрПроба. Форма. Обновить();
выполнить оператор
конЮбрПроба.Форма.дЧ.Видимост^О); // Скрываем элемент диалога дЧ
то рис. 1.44, б примет приведенный на рис. 1.45 вид.
 |
|
Рис. 1.45. Управление формой обработки Проба через ее контекст |
Замечание. Переменная контОбрПроба, возвращаемая функцией ОткрытьФорму, имеет тип ГрупповойКонтекст. В этом можно убедиться, выполнив вызов
Сообщшъ(ТипЗначенияСтр(контОбрПроба)); // Напечатает ГрупповойКонтекст
Это говорит о том, что через переменную контОбрПроба доступны все употребляемые с формой методы: методы формы, элементов ее диалога, контекста модуля формы и контекста модуля формы отчета (обработки).
Контекст формы можно передать в качестве входного/выходного параметра процедуре или функции глобального модуля. Пусть, например, в глобальном модуле определена процедура
процедура РаботаСКонтекстом(конт) экспорт конт.Дч = 7.98; конт.пер =
Перечисление.ТипПлатежа.ЗначениеПоНомеру(З); // Аванс конт.Форма.дЧ.Видимость(0); // Скрываем элемент диалога д Ч конт.Форма.ОбновшъО; // Обновляем диалог обработки Проба
конецПроцедуры // РаботаСКонтекстом
При вызове такой процедуры в качестве фактического параметра используется переменная Контекст. Например:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
РаботаСКонтекстом(Контекст); конецПроцедуры // РаботаСКонтекстом
Результат такого вызова см. на рис. 1.45.
Замечание. Реально процедура РаботаСКонтекстом после запуска вышеприведенного примера удалена из глобального модуля.
Разумеется, контекст обработки можно передать как входной/выходной параметр процедуре или функции, размещенных в модуле обработки. Например, запишем в модуле обработки Проба следующий код:
процедура РаботаСКонтекстомВМодуле(конт) конт.Дч = 7.98; конт.пер =
Перечисление.ТипПлатежа.ЗначениеПоНомеру(З); // Аванс
конт.Форма.дЧ.Видимость(0); // Скрываем элемент диалога дЧ
конт.Форма.Обновить(); // Обновляем диалог обработки Проба
конецПроцедуры // РаботаСКонтекстомВМодуле
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
РаботаСКонтекстомВМодуле(Контекст); конецПроцедуры // Выполнить
Исполнение кода даст тот же эффект, что и вызов процедуры РаботаСКонтекстом глобального модуля. В то же время очевидна избыточность такого подхода: область действия переменных диалога и процедур формы распространяется на все программные единицы ее модуля.
Замечание. Все сказанное относительно контекста обработки применимо и к контексту произвольной формы: документа, формы списка справочника и др.
1.14. ФУНКЦИИ ДЛЯ АДМИНИСТРАТОРА
Возможно, вам придется каким-либо образом управлять работой пользователей системы. Для этого могут пригодиться встроенные функции среды исполнения. Они приведены в табл. 1.6.
Таблица 1.6
Функции среды исполнения |
|
Функция |
Что возвращает |
|
заголовокСтар = ЗаголовокСистемы ([заголовок]); |
Возвращает и/или устанавливает заголовок окна системы |
|
имяЭВМ= ИмяКомпьютера(); |
Сетевое имя работающего с программой компьютера |
|
пользователь = ИмяПользователя(); |
Имя работающего с программой пользователя, взятое из списка пользователей (см. рис. 1.9) |
|
полноеИмя = ПолноеИмяПользователя( ); |
Полное имя работающего с программой пользователя (см. рис. 1.10) |
|
наборПрав = НазваниеНабораПрав( ); |
Название набора прав пользователя |
право = ПравоДоступа
(названиеПрава, объект); |
Единицу, если пользователь имеет право доступа, заданное именем названиеПрава, к объекту, заданного именем объект, или нуль - в противном случае |
|
интерфейс = НазваниеИнтерфейса(); |
Название интерфейса, заданное пользователю в конфигураторе |
|
|
Функция |
Что возвращает |
|
каталог = Катало гПользователя(); |
Заданное в конфигураторе имя рабочего каталога пользователя |
|
каталогБазы = КаталогИБ(); |
Имя каталога информационной базы данных |
|
каталогІС = КаталогПрограммы( ); |
Имя каталога с исполняемыми файлами 1С |
|
времКат = КаталогВременныхФайлов( ); |
Имя каталога временных файлов, образуемых при работе с 1С |
|
режим = МонопольныйРежим(); |
Единицу, если программа запущена в монопольном режиме, или нуль - в противном случае |
|
язык = ОсновнойЯзык(); |
Единицу, если основной язык русский, или нуль, если английский |
|
|
Пример: |
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
ОчиститьОкноСообщений();
ЗашловокСистемы(''Система с учебными формами");
Сообщить(ИмяКомпьютера()); // DEFAULT
Сообщить(ИмяПользователя()); // Ученик
Сообщить(ПолноеИмяПользователя()); // Николаев Н. А. Сообщить(НазваниеНабораПрав()); // ПолныеПрава
Сообщить(ПравоДоступа(''ВводНового'', "Справочник. КадровыеДанные")); //1
// Для справочников регулируются права доступа со следующими названиями:
// чтение;
// любыеИзменения;
// вводНового;
// удаление;
// пометкаНаУдаление;
// снятиеПометкиНаУдаление;
// корректировка
Сообщить(ПазваниеИнтерфейса()); // Ученик
Сообщить(КаталогПользователя()); , //D:\lCv77\Test\
Сообщить(КаталогИБ()); // D:\lCv77\Test\
Сообщить(КаталогПрограммы()); // D:\l CV77\BIN\ Сообщить(КаталогВременныхФайлов()); // С:\ТЕМР\ Сообщить(МонопольныйРежим()); //1
Сообщить(ОсновнойЯзык()); //1
конецПроцедуры // Выполнить
Замечания:
1. Любая встроенная функция может быть вызвана как процедура, то есть в виде самостоятельного оператора, например
ОсновнойЯзык();
В большинстве случаев такой вызов не окажет никакого воздействия на работу приложения. Так, из приведенных в табл. 1.6 функций только первая, будучи употребленная как самостоятельный оператор, позволяет вносить изменения.
2. Если при вызове встроенной функции и процедуры возникает ошибка исполнения, то выводится диагностическое сообщение и может произойти аварийное заверш е-ние программы. Выводимые в таких случаях сообщения, правда, не всегда адекватны ситуации. Так, при запуске процедуры
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем х;
ОчиститьОкноСообщений(); х = 0;
Лог(х);
конецПроцедуры // Выполнить получим сообщения х = 0;
{D:\lCV7ДTEST\EXTFORMS\ПРОБA. ERT(3)}: Деление на 0
1.15. ВЫВОДЫ
Приведенные сведения позволяют сделать ряд выводов.
1. Для каждого пользователя можно (и нужно) создать свой интерфейс с определенными правами доступа.
2. Пользовательские программы (внешние обработки и отчеты) создаются в виде ' форм, содержащих диалог, модуль, одну или более таблиц.
3. Формы разрабатываются в конфигураторе, а запускаются в 1 С: Предприятии.
4. Имена переменных, процедур и функций, заданных в форме (в ее диалоге, модуле или его программных компонентах), доступны только в этой форме. Причем имя переменной модуля или диалога может быть закрыто локальным именем процедуры или функции модуля.
5. Модуль формы в общем случае содержит объявления переменных модуля и программные компоненты - основную программу, пользовательские процедуры (в том числе и предопределенные) и функции. Предопределенные процедуры, то есть создаваемые пользователем процедуры, имеющие определенные в документации имена и интерфейсы и исполняемые либо при наступлении стандартных событий, например при открытии формы, либо при рбращении к ним из других программных компонентов модуля, включаются в модуль по мере необходимости. Порядок следования программных компонентов модуля подчиняется определенным правилам.
6. Существуют по-настоящему глобальные имена (разд. 1.6), доступные в каждом программном модуле.
7. Объекты, такие, как Таблица значений, Текст и др., становятся доступными после их создания в результате применения функции СоздатьОбъект; к иным объектам, например Константам, можно обратится по их полному имени. С каждым видом объектов связан набор методов, позволяющих выполнять необходимые для управления объектами действия.
8. Такие объекты, как Таблица и Список значений, становятся доступными в модуле формы после их размещения в диалоге формы (разд. 1.8).
9. Вывод данных может быть выполнен в окно сообщений, в некоторые элементы диалога формы, например в таблицу значений, в таблицу (отчет), в текстовый документ и другие пока что нерассмотренные объекты системы. Кроме того, объекты, это мы покажем ниже, позволяют выполнять и обратную операцию - ввод определенных в них данных.
10. Методы, применяемые с метаданными, позволяют, в частности, получить перечень объектов определенного в системе типа, например Констант, а также прочитать их свойства; изменить свойства объектов, например задать новое имя идентификатора какой-нибудь константы, можно, лишь находясь в конфигураторе системы. Любое изменение конфигурации выполняется в монопольном режиме.
11. Производительность работы повысится, если на стадии отладки кода модуля использовать возможности команды #ЗагрузитьИзФайла (разд. 1.11).
12. Отчет (обработку) можно открыть из любой другой формы, применив функцию ОткрытьФорму (ОткрытьФормуМодально) или метод ОткрытьПодбор.
13. Контекст обработки - это объект агрегированного типа ГрупповойКонтекст, обеспечивающий доступ к переменным диалога обработки и к определенным для нее методам.
14. Контекст обработки может быть передан в качестве входного/выходного параметра процедуре (функции) модуля самой обработки и глобального модуля;
15. Контекст открываемой формы возвращает функция ОткрытьФорму (Открыть-ФормуМодально) .
16. Для получения сведений о среде исполнения и управления работой пользователей полезны рассмотренные в разд. 1.12. функции.
2. БАЗОВЫЕ ПОНЯТИЯ
Теперь, когда приобретены первоначальные по составлению и запуску простых программ знания, настало время более детально рассмотреть базовые элементы языка, такие, как виды объектов данных, типы данных, операции и их приоритет, выражения, программные компоненты и др.
2.1. ОБЪЕКТЫ И ТИПЫ ДАННЫХ
В программах 1С можно оперировать следующими объектами данных:
• буквальными и системными константами (не путать с рассмотренными выше определенными в конфигурации системы константами);
• переменными.
Объекты данных могут иметь следующие типы:
• числовой;
• символьный;
• дата;
• агрегатные, например Справочник.
Замечания:
1. Диапазон задания числовых значений, а также максимально допустимая точность представления числовых данных в документации по языку не оговариваются. Также там отсутствует и указание относительно максимально возможной длины символьного объекта данных. Впрочем, о допустимой точности задания числовых данных можно судить по следующим примерам. Так, оператор
Сообщить(Лог(2.5));
выведет в окно сообщений число
0.91629073187415
имеющее 14 знаков после десятичной точки. Правда,
Сообщить(Лог(5.0)); //1.6094379124341
вернет число только с 13 знаками после десятичной точки, а
Сообщить( 1.0/Лог( 1.01)); //100.499170807131365574
напечатает число с 18 знаками после десятичной точки:
Оператор
Сообщить(2 / 3); // 0.66666666666666666667
напечатает результат, имеющий рекордное число знаков после десятичной точки - 20.
2. Агрегатный тип данных имеет разновидности. Например, разновидностями типа Справочник являются Справочник.Должности, Справочник. Сотрудники и др. Агрегатный тип данных мы рассмотрим в гл. 3.
3. Некоторые методы, например приведенный в табл. 1.2 метод НазначитьТип, принимают в качестве параметра символьное представление типа данных или разновидности типа. Это символьное представление для числового типа задается как "Число", для символьного - как "Строка". Для остальных типов оно дублирует имя типа или его разновидности. Например, символьное представление разновидности типа Справочник.Города - это строка "Справочник.Города".
2.2. БУКВАЛЬНЫЕ КОНСТАНТЫ
Буквальные константы (далее - просто константы) числового типа - это вещественные числа с точкой или без точки, со знаком или без него, например:
-2.34,2 ,+2.0, .25 // Нуль перед десятичной точкой можно опустить
Константа символьного типа - последовательность символов, обрамленная двойными кавычками, например
"Это строка"
или
// Это константа нулевой длины
Если необходимо двойную кавычку включить в состав символьной константы, то кавычку нужно повторить дважды, например процедура
Сообщить(......Константа, которая начинается и завершается двойными кавычками......);
напечатает в окне сообщений следующий текст:
"Константа, которая начинается и завершается двойными кавычками"
Длинная символьная константа - текст, расположенный на двух или более строках, записывается либо с использованием знака продолжения - вертикальной черты, проставляемой в начале строки продолжения константы, например
стрЗ = "Это длинная символьная константа,
| поскольку она размещается не на одной,
| а на трех строчках";
либо как последовательность однострочных констант, например
стрЗ = "Это длинная символьная константа,"
" поскольку она размещается не на одной,"
" а на трех строчках";
В таком тексте сохраняются символы конца строки. Длинную константу без символов конца строки на двух или более строчках записать нельзя. Заметим, что в виде подобных текстов нередко составляются запросы к базам данных.
Константы типа Дата, если год представляется в виде двух чисел, - это последовательность из трех пар чисел, обрамленных одинарными кавычками и разделенных точками. Формат даты -'ДД.ММ.ГГ', где ДД - число месяца, ММ - номер месяца, ГГ -две последние цифры в номере года. Например:
'03.11.01'
//
3 ноября 2001 г.
Год в константе типа Дата можно задать полностью:
'03.11.1942' // 3 ноября 1942 г.
Если в представлении константы типа Дата год задается двумя цифрами, то при интерпретации даты используется значение года начала рабочего столетия, которое задается на закладке Общие в окне Настройка параметров системы, появляющемся в 1С: Предприятии после выбора пунктов меню Сервис - Параметры (рис. 2.1).
 |
|
Рис. 2.1. Задание параметров, относящихся к датам |
Так, если в представлении константы типа Дата используются две цифры, то если они меньше или равны последних двух цифр года начала рабочего столетия (в нашем случае он равен 1941), то дата относится к нынешнему веку, в противном случае -к прошедшему. Например:
'03.11.1942' //3 ноября 1942 г.
'03.11.42' // Так же 3 ноября 1942 г.
'03.11.41' // Это 3 ноября 2041 г.
Убедимся в этом визуально, активизировав кнопку 4 (рис. 2.1), сохранив новую настройку и запустив обработку, содержащую два следующих сообщения:
Сообщить('03.11.42'); // Напечатает 03.11.1942
Сообщить('03.11.41'); // Напечатает 03.11.2041
Используя 4 цифры в представлении даты, можно задать любую дату от Рождества Христова, например
'01.01.0001' //1 января 1г.
Константу с датой до Рождества Христова задать нельзя.
Если константа задает несуществующую дату, то она воспринимается как пустое значение, например
Сообщить(ПустоеЗначение('33.12.01')); //Напечатает 1 (нет такой даты) Сообщить('33.12.01'); //Напечатает . .
Сообщить(ПустоеЗначение('23.12.01')); // Напечатает 0 (верная дата)
2.3. СИСТЕМНЫЕ КОНСТАНТЫ
В языке есть 3 системные именованные константы, имеющие символьный тип и следующие имена:
РазделительСтраниц;
РазделительСтрок;
Символ Табуляции.
Они, как правило, употребляются при работе с текстом. Например:
// Константа РазделительСтрок обеспечит вставку пустой строки // вслед за текстом "Список непериодических констант"
текст.ДобавитьСтроку(''Список непериодических констант" + разделительСтрок);
2.4. ПЕРЕМЕННЫЕ ЧИСЛОВЫЕ, СИМВОЛЬНЫЕ
И ДАТЫ
Переменные разделяются на скалярные и массивы. В текущей реализации 1С можно использовать только одномерные массивы, называемые также векторами. Переменные появляются в программе:
• после их объявления, например
перем а, стр; // Объявляем скалярные переменные а и стр
перем мас[20]; // Объявляем вектор из 20 элементов
• после первого размещения имени переменной (числовой, строковой и даты) в правой части оператора присваивания, например
у = Лог(а); // Вводим переменную у, определяем ее тип и значение
• при определении имен идентификаторов редактируемых элементов диалога (см. разд. 1.5);
• при задании формальных параметров процедур, например в пользовательской функции
функция ВычислитьУ(х) // х - формальный параметр функции ВычислитьУ х = 2.0 * х; // употребляется в функции как переменная
у = 2 * Лог(х); // Лог - встроенная функция
возврат у;
конецФункции // ВычислитьУ
формальный параметр x используется как скалярная переменная.
При объявлении переменной ее тип и значение не определяются. Такая переменная имеет пустое значение. Однако ее можно употреблять в выражениях. Например:
Пример 1. Тип и значение переменной а не определены. Встроенная функция Пус-тоеЗначение(а) вернет 1, а результатом последующего выражения будет 0.
б = 2 * а;
Объявляем скалярную переменную а // Напечатает 1
Напечатает пустую строку
// Напечатает 1. То есть б имеет пустое значение Напечатает 0, а не пустую строку,
// несмотря на то что б имеет пустое значение Напечатает 3
Напечатает пустую строку
Переменная обретает тип при ее определении, то есть когда она получает значение в результате выполнения оператора присваивания или если переменная является формальным параметром процедуры, при вызове этой процедуры, в котором определены соответствующие фактические параметры.
Пример 2. Переменные а и стр после выполнения присваивания будут иметь соответственно числовой и символьный тип.
перем а, стр; // Объявляем скалярные переменные а и стр
а = 1.22; // Теперь переменная а имеет числовой тип
стр = "Это строка"; // Теперь переменная стр имеет символьный тип
Пример 3. При вызове функции ВычислитьУ ее формальный параметр х будет определен как числовая переменная (текст функции ВычислитьУ см. выше).
процедура Выполнить()
б = ВычислитьУ(3.0); // При вызове функции ВычислитьУ определяется
Сообщить(''б = " + б); // тип и значение ее формального параметра х конецПроцедуры // Выполнить
Замечание. Переменные, имена которых неизвестны в программном компоненте, нельзя использовать в качестве фактических параметров других программных компонентов. Например, ошибочен следующий код:
процедура ОпределитьХ(х) х = 2.0;
конецПроцедуры // ОпределитьХ процедура Выполнить()
ОпределитьХ(х); // Этот вызов в текущей версии недопустим
Сообщить(х);
конецПроцедуры // Выполнить
В то же время вполне корректен второй вариант процедуры Выполнить:
конецПроцедуры // Выполнить
Объявляем переменную х Теперь этот вызов возможен Напечатает 2
По ходу выполнения программы одна и та же переменная может менять свой тип, например:
Объявляем скалярные переменные а Теперь переменная а имеет числовой тип Напечатает 1.22
Теперь переменная а имеет символьный тип Напечатает Это строка Теперь переменная а имеет тип Дата Напечатает 24.12.01
2.5. ВВОД ЗНАЧЕНИЙ РАЗНЫХ ТИПОВ
Значения имеющихся в программе переменных числового, символьного типа, дат и агрегатных типов можно определить, используя диалоги, вызываемые приведенными в табл. 2.1 функциями; в табл. 2.2 приведен их синтаксис, а в табл. 2.3 - описание их параметров.
Таблица 2.1
|
Функции ввода значений |
 |
Таблица 2.2
Синтаксис функций ввода значений
флаг = ВвестиЧисло(пер, заг, длина, точность, [задержка]); флаг = ВвестиСтроку(пер, заг, длина, [признак], [задержка]); флаг = ВвестиДату(пер, заг, [задержка]); флаг = ВвестиЗначение(пер, заг, тип, [длина], [точность]);
Описание параметров функций ввода значений
|
Таблица 2.3 |
|
Параметр |
Описание |
|
длина |
Длина числового или символьного поля ввода. Задается при вводе чисел и строк |
|
задержка |
Числовое выражение, задающее время ожидания ввода данных в секундах. При его превышении диалог исчезает, функция возвращает -1, значение переменной пер не изменяется. Время ожидания неограниченно, если задержка равна нулю или если этот параметр опущен |
|
заз |
Текст заголовка окна диалога, например "Ввод сотрудника" |
|
пер |
Переменная, в которую при нажатии на ОК устанавливается введенное значение; при выборе Отмена значение переменной пер не изменяется. Переменная пер должна появиться в программном компоненте до вызова
диалога ввода данных |
|
|
Параметр |
Описание |
|
признак |
Числовое выражение, задающее вид вводимой строки. Если признак равен единице, то появляется диалог ввода многострочного текста с разделителями (см. разд. 2.2), в противном случае вводится строка без разделителей строк (задано по умолчанию) |
|
тип |
Тип переменной, значение которой определяется при нажатии на ОК, например "Число", "Строка", "Дата", а также разновидности агрегатных типов
Справочник, Документ и Перечисление, например "Справочник.Сотрудники", "Документ.Договор", "Перечисление.Пол". В случае задания несуществующего типа, например "Символ", или типа, с которым функция не работает, например "Календарь", диалог ввода Ьанных не появляется и значение переменной пер сохраняется, а функция возвращает нуль |
|
точность |
Число знаков после десятичной точки в поле ввода числового значения.
Задается при вводе чисел |
|
|
Замечания: |
1. Все функции возвращают число 1, если нажата кнопка ОК, или 0 - в противном случае.
2. Функции ВвестиДату и ВвестиЗначение позволяют задавать в поле ввода несуществующие даты. В этом случае в определяемую переменную пер при нажатии ОК устанавливается пустое значение.
Примеры:
перем а, сотр;
флаг = ВвестиЧисло(а, "Введите номер документа", 10, 0); флаг = ВвестиСтроку(а, "Введите подстроку для поиска", 30); стр = "Это длинная символьная константа,
| поскольку она размещается не на одной,
| а на трех строчках";
// Задаем надлежащее (достаточно большое) число символов в тексте // Диалог, появляющийся после вызова функции, приведен на рис. 2.2, а флаг = ВвестиСтроку(стр, "Отредактируйте текст и нажмите ОК", 500, 1);
// Диалог, появляющийся после вызова функции, приведен на рис. 2.2, б // После выбора сотрудника переменная сотр будет иметь тип Справочник флаг = ВвестиЗначение(сотр, "Выберите сотрудника", "Справочник.Сотрудники");
 |
а
б
Рис. 2.2. Диалоги ввода данных: а - многострочного текста; б - сотрудника |
2.6. ВЫРАЖЕНИЯ И ОПЕРАЦИИ
2.6.1. ВЫРАЖЕНИЯ
Выражение - это формула, по которой вычисляется значение.
В выражении 1С могут присутствовать операнды разных типов (при наличии в выражении с несколькими операндами операнда агрегатного типа данных этот операнд воспринимается как пустое значение). Тип выражения определяется типом его результата. Тип результата выражения (или его подвыражения) определяется типом его первого операнда или первого заключенного в круглые скобки подвыражения. Например (выражения располагаются в правых частях операторов присваивания):
- числовое выражение из одного операнда Числовое выражение, возвращающее число 9 Числовое выражение, возвращающее число 3 Символьное выражение, возвращающее строку // "Строка и символ 2"
Числовое выражение, возвращающее число 2452267 Выражение типа Дата, возвращающее дату 23.12.01 Числовое выражение, возвращающее число 5
Из примеров видно, что порядок вычисления выражения таков: первоначально по первому операнду определяется тип выражения; затем выполняется вычисление выражения с учетом круглых скобок и приоритета выполнения операций, при этом значения операндов, имеющих тип, отличный от типа выражения (или вычисляемого в данный момент подвыражения), преобразовываются в значения, тип которых совпадает с типом выражения. Например, переменная з в операторе
з = "Результат = " + 4 / "2-я строка";
получит символьный тип и значение, равное "Результат = 2". Действительно, операция / имеет более высокий приоритет, чем операция +, поэтому прежде будет вычислено подвыражение 4/"2-я строка", которое, судя по его первому операнду, является числовым и поэтому вернет число 2. Далее это число будет преобразовано в строку "2", которая объединится со строкой "Результат = ".
Результатом выражения будет пустое значение, если первый операнд выражения имеет пустое значение. Например:
перем а; // Объявляем скалярную переменную а
б = 2 + а; // Вернет 2
в = а + 2; // Вернет пустое значение
Переменная агрегатного типа данных воспринимается в выражениях, имеющих более одного операнда, как пустое значение. Например:
табл = СоздатьОбъект("Таблица");
а = табл + 2; // Вернет пустое значение
б = табл; // Типы переменных б и табл совпадают
Выражение называется логическим, если в нем есть хотя бы одна операция отношения или логическая операция. Например:
2.5 /1.33 > 0 //Вернет 1
(а = 5) и (б = 2) // Вернет 0, если, например, а = 1
Логические выражения употребляются в управляющих конструкциях языка, например
если 2.5 /1.33 > 0 тогда Сообщить(''Да''); -иначе
Сообщить("Нет");
конецЕсли;
Замечания:
1. Логические выражения отличаются от иных, например числовых, выражений 1С тем, что их нельзя использовать в правой части оператора присваивания или в качестве фактических параметров процедур, функций и методов. Так, ошибочен оператор
флаг = (а = 5) и (б = 2); // Ошибка! В правой части оператора присваивания
// размещено логическое выражение
Этот недостаток создает определенные неудобства при записи программ.
2. Тип данных выражения возвращают функции ТипЗначения и ТипЗначенияСтр. Первая возвращает число, по которому определяется тип данных ее параметра, вторая - имя типа данных параметра. Например:
а =1.2;
Сообщить(ТипЗначения(а)); // Напечатает 1
Сообщить(ТипЗначенияСір(а)); // Напечатает Число
сСотр = СоздатьОбъект("Справочник.Сотрудники");
Сообщить(ТипЗначенияСтр(сСотр)); // Напечатает Справочник
2.6.2. АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ ДЛЯ ЧИСЛОВОГО
ТИПАДАННЫХ
С каждым типом данных связан набор операций. С числовыми данными употребляются известные арифметические операции *, /, +, - и операция %, возвращающая остаток от деления операндов, например:
|
5 % 2 |
// |
Вернет 1 |
|
5.2 % 2 |
// |
Вернет 1 |
|
5.8 % 2 |
// |
Вернет 0 |
|
5.8 % "2-я строка" |
// |
Также вернет 0 |
Из примеров видно, что при вычислении результата выражения с операцией % числовые операнды округляются до целых значений (если второй операнд является нечисловым, то он прежде приводится к числовому типу), а затем вычисляется остаток от деления двух целых чисел.
2.6.3. ОПЕРАЦИИ ДЛЯ СТРОК И ДАТ
В символьных выражениях допустима только операция +, называемая операцией конкатенации. Например:
"1-я строка и " + "строка 2" // Вернет строку "1-я строка и строка 2"
В выражениях типа Дата можно употреблять операции + и -, например
'21.12.01'+11; // Выражение типа Дата, возвращающее дату 01.01.02
'21.12.01' -11; // Выражение типа Дата, возвращающее дату 10.12.01
Следующее выражение ошибочно:
'21.12.01' * 11 // Операция * недопустима в выражениях типа Дата
2.6.4. "ИСТИНА" И "ЛОЖЬ" В 1С
Констант со значениями истина и ложь во встроенном языке 1С нет. В то же время понятия истина и ложь используются в 1С при оценке логических выражений, появляющихся в управляющих конструкциях языка.
2.6.5. ОПЕРАЦИИ ОТНОШЕНИЯ
В логических выражениях используются приведенные в табл. 2.4 операции отношения.
Таблица 2.4
|
Операции отношения |
|
Операция |
Описание |
|
< |
Меньше |
|
<= |
Меньше или равно |
|
> |
Больше |
|
>= |
Больше или равно |
|
= |
Равно |
|
<> |
Не равно |
|
Операндами операций отношения могут быть выражения числового или символьного типа, а также даты. Причем типы операндов должны совпадать. Например:
2 = 5 // Это ложь
"Строка 2">"Строка 1" // Это истина
2<'23.12.01'> // Это неверное выражение отношения, так как его
// операнды имеют разный тип
Также операндами операций = и <> могут быть переменные агрегатного типа. Например:
тЗнач1 = СоздатьОбъект("ТаблицаЗначений"); сСотр = СоздатьО6ъект("Справочник.Сотрупники"); тЗнач2 =тЗнач1;
// Круглые скобки в нижезаписанном логическом выражении обязательны если (тЗначІ = тЗнач2) и (тЗначІ = сСотр) тогда
Сообщить("Да");
иначе
Сообщить("Нет");
конецЕсли;
Если операция отношения выполняется над строками, то они сравниваются посимвольно до тех пор, пока не будут обнаружены несовпадающие символы. Они то и решат судьбу сравнения. Следует помнить, что символ сим_1 больше сим_2, если код символа сим_1 больше кода символа сим_1. Если строки-операнды операции отношения имеют разную длину и если есть необходимость продолжить сравнение символов строк-операндов (все предыдущие сравниваемые символы оказались равными), то в качестве недостающего символа более короткой строки используется символ с нулевым кодом. Например:
"Строка" > "Строка 1" // Это ложь
2.6.6. ЛОГИЧЕСКИЕ ОПЕРАЦИИ
Применяются следующие логические операции:
НЕ - логическое НЕ (отрицание);
И - логическое И;
ИЛИ - логическое ИЛИ.
Операндами логических операций должны быть логические выражения. В табл. 2.5 приведены результаты логических операций над логическими выражениями ЛВ1 и ЛВ2, принимающими значения истина (И) или ложь (Л).
Таблица 2.5
|
Таблица истинности |
|
ЛВ1 |
ЛВ2 |
ЛВ1 ИЛВ2 |
ЛВ1 ИЛИ ЛВ2 |
НЕ ЛВ1 |
|
И |
И |
И |
И |
Л |
|
И |
Л |
Л |
И |
Л |
|
Л |
И |
Л |
И |
И |
|
Л |
Л |
Л |
Л |
И |
|
|
Операция отрицания является унарной операцией, располагаемой слева от операнда. Все остальные рассмотренные операции являются бинарными. |
2.6.7. ПРИОРИТЕТ ВЫПОЛНЕНИЯ ОПЕРАЦИЙ
Все операции 1С выполняются в выражении слева направо в соответствии с их приоритетом (старшинством), то есть, если две последовательные операции имеют равный приоритет, первоначально выполняется левая операция. Подвыражения, заключенные в круглые скобки, вычисляются в первую очередь. В табл. 2.6 операции 1С расположены в порядке убывания их приоритета.
Таблица 2. б
Приоритет выполнения операций |
|
% |
*,/ |
+ , - |
НЕ |
И |
ИЛИ |
<, <=, >, >=, =, <> |
|
Замечание. Каждая ячейка таблицы содержит операции с равным приоритетом. Пример:
8 % 2 * 3 // Вернет 0
8 % (2 * 3) // Вернет 2
Поскольку логические операции старше операций отношения, то ошибочно следующее логическое выражение:
3>2и4<5 // Так неверно
так как первоначально оценивается логическое подвыражение 2и4
операнды которого не есть истина или ложь. А это неверно.
Зато верно логическое выражение
(3 > 2) и (4 < 5) // Это истина
Пример. Вычислить результат логического выражения
(х / а = 1) или (б / (а + б) < 1) и не (б = а) или (х <> 6) при х = 6.0, а = 2.0 и б=3.0.
Вычислив результат операций подвыражений, заключенных в круглые скобки, получим:
ложь или истина и не ложь или ложь.
Далее выполняем пошагово логические операции с учетом их приоритета. После выполнения не ложь:
ложь или истина и истина или ложь.
После выполнения истина и истина: ложь или истина или ложь.
Окончательный результат: истина.
2.7. МАССИВЫ
Массив - это объект данных, содержащий несколько значений, доступ к которым осуществляется по их номеру (индексу).
Число элементов массива называется его размером. Размером массива может быть только целочисленная буквальная константа.
Оператор
перем а[5];
объявляет одномерный массив (вектор) а из пяти элементов. Элементы массива имеют следующие имена: а[1], а[2], а[3], а[4] и а[5]. В этих именах величины 1-5 - индексы элементов массива.
Массив считается определенным, если заданы значения всех его элементов. Для задания начальных значений элементов массива (инициализации массива) возможен следующий цикл:
для ин = 1 по 5 цикл
а[ин] = 1; // Теперь все элементы массива равны единице
конецЦикла;
Присваивания
а[2] = 3; а[5] = -4.7;
изменят соответственно значения 2-го и 5-го элементов массива а.
В общем случае в качестве индексов массива могут использоваться числовые выражения, называемые индексными выражениями. Например:
а[6 / 2] = 9.1; // Меняем значение 3-го элемента массива а
Если индексное выражение массива вычисляется с нецелым значением, то в каче стве индекса берется целая часть этого значения. Например:
а[6 / 5] = 9.1; // Меняем значение 1 -го элемента массива а
Значение индекса не должно выходить за границы массива. Так, при работе с ранее объявленным массивом а из пяти элементов ошибочны операторы
а[0] = 5; // Индекс не может быть меньше числа 1
а[6] = 9; // Индекс не может быть больше числа 5
Элементы одного и того же массива могут быть разного типа. Например:
а[1] = 5; //Элемент числового типа
а[3] = "Строка"; // Элемент символьного типа
а[5] = '25.11.01'; // Элемент типа Дата
Элементы массива могут быть агрегатного типа. Например:
сСотр= СоздатьОбъект(''Справочник. Сотрудники"); табл = СоздатьОбъект("Таблица");
а[1] = 5; // Элемент числового типа
а[3] = сСотр; // Элемент агрегатного типа
а[5] = табл; // Элемент другого агрегатного типа
Массив не может в качестве элементов содержать другие массивы.
Массив может быть формальным параметром программного компонента (процедуры или функции). При этом размер массива не указывается, а квадратные скобки сохраняются. Для определения размера переданного процедуре (функции) массива используется встроенная функция Разм.
Пример:
процедура ИнициализаиияМассива(а[ ]) перем ин, размА;
размА = Разм(а); // Встроенная функция Разм вернет размер массива а
для ин = 1 по размА цикл
а[ин] = 1; // Теперь все элементы массива равны единице
конецЦикла; а[3] = -5;
конецПроцедуры // ИнициализацияМассива
процедура Выполнить() перем а[5];
// Вызов процедуры, устанавливающей начальные значения элементов массива // Ее фактическим параметром является имя массива ИнициализацияМассива(а);
Сообщить(а[2]); // Напечатает 1
Сообщить(а[3]); // Напечатает -5
конецПроцедуры // Выполнить
2.8. ВСТРОЕННЫЕ ФУНКЦИИ ДЛЯ РАЗНЫХ ТИПОВ ДАННЫХ
2.8.1. ВСТРОЕННЫЕ МАТЕМАТИЧЕСКИЕ ФУНКЦИИ
Приведенные в табл. 2.7 математические функции применяются с числовыми типами данных. Они имеют в качестве аргументов числовые выражения и возвращают (если при их исполнении не возникло ошибки) некоторое число.
Математические функции
|
Таблица 2.7 |
|
Функция |
Что возвращает |
результат = Окр(число, [числоЗнаков],
[способ]); |
Округленное значение параметра число. Параметр числоЗнаков, если он присутствует, задает число знаков дробной части результата. Значение по умолчанию - 0. Параметр способ, если он вычисляется со значением 1, устанавливает, что число вида 1.5 округляется до числа 2 или округляется до числа 1 в противном случае.
Значение по умолчанию - 0 |
|
результат = Цел(число); |
Целую часть параметра число |
|
минЗначение = Мин(число1, [число2],..., [числоК); |
Минимальное значение своих параметров. Может иметь только один параметр - число! |
|
максЗначение = Макс(чнсло1, [число2],..., [числоN); |
Максимальное значение своих параметров. Может иметь только один параметр - число1 |
|
результат = Лог10(число); |
Десятичный логарифм аргумента число или нуль, если аргумент меньше нуля. Возникнет завершающая ошибка, если аргумент равен нулю |
|
результат - Лог(число); |
Натуральный логарифм аргумента число или нуль, если аргумент меньше нуля. Возникнет завершающая ошибка, если аргумент равен нулю |
|
Примеры:
|
Сообщить(Окр(2.45, 1, |
1)); |
//2.5 |
|
Сообщить(Окр(2.45, 1, 0)); |
// |
2.4 |
|
Сообщить(Окр(2.597)); |
// |
3 |
|
Сообщить(Цел(2.9)); |
// |
2 |
|
Сообщить(Мин(-2.9,-5, |
12)); |
//-5 |
2.8.2. ВСТРОЕННЫЕ ФУНКЦИИ ДЛЯ СИМВОЛЬНЫХ ДАННЫХ
Приводятся в табл. 2.8. Параметры, имя которых содержит слово строка или текст, являются символьными выражениями, а имеющие слово число - числовыми. Используются целые части числовых параметров, если они являются нецелыми числами.
Таблица 2.8
Функции для строк |
|
функция |
Что возвращает |
|
длина - СтрДлина(строка); |
Длину параметра строка |
|
флаг = ПустаяСтрока(строка); |
Число 1, если строка имеет нулевую длину или состоит из одних пробелов, или 0 -в противном случае |
|
новаяСтрока - СокрЛ(строка); |
Строку, получаемую в результате удаления ведущих пробелов в аргументе строка |
|
новаяСтрока = Сокр П(строка); |
Строку, получаемую в результате удаления завершающих пробелов в аргументе строка |
|
новаяСтрока = СокрЛП(строка); |
Строку, получаемую в результате удаления ведущих и завершающих пробелов в аргументе строка |
|
подстрока = Лев(строка, число); |
Строку, содержащую первые число символов параметра
строка или всю строку строка, если число =>
СтрДлина(строка). Если число <=0, то возвращается строка нулевой длины |
|
подстрока = Прав(строка, число); |
Строку, содержащую последние число символов
параметра строка или всю строку строка, если число >
СтрДлина(строка). Если число < 0, то возвращается строка нулевой длины |
|
подстрока = Сред(строка, число1, [число 2]); |
Строку, содержащую подстроку параметра строка, начинающуюся с символа под номером число 1 длиной число2. Если параметр число2 опущен, возвращается подстрока, начинающаяся с символа под номером число1
длиной до конца строки. Если число1 >
СтрДлина(строка) или число2 < 0, то возвращается
строка нулевой длины. Если параметр число1 < 0, то он принимается равным единице |
|
позиция = Найти(строка, подстрока); |
Позицию, с которой подстрока начинается в параметре строка, или нуль, если подстрока не найдена в первом параметре |
новаяСтрока = СтрЗаменить
(строка, подстрока!, подстрока2); |
Строку, в которой все вхождения параметра подстрока 1 в параметр строка заменены на параметр подстрока2 |
|
кол = СтрЧислоВхождений(строка, подстрока); |
Число вхождений параметра подстрока в параметр строка |
|
|
Функция |
Что возвращает |
|
кол = СтрКоличествоСтрок {текст); |
Число строк в тексте текст. Строки в тексте разделены символом РазделительСтрок (см. разд. 2.3) |
|
стр = СтрПолучитьСтроку(текст, номерСтроки); |
Строку параметра текст, имеющую номер номерСтроки. Если номерСтроки < 0 или номерСтроки больше числа строк в тексте, то возвращается строка нулевой длины |
|
новаяСтрока = Врег(строка); |
Строку, в которой все символы параметра строка преобразованы в верхний регистр |
|
новаяСтрока - Нрег(строка); |
Строку, в которой все символы параметра строка преобразованы в нижний регистр |
|
новаяСтрока = OemToAnsi (строка); |
Строку, в которой OEM-коды символов параметра строка преобразованы в ANSI-коды |
|
новаяСтрока = AnsiToOem (строка); |
Строку, в которой ANSI-коды символов параметра строка преобразованы в ОЕМ-коды |
|
символ = Симв(кодСимвола); |
Символ, код которого равен значению параметра кодСимвола |
|
код = КодСимв(строка); |
Код первого символа параметра строка |
| поскольку она размещается не на одной,
| а на трех строчках"; кол = СтрКоличествоСтрок(текст); стр = СтрПолучитьСтроку(текст, 3); новаяСтрока = Врег("ааббсс"); новаяСтрока = Нрег("ААББСС"); стр = "вГСбв DOS"; новаяСтрока = OemToAnsi(CTp); новаяСтрока = АпзіТоОет(новаяСтрока); символ = Симв(200); код = КодСимв("И"); код = КодСимв("ИЛИ");
// Вернет 3
// Вернет "а на трех строчках"
// Вернет "ААББСС"
// Вернет "ааббсс"
// Содержит значение "текст DOS" в DOS-кодировке // Вернет строку "текст DOS" в кодировке ANSI // Вернет вГСбв DOS уже в кодировке OEM // Вернет И // Вернет 200 // Вернет 200
2.8.3. ВСТРОЕННЫЕ ФУНКЦИИ ДЛЯ ДАТ И ВРЕМЕНИ
1С, как и полагается программе бухгалтерского назначения, хранит много различных Дат, для управления которыми и доступа к которым используются приводимые в табл. 2.9
функции. Параметры, имя которых содержит слово дата, - это выражения типа Дата. Параметр вариант может быть либо датой, либо выражением символьного типа. Прочие параметры - это числовые выражения. Большинство функций, если они получают в качестве параметра несуществующую дату, например '33.10.01', возвращают пустое значение типа Дата. Например:
Сообщить(НачМесяца('33.10.01')); //Напечатает . .
|
|
Таблица 2.9
Функции для дат |
|
Функция |
ЧТО возвращает |
|
рДатаТек = РабочаяДата ([рДата], [режимСмены]); |
Устанавливает/возвращает рабочую дату, то есть дату, используемую при формировании документов и проводок в текущем сеансе. Параметр режимСмены применяется при смене рабочей даты на значение параметра рДата и установки режима смены рабочей даты в полночь. Причем если режимСмены задается равным числу
• 0, то рабочая дата в полночь не меняется;
• 1, то система предлагает изменить рабочую дату в полночь;
• 2, то рабочая дата меняется в полночь автоматически. Если параметр режимСмены не задан, то при вызове функции РабочаяДата сохраняются заданные в системе установки режима смены. Если новое значение даты -это несуществующая дата, то рабочая дата не меняется. Рабочую дату можно также изменить, воспользовавшись в 1 С: Предприятии пунктами меню Сервис- Параметры
и выбрав в появившемся окне закладку Общие (см. рис. 2.1). По умолчанию рабочая и текущие даты
совпадают |
|
тДата = ТекущаяДата(); |
Текущую (системную) дату |
|
новаяДата = ДобавитьМесяц (дата, числоМесяцев); |
Дату, получаемую в результате прибавления к значению параметра дата заданного вторым параметром числа месяцев. Значение параметра числоМесяцев может быть меньше нуля |
|
нМесяца = НачМесяца(дата); |
Дату начала месяца, которому принадлежит дата |
|
кМесяца = КонМесяца(дата); |
Дату конца месяца, которому принадлежит дата |
нКвартала =
НачКвартала(дата); |
Дату начала квартала, которому принадлежит дата |
кКвартала =
КонКвартала(дата); |
Дату конца квартала, которому принадлежит дата |
|
нГода = НачГода(дата); |
Дату начала года, которому принадлежит дата |
|
кГода = КонГода(дата); |
Дату конца года, которому принадлежит дата |
|
Функция |
Что возвращает |
|
нНедели = НачНедели(дата); |
Дату начала недели, которой принадлежит дата |
|
кНедели - КонНедели(дата); |
Дату конца недели, которой принадлежит дата |
|
год = ДатаГод(дата); |
Числовое значение года, которому принадлежит дата |
|
месяц = ДатаМесяц(дата); |
Номер месяца, которому принадлежит дата |
|
число = ДатаЧисло(дата); |
Номер дня месяца, заданного параметром дата |
неделя =
НомерНеделиГода(дата); |
Номер недели года, которой принадлежит дата |
деньГода =
НомерДняГода(дата); |
Номер дня года, заданного параметром дата |
деньНедели =
НомерДняНедели(дата); |
Номер дня недели, заданного параметром дата (нумерация дней начинается с понедельника) |
период = ПериодС тр
(датаНачПериода,
датаКонПериода); |
Символьное представление периода, границы которого задаются значениями параметров функции. Если период -это месяц, квартал, полугодие или год, то выводится соответствующее название периода, например 1 Полугодие 2002 г. |
нИнтервала = Начало
СтандартногоИнтервала
([вариант]); |
Устанавливает/возвращает вариант задания начала стандартного интервала отображения журнала документов. Параметр вариант, если он имеет тип Дата, задает дату начала интервала журнала документов. Если параметр -это символьное выражение, то оно должно вычисляться со следующими значениями: "День", "Месяц", "Квартал", "Год". Если параметр опущен или содержит неверное значение, имеющаяся в системе установка сохраняется. Начало стандартного интервала можно задать в 1С:Предприятии, обратившись к пунктам меню Сервис -Параметры и выбрав в появившемся окне закладку
Журналы (рис. 2.3) |
кИнтервала = Конец
СтандартногоИнтервала
([вариант]); |
Устанавливает/возвращает вариант задания конца стандартного интервала отображения журнала документов. Параметр вариант имеет тот же, что и для предшествующей функции, смысл с той разницей, что задает конец стандартного интервала |
время = ТекущееВремя
([час], [мин], [сек]); |
Строку, отображающую текущее (системное) время. Если заданы параметры час, мин и сек, то функция запишет в них числовые значения соответственно часа, минут и секунд
текущего времени |
флаг = ВвестиПериод
(нПер, кПер, заг) |
Единицу, если в выведенном диалоге (рис. 2.4) задания даты начала (нПер) и даты конца (кПер) периода нажата кнопка ОК, или нуль, если нажата кнопка Отмена, или клавиша Esc, или кнопка, закрывающая окно диалога. Символьный параметр заг задает заголовок диалогового
окна |
ВСТРОЕННЫЕ ФУНКЦИИ ПРЕОБРАЗОВАНИЯ ТИПОВ ДАННЫХ
Примеры:
длина = СірДпина("ААББСС"); флаг = ПустаяСтрока(" ААББСС"); новаяСтрока = СокрЛП(" ААББСС "); подстрока = Лев(" ААББСС", 2); подстрока = Прав("ААББСС", 2); подстрока = Сред("ААББСС", 3); подстрока = Сред("ААББСС", 3,2); позиция = Найти("ААББСС", "БС"); позиция = Найти("ААББСС", "БС1"); новаяСтрока = СтрЗаменить("ААББАА", кол = СтрЧислоВхождений("ААББАА",
текст = "Это длинная символьная константа,
// Вернет 6 // Вернет О // "ААББСС"
// Вернет "АА"
// Вернет "СС"
// Вернет "ББСС // Вернет "ББ"
// Вернет 4 // Вернет О "АА", "ДДЦ") "АА");
// Вернет "ДДЦББДДЦ" // Вернет 2
Общие I Текст | Интерфейс Журнаіы |
|
Конец интервала f~ Текшая дата Конец месяца <• Конец квартала Конец года |
 |
Начало интервала Текущая дата '• Начало иес<»іа Начало квартала Т~ Начало года Г |1010 2001 [^J
Рис. 2.3. Задание начала и конца стандартного интервала на закладке Журналы
 |
|
Рис. 2.4. Диалог задания дат начала и конца периода |
|
Примеры: |
|
рДата = РабочаяДата(); |
// 10.10.01 |
|
тДата = ТекущаяДата(); |
// 10.10.01 |
|
новая Дата = ДобавитьМесяц(рДата, -2); |
// 10.08.01 |
|
нМесяца = НачМесяца(рДата); |
//01.10.01 |
|
кМесяца = КонМесяца(рДата); |
//31.10.01 |
|
нКвартала = НачКвартала(рДата); |
//01.10.01 |
|
кКвартала = КонКвартала(рДата); |
//31.12.01 |
|
нГода = НачГода(рДата); |
//01.01.01 |
|
кГода = КонГода(рДата); |
//31.12.01 |
|
нНедели = НачНедели(рДата); |
//08.10.01 |
|
кНедели = КонНедели(рДата); |
//14.10.01 |
|
год = ДатаГод(рДата); |
//2001 |
|
месяц = ДатаМесяц(рДата); |
//10 |
|
дч = ДатаЧисло(рДата); |
//10 |
|
неделя = НомерНеделиГода(рДата); |
//41 |
|
деньГода = НомерДняГода(рДата); |
//283 |
|
деньНедели = НомерДняНедели(рДата); |
// 3 |
|
период = ПериодСтр(нКвартала, кКвартала); |
//4 Квартал 2001 г. |
|
// Новая установка начала стандартного интервала НачалоСтандартногоИнтервалаС'Месяц"); нИнтервала = НачалоСтандартногоИнтервала( ); |
// Месяц |
|
// Новая установка конца стандартного интервала
КонецСтандартногоИнтервала("Квартал"); // Квартал
кИнтервала = КонецСтандартногоИнгервала(); // 4 Квартал 2001 г.
время = ТекущееВремя(); // 19:53:12
// Подготовка к вызову диалога (рис. 2.4) задания дат начала и конца периода
// Устанавливаем значения дат, отображаемых в диалоге
нПер = '01.04.01'; кПер = '30.06.01';
флаг = ВвестиПериод(нПер, кПер, "Введите период");
Замечание. При работе с датами на всем временном интервале, начиная от рождества Христова, используется григорианский календарь, который берет отсчет от 4 октября 1582 г. по юлианскому календарю. Причем этот день юлианского календаря стах 15 октября 1582 г. в григорианском.
Функцию ТекущееВремя часто употребляют для замера времени вычисление (правда, достаточно продолжительных, поскольку функция не возвращает миллисекунды), например так:
Замеряет время вычислений нСек - время начало вычислений кСек - время конца вычислений
// Фиксируем время начала вычислений
Некоторые вычисления // А это время конца вычислений
перем времяВычислений; перем ин, с;
ТекущееВремя(нЧас, нМин, нСек);
// Некоторые вычисления с = 0;
для ин = 1 по 500000 цикл
с = с + (ин * 2) / ин; //
конецЦикла;
ТекущееВремя(кЧас, кМин, кСек);
// Время вычислений в секундах времяВычислений = (кЧас - нЧас) * 3600 + (кМин - нМин) * 60 + (кСек - нСек); Сообщшъ("Длительность процесса равна " + времяВычислений + " сек."); конецПроцедуры // Выполнить
2.8.4. ВСТРОЕННЫЕ ФУНКЦИИ ПРЕОБРАЗОВАНИЯ ТИПОВ ДАННЫХ
Как мы видели, в выражениях с операндами разных типов данных преобразования типов выполняются автоматически в соответствии с описанными в разд. 2.5 правилами. При этом тип выражения определяется типом его первого операнда. Используя такое свойстве выражений 1С, можно решать вопросы преобразования типов данных, такие, как преобразования "число - строка", "дата - число" и обратные. Покажем это на примерах.
Пример 1. Преобразования "число - строка" и "строка - число".
перем а, б, стр; а =123.45;
// Преобразование "число - строка". Переменная стр имеет символьный тип, поскольку // первый операнд выражения "" + а - это строка
стр = "" + а; // В результате имеем стр = "123.45"
стр = стр + "67"; // Имеем: стр = "123.4567"
// Имеем: стр = "25.10.02"
// Напечатает Строка
Некоторые преобразования типов данных можно выполнять, применяя приведенные в табл. 2.10 встроенные преобразовывающие функции.
Таблица 2.10
Функции преобразования типов данных |
|
Функция |
Что делает |
Вариант 1:
дат = Дата(параметр); Вариант 2:
дат = Дата(год, месяц, число); |
В первом варианте функция преобразовывает значение выражения параметр в значение типа Дата. Выражение может быть числовым, символьным или типа Дата. В первом случае значение выражения трактуется как число дней от Рождества Христова и преобразовывается в соответствующую дату, во втором случае строка преобразовывается в дату, в третьем преобразований не выполняется.
Во втором варианте функция преобразовывает дату, заданную числовыми выражениями год, месяц, число, в значение типа Дата. Причем для задания значения параметра год используются все цифры, а не две последние |
|
|
Функция |
Что делает |
|
стр = Строка(параметр); |
Преобразовывает значение выражения параметр в строку. Выражение может быть датой или иметь числовой или символьный тип. В последнем случае преобразований не выполняется |
|
чис = Чиспо(параметр); |
Преобразовывает значение выражения параметр в число. Выражение может быть датой или иметь символьный или числовой тип. В последнем случае преобразований не выполняется |
|
|
Примеры (используем при выводе две цифры для представления года даты): |
2.8.5. ФОРМАТИРОВАНИЕ ДАННЫХ
Представление данных при их выводе на различные носители можно изменять, применяя встроенную функцию Формат, имеющую следующий синтаксис:
представлениеЗначения = Формат(значение, форматнаяСтрока);
Функция Формат, получив значение, преобразовывает его в соответствии с правилами, заданными символьным параметром форматнаяСтрока, и возвращает результат в виде строки с отформатированными данными.
Пример. Выводится число -123.45 на поле длиной в 9 символов. В четырех последних символах поля отображаются знаки числа, стоящие после десятичной точки.
Сообщить(Формат(-123.45, "49.4")); // Напечатает -123.4500
Форматная строка может начинаться с символов Ч, С или Д, если форматируются соответственно числовые, символьные данные или даты. Если тип данных не соответствует, употребленному символу, то до форматирования будет выполнено соответствующее преобразование типов, например
Сообщить(Формат("21-я строка", "45.2")); // Напечатает 21.00
2.8.5.1. ФОРМАТИРОВАНИЕ ЧИСЛОВЫХ ДАННЫХ
Параметр форматнаяСтрока при форматировании числовых данных в общем случае имеет следующий вид:
"Ч[3][0][Д][.Т][Р1][Р2][>С]"
Появляющиеся в форматной строке обозначения имеют следующий смысл:
• 3 - заполнитель ведущих пробелов, присутствующих в строке-результате функции Формат. Если на месте заполнителя указать (0), то ведущие пробелы заменяются на нули;
• 0 - флаг вывода пустого поля, когда форматируемое значение равно нулю;
• Д - длина результирующей строки в символах;
• Т - число знаков после десятичной точки (точность);
• Р1 - символ, отделяющий целую часть числа от нецелой. По умолчанию в качестве разделителя Р1 используется точка;
• Р2 - символ, разделяющий триады. (Триада - это тройка последовательных чисел в целой части числа. Например, число 1234567 при форматировании с разделением на триады, когда на месте Р2 стоит символ ', примет вид 1'234'567.) По умолчанию триады не разделяются;
• С - размер правого сдвига форматируемого значения. В результате сдвига удаляются С правых символов целой части форматируемого числа.
Примеры:
Сообщить(Формат( 1234567.89, "Ч(0)20.4")); // Напечатает 000000001234567.8900
Сообщить(Формат( 1234567.89, "Ч14.4,_")); // Напечатает 1_234_567,8900
Сообщить(Формат( 123456000, "Ч(0)14>3")); // Напечатает 00000000123456
Если длина результирующей строки недостаточна для представления значения, то на месте результата напечатаются девятки и заданные разделители, например
Сообщить(Формат(1234567.89, "Ч8.2,_")); // Напечатает 9_999,99 .
Функция Формат выполнит преобразование "число - строка" без форматирования, если форматная строка не содержит компонентов Д и/или .Т или не имеет вид "ЧП[Д][С]", например
пред = Формат(21, "ЧМ"); // Вернет 21
2.8.5.2. ВЫВОД ДЕНЕЖНЫХ ВЕЛИЧИН И ЦЕЛЫХ ЧИСЕЛ ПРОПИСЬЮ
Форматируемое значение выводится
• прописью как целое число, если форматная строка имеет вид "ЧП";
• прописью в виде денежной суммы без копеек, если форматная строка имеет вид "ЧПД";
• прописью в виде денежной суммы с копейками, если форматная строка имеет вид "ЧПДС";
Примеры:
Сообщить(Формат(59421.67, "Ч П"));
Сообщить(Формат(5 9421.67, "ЧЦД"));
Сообщить(Формат(59421.67, "ЧПДС"));
Пятьдесят девять тысяч четыреста двадцать два Пятьдесят девять тысяч четыреста двадцать два рубля Пятьдесят девять тысяч четыреста двадцать один рубль 67 копеек
По умолчанию образцы для представления чисел прописью берутся из файла 1CV7.SPL, который размещен в папке BIN и содержит 5 секций со следующими данными:
{"Speller",
{"Money",
{"Рубль", "Рубля", "Рублей", "Копейка", "Копейки", "Копеек", "М"}},
{"Numbers",
{"Один", "Два", "Три", "Четыре", "Пять", "Шесть", "Семь", "Восемь", "Девять", "Одна", "Две",
"Десять", "Одиннадцать", "Двенадцать", "Тринадцать", "Четырнадцать", "Пятнадцать", "Шестнадцать", "Семнадцать", "Восемнадцать", "Девятнадцать", "Двадцать", "Тридцать", "Сорок", "Пятьдесят", "Шестьдесят", "Семьдесят", "Восемьдесят", "Девяносто", "Сто", "Двести", "Триста", "Четыреста", "Пятьсот", "Шестьсот", "Семьсот", "Восемьсот", "Девятьсот",
"Тысяча", "Тысячи", "Тысяч",
"Миллион", "Миллиона", "Миллионов",
"Миллиард", "Миллиарда", "Миллиардов",
"Триллион", "Триллиона", "Триллионов",
"Нуль"}},
{"Date",
{"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь",
"Января", "Февраля", "Марта", "Апреля", "Мая", "Июня", "Июля", "Августа", "Сентября", "Октября", "Ноября", "Декабря",
"г.", "Квартал"}},
{"DateRange",
{"Полугодие", "Месяцев"}},
{"WeekDay",
{"Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"}}
}
Замечание. Последний элемент секции Money - это латинская буква М или F (сокращения от male и female), указывающая, какой род (мужской или женский) используется для представления денежных единиц.
Изменить способ вывода числа прописью можно, обратившись к процедуре Пропись, рассмотренной в разд. 2.8.5.5.
2.8.5.3. ФОРМАТИРОВАНИЕ СИМВОЛЬНЫХ ДАННЫХ
Форматная строка при форматировании символьных данных имеет вид "С[Д]", где Д - длина результирующей строки. Если Д больше длины форматируемой строки, то последняя дополняется пробелами справа, если меньше, то в результате сохраняются первые Д символов. Например:
Сообщить(СтрДлина(Формат("ААББВВ", "С10"))); // Напечатает 10
Сообшить(Формат("ААББВВ", "С2")); // Напечатает АА
Форматируемая строка не изменяется, если компонент Д форматной строки отсутствует или на его месте стоит не число. Например:
Сообщшъ(Формат("ААББВВ", "С"))); // Напечатает ААББВВ
Сообщшъ(Формат("ААББВВ", "СК")); // Напечатает ААББВВ
2.8.5.4. ФОРМАТИРОВАНИЕ ДАТ
При форматировании дат форматная строка начинается с буквы Д. Варианты задания форматной строки приведены в табл. 2.11. В ее последнем столбце приводятся результаты форматирования дат 21.12.01 и 05.12.01.
Таблица 2.11
Форматные строки для дат |
|
Форматная строка |
Вид результата |
Примеры |
|
"ДДЦММГГ |
дд.мм.гг |
21.12.01 |
|
"ДДЦММГПТ" |
дд.мм.гггг |
21.12.2001 |
|
"ДДДММММГПТ" |
ДД месяц прописью ГГГГ г. |
5 Декабря 2001 г. |
|
"Д(0)ДДММММГГГГ" |
ДД месяц прописью ГГГГ г., если в дне две цифры |
21 Декабря 2001 г. |
|
|
ОД месяц прописью ГГГГ г., если в дне одна цифра |
05 Декабря 2001 г. |
|
"ДММММГПТ" |
Месяц прописью ГГГГ г. |
Декабрь 2001 г. |
|
"ДММММГГ" |
Месяц прописью ГГ г. |
Декабрь 01г. |
|
"ДММММ" |
Месяц прописью |
Декабрь |
|
"ДККККГПТ" |
Номер квартала ГГГГ г. |
4 Квартал 2001 г. |
|
"ДККККГТ" |
Номер квартала ГГ г. |
4 Квартал 01 г. |
|
"ДКККК" |
Номер квартала. |
4 Квартал |
|
"ДГГГММДД" |
ГГГММДЦ |
20011205 |
|
"ДНННН" |
Название дня недели даты; по умолчанию берется из секции WeekDay файла 1CV7.SPL |
Среда |
|
Представление даты не изменяется, если форматная строка не отвечает приведенным в табл. 2.11 требованиям.
28.5.5. ИЗМЕНЕНИЕ СПОСОБА ВЫВОДА ЧИСЕЛ ПРОПИСЬЮ
Осуществляется процедурой Пропись([образец]); в которой параметр образец - это
• либо строка, задающая имя файла образцов прописей;
• либо переменная типа СписокЗначений, содержащая образцы прописей (тип данных СписокЗначений рассмотрен в разд. 3.2);
• либо пустая строка.
: '25.10.02' '25.10.02'
^ '25.10.02'
: '25.10.02' '25.10.02'
: "25.10.02" "123.45"
: "25.10.02"
2452573
2452573
123.45
123.45
= -123.45
123.45
("число - дата") ("строка - дата") ("строка - дата") ("дата - дата")
("дата - строка") ("число - строка") ("строка - строка") ("дата - число") ("дата - число") ("строка - число") ("строка - число") ("строка - число") ("число - число")
дат = Дата(2452573); дат = Дата("25.10.2002"); дат = Дата("25.10.02"); дат = Дата('25.10.2002'); дат = Дата(2002, 10, 25); стр = Строка('25.10.02'); стр = Строка(+123.45); стр = Строка("25.10.02"); чис = Число('25.10.2002') чис = Число('25.10.02'); чис = Число("123.45"); чис = Число("+123.45"); чис = Число("-123.
чис = Число(123.45);
// Имеем: дат =
// Имеем: дат =
// Имеем: стр =
; // Имеем: чис =
45'); // Имеем: чис
//Имеем: чис=
В последнем случае образцы прописей берутся из заданного по умолчанию файла 1CV7.SPL. Также этот файл используется, если параметр образец опущен или если обращений к процедуре Пропись не было.
При задании файла образцов прописей нужно сохранять имеющиеся в файле по умолчанию (1CV7.SPL) секции и последовательность расположения образцов.
При задании параметра образец в виде списка значений в нем можно определять либо все секции, имеющиеся в файле 1CV7.SPL, либо часть из них. В первом случае элементами параметра образец являются 5 списков значений, элементы которых - это образцы представлений числовых данных следующих секций:
• Money;
• Numbers;
• Date;
• DateRange;
• WeekDay.
Порядок задания образцов определен в файле 1CV7.SPL.
Если образец включает не все секции, то в список значений, содержащий образец, в качестве представления заносится название соответствующей секции.
Пример. Формируется список значений сЗнач, содержащий секцию WeekDay, с образцами, отличающимися от приведенных в файле 1CV7.SPL. Далее сЗнач используется в качестве параметра образец процедуры Пропись. С использованием нового образца функцией Формат выводится день недели.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сЗнач, сЗнач2;
ОчиститьОкноСообщений();
сЗнач = СоздатьОбъект("СписокЗначений");
сЗнач2 = СоздатьОбьект(''СписокЗначений'');
// Раздел WeekDay
сЗнач2.ДобавитьЗначение(''Понед'');
сЗнач2.ДобавитьЗначение("Вт.");
сЗнач2.ДобавитьЗначение(''Ср.'');
сЗнач2.ДобавитьЗначение('Четв.");
сЗнач2.ДобавитьЗначение("Пятн.");
сЗнач2.ДобавитьЗначение("Субб.");
сЗнач2.ДобавитьЗначение("Воскр.");
// Параметр образец - список значений, элементы которого также списки значений // Не забываем определить представление "WeekDay" при добавлении в список сЗнач // элемента сЗнач!
сЗнач.ДобавитьЗначение(сЗнач2, "WeekDay");
// Теперь при выводе дней недели будут использоваться названия списка сЗнач2, //добавленного в образец сЗнач Пропись(сЗнач);
Сообщить(Формат('21.12.01', "ДНННН'')); // Напечатает Пяти. Сообщить(формат('05.12.01', "ДНННН")); // Напечатает Ср.
// Возвращаемся к установленному по умолчанию файлу с образцами прописей Пропись("");
Сообщить(Формат('21.12.01', "ДНННН")); // Напечатает Пятница Сообщить(Формат('05.12.01', "ДНННН")); // Напечатает Среда конецПроцедуры // Выполнить
2.9. УПРАВЛЯЮЩИЕ ОПЕРАТОРЫ И КОНСТРУКЦИИ
2.9.1. АЛГОРИТМ КАК СОВОКУПНОСТЬ БАЗОВЫХ СТРУКТУР
Программа и ее отдельные части создаются на основе алгоритмов. Фактически программа - это кодировка некоторого алгоритма или группы алгоритмов. Из этого следует, что до написания кода необходимо разработать и записать (последнее не всегда делается) алгоритм.
Алгоритм - это последовательность действий, либо приводящая к решению задачи, либо поясняющая, почему это решение получить нельзя. Например, отрицательный результат получается при ошибочном задании входных данных.
Алгоритм составляется из отдельных фрагментов, которые могут иметь одну из следующих структур:
• блок операторов и конструкций;
• ветвление;
• цикл.
Блок операторов и конструкций (БОК) - это выполнение одного или нескольких простых или сложных действий. БОК может содержать и ветвления и циклы, которые являются примерами сложных действий. Простым действием является, например, в ы-полнение присваивания или вызов процедуры. Конструкции состоят из нескольких операторов и используются для выполнения управляющих действий, например циклов. Так, конструкция Если ... КонецЕсли состоит из двух операторов: Если и КонецЕсли. Последний оператор конструкции должен завершаться точкой с запятой.
Ветвление - это выбор одного из возможных направлений выполнения алгоритма, осуществляемый в зависимости от значения некоторых условий. Ветвления подразделяются следующие виды:
• если - то;
• если - то - иначе;
• если - то - иначе - если;
• выбор по ключу (в 1С это ветвление не используется, вместо него употребляется "Если - то - иначе - если");
• попытка.
Цикл - это повторное выполнение некоторого БОК с разными, как правило, значениями входящих в БОК переменных. Однократное выполнение БОК цикла называют итерацией. БОК цикла также называют телом цикла.
Различают следующие циклы:
• с параметром;
• пока;
• до.
Последний вид цикла применяется крайне редко; в 1С он отсутствует.
При записи алгоритма составляющие его базовые структуры либо отображаются графически, либо записываются в виде линейных схем. Проиллюстрируем обе эти воз-
можности.
2.9.2. ВЕТВЛЕНИЯ "ЕСЛИ"
В ветвлениях "если - то", "если - то - иначе" и "если - то - иначе - если" для записи условий используется логическое выражение (ЛВ), результатом которого может быть истина (И) или ложь (Л). Графически ветвления проиллюстрирует рис. 2.5.
 |
Рис. 2.5. Ветвления: а - ветвление "если - то"; б - ветвление "если - то - иначе Ветвление "если - то" работает так:
• вычисляется значение ЛВ;
• если оно истинно, то выполняется БОК1;
• если оно ложно, то управление передается БОК2.
Записи ветвления "если - то" в линейной схеме алгоритма:
Х°. Если истинно ЛВ, то [выполнить:]
БОК1
конец если [Х°]. |
В 1С ветвление "если - то" записывается очень похоже: если ЛВ тогда
БОК
1 // Некоторые операторы
конецЕсли;
Ветвление "если - то - иначе" работает так:
• вычисляется значение ЛВ;
• если оно истинно, то выполняется БОК
1
• если оно ложно, то выполняется БОК
2;
• далее управление передается БОК
3.
Запись ветвления "если - то - иначе" в линейной схеме алгоритма:
Х°. Если истинно ЛВ, то [выполнить:]
БОК
1
иначе [выполнить:]
БОК
2
конец если [Х°].
Запись ветвления "если - то - иначе" в 1С: если ЛВ тогда
БОК
1 // Некоторые операторы
иначе
БОК
2 // Некоторые операторы
конецЕсли;
Пример использования ветвлений "если - то" и "если - то - иначе" см. в разд. 1.7.3. Замечание. Если БОК
1 и БОК
2 в ветвлении "если - то - иначе" являются выражениями, то для выбора вычисляемого выражения лучше употреблять функцию, вычисляющую выражение по условию. Ее синтаксис:
результат = ?(ЛВ, выражение,, выражение
2);
Пример:
у = ?(х > 0, Лог(х), х); // Вернет Лог(х), если х >0, или х - в противном случае
Приведенный оператор заменяет следующее ветвление:
если х > 0 тогда у = Лог(х); иначе у = х;
конецЕсли;
Для ветвления "если - то - иначе - если" укажем только способ его записи в 1 С:
если ЛВ
1 тогда
Некоторые операторы Некоторые операторы
Некоторые операторы
Последние два элемента конструкции
являются необязательными
иначеЕсли ЛВ
2 тогда
иначеЕсли ЛВ
к тогда
конецЕсли;
2.9.3. "ПОПЫТКА"
Ветвление Попытка служит для обработки исключений и реализуется в 1С виде следующей конструкции:
попытка
EOKj,
исключение
БОК,
конецПопытки;
В конструкции БОК, - это последовательность операторов, в которых может возникнуть исключение, а в БОК
2 - это последовательность операторов, обрабатывающих исключение.
Напомним, что исключение - это ошибка, возникающая при исполнении программы, например деление на нуль или выход за границы массива. В первом случае система выдаст сообщение "Деление на 0", во втором - "Значение индексного выражения
Работа программы, если не используется обработка исключений, при возникновении ошибки прекращается. Некоторые ошибки, приводящие к останову программы, могут быть, однако, устранены. Например, ошибка блокировки данных, возникающая при обращении к файлу, захваченному в настоящий момент другим приложением, устраняется после завершения работы этого приложения. Другие ошибки, если их игнорировать, не исказят конечного результата. Например, выход за границы массива. В таких случаях целесообразно применить конструкцию Попытка с тем, чтобы при возникновении ошибки выполнить ее обработку, например просто сообщить об ошибке, и продолжить расчеты.
Пример. Вычисляется сумма элементов вектора. В процедуре при обращении к вектору умышленно введена ошибка - выход за границы вектора. Для ее преодоления применяется конструкция Попытка.
процедура Выполнить() // Запускаем процедуру из обработки Проба
перем а[5], ин, сум;
// Инициализация вектора а
а[1] = 0; а[2] = 1.5; а[3] = 2.5; а[4] = -1; а[5] = 7;
// Сумма элементов массива а. Ожидаемый результат: сум = 10 сум = 0;
// Умышленно для иллюстрации работы конструкции Попытка // задаем верхний параметр цикла большим числа элементов вектора а для ин = 1 по 7 цикл
попытка // При выходе за границы вектора
сум = сум + а[ин]; // произойдет обработка исключения;
исключение // исполнение программы не прекратится
Сообщить(ОписаниеОшибки0 + ". Вычисления будут продолжены."); конецПопытки; конецЦикла; // для
Сообщить(”сум = ” + сум); // Напечатает 10
конецПроцедуры // Выполнить
Замечание. Встроенная функция ОписаниеОшибки возвращает описание ошибки в том виде, в каком оно выдается системой в окно сообщений при отсутствии обработки исключений.
Конструкции Попытка могут быть вложенными. В таких случаях при возникновении ошибки ее обработка передается оператору Исключение того уровня вложенности, на котором ошибка возникла. Чтобы передать обработку ошибки оператору более высокого уровня, применяется оператор ВызватьИсключение. Если оператор Вы-зватьИсключение применен, а внешнего обработчика не существует, то произойдет останов программы с выдачей сообщения об ошибке. Последний эффект будет, в частности, получен, если оператор ВызватьИсключение вставить в код вышеприведенного примера перед оператором КонецПопытки.
Пример. Вычисляется сумма элементов вектора. В процедуре при обращении к вектору умышленно введена ошибка - выход за его границы. Для ее преодоления применяется конструкция Попытка. Однако в этот раз в результате применения оператора ВызватьИсключение осуществляется выход из цикла и передача управления внешнему обработчику.
процедура Выполнить() // Запускаем процедуру из обработки Проба
перем а[5], ин, сум;
// Инициализация вектора а
а[1] = 0; а[2] = 1.5; а[3] = 2.5; а[4] = -1; а[5] = 7;
// Сумма элементов массива а. Ожидаемый результат: сум = 10 сум = 0;
// Умышленно для иллюстрации работы конструкций Попытка
// задаем верхний параметр цикла большим числа элементов вектора а
попытка
для ин = 1 по 7 цикл
попытка // При выходе за границы вектора передадим
сум = сум + а[ин]; // управление внешнему обработчику исключений исключение
вызватьИсключение; // Передача управления внешнему обработчику конецПопытки; // внутренней конецЦикла; // для исключение
Сообщить(ОписаниеОшибки() + ". Осуществлен выход из цикла. Работа продолжается"); конецПопытки; // внешней
Сообщить("сум = " + сум); // Напечатает 10
конецПроцедуры // Выполнить
Замечание. Внешний обработчик в данной ситуации, конечно же, избыточен и введен лишь для иллюстрации оператора ВызватьИсключение. При отсутствии внешней конструкции Попытка вместо оператора ВызватьИсключение следует употребить оператор Прервать, предваренный, например, тем же, что и в приведенном примере, вызовом процедуры Сообщить.
2.9.4. ЦИКЛЫ
В цикле "с параметром и" задаются начальное значение параметра к, его конечное значение к и шаг ш - отличная от нуля величина, на которую изменяется значение параметра и после выполнения очередной итерации. В 1С шаг ш всегда принимается равным единице. Параметр п также называют переменной цикла, которая должна быть целочисленной. Параметры ник являются в 1С числовыми выражениями и представляют соответственно нижнюю и верхнюю границы переменной цикла. Если параметр н(к) вычисляется с нецелым значением, то в качестве параметра используется целая часть результата.
Замечание. Параметр цикла часто называют его индексом, для обозначения которого в программах нередко употребляют имя ин или инд.
Графически цикл "с параметром" иллюстрирует рис. 2.6.
 |
|
Рис. 2.6. Цикл с параметром |
Цикл "с параметром" работает так (случай ш > 0):
1°. Присвоить: п = н.
2°. Если п <= к, то перейти к п. 3°, иначе завершить цикл.
3°. Выполнить БОК.
4°. Присвоить: п = п + ш и перейти к п. 2° (повтор).
Когда ш < 0, п. 2° выглядит так:
2°. Если п > к , то переход к п. 3°, иначе завершить цикл.
Замечания:
1. В цикле "с параметром" приведенные в пп. 1° и 4° операторы в тексте программы не присутствуют, но будут автоматически встроены компилятором в объектный код при компиляции программы.
2. Во многих языках программирования, например в Фортране, в цикле "с параметром" запрещается в теле цикла менять значения переменной цикла и. Изменение параметров н, к и шага ш в теле цикла не отразится на выполнении цикла: цикл будет выполняться с теми значениями параметров, какие они имели до начала первой итерации цикла. В 1С запрет на изменение значения переменной цикла п не действует. Однако следует помнить, что изменение п в теле цикла - это плохой стиль программирования.
Запись цикла "с параметром" в линейной схеме алгоритма:
Х°. С параметром п = н,к,ш [выполнить:]
БОК
конец цикла [с параметром п] | [Х°]. и в 1С:
для п = н по к цикл БОК
конецЦикла;
Цикл Пока выполняется до тех пор, пока истинно некоторое ЛВ. Причем проверка истинности ЛВ выполняется перед началом очередной итерации. Цикл До отличается от цикла Пока тем, что проверка истинности ЛВ осуществляется после выполнения очередной итерации. Графическая интерпретация циклов Пока и До приведена на рис. 2.7.
 |
|
Рис. 2.7. Циклы: а - цикл Пока; б - цикл До |
Замечание. При работе с циклами Пока и До надо следить, чтобы ЛВ обязательно рано или поздно приняло значение ложь. Иначе произойдет зацикливание - "бесконечное" выполнение операторов цикла.
Запись циклов Пока в линейной схеме алгоритма:
Х°. Пока истинно ЛВ [, выполнить:]
БОК
конец цикла Х°. и в 1С: пока ЛВ цикл
БОК // Некоторые операторы
конецЦикла;
Замечания:
1. Далее при ссылке на циклы будем использовать принятые в 1С имена операторов циклов - Для и Пока.
2. Циклы Для и Пока могут быть вложенными. То есть в теле цикла Для (Пока) могут быть другие циклы Для и/или Пока.
Проиллюстрируем второе замечание примером, записав код вывода групп подряд следующих непериодических констант, сообщающий перед выводом группы ее номер. (Уточним: в примере группа - это подмножество подряд следующих непериодических констант, не имеющее периодических констант. То есть группы разделяются одной и более периодическими константами.)
// Процедура, выводящая группы непериодических констант // Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, ин, номерГруппы, идеи;
ОчиститьОкноСообщенийО; номерГруппы = 0;
всегоКонстант = Метаданные. Константа();
ин = 1; // Номер константы
пока ин <= всегоКонстант цикл
если Метаданные.Константа(ин).Периодический = 0 тогда номерГруппы = номерГруппы + 1;
Сообщить("Выводится группа с номером " + номерГруппы);
// Вложенный цикл Пока
пока Метаданные.Константа(ин).Периодический = 0 цикл идеи = Метаданные.Константа(ин).Идентификатор;
Сообщить(иден + " " + Константа.ПолучитьАірибут(иден));
ин = ин + 1; // Не забываем перейти к следующей константе
если ин > всегоКонстант тогда
прервать; // Досрочный выход из вложенного цикла
конецЕсли;
конецЦикла; // пока Метаданные.Константа(ин).Периодический = 0 иначе // Имеем периодическую константу
ин = ин +1; // Не забываем перейти к следующей константе
конецЦикла; // пока ин <= всегоКонстант если номерГруппы = 0 тогда
Сообщшъ("В конфигураторе нет непериодических констант"); конецЕсли;
конецПроцедуры // Выполнитъ
2.9.5. О ВЫЧИСЛЕНИИ ЛОГИЧЕСКИХ ВЫРАЖЕНИЙ
В 1С Л В при их оценке всегда вычисляются полностью (по крайней мере в текущей версии). Это создает некоторые неудобства. Так, в последнем примере вложенный цикл Пока было бы лучше записать следующим образом, обойдя применение оператора Прервать:
пока (ин <= всегоКонстант) и (Метаданные. Константа(ин).Периодический = 0) цикл идеи = Метаданные. Константа(ин). Идентификатор;
Сообщитъ(иден + " " + Константа.ПолучитъАтрибут(иден));
ин = ин +1; // Не забываем перейти к следующей константе
конецЦикла; // пока (вложенного)
Однако тогда возникнет ошибка исполнения
пока (ин <= всегоКонстант) и (Метаданные.Константа(ин).Периодический = 0) цикл {В:\ПРОБАБКТ(14)}: Поле агрегатного объекта не обнаружено (Периодический)
Ее природа в том, что на некотором шаге значение переменной ин стало больше значения переменной всегоКонстант. При этом значение ЛВ
(ин <= всегоКонстант) и (Метаданные.Константа(ин).Периодический = 0)
независимо от значения второго выражения отношения будет ложь. Поэтому в принципе вычисление второго выражения отношения избыточно и его можно не выполнять. Но в 1С оно вычисляется, и, поскольку константы с номером ин = всегоКонстант + 1 нет, возникает описанная выше ошибка, приводящая к останову программы.
Рассмотрим теперь конструкцию "если" с ЛВ, состоящим из двух подвыражений отношения, объединенных логической операцией ИЛИ:
если (3 > 2) или (Лог(0) = 1) тогда сообщить("Что-то"); конецЕсли;
Результат этого ЛВ, если первое подвыражение истинно, не зависит от значения второго подвыражения, и, следовательно, оно могло бы не вычисляться. Однако в 1С ЛВ вычисляются полностью, поэтому данный код, поскольку в нем вычисляется 1п0, приведет к ошибке исполнения, о которой 1С сообщит следующим образом:
если (3 > 2) или (Лог(0) = 1) тогда
{В:\1С?7ЛСО№10МБЩБХТГОКМВ\ПГОБАБКТ(3)}: Деление на 0
2.9.6. ПРИМЕР ЗАПИСИ АЛГОРИТМА
Обратимся для иллюстрации правил записи алгоритма к ранее рассмотренной задаче вывода списка непериодических констант, для которых в метаданных задан синоним (разд. 1.7.3). В этой задаче сведения одного вида (идентификатор, синоним и значение) выводятся для различных констант. Повторное выполнение одних и тех же действий ре а-лизуется в виде цикла. Здесь наиболее уместен цикл "с параметром", в котором в качестве параметра выступает номер константы. Для учета условий, ограничивающих вывод данных, используем условие "если - то". Алгоритм решения задачи можно отобразить в виде следующей линейной схемы:
1. Начало.
// Число констант в конфигурации
2. всегоКонстант = Метаданные.КонстантаО
// Переменная флагВывода принимает значение 1, если напечатаны данные // хотя бы об одной константе
3. флагВывода = 0;
4. С параметром ин= 1, всегоКонстант выполнить:
4.1. Если константа с номером ин непериодическая, то // Синоним константы с номером ин син = Металанные.Константа(ин). Синоним;
4.1.1. Если син не является строкой нулевой длины, то флагВывода = 1;
Вывести идентификатор, синоним и значение константы с номером ин. конец если 4.1.1. конец если 4.1. конец цикла 4.
5. Если флагВывода = 0, то
Сообщить: "Нет непериодических констант с непустым синонимом." конец если 5.
6. Конец.
Код приведенного фрагмента на языке 1С будет незначительно отличаться от кода процедуры Выполнить примера 3 разд. 1.7.3.
Условия 4.1 и 4.1.1 можно объединить таким образом:
4.1. Если константа с номером ин непериодическая и константа имеет синоним, то флагВывода = 1;
Вывести идентификатор, синоним и значение константы с номером ин. конец если 4.1.
Такому объединению отвечает следующий код на 1С:
если (Метаданные.Константа(ин).Периодический = 0) и
(ПустаяСтрока(Метаданные.Константа(ин). Синоним) = 0) тогда флагВывода = 1;
син = Метаданные.Константа(ин). Синоним; идеи = Метаданные.Константа(ин).Идентификатор; значен = Константа. ПолучитьАтрибут(иден);
Сообщить(иден + " - " + син + " - " + значен); конецЕсли;
Его недостаток в том, что дважды извлекается информация о синониме, что связано с дополнительными временными издержками; с другой стороны, он компактнее первого варианта.
Замечание. Встроенная функция ПустаяСтрока(строка) вернет 1, если ее аргумент строка имеет нулевую длину или состоит из одних пробелов, в противном случае функция вернет 0.
Любой цикл с параметром можно, конечно же, заменить циклом Пока, например
ин = 1; // Подготовка к циклу Пока
пока ин <= всегоКонстант цикл
// Тело цикла см. в вышеприведенном цикле "с параметром"
// Добавляем в тело цикла оператор увеличения номера константы // Без этого оператора произойдет зацикливание ин = ин+ 1; конецЦикла;
2.9.7. ПРЕРЫВАНИЯ ЦИКЛА. ОБЪЕДИНЕНИЕ УСЛОВИЙ
Выйти из цикла и передать управление на первый следующий за циклом выполняемый оператор можно, применив оператор Прервать. Чтобы пропустить часть операторов цикла и перейти к следующей итерации, следует использовать оператор Продолжить. При этом управление передается оператору начала цикла - оператору Для или Пока. Операторы Прервать и Продолжить отдельно не применяются, а встраиваются в конструкции "если".
Пример. Сообщить значение первой непериодической константы числового типа.
// Процедура, выводящая значение первой непериодической константы числового типа // Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, флагВывода, ин, идеи;
ОчиститьОкноСообщенийО;
// флагВывода примет значение 1, если будет обнаружена // непериодическая константа числового типа флагВывода = 0;
всегоКонстант = Метаданные.КонстантаО; для ин = 1 по всегоКонстант цикл
если Метаданные.Констанга(ин).Периодический = 1 тогда
продолжить; // Передаем управление оператору Для
конецЕсли;
если Метаданные.Консташа(ин).Тип = "Число" тогда идеи = Метаданные.Констата(ин).Идентификатор;
Сообщить(иден + "" + Константа.ПолучитьАтрибут(иден)); // БалансДней 1 флагВывода = 1;
прервать; // Досрочный выход из цикла Для
конецЕсли; конецЦикла; // для если флагВывода = 0 тогда
Сообщить("В конфигураторе нет непериодических констант числового типа."); конецЕсли;
конецПроцедуры // Выполнить
Замечание. Иногда программисты в цикле Для вместо оператора Прервать прибегают к изменению значения переменной цикла ин. Так, в нашем случае оператор Прервать мог быть заменен оператором
ин = всегоКонстант;
Такие действия, однако, классифицируются как плохой стиль программирования.
Некоторые программисты считают, что операторы прерывания цикла (в 1С это Продолжить и Прервать) ухудшают структуру программы, и поэтому по возможности отказываются от их употребления. Взамен используется объединение условий.
Последуем и мы принципам структурного программирования, написав решающий вышеприведенную задачу код, использующий объединение условий. В этом коде нам придется отказаться от цикла Для, заменив его циклом Пока.
// Процедура, использующая объединение условий и выводящая значение первой // непериодической константы числового типа. Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, флагВывода, ин, идеи;
ОчистигьОкноСообщенийО;
// флагВывода примет значение 1, если будет обнаружена // непериодическая константа числового типа флагВывода = 0;
всегоКонстант = Метаданные.КонстантаО;
ин = 1; // Номер константы
пока (ин<= всегоКонстант) и (флагВывода = 0) цикл
если (Метаданные.Константа(ин).Периодический = 0) и (Метаданные.Константа(ин).Тип = "Число") тогда идеи = Метаданные.Константа(ин).Идентификатор;
Сообщить(иден + " " + КонстантаПолучитъАтрибут(иден)); флагВывода = 1; конецЕсли;
ин = ин + 1; // Не забываем перейти к следующей константе
конецЦикла; // для если флагВывода = 0 тогда
Сообщить("В конфигураторе нет непериодических констант числового типа."); конецЕсли;
конецПроцедуры // Выполнить
В приведенном коде объединение условий использовано при записи ЛВ дважды: (ин <= всегоКонстант) и (флагВывода = 0)
(Метаданные.Констата(ин).Периодический = 0) и (Метаданные.Константа(ин).Тип = "Число") Это позволило нам исключить из процедуры операторы Продолжить и Прервать.
2.9.8. ПЕРЕХОД ПО МЕТКЕ
Выполняется оператором Перейти метка;
где метка - это имя, начинающееся с тильды (знака ~), например ~М1.
Этот оператор неприемлем для сторонников структурного программирования. Однако есть ситуации, кода он полезен, например для досрочного выхода из вложенного цикла.
Пример. Записать, код вывода групп подряд следующих непериодических констант, сообщающий перед выводом группы ее номер, завершая вывод, обнаружив непериодическую константу типа Календарь.
// Процедура, выводящая группы непериодических констант
// Завершается либо при обнаружении непериодической константы типа Календарь,
// либо после вывода всех групп. Запускается из обработки Проба процедура Выполнить()
перем всегоКонстант, ин, номерГруппы, иден;
ОчистшъОкноСообщенийО; номерГруппы = 0;
всегоКонстант = Метаданные.КонстантаО;
ин = 1; // Номер константы
v
пока ин <= всегоКонстант цикл
если Метаданные.Константа(ин).Периодический = 0 тогда номерГруппы = номерГруппы + 1;
Сообщить("Выводится группа с номером " + номерГруппы);
// Вложенный цикл Пока
пока Метаданные.Константа(ин).Периодический = 0 цикл если Метаданные.Константа(ин).Тип = "Календарь" тогда перейти ~М1; // Выход из всех циклов
конецЕсли;
иден = Метаданные.Константа(ин).Идентификатор;
Сообщитъ(иден + "" + Константа.ПолучиіъАтрибут(иден));
ин = ин + 1; // Не забываем перейти к следующей константе
если ин > всегоКонстант тогда
прервать; // Досрочный выход из вложенного цикла
конецЕсли;
конецЦикла; // пока Метаданные.Константа(ин).Периодический = 0 иначе // Имеем периодическую константу
ин = ин + 1; // Не забываем перейти к следующей константе
конецЕсли;
конецЦикла; // пока ин <= всегоКонстант // Располагаем после метки ~М1 двоеточие
~М1: // Сюда передается управление оператором Перейти ~М1;
если номерГруппы = 0 тогда
Сообщить("В конфигураторе нет непериодических констант."); конецЕсли;
конецПроцедуры // Выполнить
Замечание. В данной задаче метку ~М1 нельзя расположить перед оператором конецЦикла:
~М1: конец цикла; // пока ин <= всегоКонстант
поскольку такое использование метки не приводит к выходу из цикла, а передает управление на оператор Пока внешнего цикла. В конкретном случае результатом такого размещения метки будет зацикливание программы.
Разумеется, задачу можно решить и без использования оператора, введя флаг обнаружения константы типа Календарь и применив, например, объединение условий. При желании соответствующий код вы можете составить самостоятельно.
2.10. ПОЛЬЗОВАТЕЛЬСКИЕ ПРОЦЕДУРЫ И ФУНКЦИИ
2.10.1. ПРОГРАММИРОВАНИЕ "СВЕРХУ ВНИЗ”
Разработка алгоритмов и программ осуществляется, как правило, по принципу "сверху вниз".
Суть такого подхода состоит в разбиении исходной задачи на ряд более простых задач - фрагментов - и последующей работе с ними.
При разбиении задачи на фрагменты надо придерживаться следующей схемы:
1. Проанализировать задачу и выделить в ней фрагменты.
2. Отобразить процесс разбиения в виде блок-схемы или линейной схемы и пронумеровать в ней фрагменты.
3. Установить между выделенными фрагментами связи: для каждого фрагмента определить, какие данные он получает (входные данные) и какие данные возвращает (выходные данные). Связи между фрагментами называются интерфейсом.
4. Рассмотреть далее каждый фрагмент самостоятельно; разработать для него алгоритм и записать его либо в виде линейной схемы, либо в виде блок-схемы. При необходимости подвергнуть фрагмент разбиению на более мелкие фрагменты. Такое разбиение продолжать до тех пор, пока не будут получены фрагменты, программирование которых не составляет особых затруднений.
5. Оформить выделенные фрагменты в виде программных компонентов или БОК.
При таком подходе программу можно рассматривать как совокупность фрагментов, которые, принимая некоторые данные, вырабатывают результат и передают его другому фрагменту и так вплоть до завершения вычислений.
Составляемые для фрагментов линейные схемы алгоритмов (разд. 2.8) сопровождаются заголовком и описанием интерфейса, отражающим состав входных и выходных данных.
В 1С для реализации фрагментов можно использовать программные компоненты: основную программу модуля, процедуры модуля и его функции.
Фрагмент алгоритма, как правило, оформляется в виде функции, если в результате выполненных в нем вычислений возвращается единственный скаляр. Если же фрагмент возвращает в вызывающий фрагмент в качестве результата несколько значений, в том числе и в виде массива, или не возвращает результатов, н апример осуществляет вывод данных в файл, то он оформляется в виде процедуры.
2.10.2. СТРУКТУРА ПРОЦЕДУР И ФУНКЦИЙ
Процедуры и функции имеют схожую структуру:
Процедура | Функция Имя([[3нач] парам, = [значение*]], ...,
[[Знач] парам
п = [значение] ]) [Экспорт]
[неисполняемые операторы объявления переменных]
[исполняемые операторы]
КонецПроцедуры | КонецФункции
Ключевое слово, или атрибут, Экспорт указывается для процедур и функций, располагаемых в глобальном модуле (разд. 1.6), в том случае, если их надо сделать доступными для вызова в модулях форм.
Процедуры вызываются в виде отдельного оператора с соблюдением следующего синтаксиса:
Имя_процедуры([парам], ..., [парам
в]);
Функции, как правило, вызываются из выражений, но могут, так же как и процедуры, вызываться в виде отдельно оператора:
Имя_функции([парам
І],..., [парам]);
Функция, если выход из нее осуществляется не в результате выполнения оператора Возврат выражение;
а по оператору КонецФункции возвращает число 0.
Функция, в которой нет оператора Возврат выражение;
всегда возвращает нуль.
Замечание. При программировании функции следует выходить из нее по оператору
Возврат выражение;
даже если выражение - это константа нуль. Например, функции фІ и ф2
функция ф2(а)
если а > 0 тогда
возврат 2 * конецЕсли; конецФункции // ф2
функция ф1(а)
если а > 0 тогда
а;
возврат 2 * а;
иначе
возврат 0; конецЕсли; конецФункции // ф1
возвращают одинаковый результат, однако вариант с фІ отвечает принятому для функций стилю программирования, чего нельзя сказать о функции ф2. Впрочем, в данной ситуации функцию ф1 лучше записать так:
функция ф1ф)
возврат ?(а > 0, 2 * а, 0); конецФункции // ф1
Процедуры и функции могут вызываться только из тех процедур и функций модуля, ранее которых расположены либо они сами, либо их предварительное описание (разд. 1.4.4). Например, в модуле с кодом
функция ф1(а)
возврат ?(а > 0, 2 * а, 0); .конецФункции // ф1
// Предварительное описание процедуры п\
процедура п 1 (д) далее
// б= 15; функция ф1 вызывается из выражения // б = 35; б - фактический параметр процедуры п1
// д - фактический параметр процедуры n1 // д = 4 * 7.5 + 5 = 35
процедура Выполнить() перем б; б = 2.5 * ф1(3); п1(б);
Сообщить(б);
конецПроцедуры // Выполнить
функция ф2(с) возврат с / 2; конецФункции // ф2
процедура п1(д) д = 4*ф2(д) + 5; конецПроцедуры // п1
из процедуры Выполнить можно вызвать функцию ф1 и процедуру nl, но нельзя вызвать функцию ф2.
Замечания:
1. Предварительное описание процедуры (функции) должно совершенно точно дублировать заголовок процедуры (функции). Так, не допускаются расхождения имен параметров, и если заголовок процедуры (функции) снабжен ключевым словом Экспорт, то оно должно присутствовать и в тексте предварительного описания перед ключевым словом Далее. Например: процедура п3(д1, д2) экспорт далее // Предварительное описание процедуры пЗ
2. Перечень имен процедур и функций модуля можно просмотреть, нажав, находясь
, М
в конфигураторе, на иконку на панели инструментов Текстовый редактор. Так, для вышеприведенного набора процедур и функций, если их разместить, например, в модуле обработки Проба, мы получим приведенный на рис. 2.8 список (сортировка имен не задана).
 |
|
Рис. 2.8. Окно вывода списка процедур и функций модуля |
На начало любой процедуры (функции) или на ее предварительное описание можно переместиться, выбрав в вышеприведенном окне необходимую строку и нажав на кнопку Перейти.
2.10.3. ПАРАМЕТРЫ ПРОЦЕДУР И ФУНКЦИЙ
Обмен данными между программными компонентами 1С осуществляется через глобальные объекты, переменные модуля (разд. 1.4.4), диалога (разд. 1.5) и параметры процедур и функций. Дополнительно от функции можно получить и использовать в выражении возвращаемое ею значение.
Параметры, используемые при вызове процедуры или функции, называются фактическими. Так, в выражении, стоящем в правой части оператора присваивания
д = 4 * ф2(д) + 5; // д = 4 * 7.5 + 5 = 35
из процедуры п\ предшествующего раздела параметр д функции ф2 является фактическим.
Параметры, стоящие в заголовке процедуры (функции), в том числе и в заголовке, присутствующем в тексте предварительного описания, называются формальными. Таким является, например, параметр с в следующем заголовке:
функция ф2(с) // с - формальный параметр функции ф2
При вызове процедуры (функции) между фактическими и формальными параметрами устанавливается соответствие: формальный параметр с номером к адресует фактический параметр (или его копию) с номером к.
Рассмотрим процедуру п3 с тремя формальными параметрами а, б и в. Пусть по назначению первый параметр будет входным, то есть передающим данные в процедуру, второй - выходным, то есть возвращающими данные в вызывающую программу, а третий - входным-выходным. Формальные параметры используются в процедуре как обычные переменные. Объявлять формальные параметры в теле процедуры посредством оператора Перем нельзя.
// с - промежуточная переменная процедуры п3
// Определяем значения параметров б и в
процедура пЗ(а, б, в) перем с; с = 3 * а; б = с - в - 2; в = в + б + с/3; конецПроцедуры // пЗ
Обратимся к иЗ из процедуры Выполнить обработки Проба, использовав в качестве фактических параметров переменные а1,а2 и а3.
процедура Выполнить() перем а, а2, аЗ;
ОчистшъОкноСообщенийО;
а=1;
аЗ = 3;
пЗ(а, а2, аЗ); // Вызов процедуры п3
Сообщить("а2 = " + а2 + "; аЗ = " + аЗ); конецПроцедуры // Выполнить
При таком вызове формальному параметру а процедуры п3 соответствует фактический параметр а, формальному параметру б фактический параметр а2 и формальному параметру в - фактический параметр а3. Понятно, что при вызове параметр а получит значение 1, а параметр в - значение 3. Параметр б - будет иметь пустое значение. Как видно из примера, имена формальных и фактических параметров могут и совпадать и различаться.
Замечание. Из всех присутствующих в процедуре Выполнить переменных обязательно объявление только переменной а2, в противном случае ее нельзя использовать в качестве фактического параметра процедуры п3, или - более широко - операндом любого выражения.
После исполнения п3 в окне сообщений обнаружим следующий результат: а2 = -2; а3 = 2
Приведенное нами деление параметров на входные, выходные и входные-выход-ные является условным, вытекающим из способа их употребления в программе. На месте любого фактического параметра может стоять константа. Например, вызов
п3(1, а2, аЗ); // Первый фактический параметр - константа
полностью эквивалентен вышеприведенному.
Более того, константа может быть и на месте третьего параметра:
п3(1,а2,3);
хотя соответствующий ему формальный параметр меняется в теле процедуры иЗ.
В общем случае на месте фактического параметра может быть любое правильно построенное выражение. Например:
п3(3 * а * а, а2, 3); // На месте первого параметра выражение 3 * а * а
Примеры с вызовом п3 показывают, что при выходе из процедуры фактический параметр, если он является переменной, принимает значение формального параметра. В этом случае говорят, что фактические параметры передаются по ссылке (формальный параметр адресует фактический параметр непосредственно). Можно, однако, установить и иной способ передачи параметров - по значению. Для этого в списке формальных параметров перед параметром, передаваемым по значению, следует поставить ключевое слово (атрибут) Знач, например
процедура п3(а, б, знач в) конецПроцедуры // п3
В этом случае формальный параметр адресует копию фактического параметра и изменения формального параметра не отражаются на значении фактического. Действительно, обратившись к модифицированной процедуре п3
перем а2; аЗ = 3;
// Параметр а2 передается по ссылке, а параметр а3 - по значению п3(1, а2, аЗ); // Вызов процедуры п3
Сообщить("а2 = " + а2 + "; аЗ = " + аЗ);
найдем в окне сообщений текст а2 = -2; аЗ = 3
Как и ожидалось, значение а3 осталось без изменений.
По значению параметры передаются, если есть необходимость защитить фактический параметр от изменений в процедуре или функции. Рассмотрим следующий код:
функция ф1(а) а = 2 * а; возврат а;
конецФункции // ф1
функция ф2(знач а) а = 2 * а; возврат а;
конецФункции // ф2
процедура Выполнить()
ОчиститьОкноСообщенийО;
х=1;
Сообщить(ф1(х) * х * ф1(х)); Сообщить(ф1(х) * ф1(х) * х); х = 1;
Сообщить(ф2(х) * х * ф2(х)); Сообщить(ф2(х) * ф2(х) * х); конецПроцедуры // Выполнить
Из примера видна разница между передачей параметров по ссылке (функция ф1) и передачей параметров по значению (функция ф2).
Замечание. Системные константы (РазделительСтраниц, РазделительСтрок и Сим-волТабуляции) при использовании их в фактических формальных параметрах воспринимаются как передаваемые по ссылке переменные. Эту неточность можно поправить, передавая их, если в этом есть необходимость, в программные компоненты по значению.
Формальные параметры процедур и функций являются необязательными. То есть соответствующие им фактические параметры могут быть опущены. Следующие за ними запятые должны быть при этом сохранены. Например, к вышеприведенной процедуре п3 можно обратиться, опустив все, кроме последнего, параметры:
п3(, ,аЗ);
При таком вызове и такой организации процедуры п3 в выражениях, где присутствуют формальные параметры а и б, используются пустые значения. Можно, однако, в формальные параметры установить значения по умолчанию, которые будут использоваться в выражениях при отсутствии соответствующих им фактических параметров. Для этого используется следующий синтаксис заголовка процедуры:
процедура п3(а = 1, б = -2, в = 3)
перем с; // с - промежуточная переменная процедуры п3
с = 3*а;
б = с - в - 2; // Определяем значения параметров б и в
в = в + б + с/3; конецПроцедуры // п3
Теперь, когда для последнего формального параметра в задано значение по умолЛ чанию, можно, вызывая пЗ, опустить и соответствующий ему фактический параметре не сохраняя предшествующую ему запятую:
п3(1,а2); // а2 = -2 (верно!)
Если же запятая сохранена, то процедура п3 вернет иное, ошибочное значение а2:
п3(1,а2,); // а2 = 1 (ошибка!)
Поскольку компилятор ошибку не отслеживает, что в общем-то странно, нужно придерживаться общего правила обращения к процедуре (функции) без последних параметров: "Если процедура (функция) вызывается без последних параметров, то разделяющие их запятые и запятая, отделяющая эти параметры от присутствующего фактического параметра, опускаются". Например:
// Процедура п3 вызвана без двух последних параметров п3(а);
При вызовах процедур переменные, используемые как фактические параметры, могут менять свой тип. Например:
процедура п4(а) а = "строка"; конецПроцедуры // п4
процедура Выполнить()
ОчиститьОкноСообщений(); а= 1;
Сообщить(ТипЗначенияСтр(а)); |
// |
Число |
п4(а);
Сообщить(ТипЗначенияСтр(а)); |
// |
Строка |
|
конецПроцедуры // Выполнить |
|
|
Напомним, что формальными параметрами могут быть не только скалярные переменные произвольного типа, но и массивы (разд. 2.6). В этом случае соответствующие фактические параметры также должны быть массивами.
Замечание. Формальные параметры могут иметь агрегатный тип данных, в чем мы смогли убедиться, например, в разд. 1.13, рассматривая контекст обработки. Соответствующие фактические параметры в этом случае должны иметь тот же тип.
2.10.4. ВЛОЖЕННЫЕ ВЫЗОВЫ ПРОЦЕДУР И ФУНКЦИЙ
Любая процедура или функция может содержать вызовы иных процедур и функций, но не может вызвать сама себя явно или через другую процедуру (функцию). Наличие такого вызова приведет к "зависанию" программы. Например:
процедура п6(а) далее
процедура п5(а) // Процедура п5 вызывает сама себя
а = 2 * а; // из процедуры п6. В результате имеем
п6(а); // зависание программы
конецПроцедуры // п5
процедура п6(а) а = -а; п5(а);
конецПроцедуры // п6
процедура Выполнить()
Предупреждение("Сейчас программа зависнет.
| Для продолжения вычислений нажмите Esc.");
а=1;
п5(а);
конецПроцедуры // Выполнить
2.10.5. ОПЕРАТОР ВОЗВРАТ
Как мы видели, функция возвращает результат выражения оператора Возврат выражение;
Такой оператор может быть использован в функции неоднократно. Однако его можно разместить и в процедуре (обычно внутри конструкций "если" или Попытка). При этом выражение должно быть опущено. Например:
процедура п7(а, б) если а <= 0 тогда
Сообщить("Неверное значение аргумента функции Лог."); возврат; // выражение опущено
конецЕсли; б = Лог(а);
конецПроцедуры // п7
Впрочем, лучше обойтись без оператора Возврат, применив ветвление "если-то-иначе":
процедура п8(а, б) если а <= 0 тогда
Сообщить("Неверное значение аргумента функции Лог."); иначе
б = Лог(а); конецЕсли; конецПроцедуры // п8
2.11. ВЫВОДЫ
1. В 1С переменные могут быть простыми или структурированными. Простыми являются числовые, символьные переменные и переменные типа Дата (скалярные или массивы). Сложной структурой обладают переменные агрегатных типов данных.
2. Неопределенные переменные всех типов имеют пустое значение.
3. Константы могут быть числового, символьного типа или типа Дата. Нельзя задать именованные константы, массив - константу и константу агрегатного типа данных. Среди символьных констант 3 являются системными. Нет констант со значениями истина и ложь.
4. В выражении 1С можно употреблять данные различных типов. При вычислении выражения автоматически выполняются преобразования типов данных. Также для преобразования типов данных можно применить встроенные функции Дата, Строка и Число. Тип выражения определяется типом первого операнда.
5. Все операции в выражениях 1С выполняются слева направо.
6. Логические операции имеют более высокий приоритет, чем операции отношения, что нужно учитывать при записи логических выражений.
7. Логические выражения нельзя размещать в правой части оператора присваивания, использовать в качестве фактических параметров процедур и функций и в выражении; оператора Возврат. Их место - это конструкции "если", Для, Пока и функция ?.
8. Логические выражения, состоящие из нескольких подвыражений, всегда вычисляются полностью, несмотря на то, что их результат может быть известен до оценки последнего подвыражения.
9. Массивы могут быть только одномерными. Индекс первого элемента массива всегда равен единице. Элементы массивов могут быть разных типов, в том числе; и агрегатных.
10. Для управления вычислениями в языке предусмотрены ветвления "если" и Попытка, циклы "с параметром" и Пока, операторы прерывания цикла, оператор перехода и оператор выхода из процедуры (функции).
11. Структура программы улучшается, если в ней вместо операторов прерывания цикла и перехода использовать объединение условий.
12. Фактические параметры процедур и функций, если они не являются константами и им не предшествует ключевое слово Знач, передаются по ссылке, в противном случае - по значению.
13. Фактические параметры процедур и функций являются необязательными. При oil сутствии фактического параметра используется установленное для него по умолчанию значение, если оно задано, либо пустое значение - в противном случае.
14. Формальные параметры процедур и функций могут быть скалярами и массивами-любого типа, в том числе и агрегатного.
15. Функция может вызываться, как и процедура, в виде отдельного оператора. При этом возвращаемое ею значение игнорируется.
16. Предварительное описание процедуры (функции), приведенное в начале модуля после объявления его переменных, снимает ограничение на место расположения, процедуры (функции) в теле модуля.
АГРЕГАТНЫЕ ТИПЫ ДАННЫХ ОБЩЕГО НАЗНАЧЕНИЯ
3.1. ОБЩИЕ СВОЙСТВА АГРЕГАТНЫХ ТИПОВ ДАННЫХ 1С
В 1С помимо числовых, символьных данных и дат можно работать с объектами, относящимися к данным агрегатного типа. Всего в 1С определено около 30 агрегатных типов данных. Большинство из них приведено в табл. 3.1.
Агрегатные типы данных 1С
|
Таблица 3.1 |
|
Тип |
Раздел, где рассматривается или используется |
|
БухгалтерскиеИтоги |
- |
|
ВидРасчета, ГруппаРасчетов |
7.3, 7.8,7.10, 7.11,7.12 7.15 |
|
ВидСубконто |
- |
|
ГрупповойКонтекст |
1.13,5.2,5.4 |
|
Документ |
5.8,7.6,7.9 |
|
Журнал документов |
5.8.3,7.6.5,7.9.5 |
|
ЖурналРасчетов, РасчетныйПериод, ЗаписьЖурналаРасчетов |
7.1,7.2,7.4,7.13 |
|
Запрос |
5.11.3,7.4.7,7.17.4 |
|
Календарь, Праздники |
7.5 |
|
Картинка |
3.4.4 |
|
Константа |
1.7 |
|
КорректныеПроводки |
- |
|
Метаданные |
1.6, 1.7,4.1,7.5.2.3,9.3.1.2 |
|
Операция |
- |
|
Периодический |
Гл. 6,9.3.1.2 |
|
Перечисление |
1.13, Гл. 4, 7.3.3 |
|
ПланСчетов |
- |
|
Регистр |
- |
|
СписокЗначений, ТаблицаЗначений |
1.8,3.3,3.4,7.17.2 |
|
Справочник |
Гл. 5,7.3.7, 8.5.2 |
|
Счет |
- |
|
Текст |
1.10,7.17.3 |
|
Таблица |
1.9,5.11,7.17.2 |
|
Форма |
1.8, 1.9, 3.3.4, 3.4.2, 5.3.3.1, 5.3.3.2, 5.7, 5.8.2,
5.8.3, 5.8.4, 5.10.1-5.10.3, 7.4.3, 7.6, 7.9 |
|
ФС |
1.12,7.4.6 |
|
Xbase, Ключ |
7.4.6,9.3.2 |
|
Замечание. Язык 1С не предоставляет возможности для создания иных, кроме определенных в языке, агрегатных типов данных. Также нельзя изменить атрибуты (кроме реквизитов) и методы, используемые с объектами агрегатных типов.
Агрегатные типы, введенные 1С, позволяют строить модели, отражающие процессы в различных подразделениях предприятия, например на складе, в отделе снабжения или сбыта, бухгалтерии и др.
Агрегатные типы можно разделить на две группы.
В первую отнесем типы специального назначения, например Документ, Журнал-Расчетов, ПланСчетов и др. Объекты таких типов определены в конфигурации системы, поэтому, открыв ее, вы сможете просмотреть полный перечень типов первой группы и их разновидностей.
Создавая в программе тот или иной объект этой группы, прежде необходимо удостовериться, что он присутствует в конфигурации. Если это не так, то следующий код вызовет, если убрать конструкцию Попытка, ошибку исполнения, приводящую к оста- I нову вычислений:
// Невозможно создать объект Справочник.Сотрудники_2,
// поскольку его в конфигурации системы нет
// Для преодоления ошибки, чтобы избежать останова программы,
// используем конструкцию Попытка попытка
сСотр_2 = СоздатьОбъект(''Справочник.Сотруцники_2''); исключение
// Неудачная попытка создания объекта Справочник.Сотрулники_2 Сообщшъ(ОписаниеОшибкиО); конецПопытки;
После добавления в конфигурацию справочника Сотрудники_2 приведенный выше код имеет право на существование. Однако всякое изменение конфигурации связано с нарастанием проблем по ее обновлению, поэтому мы, имея скромный опыт по обустройству 1С, отложим до лучших времен рассмотрение подобных объектов.
Во второй группе агрегатных типов данных разместим типы общего назначения, такие, как Текст, СписокЗначений, ФС и др. Объекты этих типов называются внешними объектами (поскольку они не присутствуют в конфигурации). Они создаются на время исполнения программ для решения частных, предусмотренных алгоритмом задач. Функция ТипЗначения, заметим, возвращает для внешних объектов число 100. Например:
тЗнач = СоздатьОбъект("ТаблицаЗначений");
Сообщить(ТипЗначения(тЗнач)); //Напечатает 100
К одному и тому же агрегатному типу данных в 1С могут относиться разные объекты, отличающиеся в некоторых случаях структурой. Например, переменные сКД и сСотр, появившиеся в программе в результате исполнения кода
сКД = СоздагьОбъектО'Справочник.КддровыеДанные'');
сСотр = СоздатьОбьектС'Справочник.Сотрудники'');
имеют один тип - Справочник, но разную структуру, определяемую набором их реквизитов - компонентов агрегатного типа, значения которых хранятся в полях DBF- -файлов базы данных системы. Объекты одного типа будем в дальнейшем называть разновидностями типа.
Разновидности имеющихся в конфигурации типов можно вывести, использовав применяемые с метаданными методы (разд. 1.7.3).
процедура Выполнить( ) // Вывод списка справочников
ОчиститьОкноСообщенийО; // Выводятся идентификаторы справочников
для ин = 1 по Метаданные.Справочник( ) цикл
Сообщить(Метацанные. Справочник(ин). Идентификатор); конецЦикла; // для // Имеем в окне сообщений:
// Аттестация
// БазаДополнительныхНачислений // БазаНалогов
//...
конецПроцедуры // Выполнить
Замечание. Объект, например Справочник, можно создать без определения его вида, то есть так:
спр = СоздатьОбъект("Справочник"); // спр - объект типа Справочник неопределенного вида
В дальнейшем разновидность устанавливается и изменяется методом Вид, например
// Теперь спр - это объект с разновидностью типа Справочник.Сотрудники спр.Вид("Сотрудники");
Агрегатные типы данных первой группы описываются в конфигурации своими характеристиками, в качестве которых, например, для справочника Сотрудники используются следующие величины:
Идентификатор
Синоним
Комментарий
Владелец
КоличествоУровней
ДлинаКода
ДлинаНаименования
СерииКодов
ТипКода "Числовой"
ОсновноеПредставление
КонтрольУ никальности
АвтоНумерация
ГруппыВпереди
СпособРедактирования
ЕдинаяФормаЭлемента
ОсновнаяФорма
ОсновнаяФормаДляВыбора
ОбластьРаспространения
АвтоРегистрация
"Сотрудники"
"Список сотрудников предприятия"
"3"
"8"
"40"
"ВесьСправочник"
"ВВидеНаименования" " 1"
"2"
" 1" "ВДиалоге"
"0"
"Справочник.Сотрудники.ФормаСписка.Административная"
"Справочник.Сотрудники.ФормаСписка.ДляВвода"
'ВсеИнформационныеБазы"
" 1"
Идентификатор объекта задает его имя, которое, в частности, употребляется при вызове функции СоздатьОбъект.
Доступ к характеристикам типа можно получить, как мы видели, пользуясь методами для метаданных, ну и, конечно же, через предусмотренный в конфигурации интерфейс.
С каждым агрегатным типом связаны методы - процедуры и функции, позволяющие обрабатывать объекты агрегатного типа.
Изменять и/или добавлять имеющиеся в 1С для агрегатных типов данных методы нельзя; также не разрешается удалять, редактировать названия или добавлять характеристики агрегатных типов. Значения характеристик константой не являются.
Агрегатный тип имеет атрибуты - изменяемые величины, являющиеся компонентами разновидностей типа. Так, атрибутами объектов агрегатного типа Справочник являются в частности реквизиты справочника, которые ссылаются на поля DBF-файлов, хранящих используемые справочником данные. Например, справочник Сотрудники отображает данные, записанные в файл SC2.DBF и связанные с ним файлы. Имена (идентификаторы) реквизитов и соответствующих им полей DBF-файлов различаются. Реквизиты, в отличие от характеристик типа, могут удаляться, добавляться и редактироваться.
Перечень характеристик и атрибутов каждой разновидности типа первой группы можно выгрузить в текстовый файл, выбрав в конфигурации пункты меню Конфигурация - Описание структуры метаданных. Понятно, что разновидности одного и того же агрегатного типа имеют один и тот же набор характеристик (с разными значениями).
Список идентификаторов и представлений (описаний) реквизитов, например справочника Сотрудники, выведет в окно сообщений следующий, анализирующий метаданные код:
процедура Выполнить()
ОчиститьОкноСообщений();
видСпр = "Сотрудники"; // Вид справочника
Сообщить("Реквизиты справочника " + видСпр +
" (их идентификаторы и представления).");
для ин = 1 по Метаданные.Справочник(видСпр).Реквизит( ) никл
иден = Метаданные.Справочник(видСпр).Реквизит(ин).Идентификатор; предст = Метаданные. Справочник(видСпр).Реквизит(ин).Представление(); Сообщить(иден + " -" + предст);
конецЦикла; // Результат приведен после кода процедуры конецПроцедуры // Выполнить
Результат:
Реквизиты справочника Сотрудники (их идентификаторы и представления).
Оклад - Оклад Тариф - Тариф Разряд - Разряд
РазрядРабочих - Разряд рабочих ПроцентЕжемесПремии - % ежемес. премии Ставка - Ставка Категория - Категория ГрафикРаботы - График работы МестоРаботы - Место работы
Должность - Должность Подразделение - Подразделение формаТруда - Форма оплаты труда ТипСотрудника - Тип сотрудника ПрофСоюз - Членство в профсоюзе Аванс - Аванс
ОплачиватьПитание - ОплачиватьПитание
ОплачиватьПроезд - ОплачиватьПроезд
КоличествоАкций - Количество акций
ДатаСправки - ДатаСправки
СальдоПН - Сальдо по под. налогу
ВозвратПН - ВозвратПН
ДатьЛьготы - ДатъЛьготыі
ДатаРождения - ДатаРождения
СевернНадбавка - % северной надбавки
ДатаСевернСтажа - ДатаСевернСтажа
ДатаСтажаДляВыслугиЛет - ДатаСтажаДляВыслугиЛет
ПриказОприеме - ПриказОприеме
ПриказОбУвольнении - ПриказОбУвольнении •
СправкаНаНачРасч - СправкаНаНачРасч СправкаСПрМестаР - СправкаСПрМестаР РК - Районный коэффициент Военнослужащий - Военнослужащий ХО-ХО
СальдоПН_Фед - Сальдо по под. налогу в фед. бюдж.
БезВзнСРаботод - Взимать с работодателя взносы в фонды БезВзнССотр - Взимать с сотр. взносы в фонды КоэфОплаты - Коэф-т оплаты БезВзносовВПФР - БезВзносовВПФР БезВзносовВФСС - БезВзносовВФСС БезВзносовВФОМС - БезВзносовВФОМС Срочник - Срочник
ПодоходныйПосчитан - ПодоходныйПосчитан Замечания:
1. Наименование и Код являются заданными по умолчанию, не подлежащими переименованию атрибутами (реквизитами) любого справочника 1С. Атрибут Наименование удаляется, если его длина задается равной нулю. Атрибут Код удалению не подлежит.
2. Представление реквизита несет ту же нагрузку, что и синоним константы (разд. 1.7.1).
3. Значения объектов типа Справочник, Документ и Перечисление можно получить, вызвав встроенную функцию ВвестиЗначение, рассмотренную в разд. 2.5.
4. Идентификатор реквизита, например идентификатор Должность реквизита справочника Сотрудники, используется для доступа к значению реквизита. Для этого может быть пригоден следующий код (на примере разновидности типа Справоч-ник.Сотрудники):
сСотр = СоздатьОбъект("Справочник. Сотрудники");
// Устанавливаем дату, на которую выбираются периодические реквизиты справочника сСотр.ИспользоватьДату(РабочаяДата());
// Ищем сотрудника, фамилия которого начинается с подстроки стр стр = "Га";
// Значение второго параметра - нуль, следовательно,
// поиск осуществляем во всем справочнике
флаг = сСотр.НайтиПоНаименованию(стр, 0);
если флаг = 1 тогда // Сотрудник найден
// Наименование - атрибут справочника Сотрудники, Должность - его реквизит. Сообщить(сСотр.Наименование); // Вывод фамилии найденного сотрудника Сообщить(сСотр.Должность); // Должность сотрудника иначе
Предупреждение("Сотрудник, фамилия которого начинается с букв " + стр + " не найден.");
конецЕсли;
Изучение агрегатных типов мы начнем со списка и таблицы значений, объекты которых не фиксируются в конфигурации системы, но зато часто применяются в пользовательских программах. Однако прежде вновь вернемся к понятию "пустое значение", распространив его на все типы данных 1С.
3.2. ОБОБЩЕНИЕ ПУСТОГО ЗНАЧЕНИЯ
Переменная после ее объявления оператором Перем не определена, то есть имеет пустое значение, причем неопределенного типа. Например:
перем а;
// Напечатает 0, что соответствует неопределенному типу данных Сообщить(ТипЗначения(а));
Однако неопределенной переменной, употребив встроенную функцию Полу-читьПустоеЗначение, можно присвоить пустое значение некоторых имеющихся в 1С типов данных, таких, как Число;
Строка;
Дата;
Справочник;
Документ;
Счет;
ВидСубконто;
ВидРасчета;
Календарь.
Например:
// После объявления а - неопределенная переменная неопределенного типа перем а;
а = ПолучитьПустоеЗначение("Дата");
Сообщить(ТипЗначенияСтр(а)); // Напечатает Дата
а = ПолучтъПустоеЗшчение("ВидСубконто");
Сообщить(ТипЗначенияСтр(а)); // Напечатает ВидСубконто
Другие типы данных пустых значений не имеют. Например:
а = ПолучитьПустоеЗтчение("КорректныеПроводки");
// Напечатает 0, что соответствует неопределенному типу данных Сообщить(ТипЗначения(а));
Также пустое значение заданного типа можно получить, передав функции Полу-читьПустоеЗначение не имя типа, а имя разновидности типа, например
а = ПолучитьПустоеЗначение("ВидРасчета.ВыплатаЧерезБанк");
Сообщить(ТипЗначенияСтр(а)); // Напечатает ВидРасчета
При этом функция ПолучитьПустоеЗначение вернет верное значение агрегатного типа, даже если ее аргумент задает несуществующую разновидность типа. Например:
а= ПолучитьПустоеЗначение("Справочник.НетТакогоСправочника"); Сообщить(ТипЗначенияСтр(а)); // Напечатает Справочник
Добавим, что константа или определенная переменная символьного типа, если они содержат только пробелы, считаются пустыми, например
Сообщить(ПустоеЗначение(" ")); // Напечатает 1
Равное нулю число пустым не является, например
Сообщить(ПустоеЗначение(0)); // Напечатает 0
3.3. СПИСОК ЗНАЧЕНИЙ
3.3.1. СТРУКТУРА СПИСКА ЗНАЧЕНИЙ
Объекты типа СписокЗначений хранят таблицы с тремя столбцами (колонками), имеющими следующий смысл:
• значение; данные заносимые в этот столбец, могут быть любого, в том числе и агрегатного типа;
• представление значения - описание значения, или его смысл, или комментарий, или второе значение; данные этого столбца должны быть символьного типа; если это не так, то представление значения автоматически преобразовывается в символьный тип;
• пометка.
Второй столбец списка значений может не заполняться. При этом, правда, мы лишаемся методов, управляющих списком по представлению значения, таких, как Получить и Установить.
В последний столбец для каждого значения заносится число 1 или 0. В первом случае значение считается помеченным, во втором - нет. По умолчанию все заносимые в список значения не помечены.
Замечания:
1. В дальнейшем каждую строку хранимой в списке значений таблицы будем называть элементом списка.
2. В качестве значения элемента списка значений может выступать другой список значений (пример см. в разд. 2.8.5.5).
3.3.2. ПРИМЕР СПИСКА ЗНАЧЕНИЙ
Создадим для примера список значений, содержащий представленные в табл. 3.2. данные, отражающие некоторые сведения о подразделениях предприятия.
Таблица 3.2
Состав списка значений |
|
Код подразделения (значение элемента списка) |
Подразделение
(представление элемента списка) |
|
099 |
Отдел кадров |
|
100 |
Бухгалтерия |
|
111 |
Снабжение и сбыт |
|
001 |
Цех 1 |
|
002 |
Цех 2 |
|
011 |
Цех 11 |
|
|
Выполним для начала следующие действия: |
1. Занесем исходные данные в массивы кодПодр и имяПодр, а затем переместим их, используя метод ДобавитьЗначение, в список значений. Код подразделения используем для определения столбца значение, а название подразделения - для определения столбца представление значения формируемого списка значений. Эти действия произведем в процедуре Выполнить обработки Проба.
2. Для контроля выведем элементы списка в окно сообщений. Вывод осуществим в процедуре Контроль, в которой для определения числа элементов списка применяется метод РазмерСписка, а для доступа к элементу списка - метод Получить-Значение.
3. Отсортируем (метод Сортировать) список значений по кодам подразделений и вновь выполним вывод результата.
4. Вставим после 3-й позиции списка новый элемент (088, Цех 88), удалим предпоследний элемент списка и изменим имя подразделения, код которого равен 111, на новое имя, предварительно проверив, есть ли в списке элемент с таким кодом, сдвинем измененный элемент на одну позицию вверх и выведем модифицированный список. Для выполнения намеченных действий используем методы ВставитьЗначение, Удалить-Значение, НайтиЗначение, УстановитьЗначение и СдвинутьЗначение.
5. Вновь отсортируем список, но теперь уже по именам подразделений (метод Сор-тироватьПоПредставлению) и выполним вывод результата.
6. Выведем, вызывая метод ВыбратьЗначение, диалог со списком имен подразделений и выберем в нем Цех 88. Возвращенные методом значения (код цеха и его номер в списке значений) выведем в окно сообщений.
7. Преобразуем, используя метод ВСтрокуСРазделителями, итоговый список в текст.
// Предварительное описание процедуры Контроль процедура Контроль(сЗнач, этап) далее
процедура Выполнить() перем сЗнач, ин, поз;
перем кодПодр[20], подр[20]; // Векторы для имен подразделений и их кодов
перем код, нПодр; // Код подразделения и его номер
перем число Подр; // Число подразделений
перем стр; // Строка, в которую выгружается список значений
// Перед каждым запуском процедуры Выполнить будем очищать окно сообщений ОчиститьОкноСообщений();
|
'099"; |
подр[1] = |
"Отдел кадров"; |
|
100"; |
подр[2] = |
"Бухгалтерия"; |
|
111"; |
подр[3] = |
"Снабжение и сбыт |
|
’001"; |
подр[4] = |
"Цех 1"; |
|
002"; |
подр [5] = |
"Цех 2"; |
|
011"; |
подр[6] = |
"Цех 11"; |
[ числоПодр = 6; кодПодр[1] кодПодр[2] кодПодр[3] кодПодр[4] кодПодр[5] кодПодр[6]
// сЗнач - переменная (объект) типа СписокЗначений сЗнач = СоздатьОбъект("СписокЗначений"); для ин = 1 по числоПодр цикл
// Добавляем значение и его представление // (код подразделения и его название) в список значений сЗнач сЗнач.ДобавитьЗначение(кодПодр[ин], подр[ин]); конецЦикла; // для
Контроль(сЗнач, "Контрольный вывод начального списка.");
// Сортировка списка по возрастанию значений имен подразделений сЗнач.Сортировать();
Контроль(сЗнач, "Контрольный вывод отсортированного начального списка.");
// Вставка элемента (кода подразделения и его названия) после 3-го элемента списка сЗнач.ВставитьЗначение(4, "088", "Цех 88");
// Удаляем предпоследний элемент списка. Его номер равен сЗнач.РазмерСписка() - 1 сЗнач.УдалитьЗначение(сЗнач.РазмерСписка() - 1);
// Изменяем имя подразделения с кодом 111 на новое,
// если элемент с таком кодом присутствует в списке поз = сЗнач.НайтиЗначение("111");
если поз > 0 тогда // Если элемент найден
сЗнач.УстановитьЗначение(поз, "111", "Отдел снабжения и сбыта"); // Переместим измененный элемент на одну позицию вверх сЗнач.СдвинутьЗначение(-1, поз); иначе
Предупреждение("Подразделение с кодом 111 не найдено."); конецЕсли;
Контроль(сЗнач, "Контрольный вывод измененного списка.");
// Сортировка списка по возрастанию имен подразделений сЗнач.СортироватьПоПредставлению();
Контроль(сЗнач, "Контрольный вывод итогового отсортированного списка.");
// Окно выбора подразделения по его имени см. на рис. 3.1 // Установим курсор на строку, соответствующую подразделению Цех 1 // Для этого в переменную код установим код первого цеха код = "001";
флаг = сЗнач.ВыбратьЗначение(код, "Выбор подразделения", нПодр); Сообщить(РазделительСтрок + "Выбрано подразделение с кодом " + код + ". нПодр = " + нПодр); стр = сЗнач.ВстрокуСРазделителями();
Сообщить(РазделительСтрок +
"Значения элементов списка в виде строк с разделителем:" + стр); конецПроцедуры // Выполнить
процедура Контроль(сЗнач, этап) // Выводит список в окно сообщений
перем числоПодр; // Число подразделений
перем имяПодр, кодПодр; // Имя подразделения и его код
// Контрольный вывод списка сЗнач Сообщить(РазделительСтрок + этап);
числоПодр = сЗнач.РазмерСписка(); // Метод, возвращающий размер списка для ин = 1 по числоПодр цикл
// Метод ПолучитьЗначение вернет код подразделения с номером ин // и через параметр имяПодр - имя подразделения кодПодр = сЗнач.ПолучитьЗначение(ин, имяПодр);
// Тип параметра процедуры Сообщить всегда будет символьным, поскольку // выражение, задающее значение параметра, начинается с пустой строки Сообщить("" + кодПодр + " - " + имяПодр); конецЦикла; // для конецПроцедуры // Контроль
 |
|
Рис. 3.1. Диалог выбора значения списка по его представлению |
П осле последнего контрольного вывода в окно сообщений добавится следующий текст:
Контрольный вывод итогового отсортированного списка.
099 - Отдел кадров
111 - Отдел снабжения и сбыта
001 - Цех 1 011 - Цех 11
002 - Цех 2 088 - Цех 88
Выбрано подразделение с кодом 088; нПодр = 6
Значения элементов списка в виде строк с разделителем: "099","111","001","011","002","088"
Замечание. В списки значений часто переносятся данные об объектах агрегатного типа 1С, например при работе с разновидностью типа Справочник.Сотрудники в столбце значение можно разместить идентификаторы реквизитов справочника, а в столбце представление значения - представления реквизитов. Код получения идентификаторов реквизитов и их представлений см. в предшествующем разделе.
Число создаваемых в программе списков значений произвольно. Конечно, они должны иметь разные имена (по крайней мере в одной и той же области видимости). Для указания списка, с которым используется тот или иной метод, имя метода предваряется именем списка и разделяющей точкой, например
сЗнач.РазмерСписка()
3.3.3. МЕТОДЫ СПИСКА ЗНАЧЕНИЙ
Из примера видно, что методы списка значений, как это и полагается при работе с объектами подобного рода, позволяют добавлять, изменять, удалять, сортировать, находить, отображать и выбирать данные. Следует ожидать, что аналогичные методы мы обнаружим, работая, например, с таблицей значений или текстом. Полный список методов, применяемых со списком значений, приведен в табл. 3.3.
Таблица 3.3
Методы списка значений |
|
Метод |
Описание |
|
сЗнач.ДобавитьЗначение(знач, [пред]); |
Добавляет элемент со значением знач и представлением пред в конец списка |
сЗнач.ВставитьЗначение
(поз, знач, [пред], [кол]); |
Вставляет в список кол элементов со значением знач и представлением пред начиная с позиции поз списка. Должно выполняться условие 1 <= поз <= сЗнач.РазмерСписка() + 1 |
|
разы = сЗнач.РазмерСписка(); |
Возвращает число элементов в списке |
|
поз = сЗнач.НайтиЗначение(знач); |
Возвращает номер позиции элемента списка, имеющего значение знач, или нуль, если такого элемента в списке нет. При наличии в списке
нескольких элементов со значением знач
возвращается номер первого элемента, содержащего
искомое значение |
|
знач = сЗнач.ПолучитьЗначение (поз, [пред]); |
Возвращает значение элемента с номером поз и заносит в параметр пред, если он задан, представление этого элемента |
сЗнач.УстановитьЗначение
(поз, знач, [пред], [кол]); |
Заменяет кол раз существующие значения и представления элементов списка соответственно на знач и пред начиная с позиции поз. Значение параметра кол, если он опущен, равно единице |
|
|
Метод |
Описание |
|
знач = сЗнач.Получить(пред); |
Возвращает значение элемента списка по его представлению пред или пустое значение, если представление пред в списке не найдено |
|
сЗнач.Установить(пред), знач); |
Находит первый элемент списка с заданным представлением пред и заменяет существующее значение элемента списка на знач. Если элемент не найден, метод добавляет в конец списка новый элемент со значением знач и представлением пред |
|
сЗнач.УдалитьЗначение(поз, [кол]); |
Удаляет кол элементов списка начиная с указанной позиции. Значение параметра кол, если он опущен, равно единице. Если кол > 0 и указывает за пределы списка, то удаляются все элементы списка начиная с позиции поз. Если кол < 0, метод игнорируется |
|
сЗнач.УдалитьВсе( ); |
Удаляет все элементы списка. Эквивалентен вызову сЗнач.УдалитьЗначение(1, сЗнач.РазмерСписка()); |
|
сЗнач.Сортировать([напр], [поДате]); |
Сортирует элементы списка по их значениям. Если напр = 0 или опущен, то сортировка осуществляется по возрастанию значений, в противном случае -по убыванию. Если значения списка - это документы и по Дате = 1, то документы сортируются по дате, в противном случае - по значению |
сЗнач.СортироватьПоПредставлению
([напр]); |
Сортирует элементы списка по их представлениям. Если напр = 0 или опущен, то сортировка осуществляется по возрастанию значений, в противном случае - по убыванию |
|
сЗнач.СдвинутьЗначение(кол, поз); |
Перемещает элемент списка с позиции поз на кол позиций вниз, если кол > 0, или на кол позиций вверх, если кол < 0. Если параметр кол указывает на несуществующую позицию, то сдвиг выполняется либо в вершину списка, если кол < 0, либо в его конец, если кол > 0 |
|
флаг = сЗнач.Принадлежит(знач); |
Возвращает единицу, если в списке есть элемент, значение которого равно знач, или нуль -в противном случае |
флаг = сЗнач.ВыбратьЗначение
(знач, заг, [нПоз], [задержка], [способ]); |
Вызывает, если способ опущен или не равен 1 или 2, диалог, имеющий заголовок заг и содержащий список представлений элементов списка значений.
В диалоге (или окне со списком) курсор позиционирован на элементе со значением знач или на первом элементе, если значения знач в списке нет. После выбора представления и нажатия ОК возвращает 1, в параметр знач заносит значение выбранного элемента, а в параметр нПоз, если он задан, - его номер в списке. Если способ = 1, то окно для выбора отображается в виде меню, иначе, если способ = 2, окно отображается в виде небольшого списка. Смысл параметра задержка см. в табл. 2.3 |
|
Метод |
Описание |
флаг = сЗнач.ОтметитьЗначения
(знач, заг, [нПоз], [задержка]); |
Вызывает диалог (рис. 3.2), имеющий заголовок заг и содержащий список представлений элементов списка значений, и предоставляет возможность пометить или снять пометку с элемента списка.
В диалоге курсор позиционирован на элементе со значением знач или на первом элементе, если значения знач в списке нет. После выбора представления и нажатия ОК возвращает 1, в параметр знач заносит значение выбранного элемента, а в параметр нПоз, если он задан, -его номер в списке. Смысл параметра задержка см. в табл. 2.3 |
|
отметка = сЗнач.Пометка(поз, [флаг]); |
Помечает, если флаг = 1, элемент списка значений, имеющий позицию поз, или, если флаг = 0, снимает отметку с данного элемента. Если флаг опущен, то отметка элемента не изменяется. Возвращает значение отметки элемента (0 или 1), которое он
имел до вызова метода |
|
номерДо = сЗнач.ТекущаяСтрока ([номер]); |
Возвращает номер элемента списка, на котором находится курсор в элементе диалога Список или
Поле со списком, и устанавливает курсор, если задан параметр номер, на элемент списка, номер которого
совпадает со значением параметра |
|
стр = сЗнач.ВстрокуСРазделителями(); |
Преобразовывает значения списка в строку, содержащую заключенные в двойные кавычки значения списка, если они имеют нечисловой тип,
или числа, если значения списка числового типа |
|
сЗнач.ИзСтрокиСРазделителями(стр); |
Преобразовывает строку стр, содержащую разделенные запятыми последовательности символов или цифры в значения списка |
|
сЗнач.Выгрузить(знач, [поз], [кол]); |
Выгружает в список или таблицу значений знач кол элементов списка значений начиная с позиции поз этого списка. В результирующем списке (таблице) выгруженные элементы располагаются с первой позиции. При выгрузке в таблицу в ней добавляется новый столбец. Список значений, в который производится выгрузка, может быть создан функцией СоздатьОбъект, но должен быть пустым значением. Если знач не является списком или таблицей значений, то в результате выполнения процедуры Выгрузить, знач приобретет тип СписокЗначений |
 |
Рис. 3.2. Диалог после вызова сЗнач.ОтметитьЗначения (код,
"Пометка элементов списка"); сЗнач - список из приведенной вразд. 3.3.2 процедуры Выполнить; перед вызовом диалога выполнено присваивание: код = "100" |
Замечания:
1. Имя сЗнач списка значений, употребленное в табл. 3.3 перед названием методов, может быть произвольным.
2. Если метод может вызываться как функция, то он размещается в правой части оператора присваивания. Напомним, что любой метод может вызываться как процедура.
3. В методах для списка значений ПолучитьЗначение, УстановитьЗначение, УдалитьЗна-чение и Пометка должно выполняться условие 1 < =поз < =сЗнач.РазмерСписка().
4. Если в методах ВставитьЗначение, ПолучитьЗначение, УстановитьЗначение, Уда-литьЗначение и Пометка задана неверно позиция поз, то выводится сообщение "Индекс не входит в границы списка значений", метод игнорируется, вычисления продолжаются.
5. Если в методах СдвинутьЗначение и Выгрузить задана неверно позиция поз, то возникает завершающая работу программы ошибка исполнения, сопровождав-мая сообщением "Номер за пределами значения".
6. В документации по встроенному языку 1С указано, что метод СдвинутьЗначение перемещает значение списка на новую позицию. На самом деле на новую позицию перемещаются и значение, и представление, и пометка, то есть элемент списка. Аналогичные неточности присутствуют и при описании иных методов, например указывается, что метод УдалитьЗначение удаляет значения, в то время как он удаляет, если правильно заданы параметры, элементы списка.
Пример. Строка с разделителями преобразовывается в список значений сЗнач, в котором затем определяются представления и осуществляется, начиная со второго элемента, выгрузка списка сЗнач в список сЗнач2. Полученный список выводится приведений в разд. 3.3.2 процедурой Контроль.
перем сЗнач2;
// Не забываем о том, что присутствующие в символьной константе кавычки // должны повторяться дважды
стр = ......Цех 1"", ""НПК 20"", ""Отдел 48"", 24";
сЗнач.ИзСтрокиСРазделителями(стр);
// Текст процедуры Контроль см. в разд. 3.3.2
Контроль(сЗнач, "Контрольный вывод значений полученного из строки списка.");
// Определяем представление списка сЗнач, равным номеру элемента,
// которому это представление принадлежит. Значения элементов сохраняем для ин = 1 по сЗнач.РазмерСписка() цикл
сЗнач.УстановитьЗначение(ин, сЗнач.ПолучитьЗначение(ин), ин); конецЦикла;
// Переменная сЗнач2 объявлена оператором Перем. Без этого объявления ее // нельзя использовать в качестве фактического параметра процедуры Выгрузить сЗнач.Выгрузить(сЗнач2, 2); // Копирование осуществляем со второй позиции
Контроль(сЗнач2, "Контрольный вывод значений списка сЗнач2.");
Результат после второго вызова процедуры Контроль:
Контрольный вывод значений списка сЗнач2.
НПК 20 - 2 Отдел 48-3 24-4
3.3.4. СПИСОК ЗНАЧЕНИЙ КАК ЭЛЕМЕНТ ДИАЛОГА
Представления элементов списка значений могут отображаться в двух элементах
диалога: Список и Поле со списком, вставляемых в диалог в результате выбора на п а— V —“
нели Элементы диалога иконок
Вернемся вновь к обработке Проба, загрузим ее в конфигураторе, откроем закладку Диалог и приведем его к виду, представленному на рис. 3.3, дав идентификаторам элементов Список и Поле со списком соответственно имена сЗнач2 и сЗначЗ.
 |
|
Рис. 3.3. Диалог с двумя элементами для представления списка значений |
Переменные диалога сЗнач2 и сЗнач3 имеют тип СписокЗначений, и их не нужно создавать в программе, вызывая функцию СоздатьОбъект.
При вставке элемента сЗнач2 активизируем на закладке Дополнительно (рис. 3.4, а) флаг Список с пометками, а в поле Формула занесем текст Удаление( ). Для элемента сЗнач3 на закладке Дополнительно (рис. 3.4, б) зададим формулу Перенос().
Общие Дополнительно | Описание |
Формула: |Перенос!)
Г" Пропускать при вводе
Общие Дополнительно | Описание | формула: [Удаление!)
(? Список с пометками Г Пропускать при вводе
 |
|
Рис. 3.4. Дополнительные свойства элементов сЗнач2 и сЗначЗ |
Формулы Удаление( ) и Перенос( ) - это имена процедур модуля обработки. При необходимости в поле Формула (рис. 3.4, б) можно разместить имя процедуры (функции) глобального модуля системы.
Напишем теперь код, состоящий из процедур ПриОткрытии, Удаление, Перенося и Выполнить. Первая процедура формирует начальные значения списков сЗнач2 и сЗначЗ; вторая удаляет помеченные элементы списка сЗнач2 после двойного удара мыши по любому элементу списка или нажатия на Enter в момент расположения курсора на одном из элементов списка; третья переносит выбранные в списке сЗначЗ элементы в список сЗнач2. Процедура Выполнить, связанная с кнопкой диалога Пуск, восстанавливает, обращаясь к процедуре ПриОткрытии, начальные значения списков диалога.
// Инициализация списков сЗнач2 и сЗначЗ Начальный диалог приведен на рис. 3.5 // Векторы для имен подразделений и их кодов Число подразделений
процедура ПриОткрытии( ) перем ин; //
перем кодПодр[20], подр[20]; перем числоПодр; //
ОчиститьОкноСообщенийО; числоПодр = 6;
подр[1] = "Отдел кадров"; подр[2] = "Бухгалтерия"; подр[3] = "Снабжение и сбыт"; подр[4] = "Цех 1"; подр[5] = "Цех 2"; подр[6] = "Цех И";
Операторы необходимы для повторных вызовов процедуры
кодПодр[1] кодПодр[2] кодПодр[3] кодПодр[4] кодПодр[5] кодПодр[6] сЗнач2.УдалитьВсеО;
"099";
"100";
"111";
"001";
"002";
"ОН";
//
сЗначЗ.УдалитьВсеО;
для ин = 1 по числоПодр цикл
// Добавляем значение (код подразделения и его название) в список сЗнач2 сЗнач2.ДобавитьЗначение(кодПодр [ин], подр [ин]); конецЦикла; // для сЗнач2.Сортировать(); сЗнач2.Выгрузить(сЗначЗ); конецПроцедуры // ПриОткрытии
процедура Удаление() //Удаляет помеченные элементы списка сЗнач2
перем поз, размСпис;
// При удалении очередного элемента размер списка уменьшается на единицу // Этот факт отразим в переменной размСпис размСпис = сЗнач2.РазмерСписка(); поз = 1;
пока поз <= размСпис цикл
если сЗнач2.Пометка(поз) = 1 тогда сЗнач2.УдалитьЗначение(поз);
размСпис = размСпис - 1; // Размер списка сократился на единицу иначе
поз = поз + 1; // Наращиваем позицию, если нет удаления
конецЕсли; конецЦикла; // пока конецПроцедуры // Удаление
// Переносит выбранный элемент списка сЗначЗ в список сЗнач2 // Перенесенный элемент из сЗначЗ удаляется процедура Перенос() перем поз, код, имя;
поз = сЗначЗ.ТекущаяСтрока(); // Выбранная строка списка сЗначЗ
// Код и название выбранного в сЗначЗ подразделения код = сЗначЗ.ПолучитьЗначение(поз, имя);
сЗначЗ.УдалитьЗначение(поз); // Удаляем выбранное подразделение из сЗначЗ // Добавляем (переносим) удаленное из сЗначЗ подразделение в сЗнач2 сЗнач2.ДобавитьЗначение(код, имя); сЗнач2.Сортировать( ); конецПроцедуры // Перенос
// Восстанавливает первоначальные значения списков сЗнач2 и сЗначЗ процедура Выполнить()
ПриОткрытии (); конецПроцедуры // Выполнить
 |
|
Рис. 3.5. Диалог обработки Проба после исполнения процедуры ПриОткрытии |
Замечание. Список значений с пометками можно употреблять для создания интерфейсов, уподобляя каждый элемент списка флажку - Например, в отчете 1С анализ счета 20 используется список значений, представленный на рис. 3.6.
 |
|
Рис. 3.6. Список значений с пометками как элемент интерфейса |
Однако если число элементов диалога типа Флажок фиксированно, то число флажков в списке значений может быть переменным.
3.4. ТАБЛИЦА ЗНАЧЕНИЙ
3.4.1. АТРИБУТЫ ТАБЛИЦЫ ЗНАЧЕНИЙ
Таблица значений, в отличие от списка значений, может иметь произвольное число столбцов (колонок). Объект типа ТаблицаЗначений создается функцией Создать-Объект и имеет атрибуты номер Строки и идентификаторы столбцов. Первый содержит номер выбранной строки; идентификатор столбца - значение ячейки таблицы в выбранной строке. Например, если идентификатор первого столбца таблицы тЗнач имеет имя Код, то для изменения значения элемента этого столбца в пятой строке при -меним следующий код:
тЗнач.НомерСтроки = 5; // Переходим к строке 5 таблицы тЗнач
// Новое значение кода в пятой строке первого столбца таблицы тЗнач тЗнач.Код = "037";
Если в результате присваивания значение атрибута номерСтроки стало меньше нуля, то изменится код в первой строке; если оно стало больше числа строк в таблице, то код изменится в последней строке таблицы.
Если столбец при создании имени не получил, то в методах для таблицы значений ссылка на ячейку осуществляется по номеру столбца. Например, те же изменения, что и произведенные выше, обеспечит вызов
// Новое значение кода в пятой строке первого столбца таблицы тЗнач тЗнач.УстановитьЗначение(5, 1, "037");
Такое обращение возможно и в случае, когда столбец имеет имя. Однако недопустимо присваивание
тЗнач.1 = "037"; // тЗнач.1 - недопустимое имя
Поскольку имя тЗнач. 1 является недопустимым, то ошибка возникнет уже на этапе компиляции модуля.
Пример. В процедуре Выполнить обработки Проба создается таблица значений тЗнач, содержащая приведенные в табл. 3.4 данные; доступ к ячейкам таблицы осуществляется через имена идентификаторов столбцов; выбор строки производится в р е-зультате изменения значения атрибута номерСтроки.
Таблица 3.4
Состав таблицы значений |
|
Код подразделения |
Подразделение |
Число сотрудников |
|
099 |
Отдел кадров |
10 |
|
100 |
Бухгалтерия |
15 |
|
111 |
Снабжение и сбыт |
20 |
|
001 |
Цех 1 |
100 |
|
002 |
Цех 2 |
150 |
|
011 |
Цех 11 |
200 |
|
перем тЗнач; // тЗнач - переменная модуля
процедура Выполнить() // Отображает таблицу значений
// Перед каждым запуском процедуры Выполнить будем очищать окно сообщений ОчиститьОкноСообщенийО;
// Выведем номер текущей строки, используя атрибут номерСтроки Сообщить(тЗнач.НомерСтроки); // Напечатает 6 // Покажем таблицу значений, выделив в ней четвертую строку // Результат приведен на рис. 3.7
тЗнач.ВыбратьСтроку(4, "Первый просмотр таблицы значений"); тЗнач.НомерСтроки = 5; // Переходим к строке 5 таблицы тЗнач
// Новое значение кода в пятой строке первого столбца таблицы тЗнач тЗнач.Код = "037";
тЗнач.ВыбратьСтроку(, "Второй просмотр таблицы значений"); конецПроцедуры / Выполнить
процедура Заполнить( ) // Добавляет в таблицу значений строки и заполняет
перем ин, номСтроки; // их данными из векторов кодПодр, подр и колВо;
// Векторы для имен подразделений, их кодов и численности перем кодПодр [20], подр[20], колВо[20];
перем числоПодр; // Число подразделений
числоПодр = 6;
|
кодПодр[1] = |
"099" |
подр[1] = |
"Отдел кадров"; |
колВо [1] |
= 10; |
|
кодПодр[2] = |
”100”; |
подр[2] = |
"Бухгалтерия"; |
колВо[2] |
= 15; |
|
кодПодр[3] = |
"111"; |
подр[3] = |
"Снабжение и сбыт"; |
колВо [3] |
= 20; |
|
кодПодр[4] = |
"001"; |
подр[4] = |
"Цех 1"; |
колВо[4] |
= 100; |
|
кодПодр[5] = |
"002"; |
подр[5] = |
"Цех 2"; |
колВо [5] |
= 150; |
|
кодПодр[6] = |
"011"; |
подр[6] = |
"Цех 1 Г; |
" колВо [6] |
= 200; |
для ин = 1 по числоПодр цикл
тЗнач.НоваяСтрока(); // Добавляем новую строку
// Определяем, используя идентификаторы столбцов, ячейки новой строки тЗнач.Код = кодПодр [ин]; тЗнач.Имя = подр[ин]; тЗнач.Количество = колВо[ин]; конецЦикла; // для конецПроцедуры // Заполнить
процедура ПриОткрытии() // Формирует таблицу значений
// Формируем столбцы таблицы значений тЗнач.НоваяКолонка("Код", "Строка"); тЗнач.НоваяКолонка(" Имя", " Строка"); тЗнач.НоваяКолонка("Количество", "Число");
Заполнить(); // Заполняем таблицу значений данными
конецПроцедуры // ПриОткрытии
// Основная программа модуля обработки Проба состоит из одного оператора тЗнач = СоздатьОбъект("ТаблицаЗначений");
 |
|
Рис. 3.7. Таблица значений после цикла Для процедуры Заполнить |
Замечания:
1. Переменная тЗнач.НомерСтроки, если ее употребить в качестве первого параметра метода ВыбратьСтроку, например
тЗнач.ВыбратьСтроку(тЗнач.НомерСтроки, "Второй просмотр таблицы значений");
будет передана методу по значению, то есть номер выбранной строки не будет установлен в параметр тЗнач.НомерСтроки.
2. Таблица, приведенная на рис. 3.7, приобрела такой вид после появления диалоге и изменения в нем при помощи мыши ширины столбцов. Однако надлежащую используемую при отображении таблицы ширину столбца можно установить заранее, задав ее в методе НоваяКолонка, например, так:
// Формируем столбцы таблицы значений. Опуская имена необязательных параметров,
// сохраняем разделяющие их запятые
тЗнач.НоваяКолонка(''Код'', "Строка",,,, 10); // 10 - ширина первого столбца
тЗнач.НоваяКолонка(''Имя'', "Строка",,,, 20); тЗнач.НоваяКолонка(''Количество'', "Число",,,, 15);
3.4.2. РЕДАКТИРОВАНИЕ ТАБЛИЦЫ ЗНАЧЕНИЙ В ДИАЛОГЕ
Создадим в обработке Проба диалог, содержащий таблицу значений, дав ей имя тЗнач (рис. 3.8), и свяжем с таблицей процедуру Изменить, задав ее имя на закладке Дополнительно в поле Формула, в котором имя процедуры указывается с с охранением круглых скобок - Изменить().
 |
|
Рис. 3.8. Диалог для вывода списка подразделений в таблицу значений тЗнач |
Напишем код процедуры Изменить, позволяющий редактировать значение ячейки таблицы тЗнач, после двойного удара мышью по этой ячейке или после выбора ячейки и нажатия на клавишу Enter. Таблицу тЗнач заполним данными из табл. 3.4.
Алгоритм процедуры Изменить:
1. Определить, вызывая методы ТекущаяСтрока и ТекущаяКолонка, номер строки номСтроки и номер столбца номСтолбца, на пересечении которых находится редактируемая ячейка.
2. Используя метод ПолучитьПараметрыКолонки, определить тип данных столбца, с номером номСтолбца.
3. Вызвать диалог ввода данных найденного в п. 2 типа, используя функцию ВвестиЗначение, и задать в нем новое значение ячейки. При открытии диалога передать в него старое значение ячейки.
4. Записать, применив метод УстановитьЗначение, в редактируемую ячейку введен ное в п. 3 значение.
Также в модуль обработки войдут создающая таблицу процедура ПриОткрытии и инициализирующая таблицу процедура Заполнить, которую мы заимствуем из разд. 3.4.1. В процедуре Выполнить мы будем обращаться к процедуре Заполнить с тем, чтобы восстанавливать первоначальный вид таблицы значений.
процедура Изменить()
перем номСтроки, номСтолбца;
перем типДан, флаг; // Тип редактируемых данных
перем значен; // Значение редактируемой ячейки
номСтроки = тЗнач.ТекущаяСтрока(); тЗнач.ТекущаяКолонка(, номСтолбца); тЗнач.ПолучитьПараметрыКолонки(номСтолбца, типДан); значен = тЗнач.ПолучитьЗначение(номСтроки, номСтолбца);
// Передаем диалогу старое значение ячейки
флаг = ВвестиЗначение(значен, "Введите новое значение ячейки", типДан); если флаг = 1 тогда
тЗнач.УстановитьЗначение(номСтроки, номСтолбца, значен); конецЕсли;
конецПроцедуры // Изменить
процедура Заполнить() //
конецПроцедуры // Заполнить
Инициализирует таблицу значений // Берется из разд. 3.4.1
процедура ПриОткрытии() // Формирует таблицу значений
// Формируем столоцы таблицы значений. Опуская имена необязательных параметров,
// сохраняем разделяющие их запятые
тЗнач.НоваяКолонка("Код", "Строка",,,, 10); //10 - ширина первого столбца тЗнач.НоваяКолонка("Имя", "Строка",,,, 20); тЗнач.НоваяКолонка("Количество", "Число",,,, 15);
Заполнить(); // Заполняем таблицу значений данными
тЗнач.ТекущаяСтрока(З); // Позиционируем курсор на ячейку в третьей строке
тЗнач.ТекущаяКолонка(2); // и втором столбце таблицы значений
конецПроцедуры // ПриОткрытии
процедура Выполнить() // Восстанавливает таблицу значений
// Перед каждым запуском процедуры Выполнить будем очищать окно сообщений ОчиститьОкно Сообщений();
тЗнач.УдалитьСтроки(); // Удаляем все строки таблицы значений тЗнач
Заполнить();
// Заполняем ячейки таблицы значениями
// Диалог формы обработки Проба после ее загрузки приведен на рис. 3.9 конецПроцедуры
Диалог формы обработки Проба после ее загрузки приведен на рис. 3.9.
 |
|
Рис. 3.9. Таблица значений после загрузки обработки Проба Замечание. Ясно, что похожий механизм мы могли бы применить и для редакти |
рования элементов списка значений, рассмотренного в разд. 3.3.2.
3.4.3. ТЕКУЩАЯ СТРОКА ТАБЛИЦЫ ЗНАЧЕНИЙ
При работе с таблицей значений мы, обращаясь к идентификаторам столбцов, редактируем или читаем значения ячеек текущей строки. Так, если мы работаем с вышерассмотренной таблицей значений, то исполнение оператора
т.Знач.Код = "092";
приведет к изменению значения столбца под именем Код в текущей строке таблицы.
Номер текущей строки содержит атрибут номерСтроки. После создания таблицы номерСтроки = 0 в таблице просто нет строк. Однако такое же значение атрибут номерСтроки получит и при наличии в таблице значений строк после выполнения метода ВыбратьСтроки. В этом случае мы будем говорить: таблица значений позиционир о-вана до первой строки. Чтобы перейти на первую строку, достаточно вызвать метод ПолучитьСтроку, который, если не достигнута последняя строка, увеличивает номер текущей строки на единицу. Если же метод ПолучитьСтроку применяется, когда текущей является последняя строка, то таблица позиционируется вслед за ней, в атрибут номерСтроки устанавливается значение 0. Таким образом, по этому атрибуту, если он равен нулю, нельзя узнать, где мы находимся до первой строки таблицы значений или вслед за последней строкой. Приведенные сведения, иллюстрируются процедурой В ы-вестиНомСтроки, выводящей в окно сообщений значение атрибута номерСтроки. В процедуре переменная тЗнач - это любая таблица значений, например созданная и заполненная в разд. 3.4.2.
процедура ВывестиНомСтроки()
// тЗнач - переменная модуля, поэтому доступна в процедуре ВывестиНомСтроки // Позиционируемся перед первой строкой таблицы значений тЗнач тЗнач.ВыбратьСтроки();
// Напечатает 0, так как таблица позиционирована до первой строки Сообщить(тЗнач.НомерСтроки);
// Перебор строк таблицы значений начинается с ее первой строки пока тЗнач.ПолучитьСтрокуО = 1 цикл Сообщить(тЗнач.НомерСтроки); конецЦикла // пока
// Вновь напечатает 0, хотя таблица позиционирована вслед за последней строкой Сообщить(тЗнач.НомерСтроки); конецПроцедуры // ВывестиНомСтроки
Атрибут номерСтроки является ненадежным для определения номера текущей строки и в более широком смысле. Так, присваивание
тЗнач.номерСтроки = значение;
изменит значение атрибута, но не изменит номера текущей строки.
Кроме методов ВыбратьСтроки и ПолучитьСтроку, текущую строку изменяют методы ПолучитьСтрокуПоНомеру, НоваяСтрока и Сортировать. Метод СдвинутьСтр оку меняет текущую строку, если сдвигается текущая строка. В противном случае текущая строка сохраняется. Также текущая строка меняется при переносе курсора по строкам в элементе диалога Таблица значений.
Текущая строка становится неопределенной, когда:
• методы КоличествоСтрок или Свернуть уменьшают число строк до величины, меньшей чем значение (до применения метода) атрибута номерСтроки;
• метод УдалитьСтроку удаляет строку, номер которой меньше, чем значение (до применения метода) атрибута номерСтроки или равен ему.
Текущая строка становится равной нулю после выполнения методов Выбрать-Строки и Очистить.
3.4.4. МЕТОДЫ ТАБЛИЦЫ ЗНАЧЕНИЙ
Методы приведем в трех таблицах. В первой (табл. 3.5) перечислим сами методы с указанием их назначения; во второй (табл. 3.6) - синтаксис вызова методов, а в третьей (табл. 3.6) - описание (в алфавитном порядке) их параметров.
Таблица 3.5
Методы таблицы значений |
|
Метод |
Что делает |
|
КоличествоКолонок |
Устанавливает/возвращает число столбцов в таблице значений |
|
НоваяКолонка |
Добавляет в таблицу значений вслед за последним столбцом новый столбец |
|
ВставитьКолонку |
Вставляет в таблицу значений столбец с заданным номером |
|
УдалитьКолонку |
Удаляет заданный столбец из таблицы значений |
УстановитьПараметры
Колонки |
Изменяет параметры столбца |
ПолучитьПараметры
Колонки |
Возвращает номер или идентификатор столбца, а через параметры метода - параметры столбца таблицы значений |
|
КоличествоСтрок |
Устанавливает и/или возвращает число строк в таблице значений |
|
НоваяСтрока |
Добавляет строку в таблицу значений |
|
УдалитьСтроку |
Удаляет строку из таблицы значений |
|
УдалитьСтроки |
Удаляет все строки из таблицы значений |
|
ВыбратьСтроки |
Позиционирует таблицу значений до первой строки и позволяет перебирать, применяя метод ПолучитьСтроку, строки таблицы значений начиная с ее первой строки |
|
ПолучитьСтроку |
Осуществляет переход на следующую строку таблицы значений. Может употребляться как с методом ВыбратьСтроки, так и самостоятельно, например после метода
ПолучитьСтрокуПоНомеру (см. пример 2 после табл. 3.7) |
|
ВыбратьСтроку |
Открывает диалог, позволяющий выбрать строку в таблице значений. Значение атрибута номерСтроки после выбора строки в диалоге не меняется |
ПолучитьСтрокуПо
Номеру |
Позиционирует таблицу значений на заданную параметром номСтроки строку, которая после выполнения метода становится текущей |
|
СдвинутьСтроку |
Перемещает текущую или заданную параметром номСтроки строку таблицы значений на заданное число строк |
|
|
Метод |
Что делает |
|
УстановитьЗначение |
Устанавливает значение в заданной ячейке таблицы значений |
|
ПолучитьЗначение |
Возвращает значение ячейки таблицы значений |
|
НайтиЗначение |
Находит ячейку таблицы значений, содержащую заданное значение. Если в таблице несколько одинаковых значений, то находится первая от начала таблицы ячейка с искомым
значением |
|
Сортировать |
Сортирует таблицу значений. Правила сортировки задаются символьным выражение, содержащим идентификаторы и/или номера столбцов, например "КодПоставщика, +Материал, -3".
Если перемещается текущая строка, то и соответствующим образом меняется значение атрибута номерСтроки |
|
Очистить |
Удаляет из таблицы все строки и столбцы |
|
Итог |
Суммирует значения заданного столбца |
|
Заполнить |
Устанавливает значения в заданных столбцах таблицы значений в пределах заданного диапазона строк |
|
Свернуть |
Заменяет одинаковые в заданных столбцах строки на одну, суммируя данные в указанных столбцах. Таблица, к которой применяется метод, может быть неотсортированной |
|
Выгрузить |
Копирует таблицу значений или ее часть в другую таблицу значений или в столбец значение списка значений. Копирование осуществляется по строкам, если данные переносятся в список значений. После применения метода Выгрузить таблица значений, в которую выгружаются данные, будет содержать только те столбцы и строки, которые задаются параметрами метода |
|
Загрузить |
Копирует целиком одну таблицу в другую. После применения метода Загрузить таблица-приемник будет содержать только те столбцы и строки, которые имеет таблица-источник |
|
ВидимостьКолонки |
Отображает/скрывает столбцы таблицы значений, а также изменяет позицию указанного столбца. Метод оказывает воздействие на элемент диалога Таблица значений (рис. 3.9) и диалог, отображаемый методом ВыбратьСтроку |
|
ТекущаяСтрока . |
Устанавливает/возвращает в элементе диалога Таблица значений строку, в которой отображается курсор. Значение атрибута номерСтроки метод не меняет |
|
ТекущаяКолонка |
Устанавливает/возвращает в элементе диалога Таблица значений столбец, в котором отображается курсор. Результат применения методов ТекущаяСтрока и ТекущаяКолонка приведен на рис. 3.9 |
|
Фиксировать |
Делает недоступными в элементе диалога Таблица значений заданное число строк и столбцов |
Выводить
Пиктограммы |
Выводит в заданном столбце элемента диалога Таблица значений вместо занесенных в него данных пиктограммы из ВМР-файла, подсоединенного к элементу диалога в закладке Картинка в окне Свойства таблицы. Порядок создания и употребления пиктограмм разбирается в примере 8 после табл. 3.7 |
Таблица 3.6
Синтаксис вызова методов таблицы значений |
|
Синтаксис вызова |
Комментарий |
числоСтобцовДо =
тЗнач.КоличествоКолонок
([числоСтобцов]); |
Число столбцов не меняется, если параметр числоСтобцов не задан |
номНовСтолбца = тЗнач.НоваяКолонка
([иден], [тип], [длина], [точность], [заг], [ширина], [формат], [выравнивание]); |
Если тип не задан, то в добавляемом столбце можно хранить любой тип |
|
номНовСтолбца = тЗнач.ВставитьКолонку ([иден], [номНовСтолбца], [тип], [длина], [точность], [заг], [ширина], [формат], [выравнивание]); |
Если идентификатор не задан, то обращение к столбцу выполняется по его номеру |
|
тЗнач.УдалитьКолонку(иден | номСтолбца); |
В качестве параметра передается либо идентификатор, либо номер столбца |
тЗнач.УстановитьПараметрыКолонки (иден | номСтолбца,
[тип], [длина], [точность], [заг], [ширина], [формат], [выравнивание]); |
Значение параметра столбца сохраняется, если опущен соответствующий ему параметр метода |
иден | номСтолбца =
тЗнач.ПолучитьПараметрыКолонки (номСтолбца | иден, [тип], [длина], [точность],[заг], [ширина], [формат], [выравнивание]); |
Возвращает идентификатор столбца, если первый параметр - это номер столбца, и номер столбца, если первый параметр - это идентификатор столбца. Все параметры, кроме первого, являются выходными |
числоСтрокДо =
тЗнач.КоличествоСтрок
([числоСтрок]); |
Если числоСтрок > числоСтрокДо, то добавляемые в конец таблицы строки содержат пустые значения. Если числоСтрок < числоСтрокДо, то атрибут номерСтроки обнуляется. Число строк не меняется, если параметр метода опущен |
номНовойСтроки =
тЗнач.НоваяСтрока
([номНовойСтроки]); |
Если параметр номНовойСтроки отсутствует или больше числа строк в таблице, то строка добавляется в конец таблицы значений |
|
тЗнач.УдалитьСтроку([намСтроки]); |
Если параметр номСтроки не задан, то удаляется текущая строка. Изменение текущей строки осуществляется, например, методом ПолучитьСтрокуПоНомеру (разд. 3.4.3) |
|
тЗнач.УдалитьСтроки(); |
После выполнения значение атрибута номерСтроки равно нулю |
|
тЗнач.ВыбратьСтроки(); |
Часто предшествует методу ПолучитьСтроку |
|
ПЕРЕЧИСЛЕНИЯ
|
Синтаксис вызова |
Комментарий |
|
флаг = тЗнач.ПолучитьСтроку(); |
Вернет 1, если удалось переместиться на следующую строку, или 0 - если выполняется попытка переместиться за пределы таблицы значений |
флаг = тЗнач.ВыбратьСтроку ([номВыбСтроки],
[загДиалога], [задержка]); |
Возвращает:
1, если нажата кнопка ОК;
0, если нажата кнопка Отмена;
-1, если закончилось время, заданное параметром задержка.
Параметр номВыбСтроки - входной/выходной. При вызове метода курсор позиционируется на строке, номер которой равен номВыбСтроки, или на первой строке, если значение номВыбСтроки лежит вне диапазона [1, тЗнач.КоличествоСтрок();] |
тЗнач.ПолучитьСтрокуПоНомеру
(номСтроки); |
Если номер строки номСтроки выходит за пределы диапазона [1, тЗнач.КоличествоСтрок();], то возникнет завершающая ошибка, сопровождаемая сообщением "Номер за пределами значения!" |
номНовойСтроки =
тЗнач.СдвинутьСтроку (числоСтрок, [номСтроки]); |
Если номСтроки не задан, то перемещается текущая строка. Если числоСтрок > 0, то строка перемещается вниз таблицы. Иначе, если числоСтрок < 0, - в верх таблицы. Строка станет последней (первой), если числоСтрок задает позицию за пределами таблицы значений |
|
тЗнач.УстановитьЗначение(номСтроки, иден | номСтолбца, знач); |
Ячейка, в которой устанавливается значение, задается номером строки и идентификатором или номером столбца. Если эти параметры заданы с ошибкой, то возникнет завершающая вычисления ошибка |
знач = тЗнач.ПолучитьЗначение
{номСтроки, иден | номСтолбца); |
Ячейка, значение которой возвращается методом, задается номером строки и идентификатором или номером столбца. Завершающая ошибка возникает в тех же случаях, что и для метода УстановитьЗначение |
флаг = тЗнач.НайтиЗначение(знач,
номСтроки, иден | номСтолбца); |
Возвращает 1, если значение знач найдено, или
0 - в противном случае. Параметры номСтроки и иден | номСтолбца являются входными/выходными. В качестве результата эти параметры возвращают координаты ячейки, содержащей искомое значение. Если номСтроки (иден | номСтолбца) при вызове метода задает существующую строку (столбец), то поиск осуществляется только в этой строке (этом столбце). Если на входе номСтроки (иден | номСтолбца) отличен от нуля или пустого значения (иден не является пустой строкой), и выходит за границы таблицы (или иден задает несуществующий идентификатор столбца), то возникнет завершающая ошибка |
|
Синтаксис вызова |
Комментарий |
|
тЗнач.Сортировать(столбцы, [поДате]); |
Если значения таблицы - это документы и поДате =1, то документы сортируются по дате, в противном случае - по значению. Значение по умолчанию - 0 |
|
тЗнач.Очистить(); |
После выполнения метода атрибут номерСтроки принимает нулевое значение
Вернет, если параметр метода - это числовой столбец, сумму элементов столбца, заданного параметром иден или номСтолбца, или нуль -в противном случае. Вызов метода выполнен в примере 3 после табл. 3.7 |
|
тЗнач.Заполнить(знач, [начСтрока], [конСтрока], [столбцы]); |
Если хотя бы один из последних трех параметров метода задан с ошибкой, то возникнет завершающая ошибка |
тЗнач.Свернуть(групСтолбцы,
сумСтолбцы); |
Столбцы, которых нет в символьных выражениях групСтолбцы и сумСтолбцы, будут отсутствовать в результирующей таблице значений (см. пример 4 после табл. 3.7) |
|
тЗнач.Выгрузить(новОбвект, [начСтрока], [конСтрока], [столбцы]); |
Если хотя бы один из последних трех параметров метода задан с ошибкой, то возникнет завершающая ошибка. Порядок употребления метода иллюстрирует приводимый ниже пример 5 |
|
тЗначПриемник.Загрузить(тЗначИсточник); |
Данные переносятся из таблицы тЗначИсточник в таблицу тЗначПриемник |
|
флаг = тЗнач.ВидимостьКолонки(столбцы, [видимость], [позиция]); |
Если параметр столбцы содержит один столбец, то возвращает флаг видимости этого столбца до вызова метода; флаг равен единице, если столбец виден, или нулю - в противном случае. Если параметр столбцы задает несуществующий столбец или параметр позиция указывает на несуществующую
позицию, то метод игнорируется |
|
номСтрокиДо = тЗнач.ТекущаяСтрока ([номСтроки]); |
Вернет номер строки, на которой был позиционирован курсор до применения метода, или нуль, если такой строки нет. Текущая строка не меняется, если параметр номСтроки
не задан |
иденДо^омСтолбцаДо =
тЗнач.ТекущаяКолонка
([иде^номСтолбца],
[номСтолбцаДо]); |
Вернет идентификатор, а если он не задан, то номер столбца, на котором позиционирован курсор до применения метода, или нуль, если такого столбца нет. Текущий столбец не меняется, если опущен первый параметр |
|
Синтаксис вызова |
Комментарий |
|
тЗнач. Фиксировать |
Если параметр колСтрок задан, то после |
|
([колСтрок], [колСтолбцов]); |
применения метода в элементе диалога Таблица значений будут недоступны первые колСтрок таблицы. Если параметр отсутствует, то число недоступных строк не изменяется. Аналогично на столбцы элемента диалога Таблица значений действует параметр колСтолбцов. Вызов тЗнач.Фиксировать(0, 0); делает доступными все ячейки таблицы значений |
|
тЗнач.ВыводитьПиктограммы |
Пиктограммы, имеющиеся в подсоединенном |
|
(идеи | номСтолбца, |
к элементу диалога Таблица значений ВМР- |
|
[начНомПиктограммы ]); |
файле, - это последовательность растровых образов размера 16x15 видеопикселов.
Обращение к образу осуществляется по его номеру в этой последовательности. Если ячейка
А столбца иден | номСтолбца содержит число а, то в этой ячейке отобразится пиктограмма с номером начНомПиктограммы + а - 1. Если начНомПиктограммы + а - 1 меньше единицы или больше числа пиктограмм в ВМР-файле, то ячейка А останется незаполненной |
Замечания:
1. Имя тЗнач таблицы значений, употребленное в табл. 3.6 перед названиями методов, может быть произвольным.
2. Параметры методов, если это не оговаривается особо, являются входными.
3. Как и во всех методах, процедурах или функциях, входные параметры являются выражениями соответствующих типов.
Описание параметров методов таблицы значений
|
Таблица 3.7 |
|
Параметр |
Описание |
|
видимость |
Если равен нулю, то столбцы, перечисленные в параметре столбцы метода ВидимостьКолонки, будут скрыты, или видимы -в противном случае |
|
выравнивание |
Если выравнивание =1, то данные в столбце выравниваются по левой стороне, и по правой, если выравнивание = 2 |
|
групСтолбцы |
Столбцы, строки которых объединяются в одну при наличии в столбцах с одинаковыми номерами совпадающих значений |
|
длина |
Число символов для представления числовых или символьных данных |
|
заг |
Заголовок столбца |
|
загДиалога |
Заголовок диалогового окна |
|
знач |
Значение ячейки таблицы значений |
|
|
Параметр |
Описание |
|
идеи |
Идентификатор столбца |
|
колСтрок |
Число фиксируемых строк элемента диалога Таблица значений |
|
колСтолбов |
Число фиксируемых столбцов элемента диалога Таблица значений |
|
конСтрока |
Номер строки, в которой завершается заполнение или копирование таблицы значений (методы Заполнить или Выгрузить). Если параметр отсутствует, то заполнение (копирование) выполняется до последней строки включительно |
|
начНомПиктограммы |
Номер первого образа BMP-файла, отображаемого в ячейках заданного столбца элемента диалога Таблица значений |
|
начСтрока |
Номер строки, с которой начинается заполнение или копирование таблицы значений (методы Заполнить или Выгрузить). Если параметр отсутствует, то заполнение (копирование) осуществляется с первой строки |
|
новОбъект |
Имя таблицы или списка значений, задающее объект, в который метод Выгрузить копирует данные |
|
номНовСтолбца |
Номер нового столбца |
|
номСтолбца |
Номер столбца таблицы значений, на который распространяется действие метода |
|
номСтолбцаДо |
Номер текущего столбца таблицы значений до применения метода ТекущаяКолонка |
|
номСтроки |
Номер строки таблицы значений, на которую распространяется действие метода |
|
по Дате |
Флаг задания сортировки документов, содержащихся в таблице значений, по дате |
|
позиция |
Позиция, в которой отображается столбец таблицы, заданный параметром столбцы метода ВидимостьКолонки. Если параметр позиция отсутствует, то положение столбца не меняется |
|
числоСтобцов |
Новое число столбцов, устанавливаемое методом
КоличествоКолонок |
|
числоСтобцовДо |
Старое число столбцов, возвращаемое методом
КоличествоКолонок |
|
числоСтрок |
Число строк в таблице значений, устанавливаемое методом КоличествоСтрок |
|
столбцы |
Символьное выражение, содержащее разделенные запятыми идентификаторы или номера столбцов, по которым выполняется сортировка (метод Сортировать), или в которых изменяются значения ячеек (метод Заполнить), или из которых копируются данные (метод Выгрузить). В методе Сортировать перед идентификатором (номером) столбца может стоять знак + или -.'
Если перед идентификатором (номером) столбца знака нет или стоит знак +, то сортировка выполняется по возрастанию, если расположен знак -, то по убыванию (см. пример 3 после настоящей таблицы). Если переченьСтолбцов содержит неверный идентификатор или номер столбца, то возникнет завершающая ошибка |
|
Параметр |
Описание |
|
сумСтолбцы |
Столбцы, данные в которых суммируются при объединении строк по столбцам, заданным параметром групСтолбцы |
|
тип |
Тип, возможно агрегатных, данных, отображаемых в столбце |
|
точность |
Число знаков после десятичной точки в представлении числовых данных |
|
формат |
Формат представления данных. Форматирование осуществляется по правилам, изложенным в разд. 2.8.5 |
|
ширина |
Число символов, отводимое под столбец при отображении таблицы значений в диалоге |
|
номВыбСтроки |
На входе задает номер строки таблицы значений, на которой позиционируется курсор, на выходе - номер выбранной в диалоге строки |
Пример 1. В окно сообщений выводятся значения первого столбца, имеющего имя Код, во всех строках таблицы значений, заданной в табл. 3.4. Процедура Вывести может быть вызвана из процедуры Выполнить из разд. 3.4.1.
процедура Вывести()
// тЗнач - переменная модуля, поэтому доступна в процедуре Вывести // Позиционируемся перед первой строкой таблицы значений тЗнач тЗнач.ВыбратьСтрокиО;
// Перебор строк таблицы значений начинается с ее первой строки пока тЗнач.ПолучитьСтрокуО = 1 цикл Сообщить(тЗнач. Код); конецЦикла; // пока конецПроцедуры // Вывести
Пример 2. В окно сообщений выводятся начиная с третьей строки значения первого столбца таблицы значений, заданной в табл. 3.4.
процедура Вывести2()
// тЗнач - переменная модуля, поэтому доступна в процедуре Вывести // Позиционируемся на второй строке таблицы значений тЗнач тЗнач.ПолучитьСтрокуПоНомеру(2);
// Перебор строк таблицы значений начинается с ее третьей строки пока тЗнач.ПолучитьСтрокуО = 1 цикл Сообщить(тЗнач. Код); конецЦикла; // пока конецПроцедуры // Вывести2
Пример 3. Сортировка таблицы значений по трем столбцам. Первоначально создается и заполняется данными таблица значений, имеющая столбцы КодПоставщика, Материал и Количество. Затем выполняется сортировка по строке "КодПоставщика, +Материал, -3", означающей, что прежде данные упорядочиваются по возрастанию названий поставщиков, затем в пределах одинаковых поставщиков данные упорядочиваются (так же по возрастанию) по названию материалов и, наконец, в пределах одинакового поставщика и одинакового материала данные упорядочиваются по убыванию по количеству.
процедура Выполнить() перем тЗнач; перем пост[20], мат[20], колВо[20], ост[20];
//
Пример сортировки таблицы значений тЗнач
перем ин, числоЗап; // числоЗап - число строк в таблице значений
ОчиститьОкноСообщений();
тЗнач = СоздатьОбъект('ТаблицаЗначений");
числоЗап = 9;
// Содержание таблицы значений
|
пост[1]= |
1; |
мат[1] = |
"Сталь 45"; |
колВо[1] = 10; |
ост[1] |
= 5; |
|
пост[2] = |
2; |
мат[2] = |
"Чугун"; |
колВо[2] = 20; |
ост[2] |
= 10; |
|
пост[3] = |
1; |
мат[3] = |
"Сталь 45"; |
колВо[3] = 90; |
ост[3] |
= 40; |
|
пост[4] = |
3; |
мат[4] = |
"Свинец"; |
колВо[4] = 55; |
ост[4] |
= 25; |
|
пост[5] = |
1; |
мат[5] = |
"Сталь 45"; |
колВо[5] = 150; |
ост[5] |
= 65; |
|
пост[6] = |
4; |
мат[6] = |
"Олово"; |
колВо[6] = 70; |
ост[6] |
= 30; |
|
пост[7] = |
3; |
мат[7] = |
"Свинец"; |
колВо[7] = 100; |
ост[7] |
= 70; |
|
пост[8] = |
4; |
мат[8] = |
"Олово"; |
колВо[8] = 180; |
ост[8] |
= 100; |
|
пост[9] = |
1; |
мат[9] = |
"Олово"; |
колВо[9] = 200; |
ост[9] |
= 120; |
// Формируем столбцы таблицы значений. Опуская имена необязательных параметров,
// сохраняем разделяющие их запятые тЗнач.НоваяКолонка("КодПоставщика", "Число",,,, 10);
тЗнач.НоваяКолонка("Материал", "Строка",,,, 10); // 10 - ширина второго столбца
тЗнач.НоваяКолонка("Количество", "Число",,,, 8); тЗнач.НоваяКолонка("Остаток", "Число",,,, 8); для ин = 1 по числоЗап цикл
тЗнач.НоваяСтрока( ); // Добавляем новую строку
// Определяем, используя атрибут идентификатор столбца, ячейки новой строки тЗнач.Материал = мат[ин]; тЗнач.КодПоставщика = пост[ин]; тЗнач.Количество = колВо[ин]; тЗнач.Остаток = ост[ин]; конецЦикла; // для
// Покажем таблицу значений до сортировки тЗнач.ВыбратьСтроку(1, "До сортировки");
// Строка "1, +2, -Количество" обеспечит тот же результат сортировки, что и строка // "КодПоставщика, +Материал, -3" тЗнач.Сортировать("КодПоставщика, +Материал, -3"); тЗнач.ВыбратьСтроку(1, "После сортировки");
Сообщить(тЗнач.Итог("Количество")); // Напечатает 875
конецПроцедуры
Результат приведен на рис. 3.10.
|
КопЛос... |
I Материал | Колич.. |
1 Осгзт... |
КооПос.. |
I Материал | Колич... | Осгат... |
|
И |
Сталь 45 |
10 |
5 МММ |
ІмВИ 1 |
Олово |
200 |
1201 |
|
2 |
Чугун |
20 |
10 |
1 |
Сталь 45 |
150 |
65 |
|
1 |
Сталь 45 |
30 |
40 |
1 |
Сталь 45 |
90 |
40 |
|
3 |
Свинец |
55 |
25 |
1 |
Сталь 45 |
10 |
5 |
|
1 |
Сталь 45 |
150 |
65 |
2 |
Чугун |
20 |
10 |
|
4 |
Олово |
70 |
30 |
3 |
Свинец |
100 |
70 |
|
3 |
Свинец |
100 |
70 |
3 |
Свинец |
55 |
25 |
|
4 |
Олово |
180 |
100 |
4 |
Олово |
180 |
100 |
|
1 |
Олово
а |
200 |
120 |
4 |
Олово
6 |
70 |
30 |
Рис. 3.10. Таблица значений: а - до сортировки; б - после сортировки по правилу "КодПоставщика, +Материал, -3"
Пример 4. Если до метода Сортировать в процедуру Выполнить примера 3 добавить код а)
тЗнач.Свернуть("1", "3");
тЗнач.ВыбратьСтроку(1, "После сворачивания 4, а");
б)
тЗнач.Свернуть("1, 2", "3");
тЗнач.ВыбратьСтроку(1, "После сворачивания 4, б");
в)
тЗнач.Свернуть("1, 2", "3,4"); тЗнач.ВыбратьСтроку(1, "После сворачивания 4, в");
то получим приведенный на рис. 3.11 и 3.12 результат.
|
КооПос... |
I Материал | Коли.. I |
Остат... |
|
1 |
Сталь 45 |
10 |
5 |
|
2 |
Чупц |
20 |
10 |
|
1 |
Сталь 45 |
90 |
40 |
|
3 |
Свинец |
55 |
25 |
|
1 |
Сталь 45 |
150 |
65 |
|
4 |
Олово |
70 |
30 |
|
3 |
Свинец |
100 |
70 |
|
4 |
Олово |
180 |
100 |
|
1 |
Олово |
200 |
120 |
|
|
а |
|
Рис. 3.11. Таблица значений: а-до сворачивания; б - после сворачивания 4, а |
|
КооПос... |
I Материал I Колич... |
КооПос.. |
| Материал | Ко/ич... |
I Остат... |
|
1 |
Сталь 45 |
;г' — |
1 |
Сталь 45 |
250 |
1101 |
|
2 |
Чугун |
20 |
2 |
Чуун |
20 |
10 |
|
3 |
Свинец |
155 |
3 |
Свинец |
155 |
95 |
|
4 |
Олово |
250 |
4 |
Олово |
250 |
130 |
|
1 |
Олово |
200 |
1 |
Олово |
200 |
120 |
|
|
а |
|
|
6 |
|
|
|
|
Рис. 3.12. Таблица значений: а - после сворачивания 4, б; б - после сворачивания 4, в |

Пример 5. Если до метода Сортировать в процедуру Выполнить примера 3 добавить код
сЗнач = СоздатьОбъект("СписокЗначений"); тЗнач.Выгрузить(сЗнач, 1, 4, "1, 2, 3");
сЗнач.ВыбратьЗначение(1, "Данные перенесены из таблицы тЗнач"); то получим приведенный на рис. 3.13 результат.
 |
|
Рис. 3.13. Таблица и список значений: а - фрагмент таблицы, из которой копируются данные; б - список значений после переноса в него данных |
Пример 6. Неоднократное применение метода ВидимостьКолонки приводит к искажению представляемой методом ВыбратьЗначение таблицы значений. Так, код
тЗнач.ВыбратьСтроку(1, "Исходное представление таблицы значений"); тЗнач.ВидимостьКолонки(''2'', 0); тЗнач.ВидимостьКолонки(''3'', 1, 2);
тЗнач.ВыбратьСтроку(1, "После двукратного употребления метода ВидимостьКолонки");
добавленный до метода Сортировать в процедуру Выполнить примера 3, приведет к тому, что вместо трех столбцов метод ВыбратьСтроку отобразит два столбца табли -цы значений (рис. 3.14, б)
|
КоаПос. |
1 Материал | Колич. | Оствг.. |
КоаПос 1 |
Остат . |
|
|
Сталь 45 |
10 |
|
|
1 |
|
2 |
Чуун |
20 |
10 |
2 |
10 |
|
1 |
Сталь 45 |
90 |
40 |
1 |
40 |
|
3 |
Самой |
55 |
25 |
3 |
25 |
|
1 |
Ста» 45 |
150 |
85 |
1 |
65 |
|
4 |
Олово |
70 |
Ж |
4 |
30 |
|
3 |
Самой |
100 |
70 |
3 |
70 |
|
4 |
Олово |
180 |
100 |
4 |
100 |
|
1 |
Олово |
200 |
120 |
1 |
120 |
|
а б
Рис. 3.14. Таблица значений: а - до скрытия столбцов; б - с неверным числом отображаемых столбцов |
Замечание. С элементом диалога Таблица значений метод ВидимостьКолонки работает корректно.
Пример 7. Отображение таблицы значений, приведенной на рис. 3.9, после применения метода Фиксировать. Недоступные ячейки выводятся на сером фоне (рис. 3.15).
тЗнач.Фиксировать(2, 1);
 |
|
Рис. 3.15. Элемент диалога Таблица значений, в котором недоступны две первые строки и первый столбец |
Пример 8. Отображение пиктограмм в ячейках элемента диалога Таблица значений. Возьмем таблицу значений, созданную в разд. 3.4.2 и представленную на рис. 3.9 и 3.14, и добавим в нее на третью позицию столбец под именем Состояние, использовав код
тЗнач.НоваяКолонка("Состояние",,,,, 5); // 5 - ширина столбца
Запретим, применив метод Фиксировать, редактирование столбцов Код и Имя и будем выводить взятые из рис. 3.16 и приведенные в табл. 3.8 пиктограммы.
Рис. 3.16. Последовательность пиктограмм, выводимая в столбце Состояние рассматриваемой таблицы значений
Таблица 3.8
Пиктограммы ячеек элемента диалога Таблица значений |
|
Пиктограмма |
Номер |
Когда выводится |
|
|
1 |
Данные таблицы не изменялись с момента ее создания
и начального заполнения |
|
[fl~1 |
2 |
Установлен запрет на редактирование значения ячейки столбца Количество в текущей строке. Запрет устанавливается (снимается) в результате нажатия на кнопку Запретить |
|
|
3 |
Были внесены изменения в ячейку столбца Количество текущей строки |
|
Р<1 |
4 |
Строка таблицы значений подлежит удалению. Пиктограмма проставляется (снимается) в результате двойного удара мыши по ячейке в столбце Состояние удаляемой строки. Процедура, удаляющая помеченные строки, создается читателем
самостоятельно |
|
|
Возможный вариант состояния таблицы значений приведен на рис. 3.17. |
 |
|
Рис. 3.17. Таблица значений с пиктограммами из табл. 3.8 |
Для управления таблицей значений и ее отображения создадим форму, по образцу представленному на рис. 3.18.
 |
|
Рис. 3.18. Проект формы, управляющей таблицей значений |
Свяжем, используя закладку Дополнительно, кнопку Запретить с процедурой Запрет, устанавливающей в ячейку текущей строки столбца Состояние число 2, если редактировать количество нельзя, или прежнее значение ячейки. Для пояснения назначения кнопки на закладке Описание в окне Свойства кнопки введем приведенный на рис. 3.19 текст и активизируем флажок Использовать описание, что обеспечит вывод описания в качестве подсказки, когда в процессе работы с формой мышка задержится на кнопке Запретить.
 |
|
Рис. 3.19. Используем описание в качестве подсказки |
Кнопка Запретить оказывает воздействие только на непомеченные для удаления записи.
Первые 3 пиктограммы для таблицы значений имеются на картинке (рис. 3.20) из библиотеки картинок, открываемой на закладке Картинка окна Свойства таблицы после выбора кнопки Изменить картинку.
 |
|
Рис. 3.20. Библиотека картинок |
Сохраним выделенную на рис. 3.20 картинку в файл p.bmp, выбрав на рис. 3.20
иконку ^ Загрузим файл p.bmp в Paint (графический редактор BMP-файлов, запускаемый, например, после выполнения в Windows последовательности действий Пуск -Стандартные - Paint, дорисуем в четвертом прямоугольнике картинки пиктограмму 4 из табл. 3.8, приведя таким образом картинку к рис. 3.16. Добавим далее, находясь
в окне Библиотека картинок (рис. 3.20), при помощи иконки ^ в библиотеку файл p.bmp и выберем новую картинку для таблицы, воздействовав на иконку ^ . Теперь после выполнения метода тЗнач.ВыводитьПиктоіраммы(''Состояние'', 1);
в ячейках столбца Состояние будут выводиться пиктограммы из табл. 3.8. Причем номер выводимой пиктограммы будет равен значению, хранящемуся в ячейке.
Замечание. Доступ к библиотеке картинок также осуществляется после открытия конфигурации и выбора пункта Библиотека картинок в колонке Действия. Поскольку библиотека входит в конфигурацию, система предложит при закрытии конфигурации сохранить внесенные в библиотеку изменения.
Алгоритм функционирования формы:
1. Начальные действия:
• заполним таблицу значений тЗнач начальными данными, записав во все ячейки столбца Состояние число 1;
• зададим (метод ВыводитьПиктограммы) режим отображения пиктограмм для столбца Состояние (первоначально во всех его ячейках будет видна пиктограмма 1);
• запретим (метод Фиксировать) редактирование столбцов Код и Имя таблицы значений;
• создадим список значений сЗнач и присвоим всем его элементам единичные значения. В этом списке будем хранить значения ячеек столбца Состояние. Причем в столбце Значение будем размещать числа 1 или 2, интерпретируя их в соответствии с табл. 3.8, а в столбце Представление - строку Да, если можно редактировать количество, или строку Нет - в противном случае. Все это нам понадобится для правильной смены пиктограмм при работе с таблицей значений.
2. При нажатии на кнопку Пуск процедура Выполнить восстанавливает исходные состояния переменных тЗнач и сЗнач.
3. При нажатии на кнопку Запретить выполняется процедура 3 апрет, которая:
• если выставляется запрет на редактирование количества, меняет в текущей строке значение ячейки Состояние на 2, а в столбец Представление для соответствующего элемента списка сЗнач заносит Нет (нельзя редактировать количество);
• если запрет снимается, меняет в текущей строке значение ячейки Состояние на содержимое столбца Значение для соответствующего элемента списка сЗнач (устанавливает 1 или 3), а в столбец Представление для этого элемента сЗнач заносит Да (можно редактировать количество).
4. При двойном ударе мыши по ячейке таблицы значений из столбца Состояние выполняется процедура Изменить, которая:
• если строка помечается для удаления, меняет в текущей строке значение ячейки Состояние на 4;
• если снимается пометка удаления, меняет в текущей строке значение ячейки Состояние на содержимое столбца Значение для соответствующего элемента списка сЗнач (устанавливает 1 или 2), если в столбце Представление для этого элемента стоит Да, или устанавливает 3, если там находится Нет.
Процедура Запрет( ) перем номСтроки; номСтроки = тЗнач.ТекущаяСтрока();
если тЗнач.Состояние = 4 тогда // Стока помечена на удаление
Предупреждение(''Строка, помеченная на удаление, не обрабатывается."); возврат;
// Выставляется запрет на редактирование количества иначеЕсли тЗнач.Состояние о 2 тогда
сЗнач.УстановитьЗначение(номСтроки, тЗнач.Состояние, "Нет"); тЗнач.Состояние = 2; // Пиктограмма 2 из табл. 3.8
иначе // Снимается запрет на редактирование
тЗнач.Состояние = сЗнач.ПолучитьЗначение(номСтроки); сЗнач.УстановитьЗначение(номСтроки,, "Да"); конецЕсли
конецПроцедуры // Запрет
процедура Изменить( )
перем номСтроки, номСтолбца;
перем типДан, флаг; // Тип редактируемых данных
перем значен; // Значение редактируемой ячейки
перем пред; // Представление (Да или Нет) элемента списка сЗнач
номСтроки = тЗнач.ТекущаяСтрока();
тЗнач.ТекущаяКолонка(, номСтолбца);
если номСтолбца = 4 тогда // Если выбран столбец Количество
если тЗнач.Состояние = 4 тогда // Строка помечена на удаление
Предупреждение("Данные в помеченной на удаление строке не редактируются."); возврат;
// Запрет на редактирование количества иначеЕсли тЗнач.Состояние = 2 тогда
Предупреждение('Редактирование запрещено."); возврат;
иначе // Редактирование возможно
тЗнач.ПолучитьПараметрыКолонки(номСтолбца, типДан); значен = тЗнач.ПолучитьЗначение(номСтроки, номСтолбца);
// Передаем диалогу старое значение ячейки
флаг = ВвестиЗначение(значен, "Введите новое значение ячейки", типДан); если флаг = 1 тогда
// Если новое количество отлично от старого если значен о тЗнач. Количество тогда
тЗнач.УстановитьЗначение(номСтроки, номСтолбца, значен); тЗнач.Состояние = 3; // Пиктограмма 3 из табл. 3.8
// Храним данные о столбце Состояние в списке сЗнач сЗнач.УстановитьЗначение(номСтроки, 3, "Да"); конецЕсли; // значен <> тЗнач.Количество конецЕсли; // флаг = 1 конецЕсли; // тЗнач.Состояние = 4
иначе // Выбран столбец 3 (Состояние)
// Есть пометка об удалении. Снимаем пометку - заносим в ячейку // данные из списка сЗнач если тЗнач.Состояние = 4 тогда
значен = сЗнач.ПолучитьЗначение(номСтроки, пред);
если пред = "Да" тогда // Можно редактировать количество
тЗнач. Состояние = значен;
иначе // Количество редактировать нельзя
тЗнач. Состояние = 2; конецЕсли // пред = "Да"
иначе // Строка не помечена на удаление
тЗнач.Состояние = 4; // Выполняем пометку столбца пиктограммой 4
конецЕсли // тЗнач.Сосотяние = 4 конецЕсли; // номСтолбца = 4 конецПроцедуры // Изменить
процедура Заполните( ) // Добавляет в таблицу значений строки и заполняет
перем ин, номСтроки; //их данными из векторов кодПодр, подр и колВо;
// Векторы для имен подразделений, их кодов и численности перем кодПодр [20], подр [20], колВо [20];
перем числоПодр; // Число подразделений
числоПодр = 6;
|
кодПодр[1] = |
"099"; |
подр[1] = |
"Отдел кадров"; |
колВо[1] = 10 |
|
кодПодр[2] = |
"100"; |
подр[2] = |
"Бухгалтерия"; |
колВо[2] = 15 |
|
кодПодр[3] = |
"111"; |
подр[3] = |
"Снабжение и сбыт"; |
колВо[3] = 20 |
|
кодПодр[4] = |
"001"; |
подр[4] = |
"Цех 1"; |
колВо[4] = 100; |
|
кодПодр[5] = |
"002"; |
подр[5] = |
"Цех 2"; |
колВо[5]=150; |
|
кодПодр[6] = |
"011"; |
подр[6] = |
"Цех 11" ; |
колВо[6] = 200; |
для ин = 1 по числоПодр цикл
тЗнач.НоваяСтрока(); // Добавляем новую строку
// Определяем, используя атрибут идентификатор столбца, ячейки новой строки тЗнач.Код = кодПодр[ин]; тЗнач.Имя = подр[ин];
тЗнач.Состояние = 1; // Будет отображаться пиктограмма 1 из табл. 3.8
тЗнач.Количество = колВо[ин];
// Первоначально разрешено редактировать количество в таблице значений сЗнач.ДобавитьЗначение( 1, "Да"); конецЦикла; // для конецПроцедуры // Заполнить
Процедура ПриОткрытии( ) // Формирует таблицу значений
// Формируем столбцы таблицы значений. Опуская имена необязательных параметров,
// сохраняем разделяющие их запятые
тЗнач.НоваяКолонка("Код", "Строка",,,, 10); //10 - ширина первого столбца
тЗнач.НоваяКолонка("Имя", "Строка",,,, 20);
тЗнач.НоваяКолонка("Состояние"„„, 5); // 5 - ширина столбца
тЗнач.НоваяКолонка("Количество", "Число",,,, 10); ,
Заполнить(); // Заполняем таблицу значений данными
// Столбцы Код и Имя недоступны для редактирования тЗнач.Фиксировать(0,2); ,
// Выводим пиктограммы в столбце Состояние тЗнач.ВыводитьПиктограммы("Состояние", 1); конецПроцедуры // ПриОткрытии
процедура Выполнить() // Восстанавливает таблицу и список значений
// Перед каждым запуском процедуры Выполнить будем очищать окно сообщений ОчиститьОкноСообщений();
тЗнач.УдалитьСтроки(); // Удаляем все строки таблицы значений тЗнач
сЗнач.УдалитьВсе(); // Очищаем список значений сЗнач
// Заполняем ячейки таблицы тЗнач и элементы списка сЗнач значениями Заполнить(); конецПроцедуры
// Оператор основной программы модуля сЗнач = СоздатьОбъект("СписокЗначений");
Диалог формы обработки Проба после некоторых манипуляций с таблицей и кнопкой Запретить показан на рис. 3.17.
Замечание. В 1С нет предопределенной процедуры, работающей с элементами диалога Список и Таблица значений, позволяющей отслеживать перемещение по строкам этих объектов и дополнительно по столбцам в случае таблицы значений. Это в ряде случаев н е-гативно сказывается на качестве создаваемых пользовательских интерфейсов.
3.5. ВЫВОДЫ
1. Агрегатные типы данных предназначены для создания моделей функционирования предприятия и его подразделений; создание агрегатных типов данных, помимо встроенных в 1С, невозможно.
2. Агрегатные типы разделены на две группы - специального и общего назначения. Объекты первой группы описаны в конфигурации, второй - нет.
3. Список значений отображает таблицу из трех столбцов, содержащих значения, представления и отметки элементов списка. Столбцы списка значений имен не имеют; доступ к элементам списка осуществляется только в результате исполь -зования методов списка.
4. Список значений с пометками удобен для создания интерфейсов. В таком списке каждый его элемент можно рассматривать как флажок.
5. Таблица значений может содержать произвольное число столбцов, с которыми можно связать идентификаторы. Значение ячейки таблицы можно менять, модифицируя зн а-чение идентификатора соответствующего столбца, например в результате выполнения оператора присваивания или вызывая метод УстановитьЗначение.
6. Текущую строку таблицы значений могут изменить методы ВыбратьСтроки, Полу-читьСтроку, ПолучитьСтрокуПоНомеру, НоваяСтрока, Очистить, Сортировать, а также метод СдвинутьСтроку, когда сдвигается текущая строка. Кроме того, значение атрибута номерСтроки меняется при перемещении курсора по строкам в элементе диалога Таблица значений.
7. Методы КоличествоСтрок, УдалитьСтроку и Свернуть могут сделать неопределенным значение текущей строки таблицы значений.
8. Методы Свернуть, Выгрузить и Загрузить могут изменить число строк и столбцов таблицы значений. Причем два последних метода эти изменения осуществляют в таблице-приемнике данных.
9. С каждым полем диалога можно связать формулу, имя которой - это имя процедуры, (функции) в модуле диалога или глобальном модуле. Запуск этой процедуры (функции) возможен как из модуля, так и в результате воздействия на соответст -вующий элемент диалога.
10. Нет предопределенной процедуры, позволяющей отслеживать перемещение по строкам элементов диалога Список и Таблица значений и дополнительно по столбцам в случае таблицы значений.
4. ПЕРЕЧИСЛЕНИЯ
4.1. ПЕРЕЧИСЛЕНИЯ 1С
Перечисление - это агрегатный тип данных, содержащий список некоторых значений, например перечисление ДаНет может принимать два значения - Да и Нет. Имеющиеся в конфигурации Заработная плата и кадры перечисления (их синонимы или идентификаторы, если синоним не задан) выведет следующий код:
// Процедура вывода списка имеющихся в конфигурации перечислений процедура Выполнить() // Связана с кнопкой Пуск обработки проба
перем ин, всегоПереч; // всегоПереч - число перечислений в конфигурации
ОчиститьОкноСообщенийО;
всегоПереч = Метаданные.Перечисление();
для ин = 1 по всегоПереч цикл
Сообщшъ(Метаданные. Перечисление(ин)); конецЦикла; // для конецПроцедуры // Выполнить
Результат:
ВидЗаписи
ВидыПлатежа
ВидыПовышКвалиф
Годность
ДаНет
ДопСведИТС
ИнтервалСведений
Категории ПФР
Образование
ОснованияВЛ
ОснованияИТ С
ОснованияУвольнения
ОсобыеУсловияТруда
ОтношениеКВоинскойОбязанности
ПериодичностьСкидки
Пол
ПричинаОтсутствия
РасходыНаАвторские
РезультатыАтгестации
СемейноеПоложение
СпособПеречислПоИспЛисту
СтепениРодства
Территориальные условия
ТипБЛ
ТипБолезни
ТипНалоговойЛьготы
ТипПланаСчетов
ТипПлатежа
ТипРасчетаБольничного
ТипРасчетаОтпуска
ТипРасчетаПремии
ТипСотрудника
ТипФормы
ТипыПособий
ТипыУсловийТруда
Упорядочить
формыДоковПерсУчета
формыОбучения
ФормыТруда
ХарактерДоплаты
ХарактерСкидки
Характеру держания
ЦелиПеречисления
ОснованияОплатыПоСреднему
ВидСтрокиСреднегоЗаработка
Характер работы
ТипыЧасов
БухгалтерскиеКонфигурации
ПричинаПростоя
ПЕРЕЧИСЛЕНИЕ СКИДКИ
4.2.1. СОЗДАЕМ ПЕРЕЧИСЛЕНИЕ СКИДКИ
Создадим свое перечисление, дав ему имя Скидки, содержащее размеры скидок в процентах на оплату за обучение, например на курсах повышения квалификации, и представим затем все методы, применяемые при работе с перечислениями.
Вызовем конфигуратор, откроем конфигурацию на закладке Метаданные, войдем в раздел Перечисления и в меню, всплывающем после нажатия на правую кнопку мыши, выберем пункт Новое Перечисление. В появившемся окне зададим приведенные на рис. 4.1 данные.
 |
|
Рис. 4.1. Ввод перечисления Скидки |
Каждое новое значение перечисления вводим после выбора кнопки Новый. В п о-являющемся окне определяем идентификатор и представление элемента перечисления (рис. 4.2).
Идентификатор (Стцока20Лрой
Комментарий.
Пред стае ленив [20
Рис. 4.2. Идентификатор и представление элемента перечисления
При обработке данных в качестве значения элемента перечисления используется его] представление, если оно задано, или его идентификатор - в противном случае. Значение перечисления возвращается методом ЗначениеПоНомеру или ЗначениеПоИдентифика-тору. Также оно содержится в полном имени идентификатора элемента перечисления. Количество значений в перечислении вернет функция КоличествоЗначений.
Пример 1. Выводятся представления (значения) и идентификаторы элементов перечисления Скидки.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем ном, пер;
ОчиститьОкноСообщенийО;
// Выводим заголовок
Сообщить("Значение" + СимволТабуляции + "Идентификатор"); для ном = 1 по Перечисление.Скидки.КоличествоЗначенийО цикл // Переменная пер имеет тип Перечисление пер = Перечисление. Скидки.ЗначениеПоНомеру(ном);
// Пер.ИдентификаторО вернет идентификатор очередного элемента перечисления Сообщить(Строка(пер) + Символ Табуляции + пер.ИдентификаторО); конецЦикла; // для конецПроцедуры // Выполнить
|
Результат: |
|
|
Значение |
Идентификатор |
|
0 |
НетСкидки |
|
20 |
Скидка20Проц |
|
40 |
Скидка40Проц |
|
100 |
Скидка 100Проц |
Пример 2. Значения элементов перечисления Скидки выводятся по известным именам их идентификаторов.
процедура Выполнить() . , // Связана с кнопкой Пуск обработки Проба
перем ин, пер, иден[10];
ОчиститьОкноСообщенийО;
// иден - массив имен идентификаторов элементов перечисления Скидки
иден[1] = "НетСкидки"; иден[2] = "Скидка20Проц"; иден[3] = "Скидка40Проц"; иден[4] = "Скидка100Проц";
для ин = 1 по Перечисление.Скидки.КоличествоЗначений() цикл
// Значение (представление) перечисления (переменная пер) имеет тип Перечисление пер = Перечисление.Скидки.ЗначениеПоИдентификатору(иден[ин]); Сообщить(Строка(пер) + СимволТабуляции + иден[ин]); конецЦикла; // для конецПроцедуры // Выполнить
Результат тот же, что и в примере 1.
Пример 3. Значения элементов перечисления скидки выводятся по полным именам их идентификаторов.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
ОчиститьОкноСообщений();
Сообщить(Перечисление. Скидки. НетСкидки);
Сообщить(Перечисление. Скидки. Скидка20Проц);
Сообщить(Перечисление. Скидки. Скидка40Проц); Сообщить(Перечисление.Скидки.Скидка100Проц); конецПроцедуры // Выполнить
Результат:
0
20
40
100
Если представление элемента перечисления не задано, то в качестве значения используется имя идентификатора элемента перечисления. Так, очистив представления для двух последних элементов перечисления, получим после запуска программы из примера 3 следующий результат:
0
20
Скидка40Проц
Скидка100Проц
Замечание. Вся информация о перечислениях сосредоточена в файле конфигурации 1CV7.MD.
4.2.2. МЕТОДЫ ПЕРЕЧИСЛЕНИЙ
Назовем их в табл. 4.1, приведя после нее ряд примеров, иллюстрирующих не опробованные в предшествующем разделе методы. В качестве объекта, к которому применяется метод, используем только что созданное перечисление Скидки.
|
Методы перечислений |
|
Метод |
Описание |
кол = Перечисление.Скидки.
КоличествоЗначений(); |
Возвращает число элементов в указанном перечислении. Первый элемент перечисления имеет номер 1, последний - кол |
знач = Перечисление.Скидки.
ЗначениеПоНомеру(ном); |
Возвращает значение элемента перечисления, расположенного в перечислении под номером ном.
Если номер ном больше числа элементов в перечислении, то возникнет завершающая ошибка |
знач = Перечисление.Скидки.
ЗначениеПоИдентификатору
(идем); |
Возвращает значение элемента перечисления, имеющего идентификатор иден |
|
ном = Перечисление. Скидки. <иден>. ПорядковыйНомер(); |
Возвращает номер элемента перечисления, имеющего идентификатор иден |
|
иден = пер.Идентификатор(); |
Возвращает идентификатор элемента перечисления, значение которого содержится в переменной пер |
|
иденП= пер.Вид(); |
Возвращает идентификатор перечисления по значению его элемента, которое записано в переменную пер |
|
предстП= пер.ПредставлениеВида(); |
Возвращает представление перечисления, то есть его синоним, а если он не задан, то идентификатор перечисления по значению его элемента, которое
записано в переменную пер |
|
флаг - пер.Выбран(); |
Вернет 1, если выбран элемент перечисления, значение которого занесено в переменную пер, или 0 -в противном случае |
|
Замечание. В качестве значения элемента перечисления используется его представление, если оно имеет непустое значение, или идентификатор элемента - в противном случае.
Примеры для методов ПорядковыйНомер, Вид, ПредставлениеВида и Выбран:
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем ном, пер;
ОчиститьОкноСообщений();
// Следующий метод установит в ном число 3
ном = Перечисление.Скидки.Скидка40Проц.ПорядковыйНомерО;
// Переменная пер имеет тип Перечисление пер = Перечисление.Скидки.ЗначениеПоНомеру(ном); Сообщить(ТипЗначенияСтр(пер)); // Напечатает Перечисление Сообщить(пер.Вид()); // Напечатает Скидки
Сообщить(пер.ПредставлениеВидаО); // Напечатает Льготы по оплате Сообщить(пер.Выбран( )); // Напечатает 1
конецПроцедуры // Выполнить
Те же результаты получим, употребив вызовы методов Вид, ПредставлениеВида и Выбран, в которых вместо переменной пер стоит полное имя элемента перечисления Скидка40Проц:
Сообщить(Перечисление. Скидки. Скидка40Проц.ВидО);
Сообщить(Перечисление.Скидки.Скидка40Проц.ПредставпениеВидаО);
Сообщигь(Перечисление.Скидки.Скидка40Проц.ВыбранО);
4.3. ВВОД ЗНАЧЕНИЙ ПЕРЕЧИСЛЕНИЯ
Задание перечислений выполняется в конфигурации. Для получения значения п е-речисления в программе используются его методы, а также встроенная функция ВвестиПеречисление. Функция открывает диалог со списком значений перечисления (рис. 4.3).
 |
|
Рис. 4.3. Диалог, открываемый функцией ВвестиПеречисление для перечисления Скидки |
Функция имеет следующий синтаксис:
флаг = ВвестиПеречисление(значПер, заг, [задержка]);
Параметр значПер является входным/выходным. На входе он может иметь тип Перечисление. В этом случае он задает одно из значений перечисления, на котором после открытия диалога расположится курсор. Например:
значПер = Перечисление. Скидки. Скидка40Проц;
На выходе он также будет иметь тип Перечисление, но содержать уже выбранное значение.
Также параметр значПер может на входе иметь символьный тип. В этой ситуации перед вызовом функции переменной значПер нужно присвоить строку, содержащую идентификатор перечисления, значение которого мы хотим выбрать, например
значПер = "Скидки"; // Скидки - идентификатор перечисления
На выходе, однако, мы, как и в первом случае, получим значение типа Перечисл ение. Смысл параметров заг и задержка разъяснен в табл. 2.3
Функция вернет 1, если значение выбрано, вернет 0, если не выбрано, и -1, если время отображения диалога превысило величину, заданную параметром задержка.
Пример. Отображается диалог выбора значения перечисления Скидки:
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем флаг, значПер;
ОчиститьОкноСообщенийО;
значПер = Перечисление.Скидки.Скидка40Проц;
// или значПер = "Скидки";
флаг = ВвестиПеречисление(значПер, "Выберите значение и нажмите ОК");
// Если нажали OK, Enter или дважды ударили мышью по выбранному значению если флаг = 1 тогда
// Сообщаем значение выбранного перечисления Сообщить(значПер); иначе
Предупреждение("Ничего не выбрано."); конецЕсли;
конецПроцедуры // Выполнить
Замечание. Ввод значения значПер перечисления можно также выполнить, применив встроенную функцию ВвестиЗначение (разд. 2.5), например, так:
перем флаг, значПер;
флаг = ВвестиЗначение(значПер, "Выбор скидки", "Перечисление.Скидки");
4.4. ВЫВОДЫ
1. Перечисление состоит из элементов, каждый из которых имеет идентификатор и представление. Само же перечисление задается идентификатором; для представления перечисления используется его синоним или сам идентификатор перечисл е-ния, если синоним не задан.
2. Значением элемента перечисления является либо его представление, либо его идентификатор, если представление не задано.
3. Перечисления хранятся в файле 1CV7.MD, содержащем конфигурацию системы.
4. Интерактивный ввод значения перечисления осуществляется встроенной функцией ВвестиПеречисление.
5. СПРАВОЧНИКИ
5.1. УСТРОЙСТВО СПРАВОЧНИКА 1С
Опыт, приобретенный при работе с объектами типа СписокЗначений, ТаблицаЗначе-ний и Перечисление, позволяет перейти к более серьезным объектам агрегатного типа -справочникам. Их назначение - хранить достаточно стабильные данные и предоставлять их для различных целей. Так, данные справочника Подразделения используются при учете материалов, основных средств, на эти данные ссылается справочник Сотрудники и т. д. То есть справочники должны органично встраиваться в общую модель предприятия или его подразделения.
Справочник 1С - это совокупность главной таблицы (DBF-файла) и связанных с ней других таблиц. Кроме того, справочник может иметь владельца, в качестве которого выступает другой справочник системы. Так, владельцем справочника Образов а-ние является справочник Физические лица, который уже владельца не имеет. Список справочников, подчиненных заданному владельцу, выведет следующий код:
//Вывод справочников, подчиненных встроенному в 1С справочнику Сотрудники процедура Выполнить()
ОчиститьОкноСообщенийО;
для ин = 1 по Метаданные.Справочник( ) цикл
если СокрМетаданные.Справочник(ин).Владелец) • = "Сотрудники" тогда Сообщитъ(Метаданные. Справочник(ин). Идентификатор); конецЕсли; конецЦикла; // для конецПроцедуры //Выполнить
Результат:
Аттестация
ВнутренниеСовместители
Депонент
КадровыеДанные
Квалификация
НалоговыеЛьготы
Образование
Переподготовка
ПриказыДлительногоДействия
СоставСемьи
ТрудоваяДеятельность
Доходы7
Вычеты7
Итоги7
ИтогиПоГоду7
МатВыгода7
ДоходыПФР
В общем случае справочники 1С отображают иерархическую структуру данных за счет организации главной таблицы, представленной в табл. 5.1 (на примере нового справочника Сотрудники_2 для предприятия из двух цехов, причем первый цех имеет 3 подразделения).
Таблица 5.1
|
Принцип организации главной таблицы справочника Сотрудники_2 |
|
Группа |
СсылкаНа
Группу |
Код |
Наименование |
Флаг Папки (1 или 2) |
Другие
поля |
|
1 |
0 |
1 |
01 Цех |
|
|
|
2 |
0 |
2 |
02 Цех |
|
|
|
3 |
1 |
11 |
01/1 |
|
|
|
4 |
1 |
12 |
01/2 |
|
|
|
5 |
1 |
13 |
01/3 |
|
|
|
6 |
2 |
201 |
Абрамова Лариса Сергеевна |
2 |
|
|
7 |
2 |
202 |
Куприкова Людмила Сергеевна |
2 |
|
|
8 |
2 |
203 |
Митина Ольга Владимировна |
2 |
|
|
9 |
3 |
111 |
Агальцов Юрий Алексеевич |
2 |
|
|
10 |
3 |
112 |
Добрецов Борис Юрьевич |
2 |
|
|
11 |
4 |
121 |
Волосков Михаил Андреевич |
2 |
|
|
12 |
4 |
122 |
Кузьмина Раиса Николаевна |
2 |
|
|
13 |
5 |
131 |
Васильева Елена Ивановна |
2 |
|
|
15 |
5 |
132 |
Смирнова Нина Федоровна |
2 |
|
|
16 |
5 |
133 |
Хохлов Евгений Николаевич |
2 |
|
|
Замечание. В таблице данные упорядочены по выражению СсылкаНаГруппу + Наименование.
Такая организация главной таблицы позволяет отобразить состав справочника Со-трудники_2 по группам в виде иерархического списка (рис. 5.1), в качестве которых выступают имена цехов и их подразделений.
 |
|
Рис. 5.1. Вывод справочника Сотрудники_2 по группам Если отменить вывод справочника по группам, нажав на расположенную в окне вывода справочника иконку 1:'Ь', выполнить, обратившись к главному меню, сортировку по коду (Действия - Сортировка - По коду), то получим приведенное на рис. 5.2 представление справочника, отличающееся от табл. 5.1 порядком следования данных. |
В Z] Сотруаники_2 Е ІІ 01 Цех LU 01 /1 CJ 01 /2 01/3 li 02 Цех
|
¦ j Сотрудники_2 |
|
|
Код |
Наименование |
Оклад |
|
|
¦ШІ |
01 Цех |
|
|
-I |
2 |
02 Цех |
|
|
¦| |
11 |
01 /1 |
|
|
|
12 |
01 /2 |
|
|
1 |
13 |
01 /3 |
|
|
и |
111 |
Агальцов Юрий Алексеевич |
1.500.00 |
|
И |
112 |
Добрецов Борис Юрьевич |
2.300 00 |
|
J |
121 |
Волосков Михаил Андреевич |
2.500.00 |
|
|
122 |
Кузьмина Раиса Николаевна |
2.700.00 |
|
JJ |
131 |
Васильева Елена Ивановна |
1.850.00 |
|
и |
132 |
Смирнова Нина Федоровна |
1.900.00 |
|
и |
133 |
Хохлов Евгений Николаевич |
1.900.00 |
|
и |
201 |
Абрамова Лариса Сергеевна |
2.000.00 |
|
'1 |
202 |
Куприк.ова Людмила Сергеевна |
2.100.00 |
|
3 |
203 |
Митина Ольга Владимировна |
1.900.00 |
|
Рис. 5.2. Вывод справочника Сотрудники_2 в виде неиерархического списка
Замечание. Чтобы быстро найти в справочнике сотрудника, следует переместиться на поле Наименование и начать набирать на клавиатуре его фамилию.
5.2. АТРИБУТЫ И КОНТЕКСТ СПРАВОЧНИКА
Данные, доступ к которым обеспечивает справочник, называются его атрибутами. В их число входят реквизиты справочника (соответствующие им поля главной и связанной с ней таблиц, хранящих данные справочника), а также атрибуты Родитель и Владелец.
Совокупность атрибутов и методов справочника образует его контекст, который может быть передан в качестве фактического параметра процедуры или функции, например предопределенной процедуры ОбработкаПодбора.
Два реквизита (атрибута), Код и Наименование, присутствуют в любом справочнике. В случае справочника Сотрудники_2 реквизит Код может быть использован в качестве табельного номера сотрудника или кода группы, а Наименование - для задания фамилии, имени и отчества сотрудника или имени группы. Список иных реквизитов стандартного справочника Сотрудники и программу их получения см. в разд. 3.1. Свойства реквизита можно просмотреть или изменить в конфигурации системы (рис. 5.3).
|
Общие І| Дополнительные | |
Общие і Дополнительные і| |
|
Идентификатор: |
(Оклад |
Разделять триады Р |
Использовать: |
|
?иношм: |
|0клад сотрудника |
Неотрицательный W |
| Для элемента |
|
Комментарий; |
(Меняется документом Изменение |
Периодический Р |
Р Изменяется Документами |
|
Тип значения |
|<<Число>> |
Г |
Р Ручное изменение |
|
Длина: |
|10 Г" Точность: [2-гІ |
г |
|
|
|
а |
|
б |
Рис. 5.3. Свойства периодического реквизита Оклад: а - общие; б - дополнительные
История периодического реквизита просматривается после позиционирования на поле со значением реквизита (например, в окне, приведенном на рис. 5.2) и выбора на панели инструментов формы списка справочника иконки
или нажатия
на кд
а-вишу F5.
Замечание. Проще обеспечить достоверность данных, если запретить ручное изменение периодических реквизитов справочников (рис. 5.3, б), а взамен создавать I и проводить для этих целей соответствующие документы.
Рассматриваемый нами справочник Сотрудники_2 имеет 3 уровня. Это означает, что элемент 3-го, самого низкого уровня входит в группу, которая находится на 2-м уровне справочника. Имя группы, в которую входит текущий (выбранный) элемент справочника, содержит атрибут Родитель. Понятно, что элементы 1-го j уровня родителей не имеют. Сообщить о номере уровня справочника позволяет метод Уровень.
Применим метод Уровень и определим атрибут Родитель для всех элементов справочника (табл. 5.1), употребив следующий код:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2;
ОчиститьОкноСообщенийО;
сСотр_2 = СоздатьОбъекг("Справочник.Сотрудники_2");
сСотр_2.ВыбратьЭлементы(); // Перемещаемся на начало справочника
// Заголовок таблицы результатов
Сообщить("Наименование" + СимволТабуляции +"Уровень" +
СимволТабуляции + "Родитель");
// Метод ПолучитьЭлемент выбирает элемент справочника и перемещает справочник // на следующую позицию выборки или за ее пределы, если выборка исчерпана пока сСотр_2.ПолучшъЭлементО > 0 цикл
Сообщить(сСотр_2.Наименование + СимволТабуляции +
сСотр_2.Уровень() + СимволТабуляции + сСотр_2.Родитель);
|
конецЦикла // пока конецПроцедуры // Выполнить |
|
|
|
Результат: |
|
Наименование |
Уровень |
Родитель |
|
01 Цех |
1 |
|
|
01/1 |
2 |
01 Цех |
|
Агальцов Юрий Алексеевич |
3 |
01/1 |
|
Добрецов Борис Юрьевич |
3 |
01/1 |
|
01/2 |
2 |
01 Цех |
|
Волосков Михаил Андреевич |
3 |
01/2 |
|
Кузьмина Раиса Николаевна |
3 |
01/2 |
|
01/3 |
2 |
01 Цех |
|
Васильева Елена Ивановна |
3 |
01/3 |
|
Смирнова Нина Федоровна |
3 |
01/3 |
|
Хохлов Евгений Николаевич |
3 |
01/3 |
|
02 Цех |
1 |
|
|
Абрамова Лариса Сергеевна |
2 |
02 Цех |
|
Куприкова Людмила Сергеевна |
2 |
02 Цех |
Замечание. Следует помнить, что атрибут Родитель имеет тип Справочник. Поэтому присваивание
сСотр_2.Родитель = "02 Цех";
не приведет к изменению родителя текущего элемента. На самом деле в правой части приведенного оператора присваивания должно стоять значение, возвращаемое методом ТекущийЭлемент. Механизм изменения родителя изложен в разд. 5.5.3.2.
Атрибут Владелец, также имеющий тип Справочник, связывает некоторое подмножество записей справочника, например Дети, с определенной записью справочн и-ка-владельца.
Ряд реквизитов справочника целесообразно сделать периодическими, то есть хранить их историю. Таким, например, должен быть реквизит Оклад справочника Сотрудники_2, тогда мы сможем не только проследить динамику изменения оплаты сотрудника, но и учесть эти изменения при расчете заработной платы даже в том случае, если значение реквизита изменилось в пределах заданного расчетного периода (то есть в начале месяца вы имели один оклад, а где-то в середине -уже другой).
Замечание. Значения периодического атрибута Оклад заносятся, наряду с константами и другими периодическими реквизитами, в файл 1SCONST.DBF (поэтому не следует изумляться внушительным размерам этого файла). Если периодический реквизит ссылается на объект агрегатного типа данных, например на СправочникДолжности, то в файл 1SCONST.DBF заносится ссылка на соответствующий элемент объекта; значение этого элемента употребляется в качестве значения реквизита.
5.3. СОЗДАНИЕ СПРАВОЧНИКА 1С
5.3.1. ЭТАП 1. ДОБАВЛЕНИЕ СПРАВОЧНИКА В КОНФИГУРАЦИЮ
Сконструируем теперь, следуя нашим учебным целям, представленный в разд. 5.1 справочник Сотрудники_2. Войдем в конфигурацию, раскроем на закладке Метаданные пункт Справочники и, нажав на правую кнопку мыши, выберем в появившемся меню пункт Новый справочник. В окне Конструктор справочника в поле Идентификатор внесем текст Сотрудники_2 и проследуем далее. Пропустим окно, где предлагается создать новый вид субконто, и завершим первый этап создания справочника, указав на необходимость добавления команды вызов справочника в меню интерфейса Ученик (рис. 5.4).

5.3.2. ЭТАП 2. ФОРМИРОВАНИЕ РЕКВИЗИТОВ СПРАВОЧНИКА
В конфигураторе в списке справочников появится имя объекта Сотрудники_2, ударив по которому дважды мышью мы перейдем ко второму этапу создания справочника - формированию его реквизитов (рис. 5.5).
I (не подчинено) ~Д
Подчатек
?»«»•*<
ИдентиФи<.вгор. |Сотрудники_2
|Ссгтрудмики
Размещать труты сверху Р Автоматическая нумерация Р Кодтро/ъ уникальности Р |
Тип иода (• Числовой С Текстовый
Основное представлен*
С В виде кода
(• В виде наименования |  |
Г Одна Форма для элемента и труты Редактировать' | Обоими способами ~Д
Описан* | Форма глемента | Форма группы | Фореы списка >
Рис. 5.5. Задание реквизитов справочника Сотрудники_2 |
Дл«в Ro^q
Серии кодов
Во всем слраеочнисе
<• В пределах падчкиетмя
Два реквизита, Код и Наименование, заданы по умолчанию, поэтому нам следует лишь скорректировать их свойства, в частности установить длину поля Наименов ания равной 30. Не забудем задать число уровней справочника равным трем. Тип кода, когда есть возможность, лучше устанавливать числовым.
Зададим пока один дополнительный периодический реквизит - Оклад, выбрав кнопку Новый и определив его свойства в соответствии с рис. 5.3.
Замечание. Главную таблицу созданного справочника Сотрудники_2 система разместит в DBF-файле, возможно с именем SC4194.DBF.
Второй этап завершен. На третьем этапе создадим формы для просмотра и редактирования элементов и групп справочника Сотрудники_2.
5.3.3. ЭТАП 3. СОЗДАНИЕ ДИАЛОГОВ ДЛЯ РЕДАКТИРОВАНИЯ ЭЛЕМЕНТОВ И ГРУПП
5.3.3.I. ФОРМЫ ЭЛЕМЕНТА И ГРУППЫ
По умолчанию для просмотра, ввода и редактирования данных справочника используется форма списка (рис. 5.1, 5.2), которая содержит все реквизиты справочника. Бесспорно, просматривать данные в такой форме удобно. Однако редактирование или добавление данных лучше осуществлять посредством специальных форм для элемен-
тов и групп справочника. Чтобы обеспечить вызов этих форм, предусмотрим в окне рис. 5.5 редактирование справочника как при помощи форм для элементов и групп, так и в форме списка (рис. 5.6).
 |
|
Рис. 5.6. Задание способов редактирования справочника Сотрудники_2 |
Замечание. По умолчанию после выбора для свойства Редактировать пункта Обоими способами редактирование и добавление элементов и групп осуществляется в диалоге, то есть через их формы. В форме списка будет доступен только просмотр справочника. Для получения возможности редактирования в списке следует после запуска формы списка выполнить цепочку Действия - V Редактировать в диалоге либо употребить, например в предопределенной процедуре ПриОткрытии, при вызове формы списка справочника ее метод РедактироватьВДиалоге, установив в его первый параметр нуль. В то же время добавим, что для надежного контроля данных лучше использовать единственный источник их поступления - диалог элемента (группы) и отказаться от более простого на первый взгляд способа их редактирования в списке формы.
Чтобы создать Формы элементов и групп, нажмем, оставаясь в диалоге рис. 5.5, кнопку Форма элемента и воспользуемся окном (рис. 5.7) для размещения реквизитов справочника в диалоге формы элемента.
Размещение реквизитов Справочника
гакамигы
? Наименование ? Оклад
W Вставлять пня
W Разместить в диалоге автоматически
К Вызывать для новых Форм
Помощь
Отмена
Вставить
Рис. 5. 7. Помощник размещения реквизитов справочника в диалоге формы элемента
Приведем диалог к виду, представленному на рис. 5.8, сделав дополнительно поле Код недоступным для редактирования (это выполняется на закладке Общие окна свойств элемента Код).
3
Код (кед Сотрудник |наименоеамйё ОК
Оклад ІО г лад Закрытъ I
Рис. 5.8. Диалог формы редактирования элемента справочника Сотрудники_2
Отказ от редактирования поля Код обусловлен тем, что код сотрудника генерируется автоматически, поэтому придумывать и вводить код нет необходимости. Достаточно ограничиться его просмотром.
Замечание. Если для атрибута Код установить символьный тип, то, используя встроенную процедуру ПрефиксАвтонумерации, или методы ПрефиксКода (для справочника), или ПрефиксНомера (для документа), можно задать префикс, который будет использоваться при автоматическом назначении кода. Процедура ПрефиксАвтонуме-рации имеет следующий синтаксис:
ПрефиксАвтонумерации(разновидность, префикс);
где параметр разновидность - это символьное выражение, задающее разновидность типа справочника или документа, например "Справочник. Сотрудники" или "Доку-мент.ИзменениеОклада". Если нужно применить префикс ко всем справочникам (документам), то для задания значения параметра разновидность используется строка "Справочник.*" ("Документ.*"). Параметр префикс также имеет символьный тип и задает, как это следует из его названия, префикс.
Пример:
// Установим префикс номера для документа БольничныйЛист ПрефиксАвтонумерации("Документ.БольничныйЛист", "БЛ-");
Второй способ сделать атрибут Код доступным только для просмотра - это заменить редактируемое поле на элемент диалога Текст (рис. 5.9).
 |
|
Рис. 5.9. Диалог, в котором Код выводится с использованием элемента диалога Текст |
Замена выполнена следующим образом. Во-первых, удаляется поле с идентификатором Код. Во-вторых, вставляется элемент диалога Текст с пустыми данными на закладке Общие, но с определенной на закладке Дополнительно формулой Код (рис. 5.10).
 |
|
Рис. 5.10. Задание формулы для элемента диалога Текст |
Такие свойства позволят выводить в диалоге формы элемента справочника разный текст, а точнее - значение реквизита Код, изменяющееся при переходе от одного элемента к другому. Чтобы обеспечить единообразие с имеющимися элементами диалога, прижмем выводимый текст влево и отцентрируем его по вертикали.
Замечание. В любой момент в диалог можно добавить отсутствующий в нем реквизит справочника, выбрав на панели инструментов Элементы диалога иконку l-'S-.
Ввод и редактирование групп будем выполнять при помощи отдельного, представленного на рис. 5.11 диалога, в котором также запретим редактирование поля Код.
 |
|
Рис. 5.11. Диалог формы редактирования группы справочника Сотрудники_2 |
Этот диалог создается после нажатия кнопки Форма группы приведенного на рис. 5.5 окна. При этом флаг Одна форма для элемента и группы, расположенный в этом окне, должен быть отключен.
5.3.3.2. ФОРМЫ СПИСКА
Формы списка изменяются после выбора на рис. 5.5 одноименной кнопки. Форм может быть несколько. Одну можно использовать как основную, открываемую по умолчанию из меню по команде СправочникСотрудники_2.Открыть, вторую - для использования методом ОткрытьПодбор. Так и поступим. При этом в первую форму списка мы вставим дерево групп (см. рис. 5.1), а во вторую - нет (рис. 5.12).
|
|
Код |
Наименование |
?клад |
|
|
|
|
|
|
|
|
_ _ |
|
|
|
|
|
|
Рис. 5.12. Форма списка справочника Сотрудники_2 без дерева групп
Кроме того, в первой форме мы сохраним запрет на выбор групп при вызове метода Выбрать (этот запрет в методе Выбрать задан по умолчанию), а во второй, применив в предопределенной процедуре ПриОткрытии метод ВыборГруппы(1), этот запрет снимем. (Описание методов справочника см. в разд. 5.12.2.)
Замечание. Заголовок столбца, например Наименование, можно при желании заменить на иной, например на ФИО (аббревиатура слов фамилия, имя, отчество). Для этого столбец выделяется и затем осуществляется вызов окна Свойства поля ввода (Наименование), в котором и реализуется намеченное мероприятие.
Создавая вторую форму, мы после выбора Формы списка - Редактировать должны нажать копку Новый и дать форме имя, например ФормаДляВыбора. Затем, выбирая имена форм и применяя кнопки Основная и Для выбора, разделить формы по назначению (рис. 5.13).
 |
|
Рис. 5.13. Разделение форм списков по назначению |
Пока что ФормаДляВыбора не создана. Чтобы устранить этот недостаток, выберем на рис. 5.13 кнопку Изменить и в появившемся окне (рис. 5.14) сразу нажмем ОК.
 |
|
Рис. 5.14. Помощник создания формы списка |
Теперь после запуска программы из разд. 5.4 отображаемая в результате применения метода
ОткрытьПодбор(''Справочник.Сотрудники_2''„ контПодбора);
форма будет иметь приведенную на рис. 5.12 структуру.
Тот же список откроется и при следующем вызове:
ОткрытьПодбор("Справочник.Сотрудники_2", "ФормаДляВыбора", контПодбора);
Впрочем, если метод ОткрытьПодбор вызвать так:
// Указываем явно имя основной формы списка для метода ОткрытьПодбор ОткрытьПодбор("Справочник.Сотрудники_2", "ФормаСписка", контПодбора);
то им будет использована основная, использующая дерево групп форма списка справочника Сотрудники_2.
5.3.4. ЭТАП 4. НАПИСАНИЕ МОДУЛЕЙ ФОРМ
5.З.4.1. ТРЕБОВАНИЯ К ПРОЦЕДУРАМ МОДУЛЕЙ
ФОРМ СПРАВОЧНИКА
В модулях форм элемента и группы полезно написать процедуры, осуществляющие проверку вводимых данных и, по возможности, устраняющие имеющиеся в них ошибки. Например, в модуле формы элемента связанная через поле Формула с реквизитом Наименование функция или процедура может преобразовывать вводимые ФИО таким образом, что первые буквы ФИО будут прописными, а последующие - строчными. Это позволит нам, в частности, вводить ФИО на одном регистре, поскольку после ввода
кузьмина раиса николаевна
функция преобразует ФИО в надлежащий вид:
Кузьмина Раиса Николаевна
Чтобы исключить сокращения в ФИО, можно осуществить проверку на наличие в ФИО точки и при ее обнаружении запрещать запись введенных данных. Тогда не будет возможности ввести ФИО следующим образом:
Кузьмина Р. Н.
Дополнительно функция может удалять избыточные пробелы между составляющими ФИО компонентами.
Функция, связанная с реквизитом Наименование в форме для группы, должна препятствовать созданию одноименных групп в пределах одного родителя. Тогда в пределах группы 01 Цех эта функция запретит создание двух одинаковых подразделений.
Напишем для примера в модуле формы элемента справочника Сотрудники_2 функцию КонтрольФИО, связав ее, как и планировалось, с элементом диалога Наименование (это выполняется на закладке Дополнительные в окне задания свойств элемента). В модуле формы группы разместим функцию Уникальность, также связанную с элементом диалога Наименование, но уже в форме группы.
Вызовы этих функций необходимо разместить и в процедуре, связанной с кнопкой ОК. По умолчанию формула для этой кнопки такова:
#3аписать?3акрыть
Она обеспечивает действия, выполняемые методом для справочника Записать и методом для формы Закрыть, и вдобавок предлагает изменить даты для имеющихся в диалоге периодических реквизитов.
Чтобы предварить запись элемента справочника вызовом функции КонтрольФИО (Уникальность), используем в обеих формах предопределенную процедуру ПриЗапи-си, разместив в ней вызов функции КонтрольФИО (Уникальность). Это нужно, поскольку функция КонтрольФИО (Уникальность) вызывается:
1) всегда, когда выбран реквизит диалога Наименование, значение реквизита изменено и нажата клавиша Enter;
2) только единожды, когда покидается реквизит диалога Наименование в результате нажатия на любую (кроме Enter) меняющую положение курсора клавишу, например на табуляцию, или в результате применения мыши. Если затем вновь выбрать поле Наименование, а вслед переместиться с него, не прибегая к Enter, на другой элемент диалога, связанная функция (формула) вызвана не будет.
А это означает, что если не вызывать КонтрольФИО (Уникальность) при нажатии на ОК, то мы можем осуществить запись неверного значения реквизита Наименование: с точками в случае формы элемента или дублирующего имя существующего подразделения в случае формы группы.
Второй способ избежать ошибочных записей - это сделать кнопку ОК недоступной при неверных значениях наименования, употребив метод
форма.ОКИден.Доступность(0); // ОКИден - идентификатор копки ОК
Но он хуже, поскольку в процессе редактирования записи пользователь может забыть, по какой причине кнопка ОК стала недоступной.
Третий, пожалуй, наиболее удачный вариант - это наложить запрет на перемещение с поля диалога, содержащего ошибочные данные. Но он в 1С неосуществим (метод модуля формы Активизировать, который можно было бы использовать для реализации предложенного запрета, нельзя употреблять в формулах элементов диалогов, кроме кнопок).
Также в предопределенной процедуре ПриЗаписи разместим проверки, не позволяющие сохранять пустые значения реквизитов. Запрет на запись ошибочных данных наложим, употребив в процедуре ПриЗаписи функцию
СтатусВозврата(0); // Запрещает запись ошибочных данных
Выполняемая после нажатия кнопки Закрыть в формах элемента и группы команда предлагает, если были изменения данных, приведенный на рис. 5.15 диалог.
 |
|
Рис. 5.15. Диалог после нажатия на кнопку Закрыть (при наличии изменений в данных) |
Однако нам удастся избежать ввода неверных данных, если нажать Да, поскольку в этом случае сработает предопределенная процедура ПриЗаписи, выполняющая поиск ошибок.
Замечание. Команду #3акрыть, выполняемую при нажатии на кнопку Закрыть, можно заменить вызовом метода Форма.Закрыть(0). Равный нулю аргумент метода обеспечит закрытие формы без представленного на рис. 5.15 вопроса. Однако этот вопрос все равно будет появляться при попытке закрыть форму элемента или группы с измененными данными, нажимая на Esc, или используя крестик, или применяя Ctrl+F4.
Также в обоих модулях осуществим в предопределенной процедуре ПриОткрытии вызовы методов ПанельИнструментов и Заголовок. Первый поможет нам изъять из диалога ненужные вспомогательные иконки, а второй - задать заголовок диалога.
5.3.4.2. ПРОЦЕДУРЫ МОДУЛЯ ФОРМЫ ЭЛЕМЕНТА
Проверяют и корректируют ФИО по изложенным в предыдущем разделе правилам.
процедура ПриОткрытии( )
ОчистшъОкноСообщенийО;
форма.ПанельИнструментов(0); // Отключаем панель инструментов форма. Загаловок("Сотрудник предприятия"); конецПроцедуры // ПриОткрытии
функция КонтрольФИО(место = 1) далее процедура УбратьПробелыО далее процедура ВНРег() далее
// Проверяет, все ли данные введены и вызывает функцию КонтрольФИО
// и, если нет ошибок, осуществляется запись элемента справочника Сотрудники_2
процедура ПриЗаписи()
если (ПустоеЗначение(Наименование) = 1) или (ПустоеЗначение(Оклад) = 1) или (ПустоеЗначение(Образование) = 1) тогда Предупреждение("В диалоге есть неопределенные реквизиты.");
СтатусВозврата(0); // Не записываем данные
// Функция КонтрольФИО вернет 0, если в ФИО есть точки иначеЕсли КонтрольФИО(2) = 0 тогда
СтатусВозврата(О); // Запрещает запись ошибочных данных
конецЕсли;
конецПроцедуры // ПриЗаписи функция КонтрольФИО(место = 1)
// Параметр место равен 1, если вызов осуществляется из формы, то есть // формула имеет вид КонтрольФИО() или КонтрольФИО(1),
// и равен 2, если КонтрольФИО вызывается из процедуры ПриЗаписи
// Если вызов осуществляется из процедуры ПриЗаписи, тогда нет необходимости вызывать
// процедуры УбратьПробелы и ВНРег, корректирующие при необходимости
// Наименование, поскольку все необходимые изменения Наименования функцией
// КонтрольФИО уже произведены (см. выше порядок вызова КонтрольФИО в диалоге)
если место = 1 тогда // Вызов осуществляется из диалога
УбратьПробелыО; // Удаляет избыточные пробелы между словами
// Процедура ВНРег преобразовывает ФИО так, что первые буквы каждого // составляющего ФИО слова - прописные, а остальные - строчные ВНРег(); конецЕсли;
если Найти(Наименование,".") о 0 тогда
Предупреждение("Точки в ФИО недопустимы."); возврат 0;
иначе // Точек в имени нет
возврат 1; конецЕсли; , конецФункции // КонтрольФИО
процедура УбратьПробелыО перем длина, поз, к;
// Удаляем возможные ведущие и завершающие пробелы Наименование = СокрЛП(Наименование);
поз = Найти(Наименование, " "); // Ищем 2 подряд идущих пробела
// Цикл продолжается, пока в строке есть хотя бы одна пара подряд идущих пробелов пока поз > 0 цикл
длина = стрДлина(Наименование); // Длина ФИО
к =1; // Число лишних пробелов
пока (поз < длина) и (Сред(Наименование, поз + к, 1) = " ") цикл к = к+ 1;
конецЦикла; // пока (поз < длина). ..
// Удаляем лишние пробелы и заменяем старое значение ФИО на новое Наименование = Лев(Наименование, поз) + Прав(Наименование, длина- поз - к + 1); поз = Найти(Наименование, " "); // Ищем 2 подряд идущих пробела
конецЦикла; // пока поз > О конецПроцедуры // УбратьПробелы
Замечание. В процедуре УбратьПробелы можно было бы избавиться от возможных точек в ФИО, добавив в ее начало код
// Заменяем точки на пробелы ФИО = СтрЗаменить(ФИО,"."," ");
однако тогда окажется возможным запись ФИО в виде Кузьмина Р Н
// Процедура ВНРег преобразовывает ФИО так, что первые буквы каждого // составляющего ФИО слова - прописные, а остальные - строчные процедура ВНРегО
перем к, длина;
// Обработаем каждое слово ФИО встроенными функциями Врег и Нрег // Теперь, когда слова разделены одним пробелом и в конце ФИО нет пробелов,
// выделение слов тривиально // Алгоритм:
// 1. Преобразовываем все символы наименования в нижний регистр
// 2. Находим первый символ каждого слова и преобразовываем его в верхний регистр.
// Чтобы иметь возможность употреблять функцию Найти для поиска // очередного пробела (после него следует первая буква слова), будем // заменять найденный пробел на символ % (таких символов в ФИО быть не должно), // а после выполнения всех преобразований заменим символы % на пробелы
|
длина = стрДлина(Наименование); если длина = 0 тогда |
//Длина |
ФИО |
|
возврат; |
|
|
конецЕсли;
Наименование = Нрег(Наименование); |
// |
Первый шаг алгоритма |
// Подготовка к выполнению второго шага алгоритма // Первая буква ФИО - прописная
Наименование = Врег(Лев(Наименование, 1)) + Прав(Наименование, длина- 1); // к - позиция пробела, или нуль, если пробел не найден к = Найти(Наимен(звание, " "); пока к > 0 цикл
// Найден пробел. Формируем заново Наименование, в котором,
// найденный пробел заменен на %, а первая буква очередного слова
// преобразована в прописную
Наименование = Лев(Наименование, к - 1) + "%" +
Врег(Сред(Наименование, к + 1, 1)) + Прав(Наименование, длина - к - 1); к = Найти(Наименование, " "); конецЦикла; // пока к < длина
// Заменяем символы % на пробелы Наименование = СтрЗаменить(Наименование, "%", " "); конецПроцедуры // ВНрег
Замечание. При записи измененного оклада, который является периодическим реквизитом справочника Сотрудники_2, метод Записать должен вызвать приведенный на рис. 5.16 диалог, позволяющий либо принять изменение оклада, либо нет.
 |
|
Рис. 5.16. Изменение периодического реквизита Оклад |
Однако такой диалог отображается не всегда, что не позволяет редактировать периодический реквизит Оклад. Чтобы гарантированно иметь возможность изменять оклад сотрудников, в код модуля формы элемента, например в предопределенную процедуру ПриОткрытии, нужно добавить оператор
СохранениеПериодическихРеквизитов(к, " Оклад");
в котором к - это число, равное 2, 3, 4 или 5.
5.3.4.3. ПРОЦЕДУРЫ МОДУЛЯ ФОРМЫ ГРУППЫ
Проверяют на уникальность имя вновь вводимой или редактируемой группы. Для проверки (при вводе новой группы) мог бы подойти, например, следующий алгоритм:
1. Выполнить поиск группы по наименованию (функция НайтиПоНаименованию).
2. Если группа найдена, то запретить ввод записи (нарушена уникальность).
Однако такой алгоритм непосредственно реализовать нельзя, поскольку он предполагает изменение позиции справочника, что при работе с формой группы (элемента) недопустимо. Попытка изменения позиции справочника, скажем, в результате вызова НайтиПоНаименованию вызовет ошибку, сопровождаемую сообщением: "Объект не может быть перепозиционирован!"
Чтобы это ограничение обойти, следует создать объект
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
с которым и употребить метод НайтиПоНаименованию:
// Второй параметр метода - 0, следовательно, выполняем поиск во всем справочнике флаг = сСотр_2.НайтиПоНаименованию(Наименование, 0);
где Наименование - имя вводимой или редактируемой группы.
процедура ПриОткрытии( ) // Подготовительные действия
ОчиститьОкноСообщений();
форма.ПанельИнструментов(0); // Отключаем панель инструментов
форма.Заголовок("Подразделение предприятия"); конецПроцедуры // ПриОткрытии
функция Уникальность( ) далее // Вызывает функцию Уникальность, и если она возвращает 1,
// то осуществляется запись группы справочника Сотрудники_2 процедура ПриЗаписи()
если (ПустоеЗначение(Наименование) = 1) тогда Предупреждение("Выберите подразделение.");
СтатусВозврата(0); // Не записываем данные
// Если нарушена уникальность имен подразделений иначеЕсли Уникальность() = 0 тогда
СтатусВозврата(0); // Запрещает запись ошибочных данных
конецЕсли;
конецПроцедуры // ПриЗаписи
функция Уникальность() перем сСотр_2, флаг;
// Выполняем поиск группы по ее имени // Вариант 1
// Группа не найдена, запись разрешена // Вариант 2
// Группа найдена и ее код равен коду редактируемой группы (при вводе новой группы // это невозможно, поскольку коды всех записей уникальны), запись разрешена // Вариант 3
// Группа найдена и ее код отличен от кода редактируемой // или новой группы, запись запрещена сСотр_2 = СоздатьОбъект(" Справочник. Сотрудники_2"); флаг = сСотр_2.НайтиПоНаименованию(Наименование, 0);
если флаг = 0 тогда // Вариант 1
возврат 1;
иначеЕсли (флаг = 1) и (сСотр_2.код = Код) тогда // Вариант 2
возврат 1;
иначеЕсли (флаг = 1) и (сСотр_2.код <> Код) тогда //Вариант 3
Предупреждение("Неуникальное имя подразделения."); возврат 0; конецЕсли;
// То же можно записать компактнее:
// если (флаг = 1) и (сСотр_2.код <> Код) тогда // Вариант 3
// Предупреждение("Неуникальное имя подразделения.");
// возврат 0;
// конецЕсли;
// возврат 1; // Варианты 1 и 2
конецфункции // Уникальность
Замечание. Такой простой способ контроля уникальности названия подразделения предприятия выбран потому, что в справочнике Сотрудники_2 не может быть записей с одинаковым кодом. При этом мы предполагаем, что названия подразделений и ФИО сотрудников совпадать не могут.
5.4. ПРОСМОТР И ВЫБОР ЭЛЕМЕНТОВ СПРАВОЧНИКА
Справочники можно открыть в диалоге следующими способами:
• обращаясь к меню системы;
• применяя метод справочника Выбрать;
• вызывая в модуле произвольной формы функции ОткрытьФорму или ОткрытьФормуМодально;
• употребляя метод ОткрытьПодбор, который вызывает форму списка, отображающую заданный справочник.
Дополнительно функция ОткрытьФорму и метод ОткрытьПодбор позволяют, используя контекст открытой формы (подбора), манипулировать открытой формой. В случае метода ОткрытьПодбор для этих целей применяется предопределенная процедура ОбработкаПодбора.
Функции ОткрытьФорму и ОткрытьФормуМодально позволяют открыть как формы элемента и группы справочника, так и формы списка. Методы Выбрать и От-крытьПолбор используют только форму списка справочника, имя которой передается методами качестве второго параметра.
Замечание. Размеры диалога модально открытой формы в отличие от формы, открытой немодально, не могут быть изменены.
Пример 1. Форма списка основная справочника Сотрудники_2 открывается методом Выбрать. Если элемент выбран, в окне сообщений печатается ФИО сотрудника.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2;
ОчиститьОкноСообщенийО;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); если сСотр_Выбрать("Выберите сотрудника", "ФормаСписка") = 1 тогда Сообщить(сСотр_2.Наименование);
иначе // Метод Выбрать вернул 0
Сообщить("Сотрудник не выбран."); конецЕсли;
конецПроцедуры // Выполнить
Форма, открываемая методом Выбрать, приведена на рис. 5.17; для выбора можно
употребить клавишу Enter, двойной удар мыши, а также иконку *
 |
|
Рис. 5.17. Форма, открываемая методом Выбрать |
Замечание. Область интерактивного выбора элементов ограничивается методом ИспользоватьРодителя. Так, вызовы
сСотр_2.ИспользоватьРодителя(род, 0);
сСотр_2.Выбрать('Тодителя сменить нельзя", "ФормаСписка'');
в которых параметр род метода ИспользоватьРодителя имеет значение группы справочника, откроют диалог формы списка справочника, в котором можно выбрать элемент только из группы, заданной методом ИспользоватьРодителя. 'Переместиться за пределы этой группы нельзя.
Пример 2. Выбор сотрудников ограничивается подразделением 01/1 цеха 1.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, флаг, род;
ОчистшъОкноСообщенийО;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
//11 - код подразделения 01/1 первого цеха
флаг = сСотр_2.НайтиПоКоду( 11,0); // Поиск во всем справочнике если флаг = 0 тогда
Предупреждение(''Подразделение с кодом 11 не найдено."); возврат; конецЕсли;
// Ограничиваем выбор сотрудников подразделение 01/1 // Будет после вызова метода Выбрать открыт приведенный на рис. 5.17 диалог род = сСотр_2.ТекущийЭлемент(); сСотр_2.ИспользоватьРодителя(род, 0);
// Вместо двух последних операторов можно употребить один:
// сСотр_2.ИспользоватьРодителя(сСотр_2, 0);
если сСотр_2.Выбрать("Родителя сменить нельзя", "ФормаСписка") = 1 тогда Сообщить(сСотр_2.Наименование);
иначе // Метод Выбрать вернул 0
Сообщить("Сотрудник не выбран."); конецЕсли;
конецПроцедуры // Выполнить
Пример 3. Форма списка основная справочника Сотрудники 2 открывается функцией ОткрытьФорму.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем контПодбора; // Результат работы процедуры см. на рис. 5.
ОчиститьОкноСообщений();
ОткрытьФорму("Справочник.Сотрудники_2.ФормаСписка", контПодбора);
// По умолчанию открывается форма списка основная, поэтому следующий вызов // откроет ту же форму, что и предыдущий // ОткрытьФорму("Справочник.Сотрудники_2", контПодбора); Сообщить(контПодбора.Наименование); //Напечатает 01 Цех конецПроцедуры // Выполнить
Пример 4. Форма ввода нового сотрудника второго цеха в справочник Сотрудни-ки_2 открывается функцией ОткрытьФорму. Вслед открывается форма ввода новой группы первого меха.
процедура Выполнить^ ) // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, конт1, конт2;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьО6ъекг("Справочник.Сотрудники_2"); если сСотр_2.НайтиПоКоду(2, 0) = 1 тогда //2 - код второго цеха // Открываем форму ввода нового сотрудника второго цеха // Третий параметр функции задает родительскую группу
ОткрытьФорму('Элемет\Сотру,дники_2'', конті, сСотр_2.ТекущийЭлемент( ), 0); Сообщшъ(кот1 .Код); // Напечатает код нового сотрудника
иначе .
Предупреждение(''Цех 2 не найден."); возврат; конецЕсли;
еслисСотр_2.НайтиПоКоду(1, 0) = 1 тогда //1 - код первого цеха // Открываем форму ввода новой группы первого цеха
ОткрытьФорму(''Элемет\Сотрудники_2''. конт2, сСотр_2.ТекущийЭлемент(), 1); Сообщигъ(конг2.Код); // Напечатает код новой группы
иначе
Предупреждение(''Цех 1 не найден."); возврат; конецЕсли;
конецПроцедуры // Выполнить
Замечание. В примере 4 форма группы будет находиться поверх формы элемента. Это определяется порядком их вызова.
Пример 5. Открывается форма редактирования текущей записи справочника (группы или элементах.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, конт;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбьект(''Справочник.Сотрудники_2'');
// Ищем по коду во всем справочнике если сСотр_2.НайтиПоКоду(201, 0) = 1 тогда
// При этом вызове параметр функции ОткрытьФорму имеет тип Справочник ОткрытьФорму(сСотр 2ТекущийЭлемент(), конт. 0); иначе
Предупреждение("Элемент не найден."); возврат; конецЕсли;
конецПроцедуры // Выполнить
Пример 6. Форма списка справочника Сотрудники_2 открывается методом ОткрытьПодбор. Предопределенная процедура ОбработкаПодбора запускается при выборе (двойном ударе мыши или нажатии на Enter) ячейки третьего уровня и выводит в окно сообщений атрибуты открытой формы.
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем контПодбора; // Результат работы процедуры см. на рис. 5.2
ОчиститьОкноСообщенийО;
// По умолчанию открывается форма списка для выбора ОткрытьПодбор(''Справочник.Сотрудники_2'',, контПодбора); конецПроцедуры // Выполнить // Запускается при выборе (двойном ударе мыши или нажатии на Enter) ячейки третьего уровня I // Принимает в качестве параметра контекст справочника процедура ОбработкаПодбора(конт)
Сообщить(конт. Наименование);
Сообщить(конт. Родитель);
// Дата для доступа к периодическому реквизиту Оклад конт.ИспользоватьДату(РабочаяДата());
Сообщить(конт. Оклад); конецПроцедуры // ОбработкаПодбора
Возможный вариант сообщений, поступающих из процедуры ОбработкаПодбора: Добрецов Борис Юрьевич
01/1
2300
5.5. ДОБАВЛЕНИЕ, РЕДАКТИРОВАНИЕ И УДАЛЕНИЕ ЗАПИСЕЙ
5.5.1. УПРАВЛЕНИЕ ЗАПИСЯМИ СРЕДСТВАМИ ИНТЕРФЕЙСА
Для решения обозначенных в заголовке раздела задач можно использовать возможности, предоставляемые формой списка справочника, появляющейся, например, после вызова функции ОткрытьФорму. При этом можно пользоваться иконками инструментальной панели инструментов (рис. 5.18), пунктами меню колонки Действия или меню, появляющемся при нажатии на правую кнопку мыши, установленной на записи справочника. .
 |
|
Рис. 5.18. Панель инструментов формы списка справочника |
Замечание. Положение панели инструментов формы списка изменяется в резуль тате выполнения цепочки Сервис - Панели инструментов - Дополнительные - Инструментальные панели окон (рис. 5.19).
|
Панели і*ютру^ентов | Модификация Допо/м/гельине | |
 |
|
Рис. 5.19. Задание положения панели инструментов формы списка справочника |
ПОРЯДОК УДАЛЕНИЯ ЗАПИСЕЙ В ФОРМЕ СПИСКА
Рассмотрим подробнее процесс удаления записей.
Для удаления выбранного элемента нажмите иконку "і-. Физически, однако, элемент из справочника не удаляется, а лишь помечается как кандидат на удаление. При этом система позволяет выполнять его редактирование и выбор. Проставленная пометка об удалении снимается в результате повторного задействования той же иконки.
Если удаляется группа, то будут удалены (помечены для удаления) и все ее подчиненные, входящие в нее элементы. Снять же пометку удаления можно как с группы, так и со всех ее элементов.
При простановке пометки удаления система заносит в поле Ismark DBF-таблицы справочника символ * (табл. 5.2).
Таблица 5.2
фрагмент DBF-таблицы справочника Сотрудники_2 с помеченными записями |
|
|
Id |
Parentid |
Code |
Descr |
Isfolder |
Ismark |
Verstamp |
|
|
F |
7 |
203 |
Митина Ольга Владимировна |
2 |
|
6 |
|
|
М |
7 |
204 |
Удаляемый Сергей Николаевич |
2 |
* |
1 |
|
|
N |
7 |
205 |
Изымаемый Сергей Петрович |
2 |
* |
1 |
|
|
О |
7 |
206 |
Скрываемый Сергей Михайлович |
2 |
* |
1 |
|
Такая пометка является внутренней пометкой 1С и не позволяет осуществить физическое удаление записей DBF-файла, хранящих данные справочника.
Чтобы получить возможность удалять помеченные записи физически, добавим в меню интерфейса Ученик системную колонку Сервис, разместив в ней пункт &Удаление помеченных объектов (рис. 5.20). (Амперсант перед прописной буквой У обеспечивает интерактивный выбор пункта меню по этой букве.)
Е ‘Щз Сервис
0 ^Удаление помеченных объектов Е. ‘Щз Проба і- 0 Пуск 0 Открытъ Е ‘Щз Справочники 0 Константы 0 Сотрудники_2 0 Сотрудники
Рис. 5.20. Модифицированное меню интерфейса Ученик
Свойства нового пункта меню зададим в соответствии с рис. 5.21.
Общие I Параметры | Акселератор |
Нззваже; (^Удаление помечен Тип: |команаа
Объект. I Задача
w |
Команда: | Задача. УдалениеЛомеченныхОбъектов
Подсказка: (Удаление помеченных объектов
Рис. 5.21. Свойства пункта Удаление помеченных объектов
После сохранения конфигурации и загрузки 1С:Предприятия введем в справочник Сотрудники_2 новые записи, пометив их для удаления (рис. 5.22).
|
+ Jj Ссггруді**и_2 |
|
|
Кад |
Наименование |
Оклад |
|
|
2 |
02 Цех |
|
|
|
201 |
Абрамова Париса Сергеевна |
2.000 00 |
|
|
202 |
Куприкова Людмила Сергеевна |
2.100 00 |
|
|
203 |
Митина Ольга Владнг«іиробНб |
1.900 00 |
|
204 |
Удаляемый Сергей Николаевич |
3.450 00 |
|
|
205 |
Изымаемый Сергей Петрович |
2.350.00 |
|
|
206 |
Скрываемый Сергей Михайлович |
2.75000 |
|
Рис. 5.22. Три помеченные для удаление записи
Воспользовавшись затем новым пунктом меню, мы обнаружим, что его действие распространяется на все такие объекты системы, как Документы и Справочники. На первом этапе решения задачи об удалении помеченных объектов система находит эти объекты и выводит их список (рис. 5.23).
 |
|
Рис. 5.23. Список объектов для удаления |
В диалоге, содержащем этот список, следует нажать кнопку Контроль, чтобы определить объекты, которые можно удалить из базы, не нарушая ее целостности (рис. 5.24).
 |
|
Рис. 5.24. Результат контроля помеченных на удаление объектов |
Критерий выбора удаляемых объектов прост: объект можно удалить, если на него нет ссылок, и нет - в противном случае. Если есть необходимость максимально освободить систему от ненужных объектов, то следует поработать со ссылками, препятствующими удалению. Подход к каждой ссылке индивидуален. Удаление можно произвести программой, применив соответствующие методы для разных объектов.
Нажав кнопку Удалить, мы получим в окне сообщений текст об удаленных объектах, содержащий в том числе и информацию о нашем справочнике:
Удаленные записи:.
Справочник: Сотрудники_2 02 Цех/Удаляемый Сергей Николаевич Справочник: Сотрудники_2 02 Цех/Изымаемый Сергей Петрович Справочник: Сотрудники_2 02 Цех/Скрываемый Сергей Михайлович Справочник.Сотрудники_2: удалено объектов 3
После таких действий мы сделаем очередной шаг к физическому удалению записей, а точнее, пометим их для удаления так, как это принято в DBF-файлах. Визуально такая пометка отображается в первом столбце таблицы (такой столбец имеется и в табл. 5.2) и видна при открытии DBF-файла, например, в FoxPro. Приведем одну строчку таблицы с помеченными таким образом записями:
|
7 |
204 |
Удаляемый Сергей Николаевич |
2 * |
1 |
Замечание. Пометки удаления, проставляемые 1С в поле Ismark (см. табл. 5.2), в дальнейшем будем называть 1С-пометками удаления. Пометки удаления, которые 1С заносит в первый столбец DBF-файла, будем называть DBF-пометками удаления.
Только теперь можно перейти к физическому удалению помеченных записей. Для этого нужно закрыть 1С:Предприятие, открыть конфигуратор и вызвать, выполнив цепочку Администрирование - Тестирование и исправление ИБ, приведенный на рис. 5.25 диалог, активизировав в нем флаг Упаковка таблиц информационной базы.
Тестирование и исправление информационной базы
Выполняемые действия
Выло гнить
целостности
Настройся I
итогов
Пересчет
Помощь
(• Т вотирование и исправлеше Только тест?еоеаммв
Рис. 5.25. Запуск физического удаления помеченных записей
После выполнения упаковки произойдет физическое удаление помеченных записей. Восстановить удаленные таким образом записи нельзя.
Замечание. Встроенные процедуры НайтиПомеченныеНаУдаление и НайтиСсыл-ки, осуществляющие поиск помеченных для удаления записей и имеемых ими ссылок, а также процедура УдалитьОбъекты, удаляющая помеченные объекты (проставляющая DBF-пометки удаления), рассмотрены в разд. 5.15.
5.5.3. УПРАВЛЕНИЕ ЗАПИСЯМИ ИЗ ПРОГРАММЫ
Управлять записями справочников, то есть добавлять, удалять, редактировать, выбирать, искать и сортировать записи, можно, пользуясь имеющимися в 1С методами Для справочников. В этом разделе мы рассмотрим методы, имеющие отношение к добавлению, редактированию и удалению записей.
5.5.3.1. ДОБАВЛЕНИЕ ЗАПИСЕЙ
Новый элемент и группа добавляются в справочник соответственно методами Новый и НоваяГруппа. Они применимы только с переменными типа Справочник, определенными функцией СоздатьОбъект. Для записи нового элемента употребляется метод Записать.
Пример. В справочнике Сотрудники_2 создается группа 03 Цех, в которую заносится информация о сотруднике этого цеха.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, кодЦеха;
ОчиститьОкноСообщенийО; кодЦеха = 3;
// Определяем переменную сСотр_2 как объект типа Справочник с разновидностью
// типа Справочник.Сотрудники_2
сСотр_2 = СоздатъОбъект(''Справочник.Сотрудники_2'');
если сСотр_2.НайтиПоКоду(кодЦеха, 0) = 1 тогда
Предупрежденье Цех с кодом ” + кодЦеха + ” уже есть."); возврат; конецЕсли;
сСотр_2.НоваяГруппа(); // Создаем новую группу
сСотр_2.Код = кодЦеха; // и определяем ее реквизиты
сСотр_2.Наименование = "0" + Строка(кодЦеха) + ” Цех"; сСотр_2.3аписать(); // Записываем новую группу
// Текущим элементом является только что созданная группа 03 Цех // Чтобы занести сотрудника в эту группу, необходимо применить // метод ИспользоватьРодителя. Его параметром должно быть значение группы,
// имеющее тип Справочник, возвращаемое, например, методом ТекущийЭлемент // или задаваемое именем объекта-справочника сСотр_2.ИспользоватьРодителя(сСотр_2);
//или
// сСотр_2.ИспользоватьРодителя(сСотр_2.ТекущийЭлементО);
// Записываем периодический реквизит Оклад на рабочую дату // Этот оператор должен быть размещен до вызова метода Новый сСотр_2.ИспользоватьДату(РабочаяДата());
сСотр_2.Новый(); // Создаем новый элемент
// Атрибут Код, если его не определить, будет вычислен автоматически // Мы же определим код явно, равным, например, 301 сСотр_2.Код = Число(Строка(кодЦеха * 100)) + ”1”;
// Определяем иные реквизиты нового элемента сСотр_2.Наименование = "Безверхний Игорь Петрович”; сСотр_2.0клад = 3100;
сСотр_2.3аписать(); // Записываем новый элемент
// Просмотр результата
ОткрытьФорму(”Справочник.Сотрудники_2.ФормаСписка”);
конецПроцедуры
Результат приведен на рис. 5.26.
|
II Код 1И «именование |
ОдЯвД е| |
|
з|оэи« |
- j |
|
іИиЦ Безверхими Игорь Пе-’рооі'ч |
3.100 00 |
|
ЛІ___ |
|
- Сотруцники_2 ¦ Сз 01 Цех 02 Цех
^ 03 Цех
Рис. 5.26. Новое подразделение и новый сотрудник
5.5.3.2. ПЕРЕНОС ЗАПИСИ В ДРУГУЮ ГРУППУ
Если в приведенной в предшествующем разделе процедуре не вызывать метод Ис-пользоватьРодителя, то новый сотрудник попадет на верхний уровень (рис. 5.27). Чтобы переместить сотрудника в третий цех, следует выделить и сотрудника и группу,
обозначающую цех, так, как это показано на рис. 5.27, и воспользоваться иконкой или соответствующим пунктом меню в колонке Действия, или сочетанием клавиш
Ctrl+F5.
 |
|
Рис. 5.27. Перевод нового сотрудника в третий цех |
Программно перевод осуществляется в результате выполнения следующего кода:
процедура Выполнить() //Связана с кнопкой Пуск обработки Проба
перем сСотр_2, гр; // Переносит сотрудника в указанную группу
0,чиститьОкноСообщений();
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Находим группу, в которую переносится сотрудник если сСотр_2.НайтиПоКоду(3, 0) = 1 тогда
// Запоминаем ссылку на найденную группу гр = сСотр_2.ТекущийЭлемент();
// Находим сотрудника если сСотр_2.НайтиПоКоду(301, 0) = 1 тогда если сСотр_2.Родитель = гр тогда
Предупреждение(сСотр_2.Наименование + " уже работает в " + гр); возврат; конецЕсли;
// Меняем для нового сотрудника значение атрибута Родитель,
// присваивая ему значение переменной гр, имеющей тип Справочник сСотр_2.Родитель = гр;
сСотр_2.3аписать(); // Записываем измененный элемент
Предупреждение(сСотр_2.Наименование + " переведен в " + гр);
// Просмотр результата
ОткрытьФорму("Справочник.Сотрудники_2.ФормаСписка");
иначе
Предупреждение("Сотрудник не найден."); конецЕсли; иначе
Предупреждение('Труппа не найдена."); конецЕсли;
конецПроцедуры // Выполнить
Замечание. Поскольку в каждой группе код ее подчиненного элемента связан с кодом группы, то при переносе элемента из одной группы в другую необходимо соответствующим образом изменять код элемента. Алгоритм вычисления нового кода приведен в разд. 5.8.2.2. При интерактивном перемещении элемента из одной группы в другую его код следует модифицировать в предопределенной процедуре ПриПереносеЭлементаВДругуюГруппу модуля формы списка справочника. Порядок ее употребления рассмотрен в разд. 5.12.6.
5.5.3.3. РЕДАКТИРОВАНИЕ ЗАПИСЕЙ
Редактированию записи предшествует ее поиск, который может быть выполнен одним из четырех следующих методов: НайтиЭлемент, НайтиПоКоду, НайтиПоНаи-менованию и НайтиПоРеквизиту.
Изменение непериодического реквизита осуществляется либо в результате присваивания ему нового значения, либо методом УстановитьАтрибут. Изменение префикса кода осуществляется методом УстановитьНовыйКод; с числовым кодом применять эту функцию смысла не имеет.
Периодический реквизит также можно изменить простым присваиванием или методом УстановитьАтрибут. Однако предварительно до поиска элемента методом Ис-пользоватьДату нужно установить дату записи такого реквизита. Если в коде метод ИспользоватьДату ни разу для справочника не применялся, то для изменения значения периодического реквизита можно использовать метод Установить.
Пример. Изменяется фамилия сотрудника, код которого равен 203, и его оклад.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, новФИО;
ОчиститьОкноСообщенийО;
новФИО = "Костина Ольга Владимировна";
сСотр_2 = СоздатьО&ьект(''Справочник.Сотрудники_2'');
// Записываем периодический реквизит Оклад на рабочую дату сСотр_2.ИспользоватьДату(РабочаяДата());
// Ищем во всем справочнике
если сСотр_2.НайтиПоКоду(209, 0) = 1 тогда
если СокрЛП(сСотр_2.Наименование) = новФИО тогда Предупреждение("Старая и новая фамилии совпадают."); возврат;. конецЕсли;
сСотр_2.Наименование = новФИО; сСотр_2.0клад = 2900; // Новый оклад
сСотр_2.3аписать(); // Записываем изменения
иначе
Предупреждение("Сотрудник не найден."); конецЕсли;
// Просмотр результата
ОткрытьФорму("Справочник. Сотрудники_2. ФормаСписка"); конецПроцедуры // Выполнить
Тот же результат получим, заменив присваивания на метод УстановитьАтрибут:
сСотр_2.УстановитьАтрибут("Наименование", "Костина Ольга Владимировна"); сСотр_2.УстановитьАтрибут("Оклад", 2900);
Также вместо методов ИспользоватьДату и УстановитьАтрибут можно для периодического реквизита Оклад применить вызов
сСотр_2.0клад-Установить(РабочаяЦата(), 2900);
Замечание. Если не задана дата периодического реквизита, то возникнет ошибка, сопровождаемая сообщением
Не определена дата! Элемент не может быть записан!
5.5.3.4. УДАЛЕНИЕ ЗАПИСЕЙ
Запись можно снабдить пометкой для удаления, употребляемой в 1С или в DBF-файлах, применив метод Удалить соответственно с аргументом 0 или 1. Снять пометку 1С позволяет метод СнятьПометкуУдаления. Метод-функция ПометкаУдаления вернет 1, если элемент имеет 1С-пометку удаления, или 0 -в противном случае.
Пример. Помечается для удаления в смысле 1С группа 01 /1 и все ее подчиненные элементы. Затем снимается отметка об удалении с элемента этой группы, имеющего код 112.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбъект("Справочник.Сотруцники_2");
// Ищем во всем справочнике
если сСотр_2.НайтиПоНаименованию("01 /1", 0) = 1 тогда // Если выбрана кнопка "Да"
если Вопрос("Пометить для удаления группу", 4) = 6 тогда
сСотр_2.Удалить(0); // Помечаем всю группу
// Ищем во всем справочнике если сСотр_2.НайтиПоКоду(112, 0) = 1 тогда если сСотр_2.ПометкаУдаления() = 1 тогда сСотр_2. СнятьПометкуУдаления(); конецЕсли; иначе
Предупреждение("Сотрудник не найден."); конецЕсли; конецЕсли; иначе
Предупреждение("Подразделение не найдено."); конецЕсли;
// Просмотр результата
ОткрытьФорму("Справочник.Сотрудники_2.ФормаСписка"); конецПроцедуры // Выполнить
5.6. ПОЗИЦИЯ СПРАВОЧНИКА. ВЫБОР ДАННЫХ
Справочник, если число его записей больше нуля, может быть позиционирован либо перед своей первой записью, либо на записи, либо вслед за последней записью.
Сразу после создания справочника его позиция не определена. Позицию справочника меняют методы поиска данных, например НайтиЭлемент или НайтиПоКоду. Значение элемента в текущей позиции возвращает функция ТекущийЭлемент.
В процессе работы можно выбрать все или часть элементов справочника, открыв выборку методом ВыбратьЭлементы или ВыбратьЭлементыПоРеквизиту. В результате их применения справочник позиционируется на своей первой записи. Перемещение по записям осуществляется методом ПолучитьЭлемент.
Пример 1. Выводится список цехов предприятия.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2;
ОчистшъОкноСообщенийО;
сСотр_2 = СоздатьОбьект("Справочник.Сотрудники_2");
сСотр_2.ВыбратьЭлементы();
пока сСотр_2.ПолучитьЭлемент() = 1 цикл
если (сСотр_2.ЭтоГруппа() = 1) и (сСотр_2.Уровень() = 1) тогда Сообщить(сСотр_2. Наименование); конецЕсли; конецЦикла;
конецПроцедуры // Выполнить Результат:
01 Цех
02 Цех
03 Цех
Пример 2. Выводится список подразделений первого цеха предприятия.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Если не найден первый цех (его код равен единице) если сСотр_2.НайтиПоКоду(1, 0) = 0 тогда
Предупреждение("Первый цех не найден."); возврат; конецЕсли;
// Ограничиваем выборку первым цехом сСотр_2.ИспользоватьРодш’еля(сСотр_2); с Сотр_2. ВыбратьЭлементы(); пока сСотр_2.ПолучшъЭлемент() = 1 цикл если сСотр_2.ЭтоГруппа() = 1 тогда Сообщить(сСотр_2.Наименование); конецЕсли; конецЦикла;
конецПроцедуры // Выполнить Результат:
01 / 1 02/2 03/3
Выбор по реквизиту методом ВыбратьЭлементыПоРеквизиту возможен только для непериодического_реквизита, если для него на закладке Дополнительные установлено, свойство Сортировка. (По умолчанию свойство Сортировка имеет реквизиты Код и Наименование.)
С перечисленными в этом разделе методами при выборе данных употребляются методы ОбратныйПорядок, ПорядокНаименований, ПорядокКодов, ВключатьПодчи-ненные, ИспользоватьРодителя, ИспользоватьВладельца и ИспользоватьДату.
5.7. ИЗМЕНЕНИЕ СТРУКТУРЫ И ФОРМ СПРАВОЧНИКА
Приспособим справочник Сотрудники_2 для хранения информации об образовании сотрудника. Для этого потребуется провести некоторую дополнительную работу -создать справочник Образование_2. Она необходима, поскольку встроенный справочник Образование имеет владельца - справочник Сотрудники.
Структуру справочника Образование_2 сделаем максимально простой, использовав в нем только установленные по умолчанию реквизиты Код и Наименование. Далее внесем в поле Наименование приведенные на рис. 5.28 записи.
 |
|
Рис. 5.28. Состав справочника Образование_2 |
Значения этих записей будем использовать для определения (еще несуществующего) реквизита Образование_2 справочника Сотрудники_2.
При создании справочника Образование_2 добавим команду его вызова в колонку Справочники меню интерфейса Ученик.
Переместимся вновь в конфигурацию и пополним справочник Сотрудники_2 реквизитом Образование_2, сделав его непериодическим, установив для него тип Справочники с разновидностью типа Образование_2 и задав свойство Сортировка (рис. 5.29).
55цие I Дополнительные I
Общие
. гг/ от- Г Использовать.
Неітт Г I Для элемента
Периодический ГГ. ""¦<
Сортировка 17 Г
Идентификатор I Образование ?»«ни* I Образование
Еомментарт*
Выбирается из справочника Образован Іип значения | Справочник.0бразоеание_2 3 Отбор по реквизиту W
а и
Рис. 5.29. Свойства реквизита Образование: а - общие; б - дополнительные
Изменим соответствующим образом и формы элемента и списка справочника (основную и для выбора), открыв их в конфигураторе, выбрав на панели инструментов Элементы диалога иконку и добавив в них реквизит Образование (рис. 5.30).
 |
|
Рис. 5.30. Форма элемента с добавленным полем Образование |
Сохраним конфигурацию, воспользуемся новой формой и отредактируем все элементы справочника Сотрудники_2, определив для них значение реквизита Образование. Для облегчения работы можно задать одинаковое значение этого реквизита всем сотрудникам, использовав следующий код:
// Все сотрудники после выполнения этой процедуры в поле Образование // будут иметь значение Высшее
процедура Выполнил^ ) // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, сОбр_2;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сОбр_2 = СоздатьОбъект("Справочник.Образование_2"); если сОбр_2.НайтиПоНаименованию("Высшее") = 0 тогда Предупреждение("3начение не найдено."); возврат; конецЕсли;
с Сотр_2. ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() > 0 цикл если сСотр_2.ЭтоГруппа() = 0 тогда
// Используем в правой части присваивания метод ТекущийЭлемент сСотр_2.0бразование = сОбр_2.ТекущийЭлемент(); сСотр_2.3аписать(); // Фиксируем изменения
конецЕсли; конецЦикла;
// Просмотр результата
ОткрытьФорму("Справочник.Сотрудники_2.ФормаСписка"); конецПроцедуры // Выполнить
Выполним теперь ручное редактирование значения реквизита Образование и изобразим измененный справочник на рис. 5.31.
|
- 2Л Сотраамикм_2 и CJ 01 Цех JJ 01 /1 Zl 01/2 Zi 01/3 1 * I 02 Цех til 03 Цех |
|
1 1 |
1 Наименование 10 к л ад |
Образование |
|
|
1 |
01 Цех |
|
|
|
|
13 |
01 /3 |
|
|
|
131 |
Васильева Епена Ивановна |
1.850.00 |
Начальное |
|
|
132 |
Смирнова Нина Федоровна |
1.900.00 |
Высшее |
|
2J |
133 |
Хохлов Евгеніи Ннголаевич |
1.900 00 |
Среднее |
|
|
I 1 1 |
|
|
|
Рис. 5.31. Пополненный справочник Сотрудники 2
Выберем теперь данные по реквизиту Образование.
процедура Выполнить() // Выбирает данные по реквизиту Образование
перем сСотр_2, сОбр_2; перем обр, флаг;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбъект(''Справочник.Сотрудники_2''); сОбр_2 = СоздатьОбъект(''Справочник.Образование_2''); если сОбр_2.НайгиПоНаименованию("Высшее") = 0 тогда Предупреждение("3начение не найдено."); возврат; конецЕсли;
обр = сОбр_2.ТекущийЭлемент();
// Выбираем сотрудников, имеющих высшее образование, по порядку (без учета иерархии) флаг= сСотр_2.ВыбратъЭлементыПоРеквизиту(''Образование'', обр, 0, 0); если флаг = 0 тогда
Предупреждение("Нет выбранных сотрудников."); возврат; конецЕсли;
пока сСотр_2.ПолучитЪЭлемент() > 0 цикл
Сообщить(сСотр_2.Наименование + символТабуляции + сСотр_2.Код + символТабуляции + сСотр_2.Родитель + символТабуляции + сСотр_2.Образование); конецЦикла;конецПроцедуры // Выполнить
|
Результат: |
|
Абрамова Лариса Сергеевна |
201 |
02 Цех |
Высшее |
|
Агальцов Юрий Алексеевич |
111 |
01/1 |
Высшее |
|
Безверхний Игорь Петрович |
301 |
03 Цех |
Высшее |
|
Кузьмина Раиса Николаевна |
122 |
01/2 |
Высшее |
|
Смирнова Нина Федоровна |
132 |
01/3 |
Высшее |
|
Если перед вызовом метода ВыбратьЭлементыПоРеквизиту обратиться к методу ОбратныйПорядок с равным единице параметром:
сСотр_2.0братныйПорядок(1);
то результирующая выборка будет упорядочена в обратном порядке:
|
Смирнова Нина Федоровна |
132 |
01/3 |
Высшее |
|
Кузьмина Раиса Николаевна |
122 |
01/2 |
Высшее |
|
Безверхний Игорь Петрович |
301 |
03 Цех |
Высшее |
|
Агальцов Юрий Алексеевич |
111 |
01/1 |
Высшее |
|
Абрамова Лариса Сергеевна |
201 |
02 Цех |
Высшее |
Замечание. Попытка применить с методом ВыбратьЭлементыПоРеквизиту метод ПорядокКодов, предполагающий вывод данных по возрастанию значений атрибута Код, успехом не увенчалась.
5.8. УПРАВЛЕНИЕ ЗАПИСЯМИ СПРАВОЧНИКА ПРИ ПОМОЩИ ДОКУМЕНТОВ
5.8.1. НАЗНАЧЕНИЕ ДОКУМЕНТОВ
Процессы, протекающие на предприятии, регулируются документами. Так, прием на работу осуществляется на основании соответствующего приказа. Поступление ма териалов на склад фиксируется приходными ордерами, а их отпуск в производстве выполняется на основании требований-накладных и т. д.
Не меньшее, чем на реальном предприятии, значение придается документам и в 1С. Фактически они лежат в основе реализованных в 1С моделей - модели склада, бухгалтерского учета и др.
Кадровый учет и начисление заработной платы также основываются на документах: на приказах о приеме на работу, перемещении по служебной лестнице, об изменениях оклада, о премировании и др. Отсюда следует, что большинство изменений справочника Сотрудники_2, хранящего кадровые данные, должно осуществляться на основании соответствующих документов.
Создадим и мы документы, добавляющие данные в справочник Сотрудники_2 и изменяющие в нем данные об окладах работников предприятия. Понятно, такими документами могут быть Приказ о приеме на работу и Приказ об изменении оклада. Документы, попавшие в зону нашего внимания, учитывая скромный объем хранящейся в справочнике Сотрудники_2 информации, весьма просты, что вполне отвечает учебным целям.
Документ 1С состоит из формы и модуля документа. Форма документа, как и формы других объектов 1С, имеет диалог, модуль и таблицы. Диалог формы документа в общем случае содержит шапку и табличную часть. В модуле документа в общем случае создаются процедуры ОбработкаПроведения и ОбработкаУдалени-яПроведения, выполняющие предусмотренные при проведении и удалении документа действия. (Проведение документа - это процесс, приводящий к изменению связанных с документов объектов.) Так, проведение Приказа о приеме должно приводить к появлению в справочнике Сотрудники_2 новой записи, а проведение Приказа об изменении оклада - к изменению значений периодического реквизита Оклад справочника. Выпущенные документы будем сохранять в имеющемся в конфигурации Заработная плата и кадры журнале ПриказыКадровые.
Поскольку Приказ о приеме на работу касается одного человека, то в диалоге его формы табличная часть будет отсутствовать. Приказ об изменении окладов может распространяться на несколько сотрудников, ФИО и новые оклады которых фиксируются в табличной части диалога формы документа.
Чтобы установить связь между создаваемыми документами и записями справочника Сотрудники_2, добавим в справочник еще два реквизита - ПриказПрием и При-казОклад, присвоив им тип Документ. Теперь справочник Сотрудники_2 имеет приведенные на рис. 5.32 реквизиты, а также реквизиты Код и Наименование.
 |
|
Рис. 5.32. Реквизиты справочника Сотрудники_2 |
Такая связь позволит нам обращаться к созданным документам из формы списка справочника.
5.8.2. ПРИКАЗ О ПРИЕМЕ НА РАБОТУ
5.8.2.1. РЕКВИЗИТЫ И ФОРМА ДОКУМЕНТА
Начнем с Приказа о приеме. Откроем конфигурацию, выделим раздел Документы, нажмем на правую кнопку мыши и выберем пункт Новый документ.
Определим реквизиты шапки документа в соответствии с табл. 5.3.
Таблица 5.3
Реквизиты шапки Приказа о приеме на работу |
|
Реквизит |
Тип (разновидность типа) |
Длина.Точность |
|
Код |
Числовой |
5.0 |
|
ФИО |
Символьный |
30 |
|
Подразделение |
Справочник. Сотрудники_2 |
- |
|
Образование |
Справочник. Образование_2 |
- |
|
Оклад |
Числовой |
10.2 |
|
ДатаПриема |
Дата |
- |
|
Сотрудник |
Справочник. Сотрудники_2 |
- |
|
|
Замечания: |
1. Тип (разновидность типа) и характеристики типа (длина, точность) должны соответствовать аналогичным реквизитам справочника Сотрудники_2.
2. Код сотрудника формируется автоматически при добавлении новой записи. Редактированию значение кода не подлежит, поэтому в диалоге формы документа поле Код доступно только для чтения.
3. Реквизит Сотрудник введен в документ для установления связи документа с конкретной записью справочника Сотрудники_2. Для позиционирования справочника в режиме редактирования документа можно использовать вызов
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
сСотр_2.НайтиЭлемент(Сотрудник); // Сотрудник - реквизит документа // Устанавливаем значения реквизитов записи сСотр_2.Наименование = ФИО;
сСотр_2.3аписать();
Помимо перечисленных в табл. 5.3 полей в Приказе о приеме, как, впрочем, и во всех иных документах, присутствуют реквизиты (атрибуты) НомерДок и Да-таДок, хранящие соответственно номер и дату документа. Свойства этих реквизитов задаются системой и не могут быть изменены пользователем. Поскольку номер документа назначается автоматически, то запретим редактирование реквизита
: НомерДок. Дату нового документа будем по умолчанию устанавливать равной рабочей дате.
4.
Остальные характеристики приказа определим в соответствии с рис. 5.33.
Идентифшагор. |ПриказОПриеме
Журнал: IП риказыК здроеые ^ |
|Пр*жаэ о приеме на работу
Реквизиты таблеаюй части-[-—---
JJ
Ьомментарі* | Реквизиты пипки
лі
jJ
Jii
ФИО
Подразделение
Оклад
Образование
ДвтеЛрмема
Сотруотик
Новый I Изметчсть | Удалитъ |
Номер Н хлоратор:
Периодимость
17 Автоматическая нумерация
jJ
iiJ
|
Новь* I V. м -чИТУІ . УДгГч((- I |
|
І« Не назначен » |
Тип
Числовой |
Длеіа І5 -М |
|
1 По всем данного вша _^J |
Текстовый |
|
|
17 ^онтро/ь умсатъности
\?іёгі\
Г ±J---rr,-pr.
17 расчет
Г Операпввй учет |
17 Разрешить проведемте документа 17 Автоматическое удаление движем й Г” Автоматическая нумерация строк
Рис. 5.33. Свойства документа - Приказа о приеме на работу
Откроем затем форму документа, вставим в ее диалог реквизиты и приведем диалог к виду, представленному на рис. 5.34.
 |
|
Рис. 5.34. Диалог формы Приказа о приеме на работу |
Замечание. При добавлении документа в конфигурацию 1С создаст в информационной базе для хранения данных шапки документов ПриказОПриеме 2 файла, возможно DH4216.DBF и DH4216.CDX. Если бы документ содержал вдобавок и табличную часть, то для хранения данных из этой части 1С пополнил бы информационную базу еще двумя файлами - DT4216.DBF и DT4216.CDX.
5.8.2.2. МОДУЛЬ ФОРМЫ ДОКУМЕНТА
С кнопкой ОК диалога документа связаны команды #Записать? Провести? Закрыть
Они реализуют последовательность методов
Записать(); // Запись документа
// Проведение документа. Вызывается процедура ОбработкаПроведения модуля документа
Провести();
форма.Закрыть();
Перед записью мы условились выполнять проверки введенных данных. Воспользуемся для этого предопределенной процедурой модуля формы документа ПриЗаписи, разместив в ней все проверки и завершая ее со статусом возврата 0 при наличии ошибок.
По-прежнему часть проверок будем производить функцией КонтрольФИО, разработанной для формы элемента в разд. 5.3.4.2. Только на этот раз функция Контроль-ФИО связывается через свойство Формула с полем ФИО. Дополнительно введем проверки, не позволяющие сохранять документ, если в диалоге формы документа (рис. 5.34) есть незаполненные поля.
При вводе нового документа полезно выполнять начальную установку даты документа и даты приема на работу. Используем для этого предопределенную процедуру ВводНового.
При добавлении записи (прием нового сотрудника) значение реквизита Код будем формировать автоматически, используя в качестве его первых цифр код родителя, если родитель расположен на втором уровне справочника Сотрудники_2, или код родителя, увеличенный в 10 раз, если родитель лежит на первом уровне (всего, напомним, в справочнике Сотрудники_2 три уровня). Последующие цифры кода сотрудника образуют возрастающую последовательность целых положительность чисел. Поступая таким образом, мы сохраним принцип формирования кодов, применяемый 1С для справочника Сотрудники_2.
Формирование кода выполним в процедуре СоздатьКод, которую свяжем с полем Подразделение, задав для него в окне задания свойств поля на закладке Дополнительно формулу СоздатьКод(). Тогда процедура СоздатьКод будет вызываться каждый раз при изменении подразделения. Если нужного подразделения в справочнике Сотрудни-ки_2 нет, то его придется ввести, применив форму группы справочника (разд. 5.3.3.1).
Таким образом, модуль формы Приказа о приеме на работу содержит следующие процедуры и функции:
функция КонтрольФИО(место = 1) далее процедура УбратьПробелы() далее процедура ВНРег() далее процедура СоздатьКод() далее
// Выполняет проверки вводимых данных процедура ПриЗаписи()
если ((ПустоеЗначение(Подразделение) = 1) или (ПустоеЗначение(ФИО) = 1) или
(ПустоеЗначение(Оклад) = 1) или (ПустоеЗначение(Образование) = 1) тогда Предупреждение^^ документе есть неопределенные реквизиты.");
СтатусВозврата(0); // Не записываем данные
// Функция КонтрольФИО при таком вызове вернет 0, если в ФИО есть точки иначеЕсли КонтрольФИО(2) = 0 тогда СтатусВозврата(0); конецЕсли;
конецПроцедуры // ПриЗаписи
|
// Подробный комментарий к функции и ее процедурам см. в разд. 5.3.4.2 |
|
функция КонтрольФИО(место = |
1) |
|
|
если место = 1 тогда |
// |
Вызов осуществляется из диалога |
УбратьПробелы();
ВНРег(); |
// |
Удаляет избыточные пробелы между словами |
|
конецЕсли; |
|
|
|
если Найти(ФИО,".") <> 0 тогда |
|
|
Предупреждение('Точки в ФИО недопустимы."); возврат 0;
иначе // Точек в имени нет
возврат 1; конецЕсли;
конецФункции // КонтрольФИО
процедура УбратьПробелы() перем ФИО2, длина, поз, к;
// Удаляем возможные ведущие и завершающие пробелы // Вводим ФИО2, поскольку СокрЛП не меняет длину ФИО ФИО2 = СокрЛП(ФИО);
поз = Найти(ФИО2, " "); // Ищем два подряд идущих пробела
// Цикл продолжается, пока в строке есть хотя бы одна пара подряд идущих пробелов пока поз > 0 цикл
длина = стрДлина(ФИО2); // Длина ФИО2
к =1; // Число лишних пробелов
пока (поз < длина) и (Сред(ФИО2, поз + к, 1) = " ") цикл к = к + 1;
конецЦикла; // пока (поз < длина)...
// Удаляем лишние пробелы и заменяем старое значение ФИО на новое ФИО2 = Лев(ФИО2, поз) + Прав(ФИО2, длина - поз - к + 1);
поз = Найти(ФИО2, " "); // Ищем 2 подряд идущих пробела
конецЦикла; // пока поз > 0
ФИО = ФИО2; // Результат
конецПроцедуры // УбратьПробелы
|
// Преобразовывает ФИО так, что первые буквы каждого // составляющего ФИО слова прописные, а остальные - строчные |
|
процедура ВНРег() |
|
|
перем к, длина;
длина = стрДлина(ФИО);
если длина = 0 тогда |
// |
Длина ФИО |
|
возврат; |
|
|
конецЕсли;
ФИО = Нрег(ФИО); |
// |
Первый шаг алгоритма |
|
ФИО = Врег(Лев(ФИО, 1)) + Прав(ФИО, длина - 1); // Позиция пробела или нуль, если пробел не найден к = Найти(ФИО, " "); пока к > 0 цикл
ФИО = Лев(ФИО, к - 1) + "%" + |
Врег(Сред(ФИО, к + 1, 1)) + Прав(ФИО, длина - к - 1); к - Найти(ФиО, " "); конецЦикла; // пока к < длина // Заменяем символы % точки на пробелы ФИО = СтрЗаменить(ФИО, "%", " "); конецПроцедуры // ВНрег
// Формирует и возвращает при добавлении новой записи код сотрудника // Связана через свойство Формула с полем Подразделение диалога формы документа // Вызывается после выбора подразделения предприятия // Алгоритм:
//1. Начало.
// 2. Прочитать кодПодр - код подразделения и его уровень
//3. Найти максКод - максимальное значение кода сотрудника, входящего в подразделение // 4. Найти двеЦифр - первые две цифры кода сотрудника по следующему правилу:
// если уровень = 1, то
// двеЦифр = кодПодр * 10
// иначе
// двеЦифр = кодПодр
// конец если
// 5. Найти послЦифр - цифры максКод, следующие после его первых двух цифр // 6. Последующие цифры нового кода: послЦифр = послЦифр + 1 // 7. Новый код: Код = Число(Строка(двеЦифр) + Строка(послЦифр))
//8. Конец.
процедура СоздатьКод()
перем сСотр_2, кодПодр, уровень, максКод, двеЦифр, послЦифр;
перем двеЦифрУмнНаК, к;
если ПустоеЗначение(Подразделение) = 1 тогда
Подразделение = ПолучитьПустоеЗначение("Справочник.Сотрудники_2"); Предупреждение("Подразделение не выбрано."); возврат; конецЕсли;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// В справочнике Сотрудники_2 можно в поле Подразделение выбрать как сотрудника,
// так и подразделение. В первом случае мы перейдем от сотрудника к подразделению,
// использовав атрибут Родитель. Во втором, если подразделение на следующем уровне
// имеет сотрудников, мы имеем верный выбор, если же это не так, выбор
// подразделения придется продолжить
// Если выбран сотрудник
если Подразделение.ЭтоГруппа() = 0 тогда
// Найдем родительскую группу; реквизит Подразделение имеет тип Справочник сСотр_2. НайтиЭлемент(Подразделение);
// Переходим от сотрудника к подразделению // и устанавливаем на него позицию справочника Подразделение = сСотр_2.Родитель; сСотр_2.НайтиЭлемент(Подразделение);
// Проверим, что на следующем уровне подразделения иначе
сСотр_2. НайтиЭлемент(Подразделение); сСотр_2.ИспользоватьРодителя(сСотр_2.ТекущийЭлемент()); сСотр_2.ВыбратьЭлементы(1); // Задаем выборку с учетом иерархии // Если на следующем уровне подразделение, то это не годится если сСотр_2.ПолучитьЭлемент() = 1 тогда
если сСотр_2.ЭтоГруппа() = 1 тогда
Подразделение = ПолучитьПустоеЗначение("Справочник.Сотрудники_2");
Предупреждение("Выбрано подразделение не того уровня.");
возврат;
иначе // Возвращаемся к верному подразделению
сСотр_2.НайтиЭлемент(Подразделение); конецЕсли; конецЕсли; конецЕсли;
// сСотр_2.Код может иметь символьный тип
кодПодр = ?(ТипЗначения(сСотр_2.Код) = 2, Число(сСотр_2.Код), сСотр_2.Код);
уровень = сСотр_2.Уровень();
двеЦифр = ?(уровень = 1, кодПодр * 10, кодПодр);
// Найдем максКод - максимальный код сотрудника в пределах подразделения // Осуществи это, перебирая все элементы подразделения, что достигается // в результате употребления метода ИспользоватьРодителя сСотр_2.ИспользоватьРодителя(Подразделение);
// Осуществим перебор в порядке возрастания кодов элементов с Сотр_2 .ПорядокКодов (); сСотр_2. ВыбратьЭлементы();
// максКод останется равным нулю, если в группе нет элементов максКод = 0;
пока сСотр_2.ПолучитьЭлемент() = 1 цикл
// сСотр_2.Код может иметь символьный тип
максКод = ?(ТипЗначения(сСотр_2.Код) = 2, Число(сСотр_2.Код), сСотр_2.Код); конецЦикла; // пока
// Ищем последующие цифры максКод и затем последующие цифры кода
// нового сотрудника. Будем умножать двеЦифр на 10, пока не превысим максКод
к=1;
двеЦифрУмнНаК = двеЦифр;
пока двеЦифрУмнНаК < максКод цикл
двеЦифрУмнНаК = двеЦифрУмнНаК * 10; конецЦикла; // пока
// Последующие цифры кода нового сотрудника
послЦифр = ?(максКод = 0, 1, максКод - двеЦифрУмнНаК /10 + 1);
// Итак, код нового сотрудника
Код = Число(Строка(двеЦифр) + Строка(послЦифр)); конецПроцедуры // СоздатьКод
// ВводНового - предопределенная процедура, вызываемая, если присутствует // в коде модуля формы, при вводе нового документа. Используем ее для начальной // установки даты нового документа и даты приема на работу процедура ВводНового()
ДатаДок = РабочаяДата();
ДатаПриема = РабочаяДата(); конецПроцедуры // ВводНового
процедура ПриОткрытии()
ОчиститьОкноСообщений( );
ПриЗаписиПерепроводить(1); конецПроцедуры // ПриОткрытии
Замечания:
1. В форме списка для выбора справочника Сотрудники_2, используя которую мы определяем значение поля Подразделения документа (см. рис. 5.34), в предопределенной процедуре ПриОткрытии размещен вызов метода ВыборГруппы(1), позволяющий выбирать группы. Поэтому в общем случае мы можем выбрать как подразделение, так и сотрудника. Чтобы поправить пользователя, в процедуру Соз-датьКод добавлены операторы, либо осуществляющие переход от сотрудника к подразделению, либо препятствующие выбору подразделения не того уровня (в нашем случае это Цех 01). Вот они:
// Если выбран сотрудник
если Подразделение.ЭтоГруппа() = 0 тогда
// Найдем родительскую группу; реквизит Подразделение имеет тип Справочник
// Далее см. процедуру СоздатьКод // Проверим, что на следующем уровне подразделения // Если на следующем уровне подразделение, то это не годиться иначе
// Далее см. процедуру СоздатьКод
конецЕсли;
Более совершенный способ выбора подразделения по справочнику Сотрудники_2 мы рассмотрим в разд. 7.4.3 при разработке документа Табель.
2. Хотя реквизит Код справочника Сотрудники_2 имеет числовой тип, вызов сообщить(Т ипЗначенияСтр(сСотр_2 . Код));
напечатает в строке сообщений слово Строка. Поэтому в процедуре СоздатьКод вместо операторов присваивания
кодПодр = сСотр_2.Код; максКод = сСотр_2.Код;
употреблены операторы
кодПодр = ?(ТипЗначения(сСотр_2.Код) = 2, Число(сСотр_2.Код), сСотр_2.Код); максКод = ?(ТипЗначения(сСотр_2.Код) = 2, Число(сСотр_2.Код), сСотр_2.Код);
преобразовывающие сСотр_2.Код в число, если сСотр_2.Код имеет символьный тип. Вспомнив, однако, что тип выражения в 1С определяется типом его первого операнда (разд. 2.5.1), запишем более простые (по форме) операторы, в которых кодПодр и максКод имеют числовой тип:
кодПодр = 1 * сСотр_2.Код; максКод = 1 * сСотр_2.Код;
5.8.2.3. МОДУЛЬ ДОКУМЕНТА. ПРОВЕДЕНИЕ И УДАЛЕНИЕ
ДОКУМЕНТА
При проведении документа вызывается создаваемая программистом предопределенная процедура модуля документа ОбработкаПроведения. В ней для нашего случая учитываются следующие состояния документа:
1) проводится новый документ;
2) проводится документ, с которого снята пометка удаления (при простановке пометки удаления документ становится непроведенным). Такой документ может иметь соответствующую ему запись в справочнике Сотрудники_2;
3) перепроводится ранее проведенный документ.
Удаление непроведенного документа о приеме на работу при отсутствии на него ссылок в других объектах можно выполнить методом
Удалить(1);
сразу проставляющим DBF-пометку об удалении. При упаковке базы документ будет удален из нее физически.
Удаление проведенного документа - более сложный процесс. Здесь возможны варианты:
1) в системе нет ссылок ни на документ (кроме ссылки в созданной им записи в справочнике Сотрудники_2), ни на запись в справочнике Сотрудники_2 (кроме как в самом удаляемом документе);
2) такие ссылки имеются, например в журнале расчетов Заработная плата.
В первом случае следует удалить и документ, и порожденную им запись в справочнике Сотрудники_2. Во втором - ни документ, ни запись в справочнике удалять нельзя, поскольку это приведет к нарушению целостности данных. Поскольку анализ ссылок на предназначенные для удаления объекты имеется в 1С и осуществляется после выбора в меню Сервис - Удаление помеченных объектов, то для удаления документа следует использовать подход, при котором проставляется пометка 1С на удаление как документа, так и созданной им в справочнике Сотрудники_2 записи, а анализ ссылок оставляется 1С. Код, реализующий этот подход, располагается в предопределенной процедуре ОбработкаУдаленияПроведения, которая вызывается при удалении документа или при исполнении метода СделатьНеПроведенным.
Код модуля документа с учетом вышеприведенного комментария может быть таким:
// Выполняет проведение документа, то есть добавляет или корректирует запись // в справочнике Сотрудники_2, связывает запись справочника с документом, а // документ - с соответствующей записью справочника Сотрудники_2 процедура ОбработкаПроведения() перем сСотр_2, гр, флаг, флаг2;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Храним в гр подразделение, куда принимается или переводится сотрудник сСотр_2. НайтиЭлемент(Подразделение); гр = сСотр_2.ТекущийЭлемент(); флаг = Проведен();
// Находим в справочнике Сотрудники_2 запись, с которой связан данный приказ флаг2 = сСотр_2.НайтиЭлемент(Сотрудник);
если флаг + флаг2 = 0 тогда . // Если документ не проведен
сСотр_2.Новый(); // и не снимается пометка на удаления
конецЕсли;
сСотр_2.Родитель = гр; // Фиксируем подразделение (родителя)
// Определяем и сохраняем непериодические реквизиты
сСотр_2.Наименование = ФИО;
сСотр_2.Код = Код;
сСотр_2.Образование = Образование;
сСотр_2.ПриказПрием = ТекущийДокументО;
сСотр_2.3аписать();
// Устанавливаем связь документа с записью справочника Сотрудники_2 Сотрудник = сСотр_2.ТекущийЭлемент();
// Записываем периодический реквизит Оклад с привязкой к документу УстановитьРеквизитСправочника(Сотрудник, "Оклад", Оклад, ДатаПриема);
// Снимем, если она есть, пометку удаления записи о сотруднике // в справочнике Сотрудники_2. Такая пометка может появиться при удалении // документа, породившего эту запись (ом. процедуру ОбработкаУдаленияПроведения) если (флаг2 = 1) и (сСотр_2.ПометкаУдаления() = 1) тогда сСотр_2,СнятьПометкуУдаления(); конецЕсли;
если флаг = 0 тогда // Если документ не проведен
// Ограничиваем время показа окна с предупреждением тремя секундами Предупреждение("Документ проведен.", 3); иначе
Предупреждение("Документ перепроведен.", 3); конецЕсли;
конецПроцедуры // ОбработкаПроведения
// Вызывается при удалении документа или при исполнении метода СделатьНеПроведенным процедура ОбработкаУдапенияПроведения() перем сСотр_2, флаг;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); флаг = сСотр_2.НайтиЭлемент(Сотрудник); если флаг = 1 тогда
// Помечаем для удаления запись в справочнике Сотрудники_2 сСотр_2.Удалить(0); конецЕсли;
конецПроцедуры // ОбработкаУдаленияПроведения Замечания:
1. Предопределенные процедуры модуля документа ОбработкаПроведения и ОбработкаУдаленияПроведения 1С выполняет с использованием транзакций (разд. 8.4.3), во время которых блокируются DBF-таблицы, в транзакциях участвующие. При многопользовательском режиме работы блокировка порождает конфликтные ситуации: иной пользователь не может проводить или удалять аналогичные документы. Чтобы снизить вероятность конфликтов, в процедуры ОбработкаПроведения и ОбработкаУ-даленияПроведения не следует включать вызовы процедур, приостанавливающих вычисления, например, такой, как Предупреждение, заменяя ее на вызов процедуры Сообщение.
2. Реквизит приказа о приеме Сотрудник после проведения документа позволяет непосредственно обращаться к созданной им в справочнике Сотрудники_2 записи, например, так:
док = СоздатьОбъектС'Документ.ПриказОПриеме''); флаг = док.НайтиПоНомеру(2, Дата(0)); если флаг = 1 тогда
//док.Сотрудник.Образование - значение реквизита Образование в справочнике // Сотрудники_2 для сотрудника, проведенного приказом № 2 Сообщить(док.Сотрудник.Образование); // Напечатает Высшее
иначе
Предупреждение(''Приказ № 2 не найден."); конецЕсли;
Теперь, когда есть все процедуры, управляющие документом о приеме на работу, включим пункты Приказ о приеме и Изменение оклада (документ для этого пункта будет создан ниже), вызывающие соответственно команды
Документы. ПриказОПриеме. Ввести
и
Документы.ИзменениеОклада. Ввести
в колонку Документы меню интерфейса Ученик, связав их соответственно с акселераторами Alt+б и Alt+7 (рис. 5.35), и добавим колонку Журналы с пунктом Кадровые приказы, позволяющим при помощи команды
Журналы. ПриказыКадровые.Открыть
открыть журнал, хранящий созданные документы.
ffi 1=3 Сервис В Из Проба й Из Справочники В Из Документы I r~ S Приказоприеме \ !•••• 0 Изменение оклада
0 < новый...>
? Hi Журналы
0 Кадровые приказы
Рис. 5.35. Модифицированное меню интерфейса Ученик
Сохраним изменения, откроем 1 С: Предприятие и введем несколько документов.
5.8.2.4. ВЫЗОВ ДОКУМЕНТА ИЗ ФОРМЫ СПИСКА СПРАВОЧНИКА СОТРУДНИКИ_2
Пока что с записью справочника Сотрудники_2 может быть связан только один документ - Приказ о приеме на работу. Для его вызова из формы списка справочника добавим в модуль двух имеющихся форм списка (разд. 5.3.3.2) код следующей предопределенной процедуры:
процедура ПриНачалеРедактированияСтроки( ) если ПустоеЗначение(ПриказПрием) = 0 тогда // Открываем форму документа ОткрытьФорму(ПриказПрием); иначеЕсли РедактироватьВДиалоге() = 0 тогда
// Открываем форму элемента справочника для редактирования текущей записи ОткрытьФорму(ТекущийЭлемент(),, 0);
// Отказываемся от возможности редактирования в строке формы списка справочника иначе
Предупреждение(''Редактировать в строке формы списка справочника нельзя."); конецЕсли;
СтатусВозврата(0);
конецПроцедуры // ПриНачалеРедактированияСтроки
Чтобы этим кодом воспользоваться, надо после вызова справочника Сотрудни-ки_2, используя колонку Действия, убрать флаг с пункта Редактировать в диалоге. Теперь, остановившись на записи и дважды ударив по ней мышью, вы попадете в документ, с этой записью связанный, или, если такового не имеется, в форму элемента или группы справочника Сотрудники_2.
Замечания:
1. Вызов СтатусВозврата(0);
в предопределенной процедуре ПриНачалеРедактированияСтроки, задающий статус Отменить Действие, позволяет не переходить в режим редактирования строки непосредственно в форме списка справочника Сотрудники_2, если в диалоге открытой формы приказа о приеме нажать Закрыть или если просто переместить фокус на диалог формы списка справочника.
2. При отсутствии документа, если отменен режим редактирования в диалоге, процедурой ПриНачалеРедактированияСтроки будет вызвана функция
ОткрытьФорму(ТекущийЭлемент());
открывающая форму элемента или группы. При этом может возникнуть сообщение

Однако никаких препятствий для редактирования в форме элемента или группы выбранной записи не будет.
5.8.3. ЖУРНАЛ КАДРОВЫХ ПРИКАЗОВ
5.8.З.1. ФОРМА СПИСКА ЖУРНАЛА КАДРОВЫХ ПРИКАЗОВ
Журнал кадровых приказов с идентификатором ПриказыКадровые имеет приведенный на рис. 5.36 диалог формы списка, отображающий занесенные в журнал доку- \ менты.
|
|
Дата 1: Номер |
Документ |
Сотрудник |
Ж |
|
|
|
|
|
|
|
|
|
|
|
|
|
zi |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Комментарий
<<СтрПолучитьСтрокуГГекущийДокумент.Комментар*Л. 1) ¦¦
Закрыт» I Действия.. | |
Рис. 5.36. Форма списка журнала кадровых приказов
Поскольку в журнале могут храниться приказы, порождаемые различными документами, имеющими реквизит Сотрудник, то необходимо указать все возможные значения этого реквизита. Выполним это для созданного нами документа Приказ-ОПриеме.
Откроем конфигурацию, доберемся до пункта Журналы документов, а затем до его подпункта ПриказыКадровые и ударим дважды мышью. Появившийся диалог (рис. 5.37) позволит нам осуществить намеченную цель.
Идентификатор: |ПрмказыКадроеые ?иж**#и: (Приказы кадровые
Комментарий:
 |
|
Новый |
Документы-:-
ИзмВШтРасп КаоровоеП еремещение П риказО П риемеН аРаботу П риказО 6У вольмении ПрмкаэП оП редприятио ПриказОПриеме И зменениеО клада
|
Иэмеытть |
 |
|
Рис. 5.37. Диалог задания свойств журнала кадровых приказов |
Умят\

Выберем в поле Графы запись Сотрудник и нажмем кнопку Изменить. Появившийся диалог приведем к виду, представленному на рис. 5.38, и дважды ударим по элементу Сотрудник в поле Возможные значения, или нажмем на Enter, или воспользуемся кнопкой
 |
|
Рис. 5.38. Добавление значения Документ.ПриказОПриеме. Сотрудник |
В результате в списке Выбранные значения появится элемент Доку-мент.ПриказОПриеме.Сотрудник. Теперь, если сохранить изменения, при записи документа ПриказОПриеме в графе Сотрудник диалога формы списка журнала кадровых перемещений будет отображаться значение реквизита Сотрудник этого документа (рис. 5.39).
 |
|
Рис. 5.39. Журнал кадровых приказов после ввода трех документов |
Галочка в первом столбце говорит о том, что документ проведен.
Первый документ, если открыть его для просмотра или редактирования, содержит данные, представленные на рис. 5.40.
 |
|
Рис. 5.40. Приказ номер 1 |
В справочнике Сотрудники_2 (в форме списка) он породит приведенную на рис. 5.41 запись, которую можно отредактировать как в форме элемента, так и в документе (см. разд. 5.8.2.4).
 |
|
Рис. 5.41. Проводка приказа номер 1 |
Замечания:
1. При удалении проведенного документа о приеме на работу обнуляется внесенное документом значение реквизита Оклад в соответствующей ему записи справочника Сотрудники_2. При перепроведении документа это значение восстанавливается. Автоматическое обнуление выполняется, так как периодический реквизит Оклад связывается с документом в процессе его проведения.
2. По умолчанию в журнале документов отображаются документы, даты которых находятся в пределах текущего месяца. Чтобы изменить временной диапазон журнала, называемый интервалом журнала, следует воспользоваться либо пунктом Интервал из колонки меню Действия, либо иконкой .*“*
панели инстру
ментов открьь того журнала. Программно интервал журнала задается методом Устано-витьИнтервал.
3. В программе журнал кадровых приказов можно открыть в результате следующего вызова:
ОткрытьФормуС'Журнал. ПриказыКадровые");
МОДУЛЬ ФОРМЫ СПИСКА ЖУРНАЛА КАДРОВЫХ ПРИКАЗОВ
Разместим в нем предопределенную процедуру ПриОткрытии, в которой, во-первых, определим стандартный список действий для кнопки Действия диалога формы и, во-вторых, установим интервал журнала, характеризуемый двумя датами: начала интервала и конца интервала.
Список действий разместим в переменной сДейст типа СписокЗначений, а с кнопкой Действия диалога формы списка свяжем на закладке Дополнительно в поле формула вызов процедуры глобального модуля глДействия(ТекущийДокумент, сДейст).
Начало интервала положим равным дате первого документа ПриказОПриеме, а конец - текущей дате. Если документов ПриказОПриеме в журнале кадровых приказов нет, то дату начала интервала определим по первому приказу об изменении окладов. Если нет и таковых, то дату начала установим равной текущей дате.
перем сДейст; // Список действий по документу
// Формирует список действий и устанавливает интервал журнала, отображающий // все введенные документы видов ПриказОПриеме и ИзменениеОклада процедура ПриОткрытии()
перем дНач; // Дата начала интервала журнала кадровых приказов
перем флаг, док;
// Определяем список действий для кнопки Действия сДейст.ДобавитьЗначение("Структура подчиненности"); сДейст.ДобавитьЗначение("Ввести на основании"); сДейст.ДобавитьЗначение("Движения документа");
флаг = 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 цикл подр = запС.Род; табл.ВывестиСекцию("подр"); конецЦикла; // пока
Нам уже понятно, что доступ к отдельному компоненту записи выборки запроса осуществляется по известной схеме - <имя запроса>.<имя переменной запроса>, например
Сообщить(запС.ИмяСотр); // Печатаем имя сотрудника
МЕТОДЫ И ПРЕДОПРЕДЕЛЕННЫЕ ПРОЦЕДУРЫ СПРАВОЧНИКОВ
Управление справочником осуществляется через его методы, которые можно разделить на 4 группы:
1. Методы Получить и Установить периодических реквизитов справочника.
2. Общие методы справочника; они могут быть вызваны как в модулях его форм, так и в модулях, где создан объект типа Справочник, например сСотр_2. В первом случае методы вызываются без префикса, например Записать( ), во втором - им предваряются, например сСотр_2.3аписать( ). Не все методы этой группы будут, однако, работать в форме элемента или списка справочника. Так, метод Выбрать-Элементы, будучи вставленным в модуль формы элемента справочника и использованным для текущего справочника (записывается без префикса), синтаксический контроль пройдет, но при вызове возникнет ошибка, сопровождаемая сообщением
ВыбратьЭлементы();
Объект не может быть перепозиционирован!
Но мы уже знаем: для того, чтобы эту ошибку преодолеть, нужно создать объект типа Справочник, например сСотр_2, соответствующей разновидности и употребить с ним этот метод:
сСотр_2.ВыбратьЭлементы();
3. Методы, используемые только в форме элемента, группы или списка справочника, например ПросмотрИстории. Их действие распространяется или на текущий элемент, если метод вызван в форме элемента, или на текущий справочник.
4. Методы, используемые только в форме списка справочника, например Сортировка. Их действие распространяется на текущий справочник.
5.12.1. МЕТОДЫ ПЕРИОДИЧЕСКИХ РЕКВИЗИТОВ
Метод Получить имеет следующий синтаксис:
значение = <спрЭлем>.<пРекв>.Получить([<датаПРекв>]);
Возвращает значение периодического реквизита пРекв для элемента справочника спрЭлем на заданный параметром датаПРекв момент времени. Если параметр дата-ПРекв опущен, то по умолчанию вместо него используется либо точка актуальности (ТА), если используется компонент Оперативный учет, либо рабочая дата - в противном случае.
Пояснение. Понятие ТА вводится в 1С для объектов типа Регистры. Такие объекты накапливают данные, например остатки или обороты ресурсов. Для первой цели применяются регистры остатков, для второй - оборотные регистры. Так вот, ТА - это момент времени, на который зафиксированы значения всех регистров остатков.
Метод Получить может быть использован как в модулях форм элемента и списка справочника, так и с объектами типа Справочник, возвращаемыми, например, функцией СоздатьОбъект или определенными в качестве реквизитов других объектов, например документов.
Пример. Методом Получить возвращаются на рабочую дату оклады сотрудников из справочника Сотрудники_2.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, рабДат, окл;
ОчистшъОкноСообщенийО;
// Создаем объект сСотр_1
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); рабДат = РабочаяДата(); сСотр_2.ВыбратъЭлементы(); пока сСотр_2.ПолучитъЭлемент() = 1 цикл если сСотр_2.ЭтоГруппа() = 1 тогда продолжитъ; конецЕсли;
окл = сСотр_2.0клад.Получить(рабДат);
//или
// окл = сСотр_2.ТекущийЭлемент( ).Оклад.Получить(рабДат); Сообщить(СокрП(сСотр_2.Наименование) + Символ Табуляции + окл); конецЦикла; // пока конецПроцедуры // Выполнить
Фрагмент возможного результата:
|
Горюнова Ульяна Валерьевна |
2700 |
|
Костина Ольга Владимировна |
2900 |
|
Куприкова Людмила Сергеевна |
2100 |
Замечание. Метод Получитъ (Установитъ) нельзя одновременно употреблять с методом ИспользоватьДату для одного и того же объекта типа Справочник.
Метод Установить имеет следующий синтаксис: <спрЭлем>.<пРекв>.Установить(<датаПРекв>, <значПРекв>);
Устанавливает значение периодического реквизита пРекв элемента справочника спрЭлем, равное величине, возвращаемой выражением значПРекв, на дату, заданную параметром датаПРекв. Используется только с объектами, созданными функцией СоздатьОбъект.
Пример. Сотрудникам из справочника Сотрудники_2, ставка которых меньше 2900 руб., начиная с текущей даты повышается оклад на 500 руб.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, текДат, окл, новОкл;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); текДат = ТекущаяДата( ); с Сотр_2. ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл окл = сСотр_2.0клад.Получшъ(текДат); если (сСотр_2.ЭтоГруппа( ) = 1) или (окл >= 2900) тогда
продолжить; // Пропускаем группы
конецЕсли; // и сотрудников с "большим" окладом
// Повышение оклада
сСотр_2.0клад.Установить(текДат, окл + 500); новОкл = сСотр_2.0клад.Получить(текДат);
Сообщить(СокрП(сСотр_2. Наименование) + СимволТабуляции + новОкл); конецЦикла; // пока конецПроцедуры // Выполнить
Фрагмент результата:
Горюнова Ульяна Валерьевна 3200
Куприкова Людмила Сергеевна 2600
Замечания:
1. Метод Установить меняет значение периодического реквизита справочника без последующего применения метода Записать.
2. Для метода Установить недопустим вызов типа сСотр_2.ТекущийЭлемент( ).Оклад.Установить(текДат, новОкл); // Это ошибка хотя подобный вызов вполне применим с методом Получить: сСотр_2.ТекущийЭлемент().Оклад.Получить(рабДат);
3. Повышение оклада выполнено в обход документа Приказ об изменении оклада. Это зафиксировано и в истории периодического реквизита Оклад, например для Горюновой У. В. (рис. 5.59).
 |
|
Рис. 5.59. История изменения периодического реквизита Оклад |
Обратим внимание, что факт отсутствия документа фиксируется в первом столбце таблицы с историей иконкой На практике, однако, такие неформальные манипуляции с окладами (и многими иными реквизитами) нежелательны и их лучше осуществлять на основе соответствующих документов. При этом взамен метода Установить в модуле документа следует использовать метод УстановитьРекви-зитСправочника, записывающий значение периодического реквизита справочника с привязкой к документу.
5.12.2. ОБЩИЕ МЕТОДЫ СПРАВОЧНИКОВ
Приведем их в табл. 5.8. После таблицы расположим примеры, эти методы иллюстрирующие. Напомним, что методы-функции могут быть вызваны и как процедуры, то есть в виде отдельных операторов.
|
Метод |
Описание |
|
видСпрІ = спр.Вид([видСпр2]); |
Возвращает вид справочника. Также может быть употреблен для задания вида видСпр2 объекта типа Справочник неопределенного вида, то есть созданного так: спр = СоздатьОбьект("Справочник"); |
предВида =
спр. ПредставлениеВида(); |
Возвращает представление вида справочника спр, то есть либо синоним справочника (рис. 5.5), либо его идентификатор, если синоним не задан |
|
ур = спр.Уровень(); |
Возвращает номер уровня текущего элемента справочника спр |
|
спр.УстановитьАтрибут(рекв, знач); |
Устанавливает значение непериодического реквизита рекв равным величине знач (напомним, реквизиты являются атрибутами справочника). Для сохранения изменений нужно вызвать метод Записать |
|
знач = спр.ПолучитьАтрибут(рекв); |
Возвращает значение реквизита рекв текущей записи справочника |
|
флаг = спр.ЭтоГруппа(); |
Вернет 1, если текущий элемент является группой, или 0 |
|
флаг = спр.ПринадпежигГруппе (группа); |
Вернет 1, если текущий элемент принадлежит к группе группа, или 0 -в противном случае |
|
флаг = спр.Выбран(); |
Возвращает 1, если справочник позиционирован на своей записи, или 0 -в противном случае |
|
*флаг - спр.Выбрать(заг, формаСписка); |
Открывает диалог с заголовком заг, использующий форму списка, заданную параметром формаСписка, для выбора элемента справочника. После закрытия диалога, если элемент выбран, вернет 1 и позиционирует справочник на этом элементе. Если элемент не выбран, метод вернет 0. Если формаСписка = "", то употребляется форма списка для выбора.
В открытом диалоге курсор позиционируется на текущем элементе справочника.
Диалог выбора элемента вызывается и для элементов диалога типа Справочник, расположенных в формах отчетов, справочников, журналов и документов |
Устанавливает для справочника спр, вид которого не определен, виды для выбора методом Выбрать и возвращает строку, содержащую ранее установленные виды для выбора. Может быть также употреблен и для реквизита типа Справочник неопределенного вида, являющегося компонентом иного объекта.

Новые виды для выбора задаются в виде строки, содержащей разделенные запятыми идентификаторы справочников, например видыНое = "Сотрудники_2, Образование_2";
Если видыНое содержит более одного идентификатора, то метод Выбрать активизирует диалог, предлагающий
|
Метод |
Описание |
|
|
выбрать один из справочников (рис. 5.59).
Если видыНов = "" или метод ВидыДляВыбора не употреблены вовсе, то метод Выбрать вызовет диалог, подобный изображенному на рис. 5.60, с полным списком справочников конфигурации |
|
выбТек = спр.ВыборГруппы ([выбНов]); |
Устанавливает режим выбора групп для метода
Выбрать и для элементов диалога типа Справочник. Группы можно выбирать в диалоге, если выбНов = 1, и нельзя - в противном случае. По умолчанию выбор групп разрешен для элемента диалога типа
Справочник в форме обработки (отчета) и запрещен, если диалог выбора активизируется методом Выбрать и если элемент диалога типа Справочник размещен в формах документов, журналов или справочников.
Метод возвращает существовавший до его вызова режим выбора групп. Если параметр выбНов опущен, то режим выбора групп не меняется |
|
элем = спр.ТекущийЭлемент(); |
Возвращает значение текущего элемента справочника. Возвращаемая величина имеет тип Справочник с разновидностью, возвращаемой методом Вид |
|
полнКод = спр.ПолныйКод(); |
Возвращает строку, содержащую полный код текущего элемента справочника |
полнИмя =
спр.ПолноеНаименование(); |
Возвращает строку, содержащую полное наименование текущего элемента справочника |
|
*флаг = спр.НайтиЭлемент(спрЭлем); |
Ищет элемент спрЭлем справочника и позиционирует справочник на элементе и возвращает 1, если поиск удачен, или не меняет позицию справочника и возвращает 0 в противном случае. Элемент спрЭлем должен иметь тип Справочник |
|
*флаг = спр.НайтиПоКоду(код), [режим]); |
Вернет 1 и переместит позицию справочника на элемент с кодом (или полным кодом) код, если такой элемент найден; в противном случае вернет 0, позиция справочника сохранится.
Поиск выполняется, если режим равен:
• 0, во всем справочнике;
• 1, в пределах родителя, заданного методом ИспользоватьРодителя, либо среди элементов уровня 1, если родитель явно не задан;
• 2, по полному коду.
Полный код - это строка, в которой коды уровней разделены символом /, например "1/12/121"; возвращается методом ПолныйКод.
Значение параметра режим по умолчанию есть:
• 0, для справочника, код в котором уникален в пределах всего справочника;
• 2, для справочника, код в котором уникален в пределах группы |
*флаг = спр.НайтиПоНаименованию (наим, [режим], [соотв]);
Вернет 1 и переместит позицию справочника на элемент с наименованием наим, если такой элемент найден; в противном случае вернет 0, позиция справочника сохранится.
Параметр режим принимает значения 0 или 1 и оказывает то же действие, что и одноименный параметр метода НайтиПоКоду. По умолчанию режим = 1.
Если соотв = 0, то поиск считается успешным, если наим и начальные символы реквизита Наименования совпадают, например если наим = "Еп", а фамилия сотрудника, хранимая реквизитом Наименование, Епифанов. Если соотв = 1, то для успешного поиска необходимо полное совпадение наим и Наименования.
По умолчанию соотв = 0.
Регистр задания значения параметра наим несущественным. Так, сотрудник Епифанов будет найден, если соотв = 0 и наим равен "Еп", или "еп", или "еП", или "ЕП". Если же в справочнике есть также сотрудник Епанов, то для наим = "Еп" будет найден он, поскольку поиск осуществляется среди наименований, расположенных по возрастанию их значений, а "Епанов" < "Епифанов"
*флаг -
спр. НайтиПо Реквизиту (рекв, знач, режим);
Ищет реквизит рекв, значение которого равно знач.
Если поиск успешен, что бывает, когда знач полностью совпадает со значением реквизита рекв, вернет 1, или 0 -в противн заданной методом ИспользоватьРодителя, если режим = 0, и во всем справочнике, если режим = 1. Метод может быть применен только для реквизитов, имеющих свойство Сортировка (см. разд. 5.6 и 5.7)
*флаг = спр.ВыбратьЭлементы ([режим]);
Открывает выборку элементов из справочника и возвращает 1, если можно выбрать хотя бы один элемент, или 0 - в противном случае. Элементы выбираются без учета иерархии, если режим = 0, и с учетом, если режим = 1. По умолчанию режим = 1. После вызова справочник позиционируется на первом элементе выборки. Выбор элементов осуществляется методом ПолучитьЭлемент
*флаг - спр.ВыбратьЭлементыПо Реквизиту(рекв, знач, [иерарх], [груп ]);
Открывает выборку элементов справочника, реквизит рекв которых равен знач. Собственно выборка осуществляется методом ПолучитьЭлемент. Такая выборка возможна только в том случае, если для реквизита рекв задано свойство Сортировка (см. рис. 5.29, б). Выборка осуществляется с учетом иерархии, если иерарх = 1, и без учета, если иерарх = 0. Параметр груп принимает те же значения, что и параметр иерарх. Метод вернет 0, если в выборке нет элементов, или 1 - в противном случае. Пример см. в разд. 5.7
|
Метод |
Описание |
|
*порТек = спр.ОбратныйПорядок ([порНов]); |
Если параметр порНов = 1, то выборка элементов, открываемая методами ВыбратьЭлементы или Выбрать-ЭлементыПоРеквизиту и осуществляемая методом По-лучитьЭлемент, выполняется в обратном порядке, и та же выборка выполняется в прямом порядке, если порНов = 0. Возвращает порядок выборки, существовавший до вызова метода. По умолчанию задан прямой порядок выборки. Если параметр порНов опущен, то метод только вернет текущий порядок выборки, не произведя никаких изменений. Пример см. в разд. 5.7 |
|
*флаг = спр.ПолучитьЭлемент ([режим]); |
Возвращает 1, если удалось выбрать элемент выборки, открытой методом ВыбратьЭлементы, или 0 -в противном случае (в выборке нет элементов или выборка исчерпана). После успешного выбора метод ПолучитьЭлемент перемещает справочник на следующую позицию выборки или за ее пределы, если все элементы выбраны. Выбранный элемент возвращается методом ТекущийЭлемент. Выбор очередной позиции осуществляется с учетом порядка, установленного методами:
• ВключатьПодчиненные;
• ИспользоватьВладельца;
• ИспользоватьДату;
• ИспользоватьРодителя;
• ОбратныйПорядок;
• ПорядокКодов;
• ПорядокНаименований;
• ПорядокРеквизита |
|
**датаТек = спр.ИспользоватьДату ([датаНов], [сразу]); |
Устанавливает параметром датаНов, имеющим тип Дата, дату выборки или записи периодических реквизитов справочника или объекта типа Справочник, являющегося компонентом иного объекта, например Документа. Возвращает ранее установленную для периодических реквизитов дату. Если параметр сразу = 1, то заданная методом дата используется в текущей выборке, если сразу = 0, то -в последующей. По умолчанию сразу = 0. Не может быть использован вместе с методами Получить и Установить. •
Не может иметь двойного префикса (см. пример для метода), например такого:
док. Сотрудник.ИспользоватьДату(ТекущаяДата());.
Если параметр датаНов опущен, то метод только вернет ранее установленную для периодических реквизитов дату |
|
Метод |
Описание |
**владТек =
спр.ИспользоватьВладельца ([владелец], [флагИзм]); |
Задает параметром владелец, имеющим тип Справочник с разновидностью справочника-владельца, элемент-владелец. После задания владельца методы Вы-братьЭлементы (ВыбратьЭлементыПоРеквизиту) и ПолучитьЭлемент, вызванные для подчиненного справочника, смогут выбрать только элементы, подчиненные элементу-владельцу. Также задает элемент-владелец для элемента, добавляемого в подчиненный справочник.
Если флагИзм = 1, то элемент-владелец может быть изменен интерактивно либо при выборе значения элемента диалога типа Справочник, либо при вызове метода Выбрать. Элемент-владелец не может быть изменен при интерактивном выборе элементов, если флагИзм = 0. По умолчанию флагИзм = 1.
Метод возвращает ранее установленный элемент-владелец. Причем если параметр владелец опущен, то метод только вернет существующего владельца, не производя иных действий. Пример употребления метода дан в разд. 5.10.3 и 5.10.5 |
**родТек =
спр.ИспользоватьРодителя ([родитель], [флагИзм]); |
Задает группу справочника, в которой методами справочника будет осуществляться выбор, поиск или добавление данных. Также употребляется для задания родителя с элементами диалога типа Справочник.
Группа задается параметром родитель, имеющим тип Справочник и содержащим значение группы справочника.
Параметр флагИзм имеет тот же смысл, что и одноименный параметр метода ИспользоватьВла-дельца.
Метод возвращает ранее установленного родителя. Причем, если параметр родитель опущен, то метод только вернет существующего родителя |
|
*вклТек = спр.ВключатьПодчиненные ([включать]); |
Если параметр включать = 1, то в выборку включаются подчиненные элементы, если включать = 0, то в выборку попадут только имена групп первого уровня.
По умолчанию подчиненные элементы включаются в выборку.
Возвращает текущее значения режима включения подчиненных. Если параметр включать опущен, то единственное назначение метода - это вернуть существующее значение режима включения подчиненных |
|
*спр.ПорядокКодов(); |
Если метод вызван, то выборка методом Получить Элемент будет осуществляться в порядке возрастания их кодов. Замечание. По умолчанию выборка выполняется в порядке возрастания основного представления справочника (рис 5.5), то есть Наименования или Кода |
|
Метод |
Описание |
|
*спр. ПорядокНаименований(); |
Если метод вызван, то выборка методом Получить Элемент будет осуществляться в порядке возрастания их наименований (см. также замечание к методу ПорядокКодов) |
|
*спр.ПорядокРеквизита(рекв); |
Если метод вызван, то выборка методом Получить Элемент будет осуществляться в порядке возрастания значения реквизита рекв. Метод может быть применен только с реквизитом, для которого задано свойство Сортировка (см. рис. 5.29, б). Если это условие не выполнено или реквизит задан неверно, то возникнет завершающая ошибка исполнения |
|
*спр.Новый( ); |
Создает пустую запись. Для ее добавления в справочник определяются соответствующие реквизиты и вызывается метод Записать. Пример см. в разд. 5.5.3.1 |
|
*спр.НоваяГруппа(); |
Создает пустую запись новой группы. Для ее добавления в справочник определяются реквизиты группы, например Код и Наименование, и вызывается метод Записать. Пример см. в разд. 5.5.3.1 |
|
префТек = спр.ПрефиксКода ([префНов]); |
Устанавливает префикс, употребляемый при автоматическом вычислении значения атрибута Код. Параметр префНов, содержащий значение префикса, имеет символьный тип. Возвращает префикс, заданный предыдущим вызовом метода. Если код имеет числовой тип, то префикс игнорируется |
|
спр.УстановитьНовыйКод(преф); |
Добавляет к коду элемента справочника префикс, заданный параметром преф |
спр.НазначитьТип
(рекв, тип, [длина], [точность]); |
Назначает тип или разновидность типа, заданную параметром тип, реквизиту рекв неопределенного типа. Символьный параметр тип может принимать значение базового типа ("Число", "Строка", "Дата"), любой определенной в конфигурации разновидности типа, например "Справочник.Дети" или "Доку-мент.ИзменениеОклада", или значение вида субконто |
|
спр.3аписать(); |
Обновляет текущий элемент справочника. Метод, в отличие от команды диалога #3аписать, не вызывает предопределенную процедуру ПриЗаписи |
|
*спр.Удалить(способ); |
Если способ = 1, то проставляет DBF-пометку удаления текущей записи. Такую запись средствами 1С вое-становить нельзя. Если способ = 0, то проставляет 1С-пометку удаления текущей записи (см. разд. 5.5.2).
По умолчанию способ = 1. Если удаляется запись справочника-владельца, то будут удалены (помечены для удаления) и все подчиненные ей записи |
|
флаг = спр.ПометкаУдаления(); |
Возвращает 1, если текущая запись имеет 1 С-пометку удаления, или 0 -в противном случае |
|
Метод |
Описание |
|
*спр.СнятьИометкуУдаленияО; |
Снимает 1С-пометку удаления текущего элемента справочника. Если запись, с которой снимается 1С-пометка удаления, имеет подчиненные записи в другом справочнике и они также имеют 1С-пометку удаления, то 1С-пометка удаления будет снята только с записи-владельца . |
|
флаг = спр.Блокировка([блк]); |
Возвращает/устанавливает режим блокировки записи. Если блк = 1, то блокировка устанавливается, и блокировка отключается, если блк = 0. Возвращает 1 если есть блокировка, или 0 -в противном случае |
|
Замечания: |
|
|
1. Имя спр переменной типа Справочник, употребленное в табл. 5.8 перед названи« ми методов, может быть произвольным. |
2. В форме элемента, группы или списка справочника методы, если они применяютс для текущего справочника, вызываются без префикса.
3. Методы, отмеченные в табл. 5.8 звездочкой, можно использовать только с объек тами, созданными функцией СоздатОбъект. То есть их нельзя употреблять для текущего справочника в форме его элемента, группы или списка.
4. Методы, отмеченные в табл. 5.8 двумя звездочками, можно использовать как с объектами, созданными функцией СоздатОбъект, так и для реквизитов тип Справочник, которые являются компонентами иных объектов, например докумен тов или справочников другого вида.
5. Имя реквизита рекв, используемое в методах, является символьным выражением возвращающим строку с именем реквизита, например строку "Оклад".
6. В методах УстановитьАтрибут и ПолучитьАтрибут при неверном значении пар з метра рекв возникнет завершающая ошибка, сопровождаемая сообщением "Неверное имя атрибута".
7. Параметры методов, если это не оговаривается особо, являются входными.
8. При изменении значений реквизитов методами Установить, УстановитьАтрибута УстановитьНовыйКод, Записать предопределенная процедура ПриЗаписи модуля формы элемента (группы) или списка не вызывается.
Примеры. Расположим их в процедуре Выполнить модуля обработки Проба Смысл фрагментов поясняется пользователю в окне, вызываемом встроенной процедурой Предупреждение.
процедура Выполните( ) // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, сОбр_2, спр, флаг, гр, обр; перем видыТек, видыНов, род, дети;
ОчиститьОкноСообщенийО;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Пример для метода Вид
Предупреждение(''Создаем справочник неопределенного вида.");
// спр - объект типа Справочник неопределенного вида спр = СоздатьОбъект("Справочник");
спр.Вид("Образование_2"); // Задаем разновидность типа объекта спр
Сообщить(спр.Вид( )); // Напечатает Образование_2
// Пример для методов НайтиПоНаименованию, НайтиПоКоду,
// УстановитьАтрибут, Записать и ПолучитьАтрибут
Предупреждение("Меняем реквизит Образование у сотрудника с кодом 302.");
// Ищем по части наименования
флаг = спр.НайтиПоНаименованию("Нач", 0);
если флаг = 1 тогда
// Ищем во всем справочнике
флаг = сСотр_2.НайтиПоКоду(302, 0);
если флаг = 1 тогда // Сотрудник найден
сСотр_2.УстановитьАтрибут("Образование", спр.ТекущийЭлемент()); сСотр_2.3аписать();
// Те же изменения вызовут два следующих оператора:
// сСотр_2.0бразование = спр.ТекущийЭлемент();
// сСотр_2.3аписать();
Сообщить(сСотр_2.ПолучитьАтрибут("Образование"));
// То же сообщение выведет оператор // Сообщить(сСотр_2.Образование));
// Просмотр результата
сСотр_2.Выбрать("Просмотр результата", "ФормаСписка"); иначе
Предупреждение("Сотрудник с кодом 302 не найден."); конецЕсли; иначе
Предупреждение("В справочнике Образование_2 нет |элемента с наименованием Начальное."); конецЕсли;
// Пример для методов ТекущийЭлемент. ЭтоГруппа. ПринадлежитГруппе.
// ВыбратьЭлементы, ПолучитьЭлемент и Выбран
Предупреждение("Выводится список сотрудников цеха 1." + РазделительСтрок +
"Имена подразделений цеха не печатаются."); флаг = сСотр_2.НайтиПоНаименованию("01 Цех"); если флаг = 1 тогда
если сСотр_2.ЭтоГруппа() = 1 тогда // Запоминаем найденную группу гр = сСотр_2.ТекущийЭлемент(); сСотр_2.ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл
// Не выводим имена подразделений первого цеха
если (сСотр_2.ПринадлежитГруппе(гр) = 1) и (сСотр_2.ЭтоГруппа() = 0) тогда Сообщить(сСотр_2.Наименование); конецЕсли; конецЦикла; // пока
// После такого цикла метод Выбран вернет 0
если сСотр_2.Выбран() = 0 тогда
Сообщшъ("После цикла Пока элемент справочника не выбран."); конецЕсли; иначе
Предупреждение("Найденный элемент не группа."); конецЕсли; иначе
Предупреждение("Имя 01 Цех не найдено."); конецЕсли;
// Пример для методов ВидыДляВыбора, ВыборГруппы и Выбран.
// а также для методов ПолныйКод и ПолноеНаименование спр = 0;
// спр - справочник неопределенного вида спр = Создать0бъект("Справочник"); видыНов = "Сотрудники_2, Образование_2";
Предупреждение("Если выберете вид Сотрудники, то получите полные код | и наименование выбранного вслед элемента справочника."); видыТек = спр.ВидыДляВыбора(видыНов);
// Разрешаем выбор групп в диалоге выбора. По умолчанию выбор групп запрещен
спр.ВыборГруппы(0);
флаг = спр.Выбрать(, "ФормаСписка");
если флаг = 1 тогда
если спр.Вид( ) = "Сотрудники_2" тогда
Сообщить("Выбран сотрудник: " + спр.Наименование);
// Следующий вызов напечатает, например, 1/12/121 Сообщить(спр.ПолныйКод());
// Напечатает, например, 01 Цех / 01/2 / Волосков Михаил Андреевич Сообщить(спр.ПолноеНаименование()); иначе
Сообщить("Выбрано образование:" + спр.Наименование); конецЕсли; иначе
Предупреждение("Сотрудник не выбран."); конецЕсли;
// Пример для метопа НайтиЭлемент: справочник Сотрудники_2 // позиционируется на родителе выбранного элемента Предупреждение("После выбора сотрудника откроется форма,
| в которой выбран родитель сотрудника."); сСотр_2.ВыборГруппы(0); // Запрещаем выбор групп
// Открываем диалог формы для выбора
флаг = сСотр_2.Выбрать("Выберите сотрудника", "ФормаСписка"); если флаг = 1 тогда
сСотр_2.НайтиЭлемент(сСотр_2.Родитель);
сСотр_2.ВыборГруппы(1); // Разрешаем выбор групп
сСотр_2.Выбрать("Курсор размещен на родителе ранее выбранного элемента", "ФормаСписка");
иначе
Предупреждение("Элемент не выбран."); конецЕсли;
// Пример для методов НайтиПоРеквизиту и ИспользоватьРодителя Предупреждение("После выбора вида образования и подразделения | откроется форма справочника Сотрудники_2, в которой | выбран сотрудник, имеющий выбранный вид образования.");
// Предварительно выбираются вид образования обр и подразделение (группа)
// Затем выполняется поиск сотрудника, имеющего образование обр // и работающего в выбранном подразделении сСотр_2 = 0;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сОбр_2 = СоздатьОбъект("Справочник.Образование_2");
// Выбираем вид образования обр
флаг = сОбр_2.Выбрать("Выберите вид образования",""); если флаг = 1 тогда
обр = сОбр_2.ТекущийЭлемент();
// Выбираем подразделение подр
// Разрешаем выбор групп в диалоге выбора. По умолчанию выбор групп запрещен сСотр_2.ВыборГруппы(1); флаг = сСотр_2.Выбрать("Выберите цех", ""); если сСотр_2.ЭтоГруппа() = 1 тогда // Поиск обр в группе сСотр_2 род = сСотр_2.ТекущийЭлемент(); сСотр_2.ИспользоватьРодителя(род);
флаг = сСотр_2.НайтиПоРеквизиту("Образование", обр, 0); если флаг = 1 тогда
// Покажем результат в форме списка для выбора сСотр_2.Выбрать("Курсор размещен на найденном сотруднике", ""); иначе
Предупреждение("В подразделении " + род.Наименование + " нет сотрудника |с образованием " + обр.Наименование); конецЕсли; иначе
Предупреждение("Цех не выбран."); конецЕсли; иначе
Предупреждение("Вид образования не выбран."); конецЕсли;
// Пример для методов ИспользоватьРодителя и Выбрать
// В качестве родителя задается второй цех. Затем используется метод Выбрать // Первый раз родитель может быть сменен при интерактивном выборе, второй раз - нет флаг = сСотр_2.НайтиПоКоду(2,0); // 2 - код второго цеха
если флаг = 1 тогда
Предупреждение("В первой форме родителя менять можно, а во второй - нельзя"); род = сСотр_2.ТекущийЭлемент(); сСотр_2.ИспользоватьРодителя(род, 1);
// Можно выбирать сотрудников из любой группы сСотр_2.Выбрать("Можно менять родителя", "ФормаСписка");
// Сотрудников можно выбрать только из второго цеха сСотр_2.ИспользоватьРодителя(род, 0);
сСотр_2.Выбрать("Родителя сменить не удается", "ФормаСписка"); иначе
Предупреждение("Цех с кодом 2 не найден."); конецЕсли;
// Пример для метода ИспользоватьДату
// Создается объект типа Документ с разновидностью ПриказОПриеме,
// имеющий, как известно, реквизит Сотрудник, устанавливающий связь документа // с порожденной им записью в справочнике Сотрудники_2. Используя этот реквизит,
// определим нынешний оклад сотрудника Горюновой У. В.,
// принятой на работу по приказу № 1
док = СоздатьОбъект("Документ.ПриказОПриеме");
флаг = док. НайтиПоНомеру( 1, Дата(0));
если флаг = 1 тогда
Предупреждение("В окне сообщений выведем оклады Горюнова Ульяны | по приказу и на рабочую дату.");
// Нельзя устанавливать дату периодического реквизита следующим образом:
// док. Сотрудник. ИспользоватьДату(Т екущаяДата());
// Это нужно делать так:
// Определяем объект с разновидностью типа Справочник.Сотрудники_2 сотр = док.Сотрудник;
// Устанавливаем для этого объекта дату периодических реквизитов сотр. ИспользоватьДату(док.ДатаПриема);
// Оклад на дату зачисления на работу; должен быть равен док.Оклад; оклСтар = сотр.Оклад;
// Меняем дату чтения периодического реквизита Оклад сотр. ИспользоватьДату(Т екущаяДата()); оклСегодня = сотр.Оклад;
Сообщить("Оклад по приказу: " + оклСтар); // Оклад по приказу: 2500
Сообщить("Оклад сегодня: " + оклСегодня); // Оклад сегодня: 3200
иначе
Предупреждение("Приказ № 1 не найден."); конецЕсли;
// Пример для методов Удалить, ПометкаУдаления и СнятьПометкуУдаления // Ставится пометка удаления на запись с кодом 302. Это вызывает простановку // пометок удаления и на записи в справочнике Дети, подчиненные записи-владельцу сСотр_2 - 0;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); флаг = сСотр_2.НайтиПоКоду(302, 0); если флаг = 1 тогда
если Вопрос("Удалить запись с кодом 302?", "Да+Нет") = "Да" тогда Предупреждение("Ставим пометку удаления сотруднику с кодом 302 | в справочнике Сотрудники_2 и в подчиненном справочнике Дети.");
// Проставляем 1С-пометку удаления (Рис. 5.61.)
// Если дети сотрудника занесены в справочник Дети, то соответствующие // им записи также получат пометку удаления сСотр_2.Удалить(0);
Предупреждение("Просмотр результата.");
сСотр_2.Выбрать("Запись о сотруднике с кодом 302 помечена для удаления", ""); дети = СоздатьОбъект(" Справочник. Дети"); дети.ИспользоватьВладельца(сСотр_2);
дети.Выбрать("Удалены записи и в подчиненном справочнике", ""); дети = 0; конецЕсли;
иначе
Предупреждение("Сотрудник не найден."); конецЕсли;
// Снимаем пометку удаления с текущей записи
// Однако проставленная ранее пометка удаления в подчиненном
// справочнике сохранится
если сСотр_2.ПометкаУдаления( ) = 1 тогда
если Вопрос("Снять пометку удаления?", "Да+Нет") = "Да" тогда
Предупреждение("Пометка удаления снимается только" + РазделительСтрок +
"в справочнике Сотрудники_2."); сСотр_2.СнятьПометкуУдаления();
Предупреждение("Просмотр результата.");
сСотр_2.Выбрать("С записи о сотруднике с кодом 302 снята пометка удаления", ""); дети = СоздатьОбъект("Справочник.Дети"); дети.ИспользоватьВладельца(сСотр_2);
дети.Выбрать("Дети по-прежнему имеют пометку удаления",""); конецЕсли; конецЕсли;
// Пример для метода ВключатьПодчиненные
Предупреждение("В окно сообщений благодаря методу ВключатьПодчиненные"
"выводятся только имена групп справочника Сотрудники_2."); сСотр_2.ВключатьПодчиненные(0); сСотр_2.ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл Сообщить(сСотр_2.Наименование) конецЦикла; // пока // Результат:
//01 Цех // 02 Цех // 03 Цех
конецПроцедуры // Выполнить
 |
|
Рис. 5.61. Удаление записи-владельца влечет удаление и подчиненных записей |
Замечание. Сразу после выбора нового вида справочника в результате вызова видыТек = спр.ВидыДляВыбора(видыНов); метод спр.Вид() вернет пустое значение.
5.12.3. МЕТОДЫ ФОРМЫ ЭЛЕМЕНТА СПРАВОЧНИКА
Могут быть использованы только в модуле элемента справочника. Вызываются без префикса. Приводятся в табл. 5.9.
|
Методы формы элемента справочника |
|
Метод |
Описание |
|
флаг = Модифицированное^); |
Вернет 1, если изменен хотя бы один элемент диалога формы элемента справочника, или 0, если элементы диалога не модифицировались.
Если изменения были, то в заголовке диалога появится символ * |
датаТек = ИспользоватьДату
([датаНов], [обновить]); |
Имеет то же назначение, что и одноименный метод табл. 5.8 |
списТек = СохранениеПериодических Реквизитов (вариант,
[список]); |
Задает режим отображения диалога Изменения периодических реквизитов (см. рис. 5.16). Если вариант равен 0 или 2, то диалог не отображается; и отображается, если вариант равен 1, 3, 4 или 5. Символьный параметр список содержит список анализируемых на предмет изменения периодических реквизитов, например "Оклад, Должность". Если список = "*", то в него включаются все периодические реквизиты справочника. Периодический реквизит считается измененным, если изменилась его дата, или значение, или и то и другое. Возвращает ранее установленный список периодических реквизитов |
списТек =
ПросмотрИстории([список]); |
Задает параметром список периодические реквизиты, для которых допускается просмотр
истории |
|
Замечание. Для работы с периодическими реквизитами в 1С, помимо приведенных в табл. 5.9, имеется широкий ассортимент возможностей: методы справочника Получить и Установить, метод модуля документа УстановитьРеквизитСпр а-вочника, а также методы объекта Периодический, рассматриваемые в гл. 6.
5.12.4. ПРЕДОПРЕДЕЛЕННЫЕ ПРОЦЕДУРЫ МОДУЛЯ ФОРМЫ ЭЛЕМЕНТА И ГРУППЫ СПРАВОЧНИКА
В модуле любой формы можно задать ее предопределенные процедуры, такие, как ПриОткрытии, ПриПовторномОткрытии, ПриЗакрытии, ПриВыбореЗакладки, ПриНачалеВыбораЗначения, ОбработкаПодбора, ОбработкаВыбораЗначения, При-ВыбореСтроки. Некоторые из них нами уже употреблялись, иные будут рассмотрены позже.
Вдобавок к этим процедурам в форме элемента (группы) справочника можно написать код еще двух перечисленных в табл. 5.10 предопределенных процедур.
|
Предопределенные процедуры модуля формы элемента (группы) справочника |
|
Процедура |
Описание |
ВводНового
([копир],
[объект]) |
Вызывается, если ее код присутствует в модуле формы элемента (группы), при интерактивном вводе нового элемента справочника, например в результате выбора пункта Новый в колонке меню Действия. Необязательный формальный параметр копир, если он есть и равен единице, означает, что новая запись введена копированием (Действия - Копировать или клавиша F9) и, следовательно, значения ее реквизитов известны. Если параметр равен нулю, то значения реквизитов не определены и тогда имеет смысл задать их в теле рассматриваемой процедуры. Параметр объект, если присутствует, передает скопированный объект |
ПриЗаписи
([перРекв]) |
Вызывается, если ее код присутствует в модуле формы элемента (группы), при выполнении команды #3аписать. Необязательный формальный параметр перРекв, если он есть, передает список периодических реквизитов, выбранных для обновления в окне диалога изменения периодических реквизитов (см. рис. 5.16) |
|
Пример 1. В предопределенной процедуре ВводНового модуля формы элемента справочника Сотрудники_2 (разд. 5.3.4.2) выводятся переданные параметром объект реквизиты формы.
// Для ввода копированием используем F9 или нажмем на иконку ~‘+
на панели инстру
ментов // формы списка справочника, или выберем соответствующий пункт меню конки Действия процедура ВводНового(копир, объект)
если копир = 1 тогда // Если новый элемент вводится копированием
Сообщить(объект. Наименование);
Сообщить(объект.Оклад);
Сообщить(объект.Образование);
конецЕсли;
конецПроцедуры // ВводНового Замечания:
1. Предопределенная процедура ВводНового вызывается раньше предопределенной процедуры ПриОткрытии.
2. Параметром объект не передаются периодические реквизиты. Так, при вызове Сообщить(объект.Оклад);
1С напечатает НеизвестныйОбъект
Пример 2. В предопределенной процедуре ПриЗаписи модуля формы элемента справочника Сотрудники_2 (разд. 5.3.4.2) анализируется параметр процедуры перРекв, и если он содержит реквизит Оклад, то процедура завершается со статусом возврата О, что означает запрет записи данных.
// Предопределенная процедура ПриЗаписи вызывается после появления диалога // Изменения периодических реквизитов (рис. 5.16) процедура ПриЗаписи(перРекв)
// Если планируется обновить периодический реквизит Оклад если Найти(перРекв, "Оклад") = 1 тогда
Предупреждение("Оклад можно изменить только на основании приказа."); СтатусВозврата(0); // Запрещаем запись элемента
возврат; конецЕсли;
// Последующий код
конецПроцедуры // ПриЗаписи
5.12.5. МЕТОДЫ ФОРМЫ СПИСКА СПРАВОЧНИКА
Употребляются в модулях формы списка справочника без префикса. Приводятся в табл. 5.11.
Методы формы элемента справочника
|
Таблица 5.11 |
|
Метод |
Описание |
|
датаТек = ИспользоватьДату ([датаНов]); |
Имеет то же назначение, что и одноименный метод табл. 5.8 |
|
владТек = ИспользоватьВладельца ([владелец], [флагИзм]); |
Задает владельца для формы списка подчиненного справочника. Имеет то же описание, что и одноименный метод табл. 5.8. Пример см. в разд. 5.10.3. |
|
родТек = ИспользоватьРодителя ([родитель], [флагИзм]); |
Задает родителя для формы списка подчиненного справочника. Имеет то же описание, что и одноименный метод табл. 5.8 |
|
иерархТек = ИерархическийСписок ([иерарх], [флагИзм]); |
Если иерарх =1, то многоуровневый справочник будет отображаться по группам в виде иерархического списка (см., например, рис. 5.1); если иерарх = 0, то элементы в окне вывода следуют без учета иерархии, отсортированные, например, по коду (см. рис. 5.2). Если флагИзм = 1, то пользователь может интерактивно включать/отключать режим ввода списка справочника по группам, и не может, если флагИзм = 0. По умолчанию флагИзм = 1. Возвращает 1, если показ списка элементов осуществляется по группам, или 0 -в противном случае |
|
выбТек = ВыборГруппы([выбНов]); |
Имеет то же назначение, что и одноименный метод табл. 5.8 |
|
|
Метод |
Описание |
|
редактТек = РедактироватьВДиалоге ([редакт], [флагИзм]); |
Если редакт = 1, то редактирование элемента (группы) справочника будет осуществляться с использованием формы этого элемента (группы). Такие формы, конечно же, должны бытъ заготовлены заранее. Если редакт = 0, то элемент (группа) редактируется в строке формы списка справочника. Если флагИзм = 1, то полъзователъ может интерактивно менятъ режим редактирования справочника, и не может, если флагИзм = 0. По умолчанию флагИзм = 1. Возвращает 1, если редактирование на момент вызова метода осуществляется в диалоге, или 0 -в противном случае |
|
списТек = СохранениеПериодических Реквизитов(вариант, [список]); |
Имеет то же назначение, что и одноименный метод табл. 5.8 |
сортТек = Сортировка
{[сорт], [флагИзм]); |
Задает символьным параметром сорт способ сортировки данных в диалоге формы списка справочника. Всегда параметр сорт можно задать равным "Код" или "Наименование". Также в качестве сорт можно передать строку с именем реквизита, имеющего свойство Сортировка. Если флагИзм = 1, то пользователь может интерактивно менять способ упорядочения данных, и не может, если флагИзм = 0. По умолчанию флагИзм = 1. Возвращает 1, если редактирование на момент вызова метода осуществляется в диалоге, или 0 - в противном случае |
|
УстановитьОтборркв, знач); |
Ограничивает объем выводимых в диалоге формы списка справочника данных: отображаются только те элементы, реквизит рекв которых имеет значение знач. Параметр рекв - это строка со значением, совпадающим с именем реквизита. Для этого реквизита должно быть задано свойство Отбор по реквизиту (см. рис. 5.29, б). Если рекв - пустая строка, то отбор отключается. Тип (разновидность типа) параметра знач определяется типом реквизита, по которому устанавливается отбор |
|
флаг = ПолучитъОтбор(рекв, знач); |
Возвращает в параметры рекв и знач текущий отбор элементов справочника. Параметры имеют тот же смысл, что и одноименные параметры метода Уста-новитьОтбор. Возвращает 1, если отбор задан, или 0 -в противном случае |
|
видыТек = ВидыОтбора (списокРекв); |
Задает параметром списокРекв список реквизитов, по которым в интерактивном режиме можно устанавливать отбор. Параметр списокРекв - это строка, содержащая одно или несколько разделенных запятыми имен отбора, например "Образование" или "Имя,, ГодРождения" |
|
Метод |
Описание |
|
флаг = ЗакладкиОтбора(рекв, [знач]); |
Устанавливает закладки отбора по реквизиту рекв в диалоге формы списка справочника. Параметр знач, если он задан, определяет первоначально отображаемый отбор. Описание параметров то же, что и для метода УстановитьОтбор. Возвращает пустое значение. Пример использования см. в разд. 5.9.1.2 |
ИспользоватьСписокЭлементов
(сЗнач); |
Устанавливает фильтр, позволяющий отображать только те элементы справочника, значения которых содержатся в списке значений сЗнач. Если список пуст, то фильтр отключается. После вызова метода с непустым списком нельзя вводить, копировать и перемещать элементы справочника. Пример употребления см. в разд. 5.9.2 |
|
списТек = ПросмотрИстории([список]); |
Имеет то же назначение, что и одноименный метод табл. 5.8 |
Пример. В предопределенной процедуре ПриОткрытии модуля формы списка справочника Сотрудники_2 задаются способы представления данных.
процедура ПриОткрытии() перем обр;
// Вывод данных осуществляется в диалоге формы без учета иерархии;
// способ вывода изменению не подлежит // Сортировка производится по наименованию;
// способ сортировки может меняться интерактивно // Редактирование записи выполняется в диалоге или в документе,
// если реквизит ПриказПрием содержит ссылку на документ Приказ о приеме на работу // Кроме того, устанавливаем отбор по реквизиту Образование и выводим после // открытия список сотрудников с высшим образованием ИерархическийСписок(0, 0);
Сортировка("Наименование", 1);
// Режим редактирования можно менять интерактивно РедактироватьВДиалоге(1, 1);
обр = СоздатьОбъект("Справочник.Образование_2");
// Ищем высшее образование
если обр.НайтиПоНаименованию("В", 0) = 1 тогда
// Второй параметр метода УстановитьОтбор должен иметь разновидность типа // Справочник.Образование_2
УстановитьОтбор("Образование", обр.ТекущийЭлемент()); иначе
Предупреждение
("В справочнике Образование_2 нет записи, начинающейся с буквы В."); конецЕсли;
конецПроцедуры // ПриОткрытии
5.12.6. ПРЕДОПРЕДЕЛЕННЫЕ ПРОЦЕДУРЫ МОДУЛЯ ФОРМЫ СПИСКА СПРАВОЧНИКА
Включаются программистом в модуль формы списка справочника по мере необходимости. Приводятся в табл. 5.12.
Предопределенные процедуры модуля формы списка справочника
|
Таблица5.12 |
|
Процедура |
Описание |
|
ПриВводеСтроки() |
Вызывается до начала ввода новой строки в форме списка справочника |
ПриРедактированииНовой
Строки() |
Вызывается в момент начала ввода данных в новую строку формы списка справочника |
ПриНачалеРедактирования
Строки() |
Вызывается в момент начала редактирования данных в существующей строке формы списка справочника |
|
ПриЗаписи([пер.Рекв]) |
Имеет то же назначение, что и одноименная предопределенная процедура модуля формы элемента (группы) справочника |
ПриПереносеЭлемента
ВДругуюГруппу
([элемент],
[группа]) |
Вызывается при интерактивном переносе элемента в другую группу справочника. Формальный параметр элемент содержит переносимый элемент, а группа - это группа, в которую элемент переносится |
ПриВыбореРодителя
([родитель]) |
Вызывается при выборе (двойном ударе мышью или нажатии на Enter) родителя (группы). Параметр родитель, если присутствует, имеет тип Справочник и содержит выбранный элемент-родитель |
ПриВыбореВладельца
([владелец]) |
Вызывается при интерактивном выборе владельца. Здесь выбор - это перемещение с одного элемента справочника-хозяина на другой. Параметр владелец, если присутствует, имеет тип Справочник и содержит выбранный элемент-владелец.
Пример см. в разд. 5.10.3 |
ПриСменеИерархии
([иерарх]) |
Вызывается при интерактивной смене способа представления списка элементов справочника (иерархический -неиерархический). Числовой параметр иерарх, если он присутствует, равен единице, если устанавливается иерархический способ, или нулю - в противном случае |
ПриУстановкеОтбора
([рекв], [знач]) |
Вызывается при интерактивной установке отбора (см. разд. 5.9). Параметр рекв - это строка, содержащая имя реквизита, по которому отбор установлен, например "Образование", знач -значение(критерий)отбора |
|
Пример. При переносе элемента в другую группу справочника Сотрудники_2 необходимо изменить его код, приведя в соответствие с правилами его автоматического назначения. Правила таковы: в качестве первых цифр кода элемента берется код родителя, если родитель расположен на втором уровне справочника Сотрудники_2, или код родителя, увеличенный в 10 раз, если родитель лежит на первом уровне (всего в справочнике Сотрудники_2 три уровня). Последующие цифры кода сотрудника образуют возрастающую последовательность целых положительность чисел. Эту схему реализ у-ет функция СоздатьКод. Ее алгоритм приведен в разд. 5.8.2.2. Правда, в нем вместо функции СоздатьКод использована одноименная процедура.
функция СоздатьКод(группа) далее
процедура ПриПереносеЭлеменгаВДругуюГруппу(алеменг, группа) новКод = СоздатьКод(группа);
// Новый код для переносимого в другую группу элемента УстановитьАтрибут("Код", новКод); конецПроцедуры // ПриПереносеЭлементаВДругуюГруппу
функция СоздатьКод(группа)
перем сСотр_2, максКод, двеЦифр, послЦифр; перем двеЦифрУмнНаК, к;
двеЦифр = ?(группа.Уровень() = 1, 10 * группа.Код, 1 * группа.Код);
// Найдем максКод - максимальный код сотрудника в пределах подразделения сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сСотр_2. ИспользоватьРодителя(группа);
// Осуществим перебор в порядке возрастания кодов элементов
сСотр_2.ПорядокКодов();
сСотр_2.ВыбратьЭлементы();
максКод = 0;
пока сСотр_2.ПолучитьЭлемент() > 0 цикл максКод = 1 * сСотр_2.Код; конецЦикла; // пока
// Ищем последующие цифры максКод и затем последующие цифры кода
// нового сотрудника. Будем умножать двеЦифр на 10, пока не превысим максКод
к=1;
двеЦифрУмнНаК = двеЦифр;
пока двеЦифрУмнНаК < максКод цикл
двеЦифрУмнНаК = двеЦифрУмнНаК * 10; конецЦикла; // пока
// Последующие цифры кода нового сотрудника
послЦифр = ?(максКод = 0, 1, максКод - двеЦифрУмнНаК / 10 + 1);
// Итак, вернем код нового сотрудника возврат Число(Строка(двеЦифр) + Строка(послЦифр)); конецФункции // СоздатьКод
5.13. ЧТЕНИЕ ЗНАЧЕНИЯ РЕКВИЗИТА СПРАВОЧНИКА
Все рассматриваемые в текущем разделе способы доступа к реквизитам справочника уже нами употреблялись. Здесь же мы приведем некоторые обобщения.
Значение реквизита справочника можно получить, создав объект типа Справочник и применив вслед известные методы доступа к реквизитам объекта (см. табл. 5.8). Причем значение кода (или иного реквизита) атрибута Родитель (Владелец) можно п о-лучить следующим образом: сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
сСотр_2.НайтиПоКоду(301, 0); // Ищем во всем справочнике
Сообщить(сСотр_2.Родитель.Код); // Код атрибута Родитель
В формах элемента, группы и списка справочника его реквизиты доступны непосредственно и могут быть использованы в качестве элементов диалога или переменных модулей этих форм.
Функция ОткрытьФорму и метод модуля формы ОткрытьПодбор возвращают ко н-текст открытой формы. Поэтому, если открыт справочник, можно обратиться к его р е-квизиту через полученный контекст (см. разд. 5.4).
Если объект, например Сотрудник, имеет тип Справочник и является компонентом другого объекта, например документа ПриказОПриеме, то к реквизиту объекта-компонента можно обратиться, использовав, например, такой путь:
<Создаем объект док с разновидностью типа Документ.ПриказОПриеме>
<Находим нужный документ (приказ)>
// Читаем значение реквизита Образование в справочнике, на который указывает // реквизит Сотрудник найденного документа ПриказОПриеме обр = док.Сотрудник.Образование;
5.14. ПРОГРАММНАЯ ОБРАБОТКА УДАЛЯЕМЫХ
ЗАПИСЕЙ
Все записи информационной базы, обладающие 1С-пометкой удаления, можно разместить в списке значений, вызвав процедуру НайтиПомеченныеНаУдаление. Список найденных ей объектов можно просмотреть и передать его (весь или сокращенный) затем либо процедуре НайтиСсылки, либо процедуре УдалитьОбъекты.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
// сЗнач - список значений, куда будут размещены записи об объектах,
// помеченных для удаления
// сЗнач2 - список объектов, передаваемых процедуре НайтиСсылки перем сЗнач, сЗнач2, тЗнач, ин, значен, пред;
ОчиститьОкноСообщений();
сЗнач = СоздатьОбъект("СписокЗначений");
НайтиПомеченныеНаУдаление(сЗнач); если сЗнач.РазмерСписка() > 0 тогда
// Диалог для проставления пометок в списке см. на рис. 5.62 сЗнач.ОтметитьЗначения(, "Выберите объекты для поиска ссылок");
// После проставления пометок в списке сЗнач перенесем // выбранные элементы в список сЗнач2 (рис. 5.63) сЗнач2 = СоздатьОбъект("СписокЗначений"); для ин = 1 по сЗнач.РазмерСписка() цикл // Если элемент списка не имеет пометки если сЗнач.Пометка(ин) = 1 тогда
значен = сЗнач.ПолучитьЗначение(ин, пред); сЗнач2.ДобавитьЗначение(значен, пред); конецЕсли; конецЦикла; // для
если сЗнач.РазмерСписка() > 0 тогда // Просмотр результата
сЗнач2.ВыбратьЗначение(, "Список для процедуры НайтиСсылки");
// тЗнач - таблица, в которую разместим ссылки на удаленные объекты тЗнач = СоздатьОбъектСТаблицаЗначений");
НайтиСсылки(сЗнач2, тЗнач);
// Просмотр результата. Возможный вариант приведен на рис. 5.64 тЗнач.ВыбратьСтроку(, "Таблица ссылок"); иначе
Сообщить("Список для процедуры НайтиСсылки пуст."); конецЕсли иначе
Сообщить("Нет записей с 1С-пометкой удаления."); конецЕсли;
конецПроцедуры // Выполнить
 |
|
Рис. 5.62. Объекты, отобранные в списке сЗнач для поиска ссылок |
 |
|
Рис. 5.63. Список сЗнач2 объектов для поиска ссылок |
 |
|
Рис. 5.64. Обнаружена ссылка на документ № 4 из справочника Сотрудники_2 |
Замечание. В процедуре НайтиСсылки в качестве первого параметра можно употребить не список значений, а значение одного объекта, ссылки на который нужно о б-наружить, например, так:
тЗнач = СоздатьОбъект("ТаблицаЗначений"); док = СоздатьОбъект("Документ.ИзменениеОклада"); док.НайтиПоНомеру(4); // Ищем документ
НайтиСсылки(док.ТекущийДокумент( ), тЗнач);
// Просмотр таблицы ссылок тЗнач.ВыбратьСтроку(, "Таблица ссылок");
Передаваемый процедуре объект может не иметь пометки удаления.
Процедура УдалитьОбъекты проставляет DBF-пометки удаления. Процедура, так же как и процедура НайтиСылки, может принимать в качестве первого параметра либо отдельный удаляемый объект, либо список объектов. Причем объекты могут в общем-то и не иметь 1С-пометок удаления. Процедура имеет следующий синтаксис:
УдалитьОбъекты(объект | список_объектов, [проверка], [таблица_ссылок]);
где первый параметр - это либо удаляемый объект, либо список объектов, возвращаемый, например, процедурой НайтиПомеченныеНаУдаление. Если параметр проверка = 1, то осуществляется поиск ссылок на объекты, заданные первым параметром процедуры. Найденные ссылки возвращаются выходным параметром таблица ссылок, имеющим тип ТаблицаЗначений. Причем объекты, ссылки на которые обнаружены, не удаляются. Если же проверка = 0, то ссылки и все объекты, заданные параметром 1, удаляются (разумеется, в том случае, если первый параметр задан без ошибок).
Удаленные объекты получают DBF-пометку удаления. Их физическое удаление выполняется в конфигураторе, открывающем подлежащие упаковке файлы в монопольном режиме (разд. 5.5.2).
Пример. Удаляется документ № 4 об изменении оклада.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем тЗнач, док;
тЗнач = СоздатьОбъект("ТаблицаЗначений");
док = СоздатьОбъект("Документ.ИзменениеОклада");
// Ищем документ
если док.НайтиПоНомеру(4) = 0 тогда
Предупреждение("Документ под номером 4 не найден."); конецЕсли;
// Перед удалением проводим поиск ссылок на документ № 4 УдалигьОбъекты(док.ТекушийДокумент(), 1 ,тЗнач);
// Если есть ссылки, то прежде их просмотрим, а затем примем решение,
// удалять документ или нет если тЗнач.КоличествоСтрок() > 0 тогда // Просмотр таблицы ссылок тЗнач.ВыбратьСтроку(, "Таблица ссылок");
если Вопрос("Удалить документ, на который есть ссылки?", "Да+Нет") = "Да" тогда // Удаляем документ без поиска ссылок (проставляем DBF-пометку удаления) УдалшъОбъектыСдок.ТекущийДокументО); иначе'
Предупреждение("Документ не удален."); конецЕсли; иначе
Предупреждение("Документ № 4 удален."); конецЕсли;
конецПроцедуры // Выполнить
После удаления в окне сообщений возникнет следующий текст:
Удаленные записи:
Документ: ИзменениеОклада Номер: 4 Дата: 29.11.2001 Документ.ИзменениеОклада удалено объектов 1
Замечание. Удаление объектов, на которые есть ссылки, не приветствуется, поскольку приводит к нарушению целостности информационной базы данных системы.
5.15. ВЫВОДЫ
1. Справочник 1С - это в общем случае совокупность нескольких взаимосвязанных DBF-файлов.
2. Главная таблица справочника в общем случае, кроме элементов, включает и группы, к которым эти элементы принадлежат. Такая организация таблицы позволяет представлять справочник в виде иерархического списка.
3. Периодические реквизиты справочника хранятся в файле 1 SCONST.DBF.
4. Для добавления, редактирования и просмотра данных справочника можно использовать формы элемента, группы, списка и документы, а также соответствующие методы справочника.
5. Реквизиты, автоматически формируемые программой (например код) следует делать доступными только для чтения.
6. Атрибуты Родитель и Владелец имеют тип Справочник.
7. Удаление записей справочника выполняется в 3 этапа: на первом записи помечаются для удаления символом * в поле Ismark таблицы справочника, на втором -в специально выделенном поле DBF-файла таблицы, на третьем - выполняется упаковка помеченных для удаления данных; записи, удаление которых приведет к нарушению целостности базы данных, нельзя удалить в интерактивном режиме, зато это можно выполнить программно, употребив встроенную процедуру Уда-литьОбъекты.
8. При простановке пометки удаления на запись-владелец автоматически такие пометки проставляются и на подчиненные ей записи. Для интерактивного режима справедливо и обратное: снятие пометки удаления с записи-владельца приводит, если пользователь дал согласие, к снятию таких пометок и с подчиненных записей.
9. Предопределенную процедуру ПриЗаписи следует применять для контроля ввод и-мых данных.
10. Предопределенная процедура ВводНового употребляется для задания начальных значений вводимых реквизитов.
11. Отбор значений справочника возможен только по реквизитам, имеющим свойства Сортировка и Отбор по реквизиту.
12. В подчиненном справочнике отображаются только строки, связанные с записью, выбранной в справочнике-владельце.
13. Связь между подчиненным справочником и его владельцем осуществляется через атрибут Владелец подчиненного справочника. Связь между их элементами - через поля Parentext и Id DBF-таблиц этих файлов.
14. Длинный код по выбору данных следует заменять запросами.
15. Для быстрого отображения выборки, созданной в результате выполнения запроса, ее можно выгрузить в таблицу значений, а последнюю вывести на экран, употребив метод ВыбратьСтроку.
16. Перебор записей выборки запроса выполняется в цикле Пока, использующем метод Группировка. Причем для доступа к вложенной группе выборки прежде нужно выбрать запись группы более высокого уровня.
17. Методы ИспользоватьДату, ИспользоватьВладельца и ИспользоватьРодителя употребляются для объектов, имеющих тип Справочник, которые либо возвращаются функцией СоздатьОбъект, либо являются компонентами других объектов, например документов или других справочников, либо возвращаются параметром контекст функции ОткрытьФорму или метода ОткрытьПодбор.
6. ОБЪЕКТЫ ТИПА ПЕРИОДИЧЕСКИЙ
6.1. ПОРЯДОК ИСПОЛЬЗОВАНИЯ ОБЪЕКТА ПЕРИОДИЧЕСКИЙ
Объекты типа Периодический (далее - ОП) предоставляют дополнительные возможности по управлению периодическими реквизитами справочников и периодическими константами. ОП. подобно, например, спискам или таблицам значений, не входят в состав метаданных, а создаются на время исполнения программы функций Соз-датьОбъект, Например:
оп = СоздатьОбъект(''Периодический'');
После создания ОП прикрепляется к определенному периодическому объекту - реквизиту справочника или периодической константе. Это действие выполняется методом ИспользоватьОбъект. Метод не применяется, если выборка периодических объе к-тов осуществляется по документу. Далее употребляются методы или атрибуты ОП, п о-зиционирующие периодической объект и управляющие его значениями.
С каждым периодическим объектом связано в общем случае несколько записей, содержащих каждая значение периодического объекта, дату значения и, возможно, иные компоненты, например ссылку на документ, создавший запись.
Пример 1. Выводится список периодических констант, содержащий их идентификаторы, синонимы и значения на текущую дату.
// Процедура вывода списка определенных в конфигурации периодических констант процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем всегоКонстант, дат; // Число констант в конфигурации
перем идеи, син, значен, пКонст;
ОчиститьОкноСообщений(); дат = ТекущаяДата();
// Создаем ОП
пКонст = СоздатьОбъект("Периодический"); всегоКонстант = Метаданные.Константа(); для ин = 1 по всегоКонстант цикл
если Метаданные.Константа(ин).Периодический = 0 тогда
продолжить; // Значения непериодических констант не выводятся
конецЕсли;
син = Метаданные.Константа(ин). Синоним;
// Выводим сообщения о константах, для которых задан синоним если ПустоеЗначение(син) = 0 тогда
идеи = Метаданные.Константа(ин). Идентификатор;
// Прикрепляем ОП к периодической константе, имеющей идентификатор иден пКонст. ИспользоватьОбъект(иден);
// Получаем значение периодической константы на дату дат значен = пКонст.ЗначениеНаДату(дат);
Сообщить(иден + " - " + син + " - " + значен); конецЕсли; конецЦикла; // для конецПроцедуры // Выполнить
Пример 2. Выводится история изменения константы МинимальнаяЗарплата.
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем значен, дат, пКонст;
ОчиститьОкно Сообшений();
// Создаем ОП
пКонст = СоздатьОбъект('Периодический"); попытка
// Прикрепляем ОП к периодической константе,
// имеющей идентификатор МинимальнаяЗарплата пКонст.ИспользоватьОбъектС'МинимальнаяЗарплата''); исключение
Предупреждение(ОписаниеОшибки());
возврат;
конецПопытки;
// Позиционируемся перед первой записью истории константы пКонст.ВыбратьЗначения();
Сообщить("История константы МинимальнаяЗарплата");
// Метод ПолучитьЗначение позиционирует ОП на следующей записи о константе пока пКонст.ПолучитьЗначение() = 1 цикл
значен = пКонст.Значение; // Значение и ДатаЗнач - атрибуты ОП
дат = пКонст.ДатаЗнач;
Сообщить("Минимальная заработная плата " + значен + " руб. введена с " + дат); конецЦикла // пока конецПроцедуры // Выполнить
Результат:
История константы МинимальнаяЗарплата.
Минимальная заработная плата 83.49 руб. введена с 01.01.98 Минимальная заработная плата 132 руб. введена с 01.07.00 Минимальная заработная плата 200 руб. введена с 01.01.01 Минимальная заработная плата 300 руб. введена с 01.07.01
Пример 3. Выводится история изменений оклада Горюновой У. В. с указанием документов, вызвавших эти изменения.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, оп, окл, дат, док, сооб;
ОчиститьОкноСообщений();
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Ищем сотрудника во всем справочнике Сотрудники_2 если сСотр_2.НайтиПоНаименованию("Горюнова", 0) = 1 тогда // Создаем ОП
оп = СоздатьОбъект("Периодический");
// Прикрепляем ОП к периодическому реквизиту Оклад найденного сотрудника оп.ИспользоватьОбъект("Оклад", сСотр_2.ТекущийЭлемент());
// Или проще: оп.ИспользоватьОбъект("Оклад", сСотр_2);
// Позиционируемся перед первой записью истории окладов Горюновой У. В. оп.ВыбратьЗначения();
Сообщить("История окладов Горюновой Ульяны Валерьевны.");
// Метод ПолучитьЗначение позиционирует ОП на следующей записи // периодического реквизита Оклад пока оп.ПолучитьЗначение() = 1 цикл
окл = оп.Значение; // Значение и ДатаЗнач - атрибуты ОП
дат = оп.ДатаЗнач;
// Документ, вызвавший изменение оклада док = оп.ТекущийДокументО;
// Текст для сообщения о документе сооб = ?(док.Выбран() = 1,
" согласно документу " + оп.ТекущийДокументО,
" без оформления документа");
Сообщить("Оклад " + окл + " назначен с " + дат + сооб); конецЦикла; // пока иначе
Предупреждение(''Найти госпожу Горюнову У. В. не удалось."); конецЕсли;
конецПроцедуры // Выполнить Результат.
История окладов Горюновой Ульяны Валерьевны
Оклад 2500 назначен с 20.11.01 согласно документу Приказ о приеме на работу 2 Оклад 2700 назначен с 22.11.01 согласно документу ИзменениеОклада 2 Оклад 3200 назначен с 30.11.01 без оформления документа
6.2. АТРИБУТЫ ОБЪЕКТА ПЕРИОДИЧЕСКИЙ
Имеет два атрибута: Значение и ДатаЗнач, которые после создания ОП имеют пустые значения соответственно неопределенного типа и типа Дата. После прикрепления к периодическому реквизиту или периодической константе сохраняют пустые значения, но атрибут Значение приобретает тип, совпадающий с типом объекта, к которому ОП прикреплен. Атрибут ДатаЗнач тип сохраняет. И наконец, получают значения после позиционирования на записи, отвечающей объекту, к которому прикреплен ОП. Напомним, что данные о константах и периодических реквизитах справочников хранятся в файле 1SCONST.DBF.
Примеры чтения значений атрибутов ОП приведены в предшествующем разделе. Эти же атрибуты совместно с методом Записать используются и для изменения значений периодических реквизитов и констант.
Пример. Изменяется размер минимальной заработной платы, введеной с 01.07.01, с 300 на 350 руб.
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем значен, дат, пКонст;
ОчиститьОкноСообщенийО; дат = '01.07.2001';
// Создаем ОП
пКонст = СоздатьОбъект("Периодический");
попытка
// Прикрепляем ОП к периодической константе,
// имеющей идентификатор МинимальнаяЗарплата пКонст.ИспользоватьОбъект("МинимальнаяЗарплата"); исключение
Предупреждение(ОписаниеОшибки());
возврат;
конецПопытки;
если пКонст.НайтиЗначение(дат, 0) = 1 тогда
пКонст.Значение = 350; // Новое значение константы на дату дат
пКонст. Записать();
Сообщить("Теперь минимальная зарплата равна " +
Константа. МинимальнаяЗарплата.Получить(дат) + " руб.");
// Восстанавливаем значение нужной для работы константы
пКонст.Значение = 300; // Новое значение константы на дату дат
пКонст. Записать(); иначе
Предупреждение("Константы МинимальнаяЗарплата на дату " + дат + " нет."); конецЕсли;
конецПроцедуры // Выполнить
6.3. МЕТОДЫ ОБЪЕКТА ПЕРИОДИЧЕСКИЙ
Позволяют читать, перебирать, искать, изменять и удалять периодические реквизиты справочников и периодические константы. При удалении записи сразу проставляется DBF-пометка удаления. Удаленные записи восстановлению не подлежат. Нельзя методами ОП добавлять новые значения периодических констант или реквизитов справочников.
Кроме значения и даты периодического объекта, методы ОП устанавливают связь с документами, создавшими и впоследствии обновлявшими записи периодических объектов.
Методы перечислены в табл. 6.1.
Таблица 6.1
Методы объекта Периодический |
|
Метод |
Описание |
|
флаг = оп.Использовать Объект(перОб, [элемент]); |
Прикрепляет ОП к периодическому реквизиту справочника (периодической константе), идентификатор которого (которой) содержится в строке перОб. Параметр элемент имеет тип Справочник. Параметр задается, если перОб является периодическим реквизитом справочника, и содержит значение текущего элемента справочника.
Если перОб - это пустая строка и задан параметр элемент, то ОП доступны значения всех периодических реквизитов текущего элемента справочника, заданного параметром элемент. Метод возвращает 1, если действие завершилось успешно, или 0 -в противном случае. Пример употребления см. в разд. 6.1, 6.2 |
|
|
Метод |
Описание |
оп.НазначитьТип
(тип, длина, точность); |
Назначает тип периодическому объекту неопределенного типа. Параметр тип - это строка с именем базового типа, например "Число", или разновидностью агрегатного типа, например "Справочник. Образование_2" или "Доку-мент.ИзменениеОклада". Параметр длина задается для числового или символьного типа и означает размер отводимого под значение поля. Параметр точность применяется только с числовым типом и задает число знаков после десятичной точки. Понятно, что точность < длина |
|
значен = оп.ЗначениеНаДату (дата); |
Возвращает значение периодического объекта на дату, заданную параметром дата. При исполнении метода позиция периодического объекта сохраняется. Пример употребления см. в разд. 6.1 |
|
флаг = оп.НайтиЗначение (дата, [режим]); |
Осуществляет поиск значения периодического объекта на заданную параметром дата дату. Если значение не найдено и параметр режим = -1, то ищется значение на ближайшую меньшую дату, если режим = 1, то ищется значение на ближайшую большую дату, и если режим = 0, то возвращает 0. По умолчанию режим = -1. Возвращает 1 в случае успеха. Пример употребления см. в разд. 6.2 |
|
флаг = оп.ВыбратьЗначения ([датаНачала], [датаКонца]); |
Открывает выборку значений периодического объекта. Параметры датаНачала и датаКонца задают соответственно даты начала и конца периода выборки. Собственно выборка осуществляется методом ПолучитьЗначение. Если параметр датаНачала не задан, то значения периодического объекта выбираются начиная с меньшей даты. Если не задан параметр датаКонца, то периодические значения выбираются вплоть до самой большой даты. Возвращает 1, если в выборке есть хотя бы одно значение, или 0 -в противном случае. Пример использования см. в разд. 6.1 |
флаг - оп.ВыбратьПо
Документу(док); |
Открывает выборку значений периодических объектов, созданных документом док. Дальнейшая выборка осуществляется методом ПолучитьЗначение. Возвращает 1, если в выборке есть хотя б ы одно значение, или 0 - в противном случае |
|
флаг = оп.ПолучитьЗначение(); |
Перемещает позицию выборки значений периодического объекта на одну запись. По умолчанию перемещение выполняется вниз по выборке (прямой порядок), но может быть изменено методом Обратный порядок. Возвращает 1, если следующая запись выбрана, или 0, если выборка исчерпана. Ели запись выбрана, то ее значение и дата возвращаются атрибутами ОП Значение и ДатаЗнач. Документ, установивший выбранное значение, возвращается методом ТекущийДокумент; элемент справочника, которому принадлежит выбранный периодический реквизит, вернет метод ТекущийОбъект, а идентификатор текущего периодического реквизита или периодической константы вернет метод ТекущийРеквизит |
|
Метод |
Описание |
|
флаг = оп.ОбратныйПорядок ([порядок]); |
Задает порядок получения записей выборки. Если параметр порядок отличен от нуля или не задан вовсе, то выбор записей осуществляется в обратном порядке. Если параметр порядок равен нулю, выборка производится в прямом порядке. Вызывается до применения метода ВыбратьЗначения. Вернет 1 при успешном вызове или 0 -в противном случае |
|
док = оп.ТекущийДокумент(); |
Возвращает значение документа, установившего значение выбранной записи периодического объекта. Вернет пустое значение типа Документ, если ссылки на документ нет. Пример для метода приведен в разд. 6.1 |
|
элем = оп.ТекущийОбъект( ); |
Возвращает, если выбираются значения периодического реквизита, значение элемента справочника, которому периодический реквизит принадлежит. Вернет пустое значение неопределенного типа, если выбираются значения периодической константы |
|
рекв = оп.ТекущийРеквизитО; |
Возвращает идентификатор выбранного периодического реквизита или периодической константы. При выборке по документу в возвращаемом значении в качестве префикса присутствует имя справочника, в котором в результате проведения документа добавляется (изменяется) значение
периодического реквизита, например Сотрудники 2.Оклад |
номСтроки =
оп.НомерСтроки(); |
Должен вернуть номер строки документа, получаемого методом ТекущийДокумент |
|
флаг = оп.Записать(); |
Обновляет периодическое значение текущей записи. Возвращает 1, если обновление выполнено успешно, или 0 -в случае неудачи. Пример употребления см. в разд. 6.2 |
|
флаг = оп.Удалить(); |
Удаляет (проставляет DBF-пометку удаления) запись периодического объекта. Возвращает 1, если обновление выполнено успешно, или О-в случае неудачи |
Замечание. Имя on переменной типа Периодический, употребленное в табл. 6.1 перед названиями методов, может быть произвольным.
Пример. Выбираются значения периодического реквизита Оклад справочника С о-трудники_2, созданные документом ИзменениеОклада № 3.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем жд, док;
ОчиститьОкноСообщенийО;
док = СоздатьОбъект("Документ.ИзменениеОклада"); флаг = док.НайтиПоНомеру(3, Дата(0)); если флаг = 1 тогда
оп = СоздатьОбъект("Периодический"); оп.ВыбратьПоДокументу(док.ТекущийДокумент()); пока оп.ПолучитьЗначение() = 1 цикл
окл = оп.Значение; // Значение и ДатаЗнач- атрибуты ОП
дат = оп.ДатаЗнач;
Сообщить(''Оклад " + окл + " сотрудника " +
оп.ТекущийОбъект( ).Наименование + " назначен с " + дат); конецЦикла; // пока иначе
Предупреждение(''Приказ № 3 об изменении оклада не найден"); конецЕсли;
конецПроцедуры // Выполнить Результат:
Оклад 3000 сотрудника Волосков Михаил Андреевич назначен с 22.11.01 Оклад 2700 сотрудника Горюнова Ульяна Валерьевна назначен с 22.11.01
ПРОСМОТР ИСТОРИИ ПЕРИОДИЧЕСКОГО ОБЪЕКТА
Можно выполнить интерактивно, выбирая, например, на панели инструментов
иконку ^ или нажимая F5. Программно осуществляется встроенной функцией От-крытьФорму.
Пример 1. Выводится история периодической константы МинимальнаяЗарплата. ОткрытьФорму(''История.Константа.МинимальнаяЗарплата'');
Результат см. на рис. 6.1.
 |
|
Рис. 6.1. Результат вызова функции ОткрытьФорму |
Пример 2. Выводится история окладов Горюновой У. В.
процедура Выполнить( ) перем сСотр_2;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); если сСотр_2.НайтиПоНаименованию('Торюнова", 0) = 1 тогда ОткрытьФорму(''История.Справочник.Сотрудники_2.0клад''„ сСотр_2.ТекущийЭлементО);
иначе
Предупреждение("Найти госпожу Горюнову У. В. не удалось."); конецЕсли;
конецПроцедуры // Выполнить
Результат см. на рис. 6.2.
 |
|
Рис. 6.2. История окладов Горюновой Ульяны Валерьевны |
6.5. ВЫВОДЫ
1. Агрегатный тип данных Периодический применяется для периодических реквизитов справочников и периодических констант.
2. Метод ИспользоватьОбъект, связывающий ОП с периодическим объектом, не употребляется, если выборка периодических объектов осуществляется по документу.
3. Вызов
оп.ИспользоватьОбъект("
т, элемент);
обеспечит доступ к значениям всех периодических реквизитов текущего элемента справочника, заданного параметром элемент.
4. Позиция периодического объекта изменяется методами НайтиЗначение, Выбрать Значения, ВыбратьПоДокументу и ПолучитьЗначение. Метод ЗначениеНаДату позицию периодического объекта не изменяет.
5. Записи периодического объекта, удаляемые методом Удалить, получают DBF-пометку удаления и поэтому восстановлению не подлежат.
6. Программно просмотр истории периодического объекта можно выполнить, вызывая встроенную функцию ОткрытьФорму.
7. Каждый вид документа порождает в информационной базе в общем случае два DBF-файла и два CDX-файла - одна пара файлов для шапки документов заданного вида, вторая для их табличной части.
8. 1С открывает все созданные для документов и справочников DBF- и CDX-файлы. Поэтому рост числа таких файлов ведет к снижению быстродействия программы и, следовательно, нужно стремиться к снижению числа видов документов и справочников в конфигурации системы (впрочем, как и иных ее объектов).
9. Все созданные документы перечисляются в одном, общем журнале документов, который можно просматривать по частям, давая каждой части свое имя, например ПриказыКадровые.
7. ЖУРНАЛ И ВИДЫ РАСЧЕТОВ КАЛЕНДАРИ И ТАБЕЛЬ
7.1. ЖУРНАЛ РАСЧЕТОВ В ЗАДАЧЕ НАЧИСЛЕНИЯ ЗАРАБОТНОЙ ПЛАТЫ
7.1.1. ПОНЯТИЕ ЖУРНАЛА РАСЧЕТОВ
Разного рода расчеты в 1С заносятся в журналы расчетов. Иллюстрацию методов работы с подобными журналами мы выполним на примере расчета заработной платы сотрудников из справочника Сотрудники_2, размещая расчеты и их результаты в журнале Зарплата_2. Попутно мы рассмотрим задачу учета отработанного времени, для решения которой необходимо освоить методы работы с такими объектами 1С, как Календари и Праздники.
Журнал расчетов является агрегатным типом данных и применяется в 1С:Пред-приятии, например в конфигурации Заработная плата и кадры, для начисления заработной платы сотрудникам, поэтому его второе название в этой задаче - журнал зарплаты. Также журнал расчетов можно приспособить и для иных целей, например для расчета дивидендов акционеров АО. В общем случае в конфигурации можно задать и использовать произвольное число журналов расчетов, дав им подходящие имена.
Замечание. Далее, где это возможно, вместо общего названия "журнал расчетов" (ЖР) будем употреблять частное имя "журнал зарплаты" (ЖЗ).
Каждая запись ЖЗ называется расчетом и отображает некоторое начисление, например премию, или удержание, например налог на доходы физических лиц. Расчет связан с конкретным элементом справочника сотрудников, называемым объектом расчета или просто объектом. Совокупность всех начислений и удержаний объекта за расчетный период, продолжительность которого составляет, как правило, месяц, позволяет определить размер получаемой сотрудником заработной платы.
Справочник, элементы которого являются объектами расчетов, называется владельцем ЖЗ. В свою очередь, элемент такого справочника, называется владельцем расчетов, объектом которых он является.
Расчет характеризуется результатом, который возвращается специальными объектами 1С, имеющими тип ВидРасчета Более точно: результат вычисляется в процедуре ПровестиРасчет, принадлежащей модулю вида расчета - объекту типа Вид-Расчета. Далее, упоминая объекты типа ВидРасчета, мы будем использовать сокращение ВР.
7.1.2. ПРИМЕР ПРОСТОГО РАСЧЕТА
Возьмем простой расчет - начисление премии, зависящей от проработанных часов, и на его примере рассмотрим основные свойства расчета.
Алгоритм расчета премии состоит из одной конструкции "если-то-иначе":
1. Начало.
2. Выбрать сотрудника.
3. Если оплата сотрудника производится по окладу, то
премия = (оклад
всегоЧасов / всегоЧасовПоКалендарю)
коэффициент иначе // Часовой тариф
премия = тариф
всегоЧасов
коэффициент конец если 3.
4. Конец.
Оклад мы возьмем из справочника Сотрудники 2 (согласно ему все наши люди "сидят" на окладе). Значение переменной всегоЧасов - число отработанных сотрудником часов в расчетном периоде - придется вводить (или подсчитывать по табелю) ежемесячно. Значение переменной всегоЧасовПоКалендарю - число рабочих часов в расчетном периоде - в 1С определяется при помощи объектов типа Календарь. С переменной коэффициент поступим так: установим индивидуальный для каждого сотрудника коэффициент, причем его значения в разных расчетных периодах могут не совпадать. Если коэффициент постоянен и одинаков для всех работников, то его можно добавить в список констант, причем периодических.
Из приведенного обзора входных данных алгоритма следует, что справочник Со-трудники_2 нужно дополнить еще одним реквизитом - Календарь. Тогда, зная календарь, то есть зная продолжительность рабочей недели и рабочего дня сотрудника, а также даты выходных и праздников в расчетном периоде, легко вычислить значение переменной всегоЧасовПоКалендарю. В 1С его вернет следующий код:
// Возвращает число рабочих часов в расчетном периоде по календарю // кален - параметр типа Календарь; жз - переменная типа ЖурналРасчетов.Зарплата // датаП - дата, принадлежащая текущему расчетному периоду ЖЗ функция НайгиВсегоЧасовПоКалендарю(кален, жз, датаП) возврат кален.Часов(жз.НачалоПериодаПоДате(датаП), жз.КонецПериодаПоДате(датаП)); конецфункции // НайтиВсегоЧасовПоКалендарю
// Запустим функцию НайтиВсегоЧасовПоКалендарю из обработки Проба процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем кален, жз, датаП, всегоЧасовПоКалендарю; кален = СоздатьОбъект("Календарь.Рабочие_2"); жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
// 3 марта 2001 г. - дата, принадлежащая текущему расчетному периоду ЖЗ датаП = '03.03.2001';
всегоЧасовПоКалендарю = НайтиВсегоЧасовПоКалендарю(кален, жз, датаП); Сообщить("Число рабочих часов в марте 2001 г. равно " + всегоЧасовПоКалендарю); конецПроцедуры // Выполнить
Результат;
Число рабочих часов в марте 2001 г. равно 167
Такой результат получен, потому что рабочие работают на пятидневке; продолжительность рабочего дня - 8 ч; в марте один праздник - 8 Марта; продолжительность предпраздничного дня -7 ч. Тогда имеем в марте 2001 г. 21 рабочий день и всегоЧасовПоКалендарю = 20
8 + 7 = 167. Более подробно об управлении календарями см. в разд. 7.5.
Вернемся, однако, к премии. В ЖЗ ее расчет может отобразиться в виде результата, представленного на рис. 7.1. Но чтобы его получить, придется выполнить некоторую цепочку действий. Эта цепочка должна отражать реальные процессы начисления зарплаты в целом и премии в частности.
|
|
Сотрчдник |
IBP 1 |
|
|
±1 |
Добрецов Борис |
1 Премия коэфіі 167.01 1.670.00Ц 2013001 || 01 03 01 131 03.01 |
|
|
Рис. 7.1. Премия Добрецова Бориса Юрьевича. |
Как правило, вопросы премирования отражаются в приказе о премии по отдельному подразделению или по предприятию в целом. Чтобы ускорить создание этого документа, в нем следует предусмотреть реквизиты Сотрудник, всего Часов, коэффициент, премия, а также даты, задающие период, за который премия начисляется, называемые датами начала и окончания расчета. Период, в которой эти даты входят, называется периодом действия расчета. В 1С период действия расчета всегда принадлежит одному расчетному периоду.
Кроме того, документ должен ссылаться на процедуру, выполняющую по введенным данным расчет премии. В самой же процедуре по известному календарю должен осуществляться расчет значения переменной всего ЧасовПоКалендарю.
Таким образом, табличная часть документа имеет вид, представленный в табл. 7.1.
Таблица 7.1
Табличная часть документа ПриказОПремии |
|
Сотрудник |
Отработанные часы |
Коэффициент |
Премия |
|
Добрецов Борис Юрьевич |
167 |
10 |
1,670.00 |
|
Графа Премия заполняется автоматически и для редактирования недоступна.
После формирования документа, в котором скорее всего будут фигурировать фамилии нескольких сотрудников, выполняется его проведение и, возможно, приказ печатается. Сам же документ разместим в журнале Расчеты, который является частью общего журнала документов.
Результатом проведения документа является добавление расчета в ЖЗ (см. рис. 7.1).
Список приведенных выше реквизитов документа не является исчерпывающим: для бухгалтерского учета начисления и удержания разных видов нужно отнести на соответствующие счета (дебет и кредит). То есть в документе, в его шапке, нужно добавить реквизит ХозОп (код хозяйственной операции ). Этот код можно выбирать из справочника ХозяйственнаяОперация. Однако известно, что один и тот же ВР связан с определенной хозяйственной операцией. Поэтому правильнее создать дополнительный справочник, например ХозОпДляВР, хранящий для каждого вида расчета его хозяйственную операцию.
7.1.3. НЕКОТОРЫЕ СВОЙСТВА ЖУРНАЛА ЗАРПЛАТЫ И ЕГО
РАСЧЕТОВ
Журнал зарплаты:
• характеризуется расчетным периодом;
• состоит из записей - расчетов;
• содержит для каждого объекта (сотрудника) все причитающиеся ему в расчетном периоде начисления и полагающиеся удержания.
Каждый расчет ЖЗ:
• регистрируется в некотором периоде расчета ЖЗ;
• имеет дату начала и дату окончания, которые в обязательном порядке должны находиться в пределах одного расчетного периода;
• имеет период действия;
• связан с документом, порождающим расчет;
• связан с объектом расчета;
• связан с ВР, в который в том числе входит и процедура, выполняющая расчет и возвращающая его результат.
Последние 3 ссылки попадают в ЖЗ из документа, порождающего расчет. Период действия определяется по датам начала и окончания расчета. Сами же даты либо задаются в родительском документе, либо устанавливаются равными соответственно началу и концу текущего расчетного периода, продолжительность которого мы установим равной одному месяцу.
Замечание. Период действия расчета может лежать в ином, отличном от текущего расчетном периоде. Так, расчет отпуска с 1 июня продолжительностью 40 календарных дней осуществляется в мае. Поэтому, начисляя отпускные, система должна, во-первых, разбить исходный расчет на два, задав для первого в качестве периода действия июнь, а для второго - июль (за это отвечает атрибут ЖЗ ПериодДействия), определив соответствующим образом атрибуты ЖЗ ДатаНачала и ДатаОкончания. Во-вторых, разместить обе части в майском расчетном периоде ЖЗ (за это отвечает атрибут ЖР ПериодРегистрации). Тогда процедура расчета выберет верные календари, расходы бухгалтерского учета будут отнесены на соответствующие периоды, а отпускник увидит в расчетном листке корректные даты.
7.1.4. МЕРОПРИЯТИЯ ПО СОЗДАНИЮ ЖУРНАЛА ЗАРПЛАТЫ
Общий порядок начисления заработной платы, а также рассмотренный выше алгоритм отдельного расчета позволяют определить и последовательность действий, которые необходимо предпринять для автоматизации ведения ЖЗ. Очевидно, что для этого потребуется:
1) выделить все имеющиеся на предприятии виды начислений и удержаний;
2) оформить каждый вид начисления (удержания) как объект 1С типа ВидРасчета;
3) разработать документы 1С, автоматизирующие учет отработанного времени;
4) дополнить конфигурацию вспомогательным справочником хозяйственных операций для ВР предприятия;
5) создать ЖЗ;
6) сконструировать отчеты по выполняемым расчетам, в том числе расчетный листок сотрудника.
7.2. ЗАДАНИЕ РАСЧЕТНОГО ПЕРИОДА ЖУРНАЛА ЗАРПЛАТЫ
Завершив очередной расчетный период (РП) или открыв ЖЗ в первый раз, мы, чтобы продолжить расчеты, должны задать новый РП. Для этого при открытом ЖЗ мы можем воспользоваться пунктом Сменить период расчета, принадлежащим колонке Действия меню системы, или иконкой 03, находящейся на панели инструментов диалога формы списка ЖЗ. Появившийся диалог (рис. 7.2) позволит перейти к следующему периоду.
|
Текущий период - |
Зарплата_2 |
-ві |
|
Период расчета. |
Декабрь 2001 г. |
ок |
|
с Г |
1 Декабря 2001 |
Отмена |
|
Па |
31 Декабре 2001 |
Помошь
Дополі « |
 |
|
Рис. 7.2. Задание расчетного периода |
Смена периода является ответственной процедурой, поскольку приводит к закрытию текущего РП, в результате чего его записи переносятся в разряд архивных и оказываются доступными только для просмотра (если пользоваться стандартными интерактивными средствами). Программно новый РП задается методом журналов расчетов УстановитьТекущийПериод.
Замечание. Иконки, сопровождающие расчеты архивов, отображаются в ЖЗ на синем фоне. Исключение составляют иконки фиксированных расчетов, например можно зафиксировать результаты выплат через кассу. Фон таких иконок - желтый.
Если же произошла ошибка и новый РП установлен, когда еще не завершенное расчеты в старом, то возврат к прежнему РП при помощи формы рис. 7.2 приведет к обнулению результатов его расчетов (кроме фиксированных). Этого можно избежать, если вернуться назад программно, вызвав метод УстановитьТекущийПериод и задав в нем второй параметр равным нулю. Например:
процедура Выполнить( ) перем жз, пер, флаг;
// Откат назад без отработки системных действий жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); пер = жз.ТекущийПериод();
пер = пер.ПрибавитьПериод(-1); // Получаем предыдущий период
// Возврат к прежнему РП
флаг = жз.УстановитьТекущийПериод(пер, 0); конецПроцедуры // Выполнить
Организовать просмотр прошлых периодов можно, задав соответствующую глубину просмотра архива (рис. 7.3).

Для этого при открытом ЖЗ воспользуйтесь пунктом Задать глубину просмотра архива, входящим в колонку Действия меню системы, или иконкой
7.3. ВИДЫ РАСЧЕТОВ
7.3.1. СВОЙСТВА ВИДОВ РАСЧЕТОВ
7.З.1.1. НЕСОВМЕСТИМЫЕ ВИДЫ РАСЧЕТОВ. ВЫТЕСНЕНИЕ РАСЧЕТА Введем еще несколько понятий.
Назовем интервалом действия расчета промежуток времени между датой начала и датой окончания расчета, включающий и сами даты.
Назовем виды расчетов (ВР) несовместимыми, если соответствующие им расчеты ЖЗ не могут иметь пересекающихся интервалов действия. Расчеты с такими ВР также будем называть несовместимыми. Несовместимость расчетов преодолевается при их записи в ЖЗ за счет эффекта вытеснения.
Рассмотрим ситуацию, когда расчеты А и Б являются несовместимыми, расчет А с приведенным на рис. 7.4, а интервалом действия уже введен и вводится расчет Б. Возможны случаи:
1. Интервалы действия расчетов различны. Тогда расчет Б будет благополучно введен.
2. Интервалы действия расчетов совпадают, тогда в ЖЗ останется один расчет: либо А, либо Б. Это зависит от направления вытеснения, которое устанавливается в конфигурации для несовместимых ВР при их создании или редактировании. Например, если Б вытесняет А, то А удаляется из ЖЗ, а Б вводится. При обратном направлении вытеснения Б введен не будет.
3. Интервал действия расчета Б полностью лежит в интервале действия расчета А, но А вытесняет Б. Расчет Б не вводится.
4. Интервал действия расчета Б полностью лежит в интервале действия расчета А, но теперь уже Б вытесняет А. Расчет Б вводится, расчет А разбивается на два расчета - А1 и А2, такие, что интервал действия расчета А1 лежит на временной оси слева от интервала расчета Б, а интервал А2 - справа (рис. 7.4, б).
5. Интервалы действия расчетов А и Б частично пересекаются, причем А вытесняет Б. Тогда А остается полностью и вводится часть Б1 расчета Б, такая, что интервал этой части соприкасается на временной оси с интервалом А либо слева, либо справа (в зависимости от характера пересечения) (рис. 7.4, в).
6. Интервалы действия расчетов А и Б частично пересекаются, но теперь уже Б вытесняет А. Тогда Б вводится полностью и остается часть А1 расчета А, такая, что интервал этой части соприкасается на временной оси с интервалом Б либо слева, либо справа (рис. 7.4, г).
 |
|
Рис. 7.4. Вытеснение расчета: а - интервал действия расчета А до ввода Б; б - Б полностью лежит в А и вытесняет его; в -А и Б частично пересекаются, А вытесняе г - А и Б частично пересекаются, Б вытесняет А |
В качестве расчета Б может выступать как расчет, имеющий с А тот же ВР, так и расчет с иным ВР.
ВР, который может вытеснять сам себя, называется самовытесняющимся.
Настройка вытеснения ВР (направление вытеснения), так же как и приоритет, задают-cat в конфигурации при создании или редактировании ВР. В программе можно, применив методы видов расчетов ВытесняетВидРасчета и ВытесняетсяВидомРасчета, узнать, каким образом взаимодействуют два расчета, употребленные с этими методами.
7.З.1.2. ДЛИННЫЕ РАСЧЕТЫ
Расчет называется длинным, если он начинается в одном расчетном периоде, а заканчивается в другом. Длинные расчеты могут существовать только в документах. В 1С длинный расчет при вводе разбивается на обычные, такие, что каждый из них принадлежит к одному расчетному периоду (рис. 7.5).
 |
|
Рис. 7.5. Длинный расчет А разбивается в ЖЗ на два обычных - А1 и А2, лежащих соответственно в расчетных периодах РП1 и РП2 |
7.3.2. ПЕРЕЧЕНЬ ВИДОВ РАСЧЕТОВ ПРЕДПРИЯТИЯ
Для определенности условимся, что на нашем предприятии используются приведенные в табл. 7.2 ВР, в которой сокращение ХО, употребленное в заголовке 5-го столбца, расшифровывается как хозяйственная операция.
Таблица 7.2
ВР предприятия |
|
ВР |
Идентификатор / Синоним |
Результат |
Очеред
ность |
ХО |
Документ |
|
Дебет |
|
ВР0 |
НачСальдо_2 / Начальное сальдо |
Начальное сальдо прежнего периода + Дебет - Кредит + Сторно |
1 |
2013000 |
НачПе-
риода_2 |
|
ВР1 |
Оклад_2 / Оклад |
Оклад * всегоЧасов / всегоЧасов-ПоКалендарю |
1 |
2013000 |
Табель |
|
ВР2 |
Тариф_2 / Тариф |
Тариф * всегоЧасов |
1 |
2013000 |
|
|
ВРЗ |
ПремияКоэф_2/ Премия коэффициентом |
всегоЧасов * к3, где к3 - устанавливаемый руководителем коэффициент. По умолчанию к3 =
10 для всех сотрудников |
5 |
2013001 |
Премия |
|
ВР4 |
ПремияСум_2 / Премия суммой |
Сумма премии |
1 |
2013001 |
|
|
ВР5 |
Премия1234_2/ Премия 1234 |
(ВР1 | ВР2 + ВРЗ + ВР4) * к5, где к5 - постоянный для всех сотрудников коэффициент |
10 |
2013001 |
|
|
Кредит |
|
ВР6 |
НДФЛ_2/Налог на доходы физических лиц |
(ВР1 | ВР2 + ВРЗ + ВР4 + ВР5) * ставкаНалога |
15 |
2017002 |
Табель |
|
ВР7 |
ВБанк_2 / Перечисление в банк |
Целая часть от (ВР0 + ВР1 | ВР2 + ВРЗ + ВР4 + ВР5 - ВР6) |
20 |
2300100 |
|
|
|
Замечания: |
1. Начальное сальдо - это долг за предприятием, если больше нуля, или долг за работником - в противном случае
2. Коэффициент к5 и ставкаНалога добавляются в конфигурацию 1С как периодические константы.
3. ВР Тариф_2, поскольку все сотрудники справочника Сотрудники_2 "сидят" на окладе, в конфигурацию не вводится. Чтобы им воспользоваться, нужно модифицировать справочник Сотрудники_2, добавив в него реквизиты флагОклада и Тариф, задавая флагОклада равным единице, если оплата сотрудника осуществляется по окладу, или равным нулю, если по тарифу.
Приведенных ВР вполне достаточно для демонстрации средств встроенного языка 1С, поддерживающих расчеты и их журнал.
Расчеты с ВР НачСальдо_2, Оклад_2 | Тариф_2, НДФЛ_2 и ВБанк_2 являются обязательными и присутствуют в ЖЗ для каждого сотрудника. В принципе они могли бы вводиться одним документом, например Табель. Однако с целью демонстрации методов ВР и журнала расчетов начальное сальдо будем вводить непосредственно в модуле формы списка ЖЗ, связывая с ВР НачСальдо_2 документ НачПериода_2. Это допустимо, поскольку начальное сальдо не зависит от иных расчетов текущего месяца. Остальные обязательные расчеты будет добавлять в ЖЗ документ Табель.
Премии являются дополнительными расчетами и могут не появляться в ЖЗ (или появляться не в полном объеме) для отдельных сотрудников. Премия суммой в общем случае может быть назначена сотруднику несколько раз по разным поводам. Это обстоятельство надо учесть при расчете зависящих от этой премии записей, то есть расчетов с ВР Премия1234_2, НДФЛ2 и ВБанк_2.
Для всех премий предусмотрим один документ Премия_2.
Результаты ВР5-7 зависят от результатов других расчетов, поэтому подобного рода ВР называются зависимыми. Они, понятно, должны оцениваться после каждого изменения результатов расчетов, от которых они зависят. Это достигается за счет программирования перерасчетов.
Все приведенные в табл. 7.2 расчеты, конечно же, реализуются интерактивными средствами 1С. Но наша задача - освоение возможностей встроенного языка программирования, поэтому мы остановимся на вопросах создания документов, порождающих расчеты, проведения этих документов, то есть ввода в ЖЗ расчетов и организации последующих вычислений.
Документы, связанные с расчетами, мы будем размещать в перечисленных в табл. 7.3 журналах документов.
Таблица 7.3
Журналы документов, порождающих расчеты |
|
Журнал документов |
Ускоритель |
Документ |
|
Расчеты |
Alt+U |
НачПериода_2, Премия_2 |
|
Табель |
Alt+B |
Табель |
|
7.3.3. ДОСТУП К ДОКУМЕНТАМ, ВВОДЯЩИМ РАСЧЕТЫ В ЖУРНАЛ ЗАРПЛАТЫ
В конфигурацию 1С подсистемы Заработная плата и кадры занесено более 200 ВР. Их точное число вернет вызов
Сообщить(Метаданные.ВидРасчета( )); // Сообщит о числе ВР в конфигурации
Число документов в конфигурации существенно меньше - несколько десятков. Не все из них порождают расчеты. Однако немало и таких. Выбор документа, вводящего в ЖЗ расчеты, из списка, содержащего несколько десятков наименований, обременителен. Поэтому поступим так. Разместим в новом перечислении ВР2 (рис. 7.6) имена документов из табл. 7.2, вводящих расчеты.
 |
|
Рис. 7.6. Перечисление для выбора вводимого вЖЗрасчета |
В представлениях значений перечисления В Р 2 отобразим имена соответствующих ВР:
• Начальное сальдо (представление элемента НачСальдо);
• Расчеты Оклад/Тариф, НДФЛ и ВБанк (представление элемента Табель);
• Премия коэффициентом, суммой и 1234 (представление элемента Премия).
В форме списка ЖЗ, вопросы конструирования которой рассматриваются в разд. 7.4, разместим кнопку Ввод расчета, связав с ней процедуру, предоставляющую возможность выбрать из перечисления ВР_2 необходимый для ввода расчетов документ.
7.3.4. ПОРЯДОК ВВОДА И ВЫЧИСЛЕНИЯ РАСЧЕТОВ ЖУРНАЛА ЗАРПЛАТЫ. ПРИОРИТЕТ ВИДОВ РАСЧЕТОВ
Последовательность ввода расчетов в ЖЗ произвольная. Однако в таком случае желательно предусмотреть автоматический перерасчет записей после изменения результата расчета, от которого эти записи зависят. В нашем случае зависимыми являются ВР Премия1234_2, НДФЛ_2 и ВБанк_2. При наличии таких перерасчетов окончательный верный результат будет получаться и без исполнения команды Рассчитать объект, которая находит результат каждого расчета объекта, не меняя значения фиксированных и исправленных вручную результатов.
Порядок вычисления результатов расчетов уже не может быть произвольным, и для его регулирования в 1С каждый ВР снабжается приоритетом, задаваемым целым числом и определяющим очередность выполнения расчета. Причем чем меньше число, указанное для приоритета, тем скорее произойдет вызов процедуры, выполняющей расчет. Очередности (приоритеты) ВР предприятия указаны в табл. 7.2 и пояснений, пожалуй, не требуют. Заметим только, что между значениями приоритетов оставляют промежутки, чтобы при необходимости разместить в них приоритеты вновь появившихся ВР.
Чтобы продемонстрировать методы работы с ЖЗ и его расчетами, определим все расчеты как самовытесняющиеся, а также зададим ВР4 (премия суммой) как вытесняющий ВРЗ (премия коэффициентом).
7.3.5. ДОБАВЛЕНИЕ ВИДОВ РАСЧЕТОВ В КОНФИГУРАЦИЮ
Каждое начисление (удержание) задается в виде отдельного объекта типа ВидРас-чета, хотя в принципе некоторые начисления или удержания можно было бы оформить как один объект, например для начисления всех премий создать в конфигурации ВР Премия и передавать процедуре ПровестиРасчет модуля ВР флаг, указывающий на вид начисляемой премии.
Однако разделение расчетов оправданно, поскольку позволяет задавать приоритеты ВР, управлять вытеснением и перерасчетом, формировать подходящие группы расчетов.
Последуем и мы этой линии разделения ВР. Откроем конфигурацию, переместимся на закладке Метаданные в раздел Виды расчетов и введем новые ВР, а результат отобразим на рис. 7.7.
1?) НэчСальдо_2 Оклад?
і!] ПремияКоэф_2
2] ПремияСі*м_2 ?] Премия1234_2 |] НДФЛ_2 ВБанк_2
Рис. 7.7. ВР сотрудников из справочника Сотрудники_2.
По имеющейся у нас информации мы можем пока что назначить введенным ВР указанный в табл. 7.2 приоритет, и присвоить идентификаторам ВР имена и синонимы.
Замечание. ВР хранятся в файле конфигурации системы 1CV7.MD.
7.3.6. ВИД РАСЧЕТА НАЧАЛЬНОЕ САЛЬДО
7.З.6.1. СВОЙСТВА ВИДА РАСЧЕТА НАЧАЛЬНОЕ САЛЬДО
Зададим их в соответствии с рис. 7.8.
 |
|
Рис. 7.8. Свойства ВР Начальное сальдо |
Это простой по свойствам ВР. Он не является вытесняющим, длинным или зависимым. Правда, он является обязательным и самовытесняющимся. Даты начала и окончания расчетов с ВР Начальное сальдо всех сотрудников одинаковы. Для определенности установим их равными дате начала текущего периода, возвращаемой методом ЖР НачалоТекущегоПериода.
Замечание. Идентификатор, синоним и комментарий ВР выводятся следующими сообщениями:
Сообщить(ВидРасчета.НачСальдо_2.Код);
Сообщить("" + ВидРасчета.НачСальдо_2);
Сообшить(ВидРасчета. НачСальдо_2. Наименование);
Результат:
НачСальдо_2 Начальное сальдо
Долг за предприятием или сотрудником
7.3.6.2. МОДУЛЬ ВИДА РАСЧЕТА НАЧАЛЬНОЕ САЛЬДО
Проста и формула расчета результата ВР Начальное сальдо:
// начСальдоСтар - начальное сальдо предшествующего расчетного периода начСальдоНовое = начСальдоСтар + Дебет - Кредит + Сторно;
В нашем случае
Дебет = Оклад_2 | Тариф_2 + ПремияКоэф_2 + ПремияСум_2 + Премия 1234_2;
Кредит = НДФЛ_2 + ВБанк_2;
// Сторно - результаты расчетов, возникших при исправлении ошибок
При отсутствии какого-либо ВР соответствующее слагаемое в формуле расчета начального сальдо равно нулю.
В модуль ВР Начальное сальдо включим следующий код:
функция НачСальдо(Сотрудник, нтп) далее
процедура ПровестиРасчет() // Выполняется при проведении расчета
// Результат, Объект - атрибуты ЖЗ
Результат = НачСальдо(Объект, НачалоТекущегоПериода()); конецПроцедуры
// Считает начальное сальдо функция НачСальдо(Сотрудник, нтп)
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); сальдо = 0;
жз.ВыбратьПериодПоОбъекту(Сотрудник, нтп- 1); пока жз.ПолучитьЗапись( )=1 цикл
если жз.ВидРасч.ВходитВГруппу(ГруппаРасчетов.ВсеУдержания_2) = 1 тогда сальдо = сальдо - жз.Результат; иначеЕсли жз.ВидРасч = ВидРасчета.ВБанк_2 тогда сальдо = сальдо - жз.Результат;
иначе // Дебет или сторнированный расчет
сальдо = сальдо + жз.Результат; конецЕсли; конецЦикла; // пока возврат сальдо; конецФункции // НачСальдо
В функции НачСальдо есть ссылка на группу ВР ВсеУдержания_2. Технология объединения ВР в группы, используемая 1 С, весьма продуктивна, позволяя, в частности, существенно сокращать код создаваемых программ. Внешне группа ВР представляется как список в нее входящих ВР. Но по существу группа ВР - это объект 1С, обладающий атрибутами и методами.
В нашем случае в группу ВсеУдержания_2 войдет лишь ВР НДФЛ_2 (рис. 7.9), и мы вместо строки кода
если жз.ВидРасч.ВходитВГруппу(ГруппаРасчетов.ВсеУдержания_2) = 1 тогда могли бы записать
если жз.ВидРасч = ВидРасчета.НДФЛ_2 тогда
 |
|
Рис. 7.9. Новая группа ВРВсеУдержания_2 |
Однако чтобы сохранить работоспособность кода на случай добавления новых удержаний, оставим его без изменений. Конечно, нужно всегда помнить: каждое новое удержание должно быть добавлено в группу ВсеУдержания_2, иначе ВР Начальное сальдо и все иные ссылающиеся на эту группу программы будут давать неверные результаты.
Возможность включения ВР в существующие в конфигурации группы предоставляется 1С уже при вводе ВР (см. рис. 7.8). Однако чтобы это действие выполнять осознанно, нужно иметь информацию, какие группы и для каких целей используются. Ее можно сосредоточить в описании группы ВР (рис. 7.10), корректируя его каждый раз при добавлении или удалении ссылок на группу.
 |
|
Рис. 7.10. Включаем в описание группы ВР сообщение об объекте, в котором есть ссылка на группу |
Как мы ранее условились, ввод расчетов с ВР Начальное сальдо будет осуществляться непосредственно из модуля формы списка ЖЗ. Это выполняется методами ЖР Новая, УстановитьРеквизит и Записать. Специфика метода Записать в том, что он не проверяет правила вытеснения и перерасчета ВР, даже если они есть. Поскольку ВР Начальное сальдо является самовытесняющимся, то надо либо запретить ввод начального сальдо, если расчет с таким ВР объект уже имеет, либо заменить существующий на новый. Мы остановимся на первом варианте. Он логичен, поскольку начальное сальдо вычисляется по данным закрытого, отнесенного в архив периода и не должно изменяться во времени.
При вводе ВР Начальное сальдо сразу же будем вычислять и фиксировать его значение, вызывая метод ЖР ВыполнитьРасчет и устанавливая в атрибут ЖР Фиксирована число 1.
7.3.6.3. ДОКУМЕНТ НачПериода_2
Назначение документа НачПериода_2 - это фиксация факта смены расчетного периода: каждая плановая смена должна сопровождаться расчетом начального сальдо сотрудников. На документ НачПериода_2 согласно табл. 7.2 должны ссылаться расчеты с ВР НачСальдо_2. Эта ссылка фиксируется атрибутами ЖР Документ и Родитель-скийДокумент и носит формальный характер, ибо без нее нельзя ввести расчет в ЖЗ. С другой стороны, такой документ полезен, поскольку в нем будут отражаться такие важные операции, как смены расчетных периодов.
Документ будем фиксировать в новом журнале Расчеты, в котором будут размещаться и все иные, кроме Табеля, документы, вводящие расчеты в ЖЗ Зарплата_2.
Удобнее всего факт смены расчетного периода было бы выполнять в предопределенной процедуре модуля формы ЖР ПриСменеРасчетногоПериода. Однако такой процедуры нет, но взамен есть одноименная процедура глобального модуля. Именно в нее мы поместим вызов процедуры ФиксироватьСменуРП. Чтобы гарантировать вызов этой процедуры после выполнения всех проверок, код ее вызова нужно расположить в конце предопределенной процедуры ПриСменеРасчетногоПериода.
Вызов процедуры ФиксироватьСменуРП может быть таким:
// Это предварительное описание разместим до кода // предопределенной процедуры ПриСменеРасчетногоПериода процедура ФиксироватьСменуРЩжз, период) далее
процедура ПриСменеРасчетногоПериода(Жрн, Период)
// Меняем расчетный период в ЖЗ Зарплата_2 если Жрн.Вид() = "Зарплата_2" тогда
ФиксироватьСменуРЩЖрн, Период);
конецЕсли;
конецПроцедуры // ПриСменеРасчетногоПериода
Саму же процедуру ФиксироватьСменуРП расположим в конце глобального модуля: процедура ФиксироватьСменуРЩжз, период)
// Тело процедуры ФиксироватьСменуРП
конецПроцедуры // ФиксироватьСменуРП
Написание кода процедуры завершим после создания документа НачПериода_2, в табличной части которого определим 3 реквизита: НовПериод, ДатаУстановки и Пользователь. Первому и третьему назначим символьный тип с длиной строки в 15 символов, а второму - тип Дата. Такие реквизиты позволят нам фиксировать не только факт смены расчетного периода, но и лицо, смену осуществившее.
Все столбцы табличной части документа сделаем недоступными для редактирования, а в шапке документа разместим лишь заголовок таблицы (рис. 7.11).
 |
|
Рис. 7.11. Диалог формы документа Начальное сальдо |
Иные свойства документа определим в соответствии с рис. 7.12.
Идентификатор: |НачЛериода_2
Котаиентарий | Для ЖЗ Зарплага_2
Жідная
Сменим
Расчеты
ачало периода |
|
Реквизиты шагжи |
|
Реквизиты табличной части |
|
ш |
|
|
НоеПеоиоа |
|
|
|
ЛатаУстановки |
|
|
|
|
Пользователь |
|
Новый 1 И |
|
|
Новый 1 Изменить 1 Уда/?гъ | |
|
Номер
Ніриератор: j<< Не назначен >>
-Тмі-
<• Числовой Текстовый |
~3
Г” ^онгро/ь уникальности
Г Ьу^агтер'»:'t'v"r ' :
Г* учет
Периооимюсть: | По всем данного в?ша I
- Автоматическая нумерация Г” Раэреимть проведение документа F? Автоматическая нумерация строк
Рис. 7.12. Свойства документа НачПериода 2
Теперь ясен и текст процедуры ФиксироватьСменуРП:
// Заносит данные о смене расчетного периода в документ НачПериода_2 процедура ФиксироватьСменуРП(жз, период)
// период - переменная типа РасчетныйПериод перем док;
док = СоздатьОбъект("Документ.НачПериода_2");
// Номер документа не меняется и всегда равен единице док.НайтиПоНомеру(1, Дата(0)); если док.Выбран( ) = 1 тогда
док.НоваяСтрока(); // Добавляем в документ новую строку
док.НовПериод = жз.ОписательПериода(период.ДатаНачала);
// Дата смены расчетного периода ЖЗ Зарплата_2 док.ДатаУстановки = ТекущаяДата();
док.Пользователь = ИмяПользователя( ); док.Записать();
// Открываем документ НачПериода_2 под номером 1 для контрольного просмотра ОткрытьФорму(док.ТекущицДокумент()); иначе
Предупреждение(''Документа НачПериода_2 под номером 1 нет."); конецЕсли;
конецПроцедуры // ФиксироватьСменуРП
Чтобы предотвратить интерактивное редактирование документа НачПериода_2, снабдим модуль формы документа следующими предопределенными процедурами:
процедура ПриУдаленииСтроки()
Предупреждение(''В этом документе нельзя удалять записи.");
СтатусВозврата(0);
конецПроцедуры // ПриУдаленииСтроки процедура ПриВводеСтроки()
Предупреждение("В этот документ нельзя добавлять записи.");
СтатусВозврата(0); конецПроцедуры // ПриВводеСтроки
процедура ПриОткрытии()
форма.ПанельИнструментов(0); // Отключаем панель инструментов
конецПроцедуры // ПриОткрытии
Запрет на редактирование данных мы наложили, сделав недоступными столбцы табличной части документа.
Для создания и записи в журнал Расчеты документа НачПериода_2 с номером 1 воспользуемся обработкой Проба, разместив в ней на этот раз следующий код:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем док;
док = СоздатьОбъект("Документ.НачПериода_2");
// Номер документа не меняется и всегда равен единице док.НайтиПоНомеру(1, Дата(0)); если док.Выбран() = 1 тогда
Предупреждение("Документ НачПериода_2 под номером 1 уже есть."); иначе
док.Новый(); док.НомерДок = 1; док.ДатаДок = ТекущаяДата(); док.Записать();
ОткрытьФорму("Журнал.Расчеты"); конецЕсли;
конецПроцедуры // Выполнить
Результат приведен на рис. 7.13
 |
|
Рис. 7.13. Создан документ НачПериода_2 под номером 1 |
В дальнейшем иных документов вида НачПериода_2 создаваться не будет, а все записи о смене расчетных периодов будут направляться в документ № 1.
7.3.7. СПРАВОЧНИК ХОЗЯЙСТВЕННЫХ ОПЕРАЦИЙ ВИДОВ РАСЧЕТОВ
С каждым ВР связана некоторая хозяйственная операция. Эту взаимосвязь отобразим в справочнике ХозОпДляВР, разместив в нем два дополнительных реквизита:
1) ВР типа ВидРасчета;
2) ХозОп с разновидностью типа Справочник.ХозяйственнаяОперация.
Число уровней справочника - 1. Длину атрибута Код установим равной трем, Наименования - нулю. Для редактирования используем форму списка (рис. 7.14).
 |
|
Рис. 7.14. Хозяйственные операции ВР |
Вызов справочников будем осуществлять из колонки Бухучет зарплаты меню интерфейса Ученик (рис. 7.15).
- ^ Бухучет зарплаты
0 Хозяйственные операции 0 План счетов 0 Виды аналитического учета 0 Хозоперации ВР
|
Рис. 7.15. Вспомогательные справочники для ведения бухучета зарплаты |
 |
Справочник ХозяйственнаяОперация имеется в базовой конфигурации Заработная плата и кадры и содержит, если заполнен, приведенные на рис. 7.16 данные.
Значения полей справочника ХозОпДляВР выбираются из раскрывающихся предоставляемых 1С списков. После заполнения, которое производится по данным табл. 7.2, справочник отобразится в соответствии с рис. 7.14.
Замечание. Данные, необходимые для бухгалтерского учета заработной платы и, в частности, для использования справочником ХозяйственнаяОперация, передаются в конфигурацию Заработная плата и кадры из конфигурации Бухгалтерский учет следующим образом. Первоначально из конфигурации Бухгалтерский учет в результате выполнения цепочки Сервис - Обмен данными - Выгрузка данных в конфигурацию "Зарплата + Кадры" в текстовый файл, например D:\lCv77\lsbtrans.txt, выгружаются объекты бухгалтерского учета и счета (из плана счетов) и соответствующие им статьи аналитического учета. (Если счета не выбраны, то из бухгалтерии будет выгружен заданный по умолчанию набор счетов.) Затем данные обменного файла загружаются программой Заработная плата и кадры в результате применения цепочки Сервис - Обмен данными - Загрузка данных -выбор файла с данными, например D:\lCv77\lsbtrans.txt, - Загрузить. Принятые данные используются в процессе заполнения справочника ХозяйственнаяОперация.
Создадим теперь журнал Зарплата_2 и введем в него расчеты с ВР НачСальдо_2.
7.4. ПОСТРОЕНИЕ ЖУРНАЛА ЗАРПЛАТА
7.4.1. АТРИБУТЫ ЖУРНАЛА РАСЧЕТОВ И ЕГО ПЕРИОДА
ЖР - это вполне готовый к употреблению объект, снабженный большим числом атрибутов и методов. Атрибуты журнала - это и есть те самые графы, заполняемые для каждого расчета (записи) журнала.
Поэтому, учитывая хорошую оснащенность журнала, нам не придется потратить много сил на создание свой версии ЖЗ (напомним, что ЖЗ - это одна из возможных реализаций ЖР), но понадобится детально ознакомиться с заложенными в него разработчиками 1С свойствами. Прежде остановимся на атрибутах, разместив их в табл. 7.4.
Таблица 7.4
Атрибуты ЖР и его периода |
|
Атрибут |
Описание |
Тип |
|
Атрибуты расчетного периода ЖР |
|
ДатаНачала |
Дата начала расчетного периода (РП). Устанавливается при смене РП. Является компонентом объекта типа Расчет-ныйПериод |
Дата |
|
ДатаОкончания |
Дата окончания РП. Устанавливается при его смене. Является компонентом объекта типа РасчетныйПериод |
|
|
ОписательПериода |
Символьное представление РП. Так, если ДатаНачала = '01.12.2001', а ДатаОкончания = '31.12.2001', то ОписательПериода = "Декабрь 2001 г.". Полезен при формировании отчетов |
Символь
ный |
|
Атрибуты ЖР |
|
Документ |
Ссылка на документ, на основании которого расчет введен в ЖР. Автоматически заполняется в момент проведения документа. Если документа-основания нет, то совпадает с родительским документом |
Документ |
|
Родительский
Документ
Документ, который ввел расчет в ЖР. Автоматически заполняется в момент проведения документа, добавляющего расчет в ЖР
Объект
Ссылка на элемент справочника-объекта расчета. В нашем случае имеет разновидность типа Справочник. Сотрудники_2. Для сотрудников из этого справочника в ЖЗ заносятся записи о начислениях и удержаниях, из которых складывается зарплата
Зависит от вида объекта
ВидРасч
Ссылка на процедуру, осуществляющую расчет текущей записи. Предназначен для чтения
Вид
Расчета
ДатаНачала
Дата начала действия расчета. Определяется при проведении родительского документа; если дата в нем не задана, то становится равной дате начала текущего расчетного периода. Предназначен для чтения
Дата
ДатаОкончания
Дата окончания действия расчета. Определяется так же, как и ДатаНачала. Значения атрибутов ДатаНачала и ДатаОкон-чания каждого расчета лежат в пределах одного расчетного периода. Предназначен для чтения
ПериодДействия
РП, в который попадают даты начала и окончания действия расчета. Пользователем не устанавливается, а определяется значениями атрибутов ЖР ДатаНачала и ДатаОкончания. Предназначен для чтения
Расчетный
Период
Период
Регистрации
Сторно’
Рассчитана
Исправлена
РП, в котором расчет введен в ЖР. Пользователем не устанавливается. Предназначен для чтения
Получает значение 1, если запись является сторнирующей, или 0 - для обычных записей. Сторнированные нерассчитан-ные записи отмечаются в ЖЗ иконкой G3, а рассчитанные -иконкой &3
Получает значение 1, если запись рассчитана, или О-в противном случае. Расчет выполняется либо по соответствующей команде колонки меню Действия, либо в результате применения метода ЖР Рассчитать или ВыполнитьРасчет. Нерассчитанные записи сопровождаются в ЖР иконкой СИ), рассчитанные - иконкой itl
Получает значение 1, если расчет исправлен вручную, или О, если ручная правка отменена или ее не было вовсе. Исправленные вручную записи сопровождаются в ЖР иконкой ІО. Ручное редактирование имеет больший приоритет, чем автоматический расчет, то есть исправленные вручную записи при очередном сеансе расчета не обновляются. Атрибут обнуляется в результате выполнения Действия - Отменить ручное исправление. После отмены запись считается нерассчи-танной и подлежит перерасчету
Числовой
Сторно - бухгалтерская запись, сделанная красными чернилами для исправления ошибок путем внесения дополнительной бухгалтерской проводки отрицательными числами. При подсчете итогов числа, записанные красными чернилами, вычитаются.
|
Атрибут |
Описание |
Тип |
|
[фиксирована |
Получает значение I, если расчет фиксирован, или 0 - в противном случае. Фиксируется при выполнении метода ЖР ФиксироватьЗапись. Результат расчета фиксированной записи не может быть изменен. Переводится в разряд нефиксированных расчетов методом ОсвободитъЗапись. Сопровождается в ЖР скрепкой на желтом фоне - КД Фиксируются, например, записи о перечислениях зарплаты в банк на лицевые счета сотрудников |
И |
|
Перерасчет |
Получает значение 1, если запись является перерасчетом иной записи прошлого периода, или О-в противном случае. Перерасчеты вводятся в ЖР методом ВвестиПерерасчет или ВвестиПерерасчетНаОсновании. Предназначен для чтения. Сопровождается в ЖР следующей иконкой: &У |
N |
|
ПервичнаяЗапись |
Запись, на основании которой введен текущий перерасчет. Получает значение при выполнении методов ВвестиПерерасчет и ВвестиПерерасчетНаОсновании. Предназначен для чтения |
Запись
Журнала
Расчетов |
|
Результат |
Результат расчета |
Числовой |
|
<Реквизит> |
Произвольный, дополняющий встроенные атрибуты, сопровождающий расчет реквизит |
• |
|
|
Наши ближайшие задачи - это определение дополнительных реквизитов ЖЗ и конструирование журнала. |
7.4.2. ДОБАВЛЕНИЕ ЖУРНАЛА ЗАРПЛАТЫ В КОНФИГУРАЦИЮ СИСТЕМЫ
Взамен имеющегося в 1С ЖЗ, например в конфигурации Заработная плата и кадры, создадим новый ЖЗ, дав ему имя Зарплата_2.
Откроем конфигурацию, остановимся на пункте Журналы расчетов, присутствующем на закладке Метаданные, и добавим в него новый подпункт (рис. 7. 17).
В 0 Журналы расчетов ' № Ц Зарплата ; Efr ? Зарплата_2
|
Рис. 7.17. Новый журнал расчетов |
 |
а
б |
Отвечая на вопросы конструктора ЖЗ, определим объект и период в соответствии с рис. 7.18.
В качестве дополнительных используем приведенные в табл. 7.5 реквизиты.
Таблица 7.5
Дополнительные реквизиты ЖЗ |
|
Реквизит |
Описание |
Примечание |
|
всегоЧасов |
Число часов, отработанных сотрудником в расчетном периоде |
Имеет числовой тип и формат 5.1 |
|
хозОп |
Связанная с расчетом хозяйственная операция |
Имеет разновидность типа
Справочник.Хозяйственная
Операция |
|
строкаДок |
Номер строки табличной части документа, породившего расчет |
Имеет числовой тип и формат 5.0 |
|
Встроенных атрибутов ЖЗ и трех дополнительных реквизитов вполне достаточно для расчета зарплаты, ее бухгалтерского учета, выпуска сопровождающих расчет отчетов и даже для перечислений в банк. Кстати, последние возможны, если в справочнике Сотрудники_2 хранятся лицевые счета объектов расчета. Для упрощения положим, что номера лицевых счетов совпадают с кодами сотрудников, но предваряются префиксом Б-, например Б-301.
Реквизит строкаДок полезен, если один документ порождает несколько расчетов. Такие документы у нас есть, например Табель. Тогда, зная значение строкаДок, методом документа ПолучитьСтрокуПоНомеру сразу же находится строка табличной части документа, отвечающая рассматриваемой записи ЖЗ. Правда, доверять значению этого реквизита можно, если между строками табличной части документа и расчетами существует устойчивая связь. Она может нарушиться, например, если после удаления строки табличной части документ сохраняется без перепроведения. Таким образом, для документа передающего в ЖЗ значение реквизита строкаДок, необходимо в модуле документа вызвать метод документа, причем с единичным параметром, например, так:
процедура ПриЗаписи() // Предопределенная процедура модуля документа
ПриЗаписиПерепроводить(1); конецПроцеауры // ПриЗаписи
Можно обойтись и без вызова метода ПриЗаписиПерепроводить, если с кнопкой ОК формы документа связать такую последовательность команд:
#3аписать Провести Закрыть
Окно с заданными свойствами и реквизитами ЖЗ приведем на рис. 7.19.
Журнал расчетов зарплата 2
?і*юним |. Куриал заработной плап
I Зарплата. 2
Идентификатор
М»МНІ ИМИ
Справочник
I Расисты сотруамаюе из справок »м Сотруат*<*я_2
IСотруанмки_2
Пермооичность Размер I Месяц
Дата отсчета (01 01.01
Результат
Горюетъ
Новый
Удаляь
Графы отбора
•/ Роците/ь Оклад
?Образование
ПржаэОклад
-1 Зашсымтьна...
(* конец
начало
ПржазЛрием
Описание
Рис. 7.19. Характеристики вновь построенного ЖЗ
Графами отбора могут быть реквизиты справочника, элементы которого используются в качестве объектов ЖЗ. Отмеченная нами графа отбора Родитель позволит отображать в ЖЗ не всех сотрудников одновременно, а лишь работающих в выбранном подразделении. Закладки появляются и удаляются методом модуля формы журнала ЗакдадкиОтбора. Если графой отбора является периодический реквизит справочника, то для него нужно выбрать радиокнопку Записывать на конец или начало расчетного периода.
Замечания:
1. Для нового ЖЗ система создаст файл, возможно CJ4287.DBF.
2. Впоследствии мы введем еще одну графу отбора - Образование (разд. 7.13, пример 9).
7.4.3. ФОРМА СПИСКА ЖУРНАЛА ЗАРПЛАТЫ
В форме списка ЖЗ отобразим необходимую для визуального контроля расчетов информацию: ФИО сотрудника, ВР, а точнее, его представление, число отработанных часов (графа Часы), результат и даты начала и окончания расчета (рис. 7.20).
Размещение per визитов т урнала Расчетов
? Объект
ВиоРасч
? ДатаНачала ? ДатаОкончания ? Резугьтат ? чозОп
ПвсегоЧасое
Р Разместить в диалоге автоматически
|
Приведем предложенный 1С диалог формы к представленному на рис. 7.21 виду. |
 |
|
Рис. 7.21. Диалог формы списка ЖЗ |
Все столбцы, кроме столбцов Хоз. оп. и Результат, оставим доступными только для просмотра. (Свойства столбца, напомним, меняются после его выделения и выполнения цепочки Действия - Свойства или нажатия на Alt + Enter.) Возможность смены хозяйственной операции в ЖЗ должна быть предусмотрена, так как в документах, порождающих расчеты, изменить хозяйственную операцию нельзя: она берется как есть из созданного нами справочника ХозОпДляВР (разд. 7.3.7). Заметим, что изменить хозяйственную операцию фиксированных расчетов не удастся и в ЖЗ.
Первый столбец ЖЗ предназначен для показа сопровождающих расчеты иконок (пиктограмм). Столбец с именем ВР добавлен в таблицу после выбора иконки /
на панели инструментов Элементы диалога. В поле Формула этого столбца размещено выражение
+ ВидРасч
выводящее в ячейки столбца не идентификатор ВР, а его синоним.
Размещенный в верхнем правом углу флажок, имеющий заголовок По цехам и идентификатор закл, включат и отключает закладки отбора, то есть управляет режимом вывода данных по цехам.
Радиокнопки Сотрудник и Цех, задают режимы расчетов Начало месяца, итоговой заработной платы, а также режимы вывода документов - печати расчетного листка и ведомости перечислений в банк.
Радиокнопки, или переключатели, являются новым для нас элементом диалога. Для взаимосвязи радиокнопки размещаются в группе, в нашем случае имеющей название Режим расчета. Группа формируется следующим образом:
1. Добавляется радиокнопка (выбирается иконка на панели инструментов Элементы диалога) с заголовком Сотрудник, ей присваивается идентификатор кто (имя может быть произвольным), который и будет служить идентификатором группы. На закладке Дополнительно этой радиокнопке задается свойство Первый в группе.
2. Добавляется радиокнопка с заголовком Цех, и ей присваивается идентификатор кто2, который нам пригодится для управления доступностью кнопки. Никаких дополнительных свойств для нее не задается.
3. Кнопки обводятся рамкой группы (задается иконкой И), которой присваивается заголовок Режим расчета.
Замечание. Бывает, что 1С "капризничает" и не хочет объединять обведенные радиокнопки в группы. Однако с этим можно справиться, если имя кто и свойство Первый в группе приписать крайнему справа переключателю.
Переменная диалога кто принимает значения:
• 1, если выбрана радиокнопка Сотрудник; и в этом случае команды ЖЗ, например команда печати расчетного листка или ведомости перечислений в банк, выполняются для одного выбранного в ЖЗ сотрудника;
• 2, если выбрана радиокнопка Цех; команды ЖЗ выполняются для сотрудников отображаемого в ЖЗ подразделения.
Если в ЖЗ представлено все предприятие (закл = 0), то кто = 1 и радиокнопки недоступны, и тогда расчеты производятся для одного сотрудника.
В верхней правой части диалога разместим кнопки с картинками - обычные кнопки, в которых заголовок заменен на картинку, выбираемую на соответствующей закладке окна задания свойств кнопки (рис. 7.22).
|
Обшив I Допоо«тел>но | Комамаа ;| Orwcame |
|
|
-Рисовать-
Растянуть
По центру Пропорцион |
|
|
|
Изменить карт?ыу |
|
|
Рис. 7.22. Задание картинки для кнопки |
С элементами диалога формы списка ЖЗ свяжем перечисленные в табл. 7.6 формулы. Они, напомним, пишутся на закладке Дополнительно в окне задания свойств элементов диалога.
Таблица 7.6
Элементы диалога формы списка ЖЗ и их формулы |
|
Элемент диалога |
Формула/комацда |
Описание |
По цехам (имеет
идентификатор
закл) |
ПоЦехам() |
Включает/отключает режим вывода расчетов по цехам. Радиокнопки становятся недоступными, если закл = 0. При этом значение кто устанавливается равным единице |
|
Режим расчета; радиокнопки Сотрудник и Цех (имеет идентификатор кто) |
ЗиачКтоСтар() |
Запоминает значение переменной кто, для его восстановления при выборе режима отображения по цехам, то есть когда закл = 1 |
|
Ввод расчета |
ВводРасчета() |
Позволяет выбрать документ, вводящий новые расчеты, открыть форму документа и ввести нужные расчеты (описание ВР см. в табл. 7.2) |
|
|
Элемент диалога |
Формула/команла |
Описание |
|
Расчет зарплаты |
РасчетЗП() |
Рассчитывает зарплату одного сотрудника или сотрудников выбранного подразделения |
|
|
|
ОткрытьФорму
(Объект,, 1) |
Открывает для просмо гра форму элемента справочника Сотрудники_2 |
|
¦ ш |
|
ПечатьРЛ() |
Формирует расчетные листки и выводит их на печать |
|
|
|
ВедомостьБанк() |
Формирует ведомость перечислений в банк |
|
Закрыть |
#3акрыть |
Запускается предопределенная процедура ПриЗакрытии |
Замечание. Процедуры РасчетЗП, ПечатьРЛ и ВедомостьБанк, а также расчет начального сальдо выполняются для одного сотрудника, если кто = 1 (активна радиокнопка Сотрудник), для сотрудников выбранного подразделения, либо, если кто = 2 (активна радиокнопка Цех).
Теперь можно добавить в меню интерфейса Ученик команду вызова ЖЗ Зарпла-та_2 (рис. 7.23), связав с ним указанные на рис. 7.24 свойства и задав акселератор Alt+C.
ЕЁ Журналы
0 Кадровые приказы 0 Журнал эарплаты_2
Рис. 7.23. Новый пункт меню интерфейса Ученик
 |
|
Рис. 7.24. Свойства пункта Журнал зарплаты_2 |
Теперь ЖЗ доступен для приема данных и просмотра. Для их обработки мы разместим в модуле формы списка ЖЗ подходящие программы.
7.4.4. МОДУЛЬ ФОРМЫ СПИСКА ЖУРНАЛА ЗАРПЛАТЫ
Содержит процедуры, управляющие элементами диалога, позволяющие выбирать ВР для ввода в ЖЗ, выполнить расчет зарплаты и сформировать расчетные листки и ведомости перечислений в банк. Чтобы новый сеанс работы начинался с того же места, где завершился прежний, в программе сохраняются в предопределенной процедуре ПриЗакрытии и восстанавливаются в предопределенной процедуре ПриОткрытии соответствующие параметры формы списка ЖЗ.
7.4.4.1. ПРОЦЕДУРЫ, УПРАВЛЯЮЩИЕ ЭЛЕМЕНТАМИ ДИАЛОГА
// ктоСтар - значение элемента кто до установления значения закл = О перем ктоСтар;
перем нтп; // Начало текущего периода
перем тДок; // Текущий документ
// Объект с разновидностью типа Справочник.ХозОпДляВР перем хозОп;
процедура ПоЦехам() далее
// Процедура нужна, чтобы правильно реагировать на переключения флажка закл процедура ЗначКтоСтар() ктоСтар = кто;
конецПроцедуры // ЗначКтоСтар
процедура ПриЗакрытии() // Предопределенная процедура
перем значОтбора; // Текущее значение отбора при закл = 1
перем реж, значРеж; // Представление: списком или по одному объекту
// Сохраняем на диске значения переменных диалога закл, кто и иных установок
// для следующего сеанса работы
СохранитьЗначение("ЗакладкиВЗарплате", закл);
СохранитьЗначение("КтоВЗарплате", кто);
СохранитьЗначение("ЗначениеОтбора", Объект. Родитель);
// Представление: список или один сотрудник ПолучитьПредставление(реж, значРеж);
СохранитьЗначение("РежимПредставления", реж); СохранитьЗначение("ЗначениеПредставления", значРеж); конецПроцедуры // ПриЗакрытии
процедура ПриОткрытии() // Предопределенная процедура
перем реж, значРеж;
// Восстанавливаем с диска значения переменных диалога закл и кто // для текущего сеанса работы
закл = ВосстановитьЗначение("ЗакладкиВЗарплате");
если ТипЗначения(закл) = 0 тогда // Если значение переменной закл не восстановлено закл = 1; кто= 1; иначе
кто = ВосстановитьЗначение("КтоВЗарплате"); конецЕсли; ктоСтар = кто;
ПоЦехам(); если закл = 1 тогда
значОтбора = ВосстановитьЗначение("ЗначениеОтбора");
ЗакладкиОтбора(" Родитель", значОтбора); конецЕсли;
реж = ВосстановитьЗначение("РежимПредставления"); значРеж = ВосстановитьЗначение("ЗначениеПредставления"); если реж = 1 тогда
УстановитьПредставление( 1);
иначе
УстановитьПредставление(реж, значРеж); конецЕсли;
нтп = НачалоТекущегоПериода(); конецПроцедуры // ПриОткрытии
// Включает/отключает режим вывода по цехам. Если закл = 0, то устанавливает // кто = 1 и делает недоступными радиокнопки группы Режим расчета процедура ПоЦехам()
если закл = 1 тогда // Если используются закладки отбора
ЗакпадкиОтбора("Родитель"); кто = ктоСтар;
Форма.Кто. Доступность(І);
Форма.Кто2.Доступность(1);
иначе
ЗакладкиОтбора(""); кто = 1;
Форма. Кто .Доступность(О);
Форма.Кто2.Доступность(0);
конецЕсли;
конецПроцедуры // ПоЦехам()
7.4.4.2. ВЫБОР ВИДА РАСЧЕТА ДЛЯ ВВОДА В ЖУРНАЛ ЗАРПЛАТЫ
Осуществляется из перечисления ВР_2. Ввод начального сальдо выполняется процедурами модуля ЖЗ, а иных ВР - соответствующими документами.
процедура НачСальдо() далее
процедура ВводРасчета()
перем значПер, флаг, докВид; значПер = "ВР_2";
// Вид ВР выбирается из диалога, представленного на рис. 7.25
флаг = ВвестиПеречисление(значПер, "Выберите виды расчетов для ввода");
// Если нажали OK, Enter или дважды ударили мышью по выбранному значению если флаг = 1 тогда
докВид = значПер.Идентификатор(); если докВид = "НачСальдо” тогда
НачСальдо(); // Ввод начального сальдо
жз = 0;
иначе // Табель или Премия
// Расчеты вводятся документом ОткрытьФорму(" Документ.” + докВид); конецЕсли; иначе
Предупреждение("Ничего не выбрано."); возврат; конецЕсли;
конецПроцедуры // ВводРасчета
 |
|
Рис. 7.25. Диалог для выбора вида документа |
7.4.4.3. ВВОД НАЧАЛЬНОГО САЛЬДО
Выполняется, если кто = 1, для выбранного в справочнике Сотрудники_2 сотрудника либо для выбранного подразделения. Если сотрудник уже имеет в текущем расчетном периоде расчет в ВР НачСальдо_2, то при повторном вводе меняется лишь результат расчета.
Выбранное подразделение возвращается методом модуля формы ЖР ПолучитьОтбор.
процедура одинСотр(сотр) далее функция ЕстьВЖЗ(сотр) далее
// Заполняет ЖЗ расчетами с ВР НачСадьдо_2 процедура НачСальдо()
перем док, грОт, подр; // подр - значение отбора
перем сСотр_2, флаг;
нш = НачалоТекущегоПериода();
док = СоздатьОбъект("Документ.НачПериода_2");
если док.НайтиПоНомеру(1) = 0 тогда
ПредупреждениеС'Нельзя ввести начальное сальдо. Нет документа НачПериода_2 №1”); возврат; конецЕсли;
тДок = док.ТекущийДокумент();
// Определяемся относительно хозяйственной операции для ВР НачСальдо_2 хозОп = СоздатьОбъект(”Справочник.ХозОпДляВР”);
// Ищем простым перебором в справочнике ХозОпДляВР вид расчета НачСальдо_2
хозОп.ВыбратьЭлементы();
флаг = 0;
пока хозОп.ПолучитьЭлемент() = 1 цикл
если хозОп. ВР = ВидРасчета.НачСальдо_2 тогда флаг= 1; прервать; конецЕсли; конецЦикла; // пока если флаг = 0 тогда
Предупреждение(”Хозяйственная операция для ВР Начальное сальдо не найдена”); возврат; конецЕсли;
// Начало месяца для одного сотрудника. Разрешим множественные выбор если кто = 1 тогда
ОткрытьПодбор(”Справочник.Сотрудники_2”, "ФормаСписка”,, 1); иначеЕсли закл = 1 тогда // Используем закладки отбора
// При первом использовании ЖЗ закладки отбора в нем не отображаются,
// даже если закл = 1; в этом случае начальное сальдо вводится для всех сотрудников
ПолучитьОтбор(грОт, подр); // подр - значение отбора; имеет тип Справочник сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сСотр_2.ИспользоватьРодителя(подр); сСотр_2. ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл если сСотр_2.ЭтоГруппа() = 0 тогда
// Ввод начального сальдо для одного сотрудника одинСотр(сСотр_2.ТекущийЭлемент()); конецЕсли; конецЦикла; // пока
УстановитьПредставление(1); // Отображаем записи по всем объектам // Если в ЖЗ нет записей, тогда подр имеет пустое значение; вводятся все // сотрудники и для отображения закладок отбора вызываем процедуру ПоЦехам если ПустоеЗначение(подр) = 1 тогда ПоЦехам(); конецЕсли;
Форма.Обновить();
конецЕсли;
конецПроцедуры // НачСальдо процедура ОбработкаПодбора(сотр, конт)
одинСотр(сотр); // Начальное сальдо для одного сотрудника
если закл = 0 тогда
закл = 1; // Показываем закладки отбора
ПоЦехам(); конецЕсли;
УстановитьПредставление(2, сотр); // Отображаем записи по одному объекту конецПроцедуры // ОбработкаПодбора
процедура одинСотр(сотр)
// Если расчет с ВР НачСальдо_2 объект уже имеет, то обновляем только результат если ЕстьВЖЗ(сотр) = 0 тогда
// Добавляем расчет с ВР НачСальдо_2 для выбранного сотрудника Новая();
УстановитьРеквизит("Документ", тДок); УстановитьРеквизит("РодительскийДокумент", тДок);
УстановитьРеквизит("Объект", сотр);
УстановитьРеквизит("ВидРасч", ВидРасчета.НачСальдо_2); УстановитьРеквизит("хрзОп", хозОп.ХозОП);
УстановитьРеквизит("ДатаНачала", нтп);
УстановитьРеквизит("ДатаОкончания", нтп); иначе // Делаем расчет нефиксированным
// Журнал позиционирован функцией ЕстьВЖЗ на нужной записи // Подготовка к обновлению результата
ОсвободитьЗапись(); // Делаем запись нефиксированной конецЕсли;
Записать( ); // Не забываем записать новые значения реквизитов
// Обращаемся к предопределенной процедуре ПровестиРасчет ВР НачСальдо_2 // Метод ВыполнитьРасчет должен быть расположен после вызова метода Записать ВыполнитьРасчет( ); // или Рассчитать()
ФиксироватьЗапись(); конецПроцедуры // одинСотр
// Вернет 1, если начальное сальдо для выбранного объекта уже введено,
// или О-в противном случае функция ЕстьВЖЗ(сотр)
если ВыбратьПериодПоОбъекту(сотр) = 1 тогда пока ПолучитьЗапись( ) = 1 цикл
если ВидРасч = ВидРасчета.НачСальдо_2 тогда возврат 1; конецЕсли; конецЦикла // пока конецЕсли; возврат 0;
конецФункции // ЕстьВЖЗ Замечания:
1. Процедуры РасчетЗП, ПечатьРЛ и ВедомостьБанк будут рассмотрены после завершения разработки программ ввода в ЖЗ всех ВР.
2. В ЖЗ сотрудники сортируются так же, как и в справочнике-объекте.
5. Расчеты не должны вводиться для уволенных или еще не приступивших к работе сотрудников, записи о которых, однако, есть в справочнике Сотрудники_2. Проблема решается просто, если есть соответствующие приказы с датами приема и увольнения сотрудника.
4. Записи ЖЗ, в которых неверно определены атрибуты, например в атрибут Документ занесено пустое значение типа Документ, сопровождаются в ЖЗ иконкой ?). Такие записи из ЖЗ нужно изъять. Интерактивно это можно выполнить, применив цепочку Действия - Очистить журнал расчетов.
5. Встроенная процедура СохранитьЗначение записывает на диск (в файл 1CV7.CFG) заданное вторым параметром значение. Встроенная функция ВосстановитьЗначение выполняет обратное действие. Если восстанавливается значение реквизита формы типа СписокЗначений, то функция вызывается как процедура, возвращая результат в свой второй параметр, например:
ВоостановшъЗначение("СписокПодразделений", сПодр);
УДАЛЕНИЕ ЗАПИСЕЙ ЖУРНАЛА ЗАРПЛАТЫ И МЯГКАЯ СМЕНА РАСЧЕТНОГО ПЕРИОДА
На период отладки вам может понадобиться процедура удаления записей ЖЗ текущего периода. Ее код прост:
процедура ОчиститьЖЗ()
перем жз; // Журнал заработной платы
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьПериод(жз.НачалоТекущегоПериодаО); пока жз.ПолучитьЗапись() = 1 цикл жз.УдалитьЗаписьО; конецЦикла // пока конецПроцедуры // ОчиститьЖЗ
Однако у этой процедуры есть особенность: записи удаляются через одну. Это объясняется тем, что после проставления DBF-пометки удаления запись из ЖЗ исчезает и текущей становится следующая запись. Далее вступает в действие метод Полу-читьЗапись, перемещающий позицию ЖЗ еще на одну запись. Поэтому процедуру ОчиститьЖЗ нужно запускать неоднократно, что достигается следующим кодом:
функция ОчиститьЖЗ(жз, нтп)
перем флаг; // Журнал заработной платы
флаг = жз.ВыбратьПериод(нтп); если флаг = 1 тогда
|
пока жз.ПолучитьЗапись() = 1 цикл |
|
жз.УдалитьЗапись(); конецЦикла // пока конецЕсли; |
|
возврат флаг;
конецФункции // ОчиститьЖЗ |
// |
флаг = О, если в ЖЗ нет записей |
|
процедура Выполнить() |
|
перем жз; |
// |
Журнал заработной платы |
|
перем нтп; перем флаг; |
// |
Начало текущего периода |
|
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2'');
нтп = жз.НачалоТекущегоПериода();
флаг=1;
пока флаг = 1 цикл
флаг = ОчиститьЖЗ(жз, нтп); конецЦикла // пока
// Вызов формы ЖЗ для просмотра результата ОткрытьФорму('ЖурналРасчетов.Зарплата_2''); конецПроцедуры // Выполнить
После удаления записей текущего периода, возможно, потребуется вернуться к прежнему расчетному периоду и сделать его текущим. Если смена периода вперед была выполнена интерактивно, то записи сменяемого периода получают статус архи в-ных. При интерактивном откате назад произойдет обнуление р езультатов записей, период регистрации которых принадлежит к устанавливаемому расчетному периоду. Чтобы этого не произошло, следует воспользоваться следующей программой:
// Осуществляет мягкую, то есть без отработки системных действий,
// смену расчетного периода ЖЗ процедура Выполнить()
перем жз; // Журнал заработной платы
перем пер; // Переменная типа РасчетныйПериод
если Вопрос("Вернуться к предыдущему расчетному периоду?", "Да+Нет") = "Нет" тогда возврат; конецЕсли;
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
// Перемещаемся на один период назад
пер = жз.ТекущийПериод( ).ПрибавитьПериод(-1);
// Устанавливаем период пер в качестве текущего, не отрабатывая системные действия если жз.УстановитьТекущийПериод(пер, 0) — 1 тогда
Предупреждение('Тотово.");
// Вызов формы ЖЗ для просмотра результата
// После открытия формы, возможно, придется сменить границу просмотра ЖЗ ОткрытьФорму("ЖурналРасчетов.Зарплата_2"); иначе
Предупреждение("Сменить период не удалось."); конецЕсли;
конецПроцедуры // Выполнить
7.4.6. ЗАГРУЗКА НАЧАЛЬНОГО САЛЬДО ИЗ DBF-ФАЙЛА
При смене программных средств неизбежно возникают задачи переноса остатков из старых файлов в новые. Нередко переносимые данные можно записать в DBF-файлы. Предположим, что так оно и есть и начальное сальдо нужно перенести из файла bal.dbf, фрагмент которого представлен в табл. 7.7, в созданный нами и пока что пустой ЖЗ.
Фрагмент файла bal.dbf с начальным сальдо
|
Таблица 7.7 |
|
Employee |
Balance |
|
Абрамова Лариса Сергеевна |
2.60 |
|
Агальцов Юрий Алексеевич |
1.70 |
|
Бараненков Иван Ильич |
0.30 |
|
|
Алгоритм переноса нетруден: |
|. Начало.
2. Открыть файл bal.dbf и переместиться на его первую запись. ,
3. Пока не обнаружен конец файла bal.dbf, выполнить:
3.1. Осуществить поиск по наименованию элемента справочника Сотрудники_2, применяя в качестве наименования значение поля Employee файла bal.dbf.
3.2. Если элемент найден, то
Добавить в ЖЗ запись, объектом которой является найденный элемент, используя в качестве результата значение поля Balance файла bal.dbf. конец если 3.2.
Перейти к следующей записи файла bal.dbf конец цикла 3.
4. Добавить запись в документ НачПериода_2 о первом расчетном периоде ЖЗ. р. Конец.
В 1С подобные алгоритмы программируются с помощью объектов типа XBase, позволяющих управлять DBF-файлами. Разместим по обычаю код, реализующий алгоритм переноса в модуле обработки Проба. Рисунки, отображающие результаты работы программы переноса данных, приведены сразу после ее текста.
Процедура одинСотр(жз, сотр, тДок, хозОп, нтп, начС) далее
функция ЕстьВЖЗ(жз, сотр) далее
Процедура ФиксироватьСменуРП(жз, док, нтп) далее
процедура Выполнить( ) перем дбф;
перем файл, папка, фио, сотр;
перем сСотр_2, жз, док, тДок, хозОп, флаг, флагЖЗ, нтп;
ОчиститьОкноСообщений();
// Открываем диалог для выбора файла bal.dbf
флаг = ФС.ВыбратьФайл(0, файл, папка, "Выберите файл"," | *.DBF"); если флаг = 0 тогда возврат; конецЕсли;
дбф = СоздатьОбъект("ХВаве"); дбф.ОткрытьФайл(папка + файл); если дбф.Открыта() = 0 тогда
Предупреждение("Не удалось открыть файл " + файл); возврат; конецЕсли;
сСотр_2 = СоздатьОбъект(" Справочник. Сотр удники_2"); жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); хозОп = СоздатьОбъект("Справочник.ХозОпДляВР");
// Ищем простым перебором в справочнике ХозОпДляВР вид расчета НачСальдо_2
хозОп.ВыбратьЭлементы();
флаг = 0;
пока хозОп.ПолучитьЭлемент() = 1 цикл
если хозОп.ВР = ВидРасчета.НачСальдо_2 тогда флаг = 1; прервать; конецЕсли; конецЦикла; // пока если флаг = 0 тогда
Предупреждение("Хозяйственная операция для ВР Начальное сальдо не найдена."); возврат; конецЕсли;
док = СоздатьОбъект("Документ.НачПериода_2");
// Номер документа не меняется и всегда равен единице док. НайтиПоНомеру( 1, Дата(0)); если док.Выбран() = 0 тогда
Предупреждение("Создаю документ НачПериода_2 под номером 1.", 2); док.Новый(); док.НомерДок = 1; док.ДатаДок = ТекущаяДата(); док.Записать(); конецЕсли;
тДок = док.ТекущийДокумент(); нтп = жз.НачалоТекущегоПериода(); флагЖЗ = 0;
дбф.КодоваяСтраница(0); // Используем Windows-кодировку
дбф.Первая(); // Перемещаемся на первую запись DBF-файла
// Перебираем все, кроме удаленных, записи ранее открытого DBF-файла дбф.Показывать Удаленные(0);
пока дбф.ВКонце( ) = 0 цикл // Пока не достигнут конец DBF-файла фио = дбф.Employee; // ФИО сотрудника // Задаем поиск во всем справочнике Сотрудники_2 флаг = сСотр_2.НайтиПоНаименованию(фио, 0); если флаг = 1 тогда
флагЖЗ = 1; // В ЖЗ добавлена по крайней мере одна запись
сотр = сСотр_2.ТекущийЭлемент();
// Запись для одного сотрудника одинСотр(жз, сотр, тДок, хозОп, нтп, дбф.Balance); конецЕсли;
дбф.Следующая(); // Переход на следующую DBF-запись
конецЦикла; // Результат см. на рис. 7.26
если флагЖЗ = 1 тогда // Если в ЖЗ добавлены записи
// Добавляем запись в документ НачПериода_2 о первом расчетном периоде ЖЗ // Результат см. на рис. 7.27 ФиксироватьСменуРП(жз, док, нтп);
// Вызовы форм ЖЗ и документа НачПериода_2 под номером 1 // для просмотра результата ОткрытьФорму(
,ЖурналРасчетов.Зарплата_2'');
ОткрытьФорму(тДок); иначе
Предупреждение("В ЖЗ не перенесено ни одной записи."); конецЕсли;
конецПроцедуры // Выполнить
процедура одинСотр(жз, сотр, тДок, хозОп, нтп, начС)
// Если расчет с ВР НачСальдо_2 объект уже имеет, то обновляем только результат если ЕстьВЖЗ(жз, сотр) = 0 тогда
// Добавляем расчет с ВР НачСальдо_2 для выбранного сотрудника жз.Новая();
жз.УстановитьРеквизит("Документ", тДок); жз.УстановитьРеквизит("РодительскийДокумент", тДок); жз.УстановитьРеквизит("Объект", сотр);
жз.УстановитьРеквизит("ВидРасч", ВидРасчета.НачСальдо_2); жз.УстановитьРеквизит("хозОп", хозОп.ХозОП); жз.УстановитьРеквизит("ДатаНачала", нтп); жз.УстановитьРеквизит("ДатаОкончания", нтп); жз.УстановитьРеквизит("Рассчитана", 1); иначе // Делаем расчет нефиксированным
// Журнал позиционирован функцией ЕстьВЖЗ на нужной записи // Подготовка к обновлению результата
жз.ОсвободитьЗапись(); // Делаем запись нефиксированной
конецЕсли;
// Заносим в атрибут Результат величину начального сальдо сотрудника жз.УстановитьРеквизит("Результат", начС);
// Не забываем записать новые значения реквизитов
жз.3аписать();
жз.ФиксироватьЗапись();
конецПроцедуры // одинСотр
// Вернет 1, если начальное сальдо для выбранного объекта уже введено,
// или О-в противном случае функция ЕстьВЖЗ(жз, сотр)
если жз.ВыбратьПериодПоОбъекгу(сотр) = 1 тогда пока жз.ПолучитьЗапись() = 1 цикл
если жз.ВидРасч = ВидРасчета.НачСальдо_2 тогда возврат 1; конецЕсли; конецЦикла // пока конецЕсли; возврат 0;
конецФункции // ЕстьВЖЗ
// Заносит данные о смене расчетного периода в документ НачПериода_2 процедура ФиксироватьСменуРЩжз, док, нтп)
// период - переменная типа РасчетныйПериод
док.НоваяСтрока(); // Добавляем в документ новую строку
док.НовПериод = жз.ОписательПериода(нтп);
// Дата смены расчетного периода ЖЗ Зарплата_2 док.ДатаУстановки = ТекущаяДата(); док.Пользователь = ИмяПользователя(); док.Записать();
конецПроцедуры // ФиксироватьСменуРП
 |
|
Рис. 7.26. Расчеты НачСальдо_2 введены из файла bal. dbf |
 |
Рис. 7.27. Первый расчетный период в документе НачПериода_2 № 1 Замечания:
1. Первый расчетный период задается при создании ЖЗ в поле Дата отсчета (см. рис. 7.19).
2. Не исключено, что для изменения кодировки записей DBF-файла, вам придется прибегнуть к встроенным функциям OemToAnsi и AnsiToOem, приведенным в табл. 2.8. |
7.4.7. ОТЧЕТ ПО НАЧАЛЬНОМУ САЛЬДО
Отчеты, как мы уже знаем, сподручнее всего строить на базе запросов. Напишем запрос, осуществляющий выбор из ЖЗ расчетов с заданным типом ВР, и разместим его в модуле обработки Проба. Запрос и сопровождающий его код крайне просты:
// Формирует и выполняет запрос запр функция ВыпЗапр(запр, ВРДляЗапр) далее
процедура ВыводЗапрТЗнач(запр) далее // Выводит запрос в таблицу значений процедура ВыводЗапрСооб(запр) далее // Выводит запрос в окно сообщений
процедура Выполнить()
перем запр, ВРДляЗапр;
ВРДляЗапр = ВидРасчета.НачСальдо_2; запр = СоздатьОбъект("Запрос");
// Передаем функции ВыпЗапр значение ВР для отбора расчетов // Функция ВыпЗапр формирует и выполняет запрос запр // Если запрос выполнен если ВыпЗапр(запр, ВРДляЗапр) = 1 тогда
ВыводЗапрТЗнач(запр); // Выводит запрос в таблицу значений ВыводЗапрСооб(запр); // Выводит запрос в окно сообщений конецЕсли;
конецПроцедуры // Выполнить
функция ВыпЗапр(запр, ВРДляЗапр) // Формирует и выполняет запрос запр перем жз, нтп, текстЗапр; // текстЗапр - текст запроса
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); нтп = жз.НачалоТекущегоПериода(); текстЗапр ="
| период с нтп по нтп; // Подходящий для Начального сальдо период
// Определяем переменные запроса; они содержат нужные нам данные | сотр = ЖурналРасчетов.Зарплата_2.0бъект;
| ВР = ЖурналРасчетов.Зарплата_2.ВидРасч;
| рез = ЖурналРасчетов.Зарплата_2.Результат;
// Задаем порядок выборки данных
| группировка сотр упорядочить по сотр.Наименование;
// Условие отбора данных | условие (ВР = ВРДляЗапр);";
// Выполняем запрос возврат запр. Выполнить(текстЗапр); конецФункции // ВыпЗапр
процедура ВыводЗапрТЗнач(запр) // Выводит запрос в таблицу значений перем тЗнач;
// Объект тЗнач создаем для промежуточной демонстрации выборки запроса тЗнач = СоздатьОбъект("ТаблицаЗначений");
// Выгружаем для предварительного просмотра все переменные запроса // в таблицу значений тЗнач запр.Выгрузить(тЗнач, 1);
// Просмотр таблицы значений (результатов запроса). Результат см. на рис. 7.28 тЗнач.ВыбратьСтроку(, "Начальное сальдо в таблице значений"); энецПроцедуры // ВыводЗапрТЗнач
выводит запрос в окно сообщений
Результат имеет ту же структуру, что и данные в таблице, приведенной на рис. 7.28 эоцедура ВыводЗапрСооб(запр)
// В этой процедуре еще раз иллюстрируется метод запросов Группировка пока запр.Группировка("сотр") = 1 цикл если запр.ЭтоГруппа("сотр") = 1 тогда
Сообщить("Сотрудники подразделения " + запр.сотр);
иначе
Сообщить(СокрЩзапр.сотр) + СимволТабуляции + запр.ВР + СимволТабуляции + запр.рез); конецЕсли; конецЦикла; // пока конецПроцедуры // ВыводЗапрСооб
 |
Рис. 7.28. Результат запроса о начальном сальдо с группами
Группы (имена родителей) не попадут в запрос, если оператор Группировка дополнить опцией Без групп:
[группировка сотр упорядочить по сотр.Наименование без групп; что приведет к следующему результату: |
 |
|
Рис. 7.29. Результат запроса о начальном сальдо с группами |
Из рис. 7.28 и 7.29 видно, что элементы-родители справочника Сотрудники_2 являются в запросе группами и метод запр.ЭтоГруппа("сотр") вернет для них единицу. Для иных записей этот метод вернет нуль.
Первая строка таблицы значений отображает начало выборки. Строка содержит пустое значение переменной запроса сотр. Первое же употребление метода
запр.Группировка("сотр");
приведет к перемещению позиции выборки на ее первую, содержащую непустое значение переменной сотр запись.
Если в текст запроса добавить переменную род, содержащую родителя объекта:
| род = ЖурналРасчетов.Зарплата_2.0бъект.Родитель; то результат запроса не изменится.
Если же вдобавок в тексте запроса разместить и группировку по род, то есть передать методу Выполнить такой текст:
текстЗапр ="
| период с нтп по нтп;
| род = ЖурналРасчетов.Зарплата_2.Объект.Родитель;
| сотр = ЖурналРасчетов.Зарплата_2.Объект;
I BP = ЖурналРасчетов.Зарплата_2.ВидРасч;
| рез = ЖурналРасчетов.Зарплата_2.Результат;
| группировка род;
| группировка сотр упорядочить по сотр.Наименование;
| условие (ВР = ВРДляЗапр);";
то в таблице значений мы увидим дополнительные строки, в которых переменная запроса сотр имеет пустое значение (рис. 7.30).
 |
|
Рис. 7.30. Запрос с двумя группами |
Эти строки, кроме первой, начинают группы род. Первая строка - это начало выборки. В ней и род и сотр имеют пустые значения.
При двойной группировке, чтобы получить доступ к данным запроса более низкого уровня, необходимо прежде выбрать вышестоящие группы. Поэтому придется изменить код процедуры ВыводЗапрСооб на следующий:
// Выводит запрос в окно сообщений для случая двойной группировки процедура ВыводЗапрСооб(запр)
// В этой процедуре еще раз иллюстрируется метод запросов Группировка пока запр.Группировка("род") = 1 цикл
Сообщить("Сотрудники подразделения " + запр.род); пока запр.Группировка("сотр") = 1 цикл если запр.ЭтоГруппа("сотр") = 0 тогда
Сообщить(СокрП(запр.сотр) + Символ Табуляции + запр.ВР + СимволТабуляции + запр.рез); конецЕсли;
конецЦикла; // пока запр.Группировка("сотр") = 1 конецЦикла; // пока запр.Группировка("род") =1 конецПроцедуры // ВыводЗапрСооб
|
Результат соответствует рис. 7.28: |
|
Сотрудники подразделения 01 Цех Сотрудники подразделения 01/1 Агальцов Юрий Алексеевич |
Начальное сальдо |
1.7 |
|
Добрецов Борис Юрьевич |
Начальное сальдо |
0.1 |
|
Сотрудники подразделения 01/2 Ьараненков Иван Ильич |
Начальное сальдо |
0.3 |
|
Сравнение двух запросов показывает, что при запросах к ЖЗ для вывода сотрудников с разбивкой по цехам нет необходимости вводить в текст запроса переменную род и устраивать вторую группу. Все необходимые данные даст группировка по переменной запроса сотр.
7.5. КАЛЕНДАРИ И ПРАЗДНИКИ
Наша задача - употребить календари 1С для вычисления общего числа рабочих дней и часов. Учет рабочего времени осуществляется по табелю, который мы оформим как самостоятельный документ 1С.
7.5.1. СОЗДАНИЕ КАЛЕНДАРЯ
Пусть на нашем виртуальном предприятии имеются служащие и рабочие. Создадим для этих категорий свои календари. Войдем в конфигурацию, откроем подменю Календарь и разместим в нем календари Служащие_2 и Рабочие_2 (рис. 7.31).
 |
|
Рис. 7.31. Новые календари системы |
|
Свойства календарей определим в соответствии с рис. 7.32. |
 |
а б
Рис. 7.32. Рабочая неделя: а - календаря Служащие_2; б - календаря Рабочие_2
Добавим в меню интерфейса Ученик колонку Календари и табель и определим в ней указанные на рис. 7.33 пункты.
Б 1=3 Календари и табель 0 Календари і 0 Праздники 0 Табель
Рис. 7.33. Новая колонка меню интерфейса Ученик
С новыми пунктами Календари и Праздники свяжем приведенные на рис. 7.34 название, объект и команды.

а б
Рис. 7.34. Свойства пунктов меню: а - Календари; б - Праздники
Объект и команду для пункта Табель зададим несколько позже - после создания документа Табель.
Сохраним изменения конфигурации. Загрузим 1 С: Предприятие. Откроем прежде таблицу для ввода праздников и внесем в нее праздники текущего года, проставив в столбце Значение нулевую продолжительность рабочего дня (рис. 7.35).
 |
|
Рис. 7.35. Два праздника |
Откроем далее последовательно календари Служащие_2 и Рабочие_2 и выполним их автоматическое заполнение с включенным флажком Учитывать праздники (рис. 7.36).
 |
|
Рис. 7.36. Календарь Служащие_2 в ноябре 2001 г. |
В поле Значение по текущей дате (рис. 7.36) заполненного календаря отображается число часов, взятое из определенного в конфигурации и изображенного на рис. 7.32, а календаря Сотрудники_2. Для праздничных дней календарь использует данные приведенной на рис. 7.35 таблицы.
Замечание. И календари и праздники хранятся в файле CL.DBF информационной базы.
7.5.2. ПРИМЕНЕНИЕ КАЛЕНДАРЕЙ И ПРАЗНИКОВ
7.5.2.1. ДОСТУП К КАЛЕНДАРЯМ И ПРАЗДНИКАМ
Объекты типа Календарь присутствуют в конфигурации и доступны непосредственно по именам (идентификаторам), которые можно использовать с методами для календарей и чтения их атрибутов.
Пример. Методом Часов вычисляется число рабочих часов в ноябре 2001 г. по календарю Служащие_2.
всегоЧасов = Календари.Служащие_2.Часов('01.11.200Г, КонМесяца('01.11.2001')); Сообщить(всегоЧасов); //Напечатает 167
Тот же результат метод предоставит, будучи употребленным с объектом типа Календарь, возвращаемым функцией СоздатьОбъект:
кален = СоздатьОбъект(''Календарь.Служащие_2''); всегоЧасов = кален.Часов('01.11.2001', КонМесяца('01.11.2001'));
Сообщить(всегоЧасов); // Напечатает 167
Еще один вариант применения методов календарей, например метода Часов, - это использование в составе префикса метода ПолучитьАтрибут:
всегоЧасов = Календари. ПолучитьАтрибут(''Служащие_2'').Часов('01.11.2001',
КонМесяца('01.11.2001'));
Сообщить(всегоЧасов); //Напечатает 167
Переменные типа Праздники относятся к внешним объектам и создаются, как и иные внешние объекты, например таблицы значений, функцией СоздатьОбъект. Имя переменной используется в качестве префикса методов и атрибутов объекта типа Праздники.
Пример. Печатаются праздники текущего года.
процедура Выполнить()
перем празд, нг, кг, флаг;
ОчиститьОкноСообщений();
нг = НачГода(ТекущаяДата()); // Начало и конец текущего года
кг = КонГода(ТекущаяДата()); праздн = СоздатьОбъект("Праздники");
// Перемещаемся на первую запись (дату) выборки флаг = праздн.ВыбратьДаты(нг, кг); если флаг = 1 тогда
пока праздн.СледующаяДата() = 1 цикл
Сообщить("" + праздн.Дата + " - это праздник");
// или Сообщить("" + праздн.ПолучитьАтрибут("Дата") + " - это праздник"); конецЦикла; // пока иначе
Сообщить("В текущем году нет праздников."); конецЕсли;
конецПроцедуры // Выполнить
Результат (соответствует рис. 7.35):
07.11.01 - это праздник
12.12.01 - это праздник
7.5.2.2. А ТРИБУТЫ КАЛЕНДАРЕЙ И ПРАЗДНИКОВ
Календари имеют следующие атрибуты:
- <имя капендаря>; имеет тип Календарь и возвращается методом ПолучитьАтрибут;
- Дата; имеет тип Дата, читается непосредственно по имени или методом ПолучитьАт-
рибут;
- Значение; имеет числовой тип.
Пример. Печатаются нерабочие даты текущего месяца (с нулевой продолжительностью рабочего дня) календаря Служащие_2.
процедура Выполнить()
перем кален, нм, км, нерДни;
ОчиститьОкноСообщенийО;
нм = НачМесяца(ТекущаяДата()); // Начало и конец текущего месяца
км = КонМесяца(ТекущаяДата());
попытка
// Создаем объект типа Календарь. Для этого у нас имеется 3 возможности кален = Капендари.ПолучитьАlрибут("Служащие_2");
// или кален = Календари.Служащие_2;
// или кален = СоздатьОбъект("Календарь.Служащие_2"); исключение
Предупреждение("Нет такого календаря."); возврат; конецПопытки; нерДни = "";
// Перемещаемся на первую запись (дату) выборки
кален.ВыбратьДаты(нм, км);
пока кален.СледующаяДата() = 1 никл
если кален. Значение = 0 тогда // Если нерабочий день нерДни = нерДни + Строка(кален.Дата) + ";";
// или нерДни = нерДни + Строка(кален.ПолучигьАірибут("Даіа")) + ";"; конецЕсли; конецЦикла; // пока если СтрДлина^ерДни) = 0 тогда
Сообщить("В текущем месяце все дни рабочие"); иначе
// Заменяем в строке нерДни последнюю точку с запятой на точку нерДни = Лев(нерДни, СтрДлина(нерДни) - 2) + ".";
Сообщшь("Нерабочие дни текущего месяца: " + нерДни); конецЕсли;
конецПроцедуры // Выполнить Результат:
Нерабочие дни текущего месяца: 02.12.01; 09.12.01; 12.12.01; 16.12.01; 23.12.01; 30.12.01.
Праздники имеют два атрибута:
• Дата; имеет тип Дата;
• Значение; имеет числовой тип.
Замечание. Атрибуты календарей и праздников Дата и Значение читаются непосредственно по имени или методом ПолучитьАтрибут; изменяются методом Устано-витьЗначение.
7.5.2.3. МЕТОДЫ КАЛЕНДАРЕЙ И ПРАЗДНИКОВ
Сведены в табл. 7.8, в которой первоначально следуют общие методы рассматриваемых объектов, а далее их специфические методы.
Методы календарей и праздников
|
Общие методы календарей и праздников |
знач = кален|праздн.Получить
Атрибут("Дата"|"Значение"); |
Возвращает значение атрибута Дата или Значение в текущей записи объекта. Возможно прямое обращение к атрибуту, например дт = кален.Дата; часы = праздн.Значение; |
|
кален|праздн.УстановитьАтрибут ("Дата"|"3начение", знач); |
Изменяет значение атрибута Дата или Значение в текущей записи объекта на величину знач |
|
флаг = кален|праздн.ВыбратьДаты (датаНачала, датаКонца); |
Открывает выборку записей объекта, расположенных между датами датаНачала и датаКонца, перемещая его позицию на первую запись выборки.
Вернет 1, если в выборке есть хотя бы один элемент, или 0, если выборка пуста |
|
флаг = кален|праздн. Следующая Дата(); |
Выбирает текущую запись и перемещает позицию выборки на следующую запись. Вернет 1, если запись выбрана, или 0, если вся выборка исчерпана |
|
|
Методы календарей |
|
кален = Календари.ПолучитьАтрибут (идент); |
Возвращает объект типа Календари с разновидностью типа идент, где идент - строка, содержащая идентификатор календаря, например "Служа-щие_2". Возникнет завершающая ошибка, если идент содержит несуществующий идентификатор |
|
идент = кален.Вид(); |
Вернет строку, содержащую идентификатор календаря кален. Если, например, в справочнике сСотр_2 есть реквизит Календарь типа Календари, то идентификатор календаря выбранного сотрудника вернет вызов
идент = сСотр_2.Календарь.Вид(); |
|
флаг = кален.Выбран(); |
Вернет 1, если календарь выбран, или О-в противном случае. Для справочника сСотр_2, в котором есть реквизит Календарь типа Календари, для текущей записи признак выбран календарь или нет вернет вызов
флаг = сСотр_2. Календарь. Выбран(); |
|
|
Метод |
Описание |
числоРабДней = кален. Дней
(датаНачала, датаКонца); |
Вернет число дней с ненулевой величиной атрибута Значение в календаре кален, расположенных между датами датаНачала и датаКонца. Выдаст сообщение "Неверные даты", если датаКонца < датаНачала |
числоРабЧасов = кален.Часов
{датаНачала, датаКонца); |
Вернет сумму значений атрибута Значение календаря кален для записей, расположенных между датами датаНачала и датаКонца. Выдаст сообщение "Неверные даты", если датаКонца < датаНачала |
флаг = кален. Автозаполнение
(датаНачала, датаКонца); |
Заполняет календарь кален в заданном параметрами датаНачала и датаКонца временном интервале, используя определенные в конфигурации для этого календаря данные о продолжительности рабочей недели (разд. 7.5.1). При заполнении учитываются занесенные в базу данных праздники (разд. 7.5.1, рис. 7.35), если перед вызовом метода употреблен метод УчитыватьПраздники(1). Вернет 1, если заполнение произведено, или 0 - при неудаче |
праздСтар =
кален.УчитыватьПраздники
(праздНов); |
Задает, если числовой параметр праздНов = 1, режим учета занесенные в базу данных праздников (разд. 7.5.1, рис. 7.35) при выполнении метода Автозаполнение для календаря кален. Если праздНов = 0, то праздники при автозаполнении календаря кален не учитываются. Если метод для календаря кален не вызывался, то при его автозаполнении праздники учитываются. Возвращает текущую установку режима учета праздников |
|
дат = кален. ПолучитьДату (датаНачала, числоРабДней); |
Возвращает дату, отстоящую от даты, заданной параметром датаНачала, на число рабочих дней, заданное параметром числоРабДней. День считается рабочим, если атрибут Значение соответствующей записи календаря кален не равен нулю. Параметр числоРабДней не должен быть меньше нуля |
|
Методы праздников |
праздн.Новый(датаЛраздн,
числоРабЧасов); |
Добавляет в базу данных (файл CL.DBF) новый праздник. Параметр датаПраздн задает дату праздника, а числоРабЧасов - число рабочих часов в праздник. Параметр числоРабЧасов неотрицателен и меньше 100 |
|
праздн.Удалить(датаЛраздн); |
Удаляет из базы данных праздник, приходящийся на дату датаПраздн. Если записи о таком празднике нет, то метод никаких изменений не производит |
|
Замечание. Имена кален и праздн, употребленные в табл. 7.8 перед названиями методов, могут быть произвольными.
Пример. В текущем году праздник 12 декабря переносится на 14 декабря. Поскольку перенос затрагивает все календари, то для их модификации используем объект Метаданные и методы календарей Автозаполнение и УчитыватьПраздники.
процедура Выполнить()
перем празд, тГод, пСтар, пНов, нм, км, всегоКален, ин, идеи, кален; |
|
ОчиститьОкноСообщений(); тГод = ДатаГод(ТекущаяДата()); |
// |
Текущий год, например 2001 |
|
пСтар = Дата("12.12." +тГод); |
//Дата |
старого праздника |
|
пНов = Дата("14.12." + тГод); |
// |
Дата нового праздника |
|
праздн = СоздатьОбъект("Праздники"); |
|
|
// Перенос праздника праздн.Удалить(пСтар); праздн.Новый(пНов, 0); |
// |
Число рабочих часов равно нулю |
|
нм = Дата("01.12." + тГод); |
// |
Начало и конец декабря |
|
км = КонМесяца(нм); |
|
|
|
// Всего календарей в конфигурации (в метаданных) всегоКален = Метаданные.КалендарьО; для ин = 1 по всегоКален цикл
// Атрибут очередного календаря
идеи = Метаданные.Календарь(ин).Идентификатор;
// Календарь как объект
кален = Календари.ПолучитьАтрибут(иден);
// Учитываем при автозаполнении праздники кален.У читыватьПраздники(1); кален.Автозаполнение(нм, км); конецЦикла; // для Предупреждение("Готово."); конецПроцедуры // Выполнить
Замечание. Функция ОткрытьФорму непригодна для активизации формы списка объекта Праздники (см. рис. 7.35) и отображения календарей.
7.5.2.4. УСОВЕРШЕНСТВОВАНИЕ СПРАВОЧНИКА СОТРУДНИКИ_2
Если стоит задача автоматизировать учет рабочего времени сотрудника, то его следует связать с подходящим календарем. Такие календари у нас уже есть (см. рис. 7.32). Если нет отклонений, то рабочее время сотрудника полностью определяется его календарем. В противном случае необходимо использовать табель.
Поскольку учет рабочего времени - задача трудоемкая, дополним справочник Сот-рудники_2 реквизитом Календарь (рис. 7.37, а), задав ему свойства в соответствии с рис. 7.37, б.
 |
|
б |
Идентификатор:
?ино«*и:
^«¦еаентармй:
Іш значения | «Календарь»
РакаИЭИГЫ
О клан
Образование
ПрикаэОклаа
ПршаэЛрием
Рис. 7.37. Новый реквизит Календарь и его свойства: а -реквизит; б - свойства
Внесем изменения и в диалог формы элемента, приведя его в соответствие с рис. 7.38. (О порядке выполнения изменений см. разд. 5.7.)
 |
|
Рис. 7.38. Обновленный диалог формы элемента справочника Сотрудники_2 |
Календарь - обязательный для заполнения реквизит справочника, поэтому модуль формы элемента, его предопределенную процедуру ПриЗаписи (разд. 5.3.4.2), дополним следующей проверкой:
если Календарь.Выбран() = 0 тогда
Прелупреждение("3адайге Календарь");
СтатусВозврата(0); // Данные не записываются; форма не закрывается // Перемешаемся на элемент диалога Календарь Активизировать("Календарь", 0); возврат; конецЕсли;
Формы списка (основную и для ввода) справочника Сотрудники_2 оставим без изменений.
Ускорим ввод начальных значений нового реквизита, запустив в обработке Проба программу, назначающую работникам с высшим и неоконченным высшим образованием календарь Служащие_2, а всем прочим - Рабочие_2.
процедура Выполнить() перем сСотр_2;
ОчистшъОкноСообщений();
сСотр_2 = СоздагъОбъект("Справочник.Сотрудники_2");
сСотр_2.ВыбратьЭлементы();
пока сСотр_2.ПолучигьЭлемент() = 1 цикл
если (сСотр_2.0бразование.Наименование = "Высшее") или
(сСотр_2.0бразование.Наименование = "Неоконченное высшее") тогда сСотр_2.Календарь = Календари.Служащие_2; иначе
сСотр_2. Календарь = Календари.Рабочие_2; конецЕсли;
// Не забываем сохранить изменения сСотр_2.3аписать(); конецЦикла; // пока Предупреждение('Тотово.");
// Просмотр результата. Для просмотра необходимо в открытой форме списка // войти в режим редактирования элемента ОткрытьФормуС'Справочник. Сотрудники_2"); конецПроцедуры // Выполнить
7.6. ТАБЕЛЬ
7.6.1. ПОРЯДОК ЗАПОЛНЕНИЯ ТАБЕЛЯ
На предприятии табель - это документ, учитывающий отработанное время. Изначально табель сотрудника может формироваться на бумажном носителе. Далее данные переносятся в документ 1С, которому мы также дадим имя Табель. В дальнейшем, употребляя это имя, мы будем иметь в виду документ 1С.
Табель играет важную роль в задаче начисления зарплаты. В частности, все документы, вводящие начисления (удержания) и зависящие от проработанного времени, должны оформляться на основании табеля.
Алгоритм учета рабочего времени за месяц (для одного сотрудника):
1. Начало.
2. Выбрать сотрудника.
3. Заполнить, используя календарь сотрудника, табель
4. Внести при необходимости в табель коррективы.
5. Вычислить суммарное отработанное время. Результат разместить в столбце Всего часов.
6. Провести документ. Результатом его проведения является добавление в ЖЗ расчетов с Оклад_2, НДФЛ_2 и ВБанк_2.
Расчет регистрируется в текущем расчетном периоде.
7. Конец.
Данный алгоритм воспроизводится для каждого сотрудника предприятия, занесенного в табель, то есть в общем случае один табель порождает несколько расчетов. Предоставим пользователю следующие возможности по заполнению табеля:
1. Добавление в табель (его табличную часть) по одному сотруднику. Производится при помощи метода модуля формы ОткрытьПодбор и предопределенной процедуры модуля формы ОбработкаПодбора; существующие записи сохраняются.
2. Заполнение табличной части для сотрудников выбранного подразделения; существующие записи удаляются.
3. Занесение в табличную часть всех сотрудников предприятия; существующие записи удаляются.
В каждом из режимов табличная часть после перенесения в нее сотрудника автоматически заполняется данными его календаря.
Также предусмотрим в интерфейсе документа удаление одной выбранной записи табличной части или всех ее записей.
При каждом сохранении документа будем выполнять его перепроведение. Позаботимся о том, чтобы в документ один и тот же сотрудник не попал дважды. Однако если по какой-либо причине данные о сотруднике введены дважды в разные табели, то проведение любого из этих табелей должно приводить к обновлению соответствующих ему расчетов в ЖЗ.
Замечание. Имеющийся в 1С документ ВводОтработанногоВремени весьма сложен, так как рассчитан на многие случаи жизни. Внушителен и объем кода, сопровождающий этот документ. Так, модуль формы документа содержит около 600 строк плотного кода. Поскольку наш алгоритм ввода рабочего времени и последующей проводки документа гораздо проще, то имеет смысл взамен существующего в 1С документа создать и использовать свой, более простой и эффективный. Так и поступим.
7.6.2. РЕКВИЗИТЫ И ДИАЛОГ ТАБЕЛЯ
Перечисленные требования к табелю позволяют определиться относительно состава диалога документа и его реквизитов (табл. 7.9).
Таблица 7.9
Реквизиты документа Табель
Тип (разновидность типа) /Длина.Точность
Реквизиты
Описание
Способ заполнения табличной части документа. Используется как идентификатор радиокнопок диалога формы списка документа. Если кто = 1, то подбор выполняется по одному сотруднику; если кто = 2, то в табличную часть документа заносятся сотрудники выбранного подразделения, и если кто = 3, в табличную часть заносятся сотрудники всего предприятия. Используется при открытии проведенного документа
Числовой/ 1.0
кто
Номер выбранной строки в списке подразделе • ний сПодр. Используется при открытии проведенного документа для верного позиционирования списка подразделений
текСтрока
Числовой/3.0
Дата документа (реквизит задан по умолчанию)
Дата
ДатаДок
Номер документа (реквизит задан по умолчанию)
НомерДок
Числовой /5.0
Сотрудник
Сотрудник, табель которого вводится
Справочник. Сотрудники 2
ч1-ч31
ч, - число фактически отработанных часов в день й=1.2. ...31
Числовой/4.1 |
 |
Создавая документ, попутно, пользуясь услугами конструктора (рис. 7.39), добавим в конфигурацию журнал Табель, в котором и будут размещаться формируемые пользователями документы учета отработанного времени.
 |
|
Рис. 7.39. Новый журнал для документа Табель |
Задавая свойства документа Табель (рис. 7.40), не забудем активизировать флажок Расчет.
 |
|
Рис. 7.40. Свойства и реквизиты документа Табель |
|
Диалог формы табеля оформим, следуя рис. 7.41. |
 |
|
Рис. 7.41. Диалог формы табеля |
Замечания:
1. Чтобы просмотреть неотображенные столбцы табличной части формы, следует воспользоваться стрелками горизонтальной полосы прокрутки.
2. Элемент диалога сПодр является списком значений. Он заполняется в предопределенной процедуре ПриОткрытии, которая, используя справочник Сотрудики_2, заносит в сПодр список подразделений предприятия.
Нажав для проверки диалога Ctrl+R, обнаружим некоторое несоответствие в расположении граф 1-31, а также дополнительную неименованную графу 32 (рис. 7.42).
 |
|
Рис. 7.42. Расположение граф 1-32 |
Графа 32 введена с целью симметричного размещения столбцов 1-16 и 17-31, что и получилось на рис. 7.42. Для достижения такого результата необходимо ячейки 1-32 сделать одной ширины. К сожалению, простого средства выравнивания ширины столбцов табличной части в 1С нет.
С 32-й графой связана формула "X", обеспечивающая вывод этой буквы в ячейки столбца. Добавление столбца таблицы, напомним, осуществляется при помощи иконки Г, расположенной на панели инструментов Элементы диалога.
Чтобы разместить столбцы 17-32 под столбцами 1-16, столбец 1 получил свойство Новая колонка (рис. 7.43, а), а последующие столбцы - свойство В той же колонке (рис. 7.43, б).

а 6
Рис. 7.43. Положение полей ввода ч1-ч32: положение поля ввода ч1; положение полей ввода ч2-ч32
Соответствие между заголовками столбцов табличной части документа и их идентификаторами (реквизитами документа) отображено в табл. 7.10.
Таблица 7.10
Заголовками столбцов табличной части документа и их идентификаторы |
|
Заголовок столбца |
Идентификатор |
Примечание |
|
Сотрудник |
Сотрудник |
Ячейки столбца доступны только для чтения; заполняются в результате работы процедуры Заполнить |
|
Всего |
всегоЧасов |
Ячейки столбца доступны только для
?^ЗІ
чтения; всегда всего Часов = / Ч; |
|
1,2.....31 |
чі, ч2.....чЗІ |
Доступны как для чтения, так и для редактирования; заполняются в результате работы процедуры Заполнить |
|
|
Замечание. Ввод одного сотрудника, так же как и группы сотрудников, осуществляется при нажатии на кнопку Заполнить. То есть мы отказались от выбора сотрудника непосредственно в табличной части, задав свойства ячеек столбца Сотрудник в соответствии с рис. 7.44. |
 |
|
Рис. 7.44. Свойства ячеек столбца Сотрудник |
Это, несомненно, делает диалог более дружественным. Действительно, каждый выббр сотрудника приводит к заполнению реквизитов ч1-ч31. При этом случайный выбор сотрудника в строке, содержащей ранее введенные данные, приведет к обновлению значений этих реквизитов. Если же они содержали ручную правку, то ее результаты будут этим обновлением уничтожены. Теперь же, когда ячейки столбца недоступны, такой ошибки быть не может.
Группа радиокнопок, имеющая название Режим заполнения, формируется следующим образом:
1. Добавляется радиокнопка с заголовком Сотрудник, ей присваивается идентификатор, например кто, который и будет служить идентификатором группы. На закладке дополнительно этой радиокнопке задается формула Проследить() и свойство Первый в группе.
2. Добавляются радиокнопки с заголовками Цех и Все. Никаких дополнительных свойств для них не задается.
3. Кнопки обводятся рамкой группы, которой присваивается заголовок Режим заполнения.
После таких действий переменная диалога кто принимает значение:
• 1, если выбрана радиокнопка Сотрудник; и в этом случае табель заполняется в результате подбора сотрудников;
• 2, если выбрана радиокнопка Цех; табель заполняется на сотрудников подразделения, выбранного в поле сПодр;
• 3, если выбрана радиокнопка Все; в табель заносятся все сотрудники предприятия. Кроме задания режима заполнения, радиокнопки управляют доступностью элементов диалога сПодр и Заполнить.
С текстом заголовка свяжем следующую формулу:
"Ввод отработанного времени за "+ Формат(ЦащЦок, "ДММММГ ПТ") + ", " +
?(кто = 2, сПодр.ПолучитъЗначение(сПодр.ТекущаяСтрокаО),
?(кто = 3, "все предприятие", "")) + "."
Тогда, если, например, ДатаДок - это '12.12.200Г и выбран второй цех, в заголовке появится сообщение, в котором благодаря встроенной функции Формат дата '12.12.2001' преобразована в текст Декабрь 2001 г.:
Ввод отработанного времени за Декабрь 2001 г., 02 Цех
Формулы (процедуры), с которыми связываются поля диалога, перечислим в табл. 7.11, в которой в графе Элементы диалога курсивом приводятся идентификаторы элементов диалога, а прямым шрифтом - их имена (идентификаторы не заданы). Имена, соответствующие идентификаторам, легко узнаваемы.
Таблица 7.11
|
Элементы диалога документа Табель и их формулы |
 |
Проследить()
Управляет доступностью элемента диалога сПодр. Если кто = 1 (активна радиокнопка Сотрудник) или кто = 3, то элемент сПодр недоступен; если кто = 2, то доступен
кто |
сПодр
ОтобразитьСПодр()
Отображает имя выбранного в списке сПодр подразделения и запоминает значение текущей строки списка текСтрока
Заполнить
Заполнить( )
Заполняет табличную часть для сотрудников выбранного подразделения, если кто = 2, или всего предприятия, если кто = 3. Открывает форму подбора сотрудников, если кто = 1
Удаляет текущую строку табличной части. Удалению предшествует запрос о необходимости удаления. Доступен, если в табличной части есть хотя бы одна запись
Удалить
УдалитьЗап(1)
Очистить
УдалитьЗап(2)
Удаляет все строки табличной части. Удалению предшествует запрос о необходимости удаления. Доступен, если в табличной части есть хотя бы одна запись
Распечатывает, если не пуста табличная часть, табель по форме Т-13, которая предоставляется 1С
Т13()
ФормаТ-13
Действия
гдДействия(, сДейст)
Открывает документ в журнале (если он в нем есть). Переменная модуля сДейст (список значений) заполняется в процедуре ПриОткрытии формы документа значением "Открыть в журнале". Процедура глДействия расположена в глобальном модуле и поставляется с 1С
Выполняет проведение (перепроведение) документа Табель, то есть заносит в ЖЗ расчеты с ВР Оклад_2, НДФЛ_2 и ВБанк_2
#Провести
Провести
ОК
#3аписать Провести Закрыть
Проводит (перепроводит) и сохраняет документ в журнале документов Табель
Закрыть
#3акрыть
Закрывает документ
Теперь у нас есть достаточно информации, чтобы перейти к созданию кода модуля формы документа и самого документа. Напомним, что в модуле документа можно разместить его предопределенные процедуры ОбработкаПроведения и/или Обрабо тка-УдаленияПроведения.
7.6.3. МОДИФИКАЦИЯ МЕНЮ ИНТЕРФЕЙСА УЧЕНИК
Для доступа к созданным журналам и документам модифицируем отдельные колонки меню интерфейса Ученик (рис. 7.45). Для вновь введенных в колонку Журналы документов пунктов (Расчеты и Табель) укажем соответственно объекты Жур-нал.Расчеты и Журнал.Табель.
|
Hjj Документы |
^ Журналы документов |
^ Журналы расчетов |
^ Календари |
|
И Приказ о приеме |
;--0 Кадровые приказы |
0 Журнал зарплаты_2 |
г- 0 Календари |
|
S Изменение оклада S Табель |
!— 0 Расчеты -0 Табель |
|
|- 0 Праздники |
|
У Премия |
|
|
|
|
|
Рис. 7.45. Модифицированные колонки меню интерфейса Ученик |
7.6.4. МОДУЛЬ ФОРМЫ СПИСКА ДОКУМЕНТА
Содержит, кроме названных в табл. 7.11, процедуру ПриОткрытии. перем часы[31], сДейст; // часы - массив часов по календарю
процедура Проследить() далее
процедура Заполнить() далее
процедура ОбработкаПодбора(значен, конт) далее
процедура ОдинСотрудник() далее
процедура Ч131 () далее
процедура Всего () далее
процедура УдалитьЗап(флаг) далее
// Формирует список подразделений сПодр и устанавливает начальные значения // переменных диалога процедура ПриОткрытии() перем сСотр_2, дост;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Формируем, анализируя справочник Сотрудники_2, список подразделгний // Задаем выбор элементов справочника в порядке возрастания их кодов сСотр_2 .ПорядокКодов(); сСотр_2.ВыбратьЭлементы( ); пока сСотр_2.ПолучитьЭлемент() = 1 цикл если сСотр_2.ЭтоГруппа() = 1 тогда
Если документ не проведен Табель на сотрудников выбранного подразделения Позиционируемся на цехе 01 в списке сПодр Документ проведен
Правильно позиционируем список значений сПодр
сПодр.ДобавитьЗначение(сСотр_2.ТекущийЭлемент(), сСотр_2.Наименование); конецЕсли; конецЦикла; // пока если Проведен()= 0 тогда //
сПодр.ТекущаяСтрока(текСтрока); конецЕсли; конецЕсли;
Проследить();
// дост = 1, если в табличной части есть записи. Переменная используется // для управления доступностью элементов диалога формы списка документа дост = ?(КоличествоСтрок() = 0, 0, 1); формаУдалтъДоступность(цост); форма. Очистить.Доступность(цост);
форма.ПанельИнструментов(О); // Отключаем панель инструментов форма.Заголовок("Табель");
// Для кнопки Действия (рис. 7.40) сДейст = СоздатьОбъект("СписокЗначений"); сДейстДобавитьЗначение("Открьнь в журнале"); конецПроцедуры // ПриОткрытии
// Управляет доступностью элемента диалога сПодр процедура Проследить()
если (кто = 1) или (кто = 3) тогда // Табель на отобранных или всех сотрудников форма.СПодр.Доступность(О); иначе // кто = 2
форма.СПодр.Доступность(І); конецЕсли;
конецПроцедуры // Проследить
процедура ОтобразитьСПодр() // Формула элемента диалога сПодр текСтрока = сПодр.ТекущаяСтрока(); сПодр.ПолучитьЗначение(текСтрока); конецПроцедуры // ОтобразитьСПодр
процедура ОдинСотрудник() // Заполняет массив часы для одного сотрудник перем ин, кален;
для ин - 1 по 31 цикл // Инициализация массива часов
часы[ин] = 0; конецЦикла; // для кален = СотрудникКалендарь; если кален.Выбран() = 1 тогда
кален.ВыбратьДаты(НачМесяца(ДатаЦок), КонМесяца(ДатаДок)); ин = 0;
// Заносим в массив часы данные календаря сотрудника пока кален.СледующаяДата() = 1 цикл ин = ин+ 1;
часы[ин] = кален.Значение; конецЦикла; // пока конецЕсли;
конецПроцедуры // ОдинСотрудник
// Определяем значения реквизитов документа ч 1 - чЗ 1 // Далее эти значения могут быть отредактированы процедура Ч131()
ч1 = часы[1]; ч2 = часы[2]; чЗ = часы[3]; ч4 = часы[4]; ч5 = часы[5]; чб = часы[6]; ч7 = часы[7]; ч8 = часы[8]; ч9 = часы[9]; ч10 = часы[10]; ч11 = часы[11]; ч12 = часы[12]; ч13 = часы[13]; ч14 = часы[14]; ч15 = часы[15];
ч16 = часы[16]; ч17 - часы[17]; ч18 = часы[18] ч19 = часы[19]; ч20 = часы[20]; ч21 = часы[21] ч22 = часы[22]; ч23 = часы[23]; ч24 = часы[24] ч25 = часы[25]; ч26 = часы[26]; 427 = 4асы[27]
428 = 4асы[28]; 429 = часы[29]; 430 = часы[30]; 431 = 4асы[31]; конецПроцедуры // Ч131
процедура Всего() // Возвращает общее 4исло отработанных 4асов
всегоЧасов = ч1 + ч2 + ч3 + ч4 + ч5 + ч6 + ч7 + ч8 + ч9 + ч10 + ч11 + ч12 + ч13 + ч14 + ч15 + ч16 + ч17+ ч18+ч19 + ч20 + ч21 + ч22 + ч23 + ч24 + ч25 + ч26 + ч27 + ч28 + ч29 + ч30 + ч31; конецПроцедуры // Всего
// Заполняет табличную часть документа Табель для одного или группы сотрудников процедура Заполнить() перем подр;
// Удаляем, если табличная часть заполняется для подразделение или всего предприятие, // ее строки, но только с согласия пользователя если (кто > 1) и (КоличествоСтрок() > 0) тогда
если Вопрос("Удалить имеющиеся строки?", "Да+Нет") = "Да" тогда
УдалитьСтроки(); // 04ищаем табли4ную 4асть документа
иначе
возврат; конецЕсли; конецЕсли; если кто = 1 тогда
// Указываем явно имя основной формы списка для метода ОткрытьПодбор // Задаем режим множественного выбора
// Добавляем в табличную часть в результате каждого выбора в открытой форме // данные одного сотрудника. Собственно добавление осуществляет // предопределенная процедура модуля формы ОбработкаПодбора ОткрытьПодбор("Справо4ник.Сотрудники_2", "ФормаСписка",, 1); ина4еЕсли кто >= 2 тогда // Подразделение или все предприятие
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Заносим в табличную часть данные о сотрудниках выбранного подразделения подр если кто = 2 тогда // Подразделение
подр = сПодр.ПолучитьЗначение(сПодр.ТекущаяСтрока()); сСотр_2.ИспользоватьРодителя(подр); конецЕсли;
с Сотр_2 .ВыбратьЭлементы();
пока сСотр_2.ПолучитьЭлемент() = 1 цикл
если сСотр_2.ЭтоГруппа() = 0 тогда // Только сотрудники
// Используем уже имеющуюся процедуру ОбработкаПодбора,
// выполняющую обработку одного сотрудника ОбработкаПодбора(сСотр_2,""); конецЕсли; конецЦикла; // пока конецЕсли;
если КоличествоСтрок() > 0 тогда форма.Удалить. Доступность(1); форма. Очистить .Доступность(1); конецЕсли;
конецПроцедуры // Заполнить
процедура ОбработкаПодбора(значен, конт)
// Запрещаем, если добавляем по одному сотруднику, выбор того же лица дважды если (кто = 1) и (ВыбратьСтроки( ) = 1) тогда пока ПолучитьСтроку( ) = 1 цикл
если Сотрудник = значен.ТекущийЭлемент( ) тогда Предупреждение("Сотрудник уже выбран."); возврат; конецЕсли; конецЦикла; // пока конецЕсли;
НоваяСтрока(); // Новая строка в табличной части табеля
Сотрудник = значен.ТекущийЭлемент();
ОдинСотрудник(); // Заполняет массив часы для одного сотрудника
// Определяем значения реквизитов документа ч1-чЗ 1 и всегоЧасов
Ч131();
Всего();
// Если есть хотя бы одна запись, то есть что удалять если (кто = 1) и (КоличествоСтрок() = 1) тогда форма.Удалить. Доступность(1); форма.Очистить.Доступность(1); конецЕсли;
конецПроцедуры // ОбработкаПодбора
// Удаляет с согласия пользователя, если флаг = 1, текущую запись табличной // части документа, и, если флаг = 2, все записи процедура УдалитьЗап(флаг) перем вопр;
вопр = "Удалить " + ?(флаг= 1, "одну запись", "все записи") + "?"; если Вопрос(вопр, "Да+Нет") = "Да" тогда если флаг = 1 тогда УдалитьСтроку();
иначе // флаг = 2
УдалитьСтроки(); конецЕсли;
если КоличествоСтрок() = О тогда форма.Удалить.Доступность(О); форма.Очистить.Доступность(О); конецЕсли; конецЕсли;
конецПроцедуры // УдалитьЗап
Результат автоматического заполнения табеля для сотрудников второго цеха приведен на рис. 7.46.
 |
|
Рис. 7.46. Фрагмент табеля цеха 02 |
7.6.5. МОДУЛЬ ДОКУМЕНТА
Содержит предопределенную процедуру ОбработкаПроведения. Она для каждого сотрудника табличной части заносит в ЖЗ расчеты Оклад_2, НДФЛ2 и ВБанк_2, а также вычисляет результат каждого введенного расчета. Поскольку вводимые расчеты должны обновляться при перепроведении, то метод их ввода - ВвестиРасчет, а не ЗаписатьРасчет. Даты начала и окончания всех расчетов совпадают с датами начала и конца текущего периода ЖЗ. Функция НайтиХозОп возвращает связанную с ВР хозяйственную операцию. Эти связи хранит справочник ХозОпДляВР (разд. 7.3.7). Число отработанных часов вводится только для ВР Оклад_2.
функция НайтиХозОп(хозОп, ВР) далее
процедура ВводРасчВЖЗ(жз, нтп, ктп, хозОп, ВР) далее
процедура ОбработкаПроведения() перем жз, нтп, ктп;
// Объект с разновидностью типа Справочник.ХозОпДляВР перем хозОп;
// Для поиска хозяйственных операций ВР
хозОп = СоздатьОбъект("Справочник.ХозОпДляВР");
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
нтп = жз.НачалоТекущегоПериодаО;
ктп = жз.КонецТекущегоПериодаО;
ВыбратьСтроки(); // Открываем выборку строк документа
пока ПолучитьСтроку( ) = 1 цикл
// Устанавливаем реквизиты для каждого вводимого ВР // ВР Оклад_2
жз.УстановитьРеквизит("всегоЧасов", всегоЧасов);
ВводРасчВЖЗ(жз, нтп, ктп, хозОп, ВидРасчета.Оклад_2);
// ВР НДФЛ_2
ВводРасчВЖЗ(жз, нтп, ктп, хозОп, ВидРасчета.НДФЛ_2);
// ВР ВБанк_2
ВводРасчВЖЗ(жз, нтп, ктп, хозОп, ВидРасчета.ВБанк_2); конецЦикла; // пока
// Вычисляем результаты введенных расчетов // Выборка записей ЖЗ по документу не дает верного результата // Поэтому используем выбор записей текущего периода по объекту ВыбратьСтроки(); // Открываем выборку строк документа
пока ПолучитьСтроку() = 1 цикл
жз.ВыбратьПериодПоОбъекту(Сотрудник, нтп); пока жз.ПолучитьЗапись() = 1 цикл
если жз.Документ = ТекущийДокументО тогда
// Метод Рассчитать вызывает процедуру ПровестиРасчет соответствующего ВР жз.Рассчитать( ); // или жз.ВыполнитьРасчет
конецЕсли; конецЦикла; // пока конецЦикла; // пока
если Проведен() = 0 тогда // Если документ проводится впервые
// Ограничиваем время показа окна с предупреждением тремя секундами Предупреждение(''Документ проведен.", 3); иначе
ПредупреждениеСДокумент перепроведен.", 3); конецЕсли;
конецПроцедуры // ОбработкаПроведения
// Вводит новые или редактирует имеющиеся в ЖЗ расчеты с заданным ВР процедура ВводРасчВЖЗ(жз, нтп, ктп, хозОп, ВР)
жз.УстановитьРеквизит("строкаДок", НомерСтроки); жз.УстановитьРеквизит("хозОп", НайтиХозОп(хозОп, ВР)); жз.ВвестиРасчет(Сотрудник, ВР, нтп, ктп); конецПроцедуры // ВводРасчВЖЗ
// Возвращает хозяйственную операцию ВР функция НайтиХозОп(хозОп, ВР)
// Ищем простым перебором в справочнике ХозОпДляВР вид расчета ВР
хозОп.ВыбратьЭлементы();
флаг = 0;
пока хозОп.ПолучитьЭлемент() = 1 цикл если хозОп.ВР = ВР тогда флаг = 1; прервать; конецЕсли; конецЦикла; // пока если флаг = 1 тогда
возврат хозОп.хозОп; иначе
возврат ПолучитьПустоеЗначение(хозОп); конецЕсли;
конецФункции // НайтиХозОп
Фрагмент ЖЗ после проведения табеля, например для сотрудников 2-го цеха, показан на рис. 7.47.
|
|
Сотрудник |
ВР |
Часы |
ІРезчльтаті |
Хоз. on. |
Начало I |
Оконча... |
|
Горюнова У льяна |
Начальное салъд |
|
0.50 |
2013000 |
01.12.01 I |
01.1201 | |
|
t] |
Горюнова Ульяна |
Оклад |
1Б5.0 |
3.200.00 |
2013000 |
01.12.01 |
31.12.01 |
|
|
Горюнова Ульяна |
НДФЛ |
|
|
2017002 |
01.12.01 |
31.12.01 |
|
ь |
Горюнова Ульяна |
Перечисление в С |
|
2.784.00 |
2300100 |
01.12.01 |
31.12.01 |
|
|
Рис. 7.47. Документ Табель проведен для сотрудников 2-го цеха |
Замечания:
1. Расчеты одного объекта располагаются в ЖЗ в порядке очередности их исполнения.
2. Чтобы быстро найти в ЖЗ сотрудника, следует переместиться на поле Сотрудник и начать набирать на клавиатуре его фамилию (рис. 7.48).
 |
|
Рис. 7.48. Локализация сотрудника в форме списка ЖЗ |
[«I
При поиске должна быть выбрана иконка , обеспечивающая отображение всех сотрудников текущего подразделения.
3. Ввод нового документа Табель проще всего выполнить, воспользовавшись кнопкой Ввод расчета, предусмотренной в диалоге формы ЖЗ (см. рис. 7.21).
4. Чтобы открыть документ Табель, породивший текущий расчет, достаточно, находясь в ЖЗ, нажать на правую кнопку мыши и выбрать соответствующий пункт появившегося меню (рис. 7.49).
 |
|
Рис. 7.49. Открываем документ Табель |
Тот же пункт можно выбрать и из колонки Действия меню интерфейса Ученик.
Команда проведения документа при выполнении перепроведения отслеживает все возможные произошедшие в документе изменения. Так, если в предопределенной процедуре ОбработкаПроведения после проведения документа закомментировать код, вводящий, например, расчеты с ВР ВБанк_2, то соответствующие расчеты исчезнут из ЖЗ в результате перепроведения документа. Если из проведенного документа удалить табель для какого-либо сотрудника, то в результате перепроведения все ранее порожденные документом расчеты, относящиеся к удаленному сотруднику, будут удалены и из ЖЗ и т. д.
Если по какой-либо причине табель на сотрудника заполняется повторно, то его проведение не приведет к появлению в ЖЗ новых расчетов, поскольку расчеты с ВР Оклад_2, НДФЛ_2 и ВБанк_2 созданы как самовытесняющиеся. Однако при этом старые расчеты будут заменены на вновь вводимые, поскольку нами использован метод ВвестиРасчет. Метод ЗаписатьРасчет также вводит расчеты в ЖЗ, но при этом само-вытесняющиеся расчеты остаются в ЖЗ неизмененными.
Если же перепроводится существующий Табель, то методы ВвестиРасчет и Запи-сатьРасчет работают совершенно одинаково.
Результаты введенных документом Табель расчетов оцениваются в процедуре Об-работкаПроведения после ввода расчетов следующим кодом:
// Выполняем расчет всех введенных записей жз.ВыбратьЗаписиПоДокументу(ТекущийДокумент( ));
пока жз.ПолучитьЗапись() = 1 цикл
// Метод Рассчитать вызывает процедуру ПровестиРасчет соответствующего ВР жз.Рассчитать( ); // или жз.ВыполнитьРасчет( );
конецЦикла; // пока
Рассмотрим теперь, как задаются свойства используемых нами ВР, и запишем для них код, возвращающий результат расчета. Прежде, однако, зададим правила перерасчета ВР.
ФОРМА СПИСКА ЖУРНАЛА ДОКУМЕНТОВ ТАБЕЛЬ
Документы Табель отображаются в одноименном журнале документов (см. рис. 7.40). Диалог формы списка этого журнала документов создадим в соответствии с рис. 7.50.
 |
|
Рис. 7.50. Диалог формы списка журнала документов Табель |
Модуль формы списка журнала документов Табель содержит предопределенную процедуру ПриОткрытии. Назначение процедуры такое же, как и у одноименной процедуры модуля формы списка журнала кадровых приказов (раз. 5.8.3.2).
// Список действий по документу. Передается процедуре глобального модуля // глДействия(ТекущийДокумент, сДейст) перем сДейст;
// Формирует список действий и устанавливает интервал журнала,
// отображающий все введенные документы вида Табель процедура ПриОткрытии()
перем дНач; // Дата начала интервала журнала Табель
перем флаг, док;
ОчиститьОкноСообщений();
// Определяем список действий для кнопки "Действия" сДейстДобавитьЗначение("Структура подчиненности"); сДейстДобавитьЗначение("Ввести на основании"); сДейст.ДобавитьЗначение("Движения документа");
флаг =1; // Равен единице, если удалось создать док
попытка
док = СоздатьОбъект("Документ.Табель"); исключение флаг = 0; конецПопытки;
если флаг = 1 тогда // Если документ Табель создан
// Находим документ с наименьшей датой. По умолчанию документы // располагаются в выборке по возрастанию их дат док. ВыбратьДокументы();
если док.ПолучитьДокумент() = 1 тогда дНач = док.ДатаДок; иначе
дНач = ТекущаяДата(); конецЕсли;
иначе // Искомого документа нет
дНач = ТекущаяДата();
конецЕсли;
УстановитьИнтервал(дНач, ТекущаяДата()); конецПроцедуры // ПриОткрытии
// В основной программе модуля всего один оператор сДейст = СоздатьОбъект(''СписокЗначений'');
7.7. ПРАВИЛА ПЕРЕРАСЧЕТА ВИДОВ РАСЧЕТОВ
Все используемые нами ВР в конфигурацию уже добавлены (разд. 7.3.5). Теперь нам нужно уточнить их свойства.
Известно, что результаты одних расчетов зависят от результатов других. Так, налогом облагаются ВР Оклад_2 и все премии. Поэтому ВР НДФЛ_2, возвращающий размер налога, называется зависимым или подчиненным. Виды расчетов, от которых ВР НДФЛ2 зависит, называются ведущими. Другой пример: ВР ВБанк_2 зависит от всех иных ВР и должен пересчитываться при вводе каждого расчета.
Система информирует о необходимости расчета зависимых записей ЖЗ, меняя значение их атрибута Рассчитана с 1 на 0. Соответствующим образом изменяются и иконки, сопровождающие записи. Такая смена значения атрибута Рассчитана обеспечивается правилами перерасчета, которые определяются в конфигурации в подразделе Правила перерасчета раздела Виды расчетов.
Добавим новое правило с именем НДФЛ2, определив ведущие и зависимый ВР в соответствии с рис. 7.51.
 |
|
Рис. 7.51. Правило перерасчета для ВРНДФЛ_2 |
Это правило будет срабатывать при вводе ВР, отмеченных в левом списке рисунка, приводя к обнулению значения атрибута Рассчитана у ВР, отмеченного в правом списке. В нашем случае галочку возле ВР Оклад_2 из левого списка можно убрать, поскольку расчеты с ВР Оклад_2 и НДФЛ_2 вводятся в ЖЗ одним документом, что явным образом обеспечивает изменение значения атрибута Рассчитана.
Добавим теперь в конфигурацию и другие нужные нам правила перерасчета. Их общий список приведем в табл. 7.12.
Таблица 7.12
Новые правила перерасчета |
Идентифи
катор |
Ведущие ВР |
Зависимый
ВР |
|
НДФЛ_2 |
Оклад_2, ПремияКоэф_2, ПремияСум_2, Премия 1234_2 |
НДФЛ_2 |
|
ВБанк_2 |
НачСальдо 2, Оклад 2, ПремияКоэф 2, ПремияСум 2, Премия1234_2, НДФЛ_2 |
ВБанк_2 |
|
Премия 1234_2 |
Оклад_2, ПремияКоэф_2, ПремияСум_2 |
Премия1234_2 |
|
Таким образом, благодаря этим правилам мы будем практически всегда иметь в ЖЗ верные сведения о том, какие записи нужно рассчитать заново, воспользовавшись, например, соответствующим пунктом колонки Действия меню системы (рис. 7.52).
|
Я Рас с читалъ іашкь |
|
|
“р Рассчитать объект |
л |
Горюнова Улына |
Начальное с- |
|
-о^о] |
|
«1 |
Горюнова Ульяна |
Оклад |
165.0! |
3200 00І |
V
т
1
1 |
? |
Горюнова У льяна |
НДФЛ |
|
416.001 |
|
-1 |
О |
Горюнова Ульяна |
Перечне лет* |
|
2.784.001 |
|
|
Рис. 7.52. Расчет отдельной записи ЖЗ |
Правила перерасчета срабатывают не только при вводе, но и при ручной правке ведущего ВР.
Замечание. Ситуация, когда не работают правила перерасчета, анализируется в разд. 7.10.1.
7.8. ВИДЫ РАСЧЕТОВ ДОКУМЕНТА ТАБЕЛЬ
7.8.1. ВИД РАСЧЕТА ОКЛАД_2
Выполним всю цепочку задания свойств ВР Оклад_2, включающую также и написание кода процедуры получения результата.
Предварительно, однако, нам потребуется создать группу ВР ВсеНачисления_2, в которую мы будем включать расчеты-начисления, облагаемые НДФЛ.
Войдем к конфигурацию, добавим группу ВР ВсеНачисления_2 (рис. 7.53), включив в нее указанные на рис. 7.54 ВР.
В Л Группы расчетов
м ВсеУдержания_2 •« ВсеНачисления_2
Рис. 7.53. Добавляем группу ВР ВсеНачисления_2 в конфигурацию системы
Группа расчетов ВсеНачисления 2
?мионим: |Все начисления
ИдемгиФшатор: |ВсеНачисления_2
комментарий: |Для сотрудников из справочника Сотруаники_2
Включает вины расчетов
Не включает еиоы расчетов
Авторские АвторскиеЗаАП АвторскиеЗаИП
Оклад.2
Премчяі 234_2
Прениям рои 2
АвторскиеЗаЛП
ПремияСуи_2
|
Рис. 7.54. Группа ВР ВсеНачисления_2 |
 |
Раскроем далее окно задания свойств ВР Оклад_2 (рис. 7.55).
-•• Рис. 7.55. Окно задания свойств ВР Оклад_2
Воспользовавшись кнопкой Настройка вытеснения, зададим ВР Оклад_2 как само-вытесняющийся (рис. 7.56).
 |
|
Рис. 7.56. Теперь ВР Оклад_2 является самовытесняющимся |
Допишем в модуль ВР следующий код:
процедура ПровестиРасчет() // Процедура модуля ВР Оклад_2
// Процедура выполняется при проведении расчета с ВР Оклад_2 перем всегоЧасовПоКалендарю, нтп, ктп;
// На случай непредусмотренной ошибки
если ПустоеЗначение(Объект.Календарь) = 1 тогда
Сообщшъ("Сотруцник " + СокрП(Объект.Наименование) + " не имеет календаря."); возврат; конецЕсли;
нтп = НачалоТекущегоПериода(); ктп = КонецТекущегоПериода();
всегоЧасовПоКалендарю = Объекг.Календарь.Часов(нгп, ктп); если всегоЧасовПоКалендарю > 0 тогда
результат = Объект.Оклад.Получитъ(ктп) * всегоЧасов / всегоЧасовПоКалендарю; -иначе // На случай непредусмотренной ошибки
Сообщить("В календаре сотрудника " + СокрП(Объект.Наименование) +
" нет рабочих дней."); конецЕсли;
конецПроцедуры // ПровестиРасчет Замечания:
\i. Значение периодического реквизита Оклад, возвращается методом справочника Получитъ. Простое использование Объект.Оклад даст нулевой результат
2. Весь код, если бы не проверки, можно было бы разместить в одном операторе:
результат = Объект.Оклад.Получит^КонецТекущегоПериодаО) * всегоЧасов /
Объект.Календарь.Часов(НачалоТекущегоПериодаО, КонецТекущегоПериода());
7.8.2. ВИД РАСЧЕТА НДФЛ_2
ВР НДФЛ_2 также сделаем самовытесняющимся. Ранее этот ВР мы включили в группу ВР ВсеУдержания_2, которую употребили при оценке начального сальдо. Нам же для расчета налога понадобится группа ВР ВсеНачисления_2. Ее присутствие сократит код процедуры вычисления результата:
процедура ПровестиРасчет() // Процедура модуля ВР НДФЛ_2
// Процедура выполняется при проведении расчета с ВР НДФЛ_2 перем жз, нтп, ктп, налог;
жз = СоздатъОбъект("ЖурнапРасчетов.Зарплата_2"); нтп = жз.НачалоТекущегоПериода(); ктп = жз.КонецТекущегоПериода(); налог = 0;
жз.ВыбратьПериодПоОбъекту^бъект, нтп); пока жз.ПолучитьЗапись() = 1 никл
если жз.ВидРасч.ВходитВГруппу(ГруппаРасчетов.ВсеНачисления_2) = 1 тогда налог = налог + жз.результат; конецЕсли; конецЦикла; // пока
// Константа СтавкаНалога является периодической
результат = налог * Константа.СтавкаНалогаПолучит^ктп) /100;
КонецПроцедуры // ПровестиРасчет
Замечание. Будет неверным вместо метода
жз.ВыбратьПериодПоОбъекіу^бъект, нтп);
использовать метод
жз.ВыбратьЗаписиПоОбъекту(Объект, нтп, ктп);
поскольку последний выбирает записи, период действия которых лежит между нтп и ктп. В то же время метод ВыбратьПериодПоОбъекту выбирает все записи, зарегистрированные в текущем периоде и действующие как в текущем, так и в будущих или прошлых периодах.
Чтобы процедура работала, в конфигурацию необходимо добавить периодическую числовую константу СтавкаНалога, положив ее равной, например, 13 %. Последнее можно сделать, запустив после создания константы следующую процедуру:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
Константа.СтавкаНалога.Установить(ТекущаяДатаО, 13); конецПроцедуры // Выполнить
7.8.3. ВИД РАСЧЕТА ВБАНК_2
Самовытесняющийся ВР ВБанк_2 оценивается следующей процедурой: процедура ПровестиРасчет() // Процедура модуля ВР ВБанк_2
// Процедура выполняется при проведении расчета с ВР ВБанк_2 // Формула расчета:
// банк = Целая часть(Начальное сальдо + Все начисления - Все удержания) перем жз, нтп, ВР, банк;
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2''); нтп = жз.НачалоТекущегоПериодаО; банк = 0;
// См. замечание относительно метода ВыбратьЗаписиПоОбъекту в предыдущем разделе жз.ВыбратьПериодПоОбъекту(Объект, нтп); пока жз.ПолучитьЗапись() = 1 цикл ВР = жз.ВидРасч;
если (ВР.ВходитВГруппу(ГруппаРасчетов.ВсеНачисления_2) = 1) или (ВР = ВидРасчета.НачСальдо_2) тогда банк = банк + жз.результат;
иначеЕсли ВР.ВходитВГруппу(ГруппаРасчетов.ВсеУдержания_2) = 1 тогда банк = банк - жз.результат; конецЕсли; конецЦикла;//пока
результат = Цел(банк); // Для записи в ЖЗ берем целую часть результата конецПроцедуры // ПровестиРасчет
7.9. ПРЕМИИ
7.9.1. СВОЙСТВА ДОКУМЕНТА
В ЖЗ на данный момент введены расчеты только с обязательными ВР (рис. 7.47). Позаботимся теперь о премиях.
Ввод расчетов-премий будем, как и договаривались, выполнять одним документом - Премия (см. табл. 7.2). Этим документом можно вводить как один выбранный ВР, например ПремияКоэф_2, так несколько премиальных ВР. Проведение документа осуществляется лишь в том случае, когда все сотрудники, представленные к премии и перечисленные в табличной части документа, имеют ненулевую премию. Причем в режиме одновременного начисления нескольких премий, например ПремияКоэф_2, ПремияСум_2 и Премия 12342, они должны быть ненулевыми для каждого сотрудника, занесенного в документ.
Расчеты, порождаемые документом, будут иметь один период действия, задаваемый в шапке документа. В табличной части мы перечислим сотрудников, получивших премию и ее размер.
Напомним формулы для расчета премиальных:
ПремияКоэф_2 = всегоЧасов * к3; // к3 - устанавливаемый руководителем коэффициент
// По умолчанию к3 = 10 для всех сотрудников ПремияСум_2 = Сумма_премии; // Сумма премии устанавливается руководителем // к5 - постоянный для всех сотрудников коэффициент // Берется из списка периодических констант Премия 1234_2 = (Оклад_2 + ПремияКоэф_2 + ПремияСум_2) * к5;
Премия 12342 не требует ввода какого-либо числового значения. Достаточно указать факт ее начисления, что можно сделать, например, при помощи, перечисления ДаНет. По умолчанию, если начисляется Премия1234_2, всем попавшим в список документа сотрудникам установим значение Да. Сотрудники, не получающие премию это вида, из списка удаляются.
Период действия ВР-премий может быть разным. Поэтому нужно иметь возможность задавать даты начала и конца действия каждого ВР.
Учитывая приведенные сведения, определим свойства документа в соответствии с рис. 7.57.
 |
|
Рис. 7.57. Свойства документа Премия |
Свойства реквизитов документа, кроме заданных по умолчанию, опишем в табл. 7.13.
Таблица 7.13
Реквизиты документа Премия |
|
Реквизиты |
Описание |
Тип
(разновидность типа) /Ддина-Точность |
|
Реквизиты шапки документа |
ДатаНачКоэф,
ДатаКонКоэф |
Соответственно дата начала и конца действия расчетов с ВР ПремияКоэф_2 |
Дата |
ДатаНачСум,
ДатаКонСум |
Соответственно дата начала и конца действия расчетов с ВР ПремияСум_2 |
|
ДатаНач1234,
ДатаКон1234 |
Соответственно дата начала и конца действия расчетов с ВР Премия 1234_2 |
|
|
кто |
Способ заполнения табличной части документа. Используется как идентификатор радиокнопок диалога формы списка документа. Если кто = 1, то подбор выполняется по одному сотруднику; если кто = 2, то в табличную часть документа заносятся сотрудники выбранного подразделения. Используется при открытии проведенного документа |
Числовой /1.0 |
|
коэф, сум, п1234 |
Флаги начисления премий соответственно коэффициентом, суммой или 1234. Премия начисляется, если флаг равен единице, и не начисляется, если флаг равен нулю |
Числовой /1.0 |
|
текСтрока |
Номер выбранной строки в списке подразделений сПодр. Используется при открытии проведенного документа для верного позиционирования списка подразделений |
Числовой / 3.0 |
|
Реквизиты табличной части документа |
|
Сотрудник |
Сотрудник, получающий премию |
Справочник.
Сотрудники_2 |
|
к3 |
Коэффициент для расчета ПремииКоэф_2.
По умолчанию к3 = 10. Соответствующий столбец табличной части имеет заголовок Коэф. |
Числовой / 3.0 |
|
Сумма |
Сумма премии по ВР ПремияСум_2 |
Числовой /10.2 |
|
Премия1234 |
Флаг начисления премии по ВР Премия 1234_2 |
Перечисление ДаНет |
|
Новый документ можно завести как из формы списка ЖЗ Зарплата_2, нажав на кнопку Ввод расчета (см. рис. 7.21), так и из колонки Документы меню интерфейса Ученик (см. рис. 7.45). Старые документы по премии доступны из ЖЗ и могут быть открыты в журнале документов Расчеты.
|
Замечание. Выбор значения перечисления ДаНет выполняется из отображенного на рис. 7.58 списка. |
 |
|
Рис. 7.58. Выбор значения перечисления в ячейке столбца Премия 1234 табличной части документа |
7.9.2. ДИАЛОГ ФОРМЫ СПИСКА ДОКУМЕНТА
7.9.2.1. СЛОИ ДИАЛОГА
Диалог формы списка документа Премия оформим (больше с учебной целью) с двумя закладками, расположив его реквизиты на четырех слоях. Состав основного слоя приведем в соответствие с рис. 7.59.
 |
|
Рис. 7.59. Основной слой диалога формы списка документа Премия |
На втором слое, которому мы дали имя ВидПремии, расположим флажки коэф, сум и и 1234, указывающие на вид начисляемой премии (рис. 7.60).
 |
|
Рис. 7.60. Элементы диалога слоя ВидПремии |
Конечно же, основной и второй слои можно было бы благополучно совместить, переместив вид премии на первый слой. Однако, вновь руководствуясь учебными целями, мы сохраним существующее разбиение элементов диалога по слоям.
На слое номер 3, имя которого ИнтервалыРасчетов, предусмотрим задание дат начала и конца всех ВР (рис. 7.61), оставив справа полосу для размещения трех нижних кнопок четвертого слоя.
Интервалы действия расчетов Вид премии Начало интервала Конец интервала
Премия коэффициентом (датаНачКсо^ |ДатаКоиКсо[?|
Премия суммой |ДатаНачСуг^П| . [ДэтаКо«Су*{П]
Премия 1234 |ЛатаНач12з|о| |Дата*Сон123{?|
Рис. 7.61. Состав слоя третьего слоя
Последний, четвертый слой отведем под кнопки (рис. 7.62).
ЗапоФФпъ
Удалить
Очистить
Провести
ОК
Закрыть
Рис. 7.62. Расположение кнопок на четвертом слое диалога
Замечание. При вставке в диалог числового реквизита формата 1.0 (или нескольких числовых реквизитов такого формата) имеется возможность разместить его как поле ввода, флажок или переключатель. Если хотя бы один вставляемый реквизит имеет иной тип или формат, то все реквизиты можно вставить только как поля ввода. Поэтому мы выполнили поэтапную вставку, выбрав для реквизитов кто и прем поле типа переключатель.
Задание дополнительных слоев осуществляется в результате выполнения цепочки Диалог - Слои - выбрать иконку Новый слой ( ) в появившемся диалоге (рис. 7.63) -ввести имя слоя (рис. 7.64) - ОК.
 |
|
Рис. 7.63. Слои диалога формы списка документа Премия |
 |
|
Рис. 7.64. Новый слой диалога |
В окне слоев (рис. 7.63) также осуществляется переход со слоя на слой, удаление слоев и их сортировка. Перемещение выделенных элементов диалога с одного слоя на другой производится посредством пункта Поместить колонки Диалог меню системы (рис. 7.65).
 |
|
Рис. 7.65. Пункты меню для перемещения выделенных элементов диалога на другой слой |
7.9.2.2. ЗАКЛАДКИ ДИАЛОГА
Созданные слои будем отображать на двух закладках: Ввод премий и Интервалы расчетов. На первой закладке одновременно выводятся слои 1, 2 и 4 (Основной, ВидПремии и Кнопки), а на второй - слои 3 (ИнтервалыРасчетов) и 4. Причем при выводе слоя 4 на закладке 2 первые 3 кнопки невидимы.
Описание закладок заносится в атрибут формы Закладки, который является объектом типа СписокЗначений. Это можно сделать, например, в предопределенной процедуре модуля формы ПриОткрытии, разместив в ней следующий код:
// Следующий метод обеспечивает доступ к атрибуту Закладками Форма. ИспользоватьЗакладки( 1);
Форма.Закладки.ДобавитьЗначение(1, "Ввод премий");
Форма.Закладки.ДобавитьЗначение(2, "Интервалы расчетов");
// Теперь можно задать отображаемые на закладке слои Форма.ИспользоватьСлой("Основной, ВидПремии, Кнопки");
Таким образом, с каждой закладкой можно связать один или более слоев. Информация о том, какие слои и какие их элементы должны отображаться при выборе закладки, располагается в предопределенной процедуре модуля формы ПриВыбореЗакладки. В нашем случае она может содержать следующий код:
процедура ПриВыбореЗакладки(номЗакл, значЗакл)
// номЗакл, значЗакл - соответственно номер и значение закладки. В нашем случае // значения этих параметров совпадают если номЗакл = 1 тогда
Форма.ИспользоватьСлой("Основной, ВидПремии, Кнопки");
// заполнить, удалить и очистить - идентификаторы одноименных кнопок Форма. Заполнить. Видимость( 1);
Форма.Удалить. Видимость( 1);
Форма. Очистить. Видимость( 1); иначе
Форма.ИспользоватьСпой(''ИнтервалыРасчетов, Кнопки");
Форма. Заполнить. Видимость(0);
Форма.Удалить. Видимость(0);
Форма. Очистить. Видимость(0); конецЕсли
конецПроцедуры // ПриВыбореЗакладки
В результате проделанной работы мы будем получать на введенных заклад: приведенные на рис. 7.66 и 7.67 изображения.
Ввод прений Интервалы расчетов]
221201
Приказ о прении №
Вид преміи
Режим заполненія
р Коэффициент
Р Счьвла
р Прения 1234
Цех 01 Цех
Премия! 234
Заполигъ
Агальцов Юрий Алексеевич
500 00
Добрецов Борис Юрьевич
Удалитъ
Бараненков Иван Ильич
Очистить
Волосков Михаил Андреевич
Кузьмина Раиса Николаевна
500.00
Провести
Васильева Елена Ивановна
Смирнова Нина Федоровна
500 00
Закрыть
Рис. 7.66. Закладка Ввод премий |
|
Весе пренаай Интервалы расчетов! |
|
|
Интервалы действия расчетов |
|
|
|
Вид премии Начало интервала Конек интервала
Премия коэффициентом |оі.і201 |п| |11.1201 |g| |
|
Премия суммой |121201 |п| |221201 [?] |
Провести 1 |
|
Премия 1234 J231201 |п| |31.1201 |п| |
ОК |
|
Закрыть |
|
Рис. 7.67. Закладка Интервалы расчетов
Замечание. Код подготовки закладок несколько упростится, если кнопки Заполнить, Удалить и Очистить разместить на основном слое.
7.9.2.3. ЭЛЕМЕНТЫ ДИАЛОГА И ИХ ФОРМУЛЫ
Свод элементов диалога дадим в табл. 7.14.
Таблица 7.14
Элементы диалога формы списка документа Премия и их формулы |
Элементы
диалога |
Формула/команда |
Описание |
|
Режим заполнения; радикнопки Сотрудник и Цех (имеет идентификатор кто) |
Проследить() |
Управляет доступностью элемента диалога сПодр. Если кто = 1 (активна радиокнопка Сотрудник), то элемент сПодр недоступен, если кто = 2, то элемент доступен |
|
сПодр |
ОтобразитьСПодрО |
Отображает имя выбранного в списке сПодр подразделения и запоминает значение текущей строки списка текСтрока |
|
флажки коэф, сум и п1234 |
Столбцы() |
Задают вид вводимого ВР. Регулируют видимость столбцов табличной части следующим образом: если коэф = 1, то виден только столбец Коэф.; если сум = 2, то - столбец Сумма, если п1234 = 1, то - столбец 1234, если какая-либо переменная диалога равна нулю, то соответствующий столбец не виден |
|
Заполнить |
Заполнить() |
Заполняет табличную часть для сотрудников выбранного подразделения, если кто = 2, или открывает форму подбора сотрудников, если кто = 1 |
|
Удалить |
УдалитьЗап(1) |
Удаляет текущую строку табличной части. Удалению предшествует запрос о необходимости удаления. Доступен, если в табличной части есть хотя бы одна запись |
|
Очистить |
УдалитьЗап(2) |
Удаляет все строки табличной части. Удалению предшествует запрос о необходимости удаления. Доступен, если в табличной части есть хотя бы одна запись |
|
Провести |
#Провести |
Выполняет проведение (перепроведение) документа Премия, то есть заносит в ЖЗ расчеты выбранными ВР-премиями |
|
ОК |
#3аписать Провести Закрыть |
Выполняют проведение (перепроведение), запись и закрытие документа. Документ сохраняется в журнале документов Расчеты |
|
Закрыть |
#3акрыть |
Закрывает документ |
|
Элементы диалога НомерДок, ДатаДок, № и Сотрудник сделаем недоступными. Доступность и видимость других элементов определяется состоянием диалога.
7.9.3. МОДУЛЬ ФОРМЫ СПИСКА ДОКУМЕНТА
Содержит, кроме названных в табл. 7.14, процедуры ПриОткрытии, ПриЗаписи и ПремияДа.
перем кЗПоУмолчанию; // Значение задается в процедуре ПриОткрытии процедура Проследить() далее
процедура Столбцы() далее
процедура ПремияК10() далее
процедура ПремияДа(пЗнач) далее
процедура Заполнить() далее
процедура ОбработкаПодбора(значен, конт) далее
процедура УдалитьЗап(флаг) далее
процедура КнопкиВидимость(флаг) далее
// Формирует список подразделений сПодр и устанавливает начальные значения // переменных диалога. Причем, если документ проведен, то начальные // значения берутся из ЖЗ процедура ПриОткрытии() перем жз, сСотр_2, дост;
// Значение коэффициента к3 по умолчанию; можно оформить как константу 1С кЗПоУмолчанию = 10;
сСотр_2 = СоздатъОбъект(''Справочник.Сотрудники_2'');
// Формируем, анализируя справочник Сотрудники_2, список подразделений сСотр_2.ПорядокКодов(); с Сотр_2. ВыбратьЭлементы (); пока сСотр_2.ПолучитьЭлемент() = 1 цикл
если сСотр_2.ЭтоГруппа() = 1 тогда
сПодр.ДобавитъЗначение(сСотр_2.ТекущийЭлемент(), сСотр_2.Наименование); конецЕсли; конецЦикла; // пока если Проведен() = 0 тогда
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
// Начальные значения для периодов действия вводимых расчетов
датаНачКоэф = жз.НачалоТекущегоПериода();
датаКонКоэф = датаНачКоэф +10;
датаНачСум = датаКонКоэф + 1;
датаКонСум = датаНачСум + 10;
датаНач1234 = датаКонСум + 1;
датаКон1234 = жз.КонецТекущегоПериода();
жз = 0;
кто = 2; // Премия сотрудникам выбранного подразделения
коэф =1; // Можно начислить премию коэффициентом
сум = 0; п1234 = 0;
текСтрока =1; // Позиционируемся на цехе 01 в списке сПодр
иначе // Документ проведен
если кто = 2 тогда // Правильно позиционируем список значений сПодр сПодр.ТекущаяСтрока(текСтрока); конецЕсли; конецЕсли;
// Регулируем доступность и видимость элементов диалога Проследить( );
Столбцы( );
// дост — 1, если в табличной части есть записи дост = ?(КоличествоСтрок() = 0, 0, 1); форма.Удалить.Доступность(дост); форма.Очистить.Доступность(дост);
форма.ПанельИнструментов(0); // Отключаем панель инструментов
форма.ЗаголовокС'Премии'');
// Следующий метод обеспечивает доступ к атрибуту Закладками Форма.ИспользоватьЗакладки(1);
Форма.Закладки.ДобавитьЗначение(1, "Ввод премий"); Форма.Закладки.ДобавитьЗначение(2, "Интервалы расчетов");
// Теперь можно задать отображаемые на закладке слои Форма.ИспользоватьСлой("Основной, ВидПремии, Кнопки"); конецПроцедуры // ПриОткрытии
// Распределяет слои диалога формы по закладкам процедура ПриВыбореЗакладки(номЗакл, значЗакл)
// номЗакл, значЗакл - соответственно номер и значение закладки // В нашем случае значения этих параметров совпадают если номЗакл = 1 тогда
Форма.ИспользоватьСлой("Основной, ВидПремии, Кнопки "); КнопкиВидимость(1); // Показываем все кнопки
иначе
Форма.ИспользоватьСлой("ИнтервалыРасчетов, Кнопки ");
КнопкиВидимость(0); // Скрываем три верхние кнопки
конецЕсли
конецПроцедуры // ПриВыбореЗакладки
// Управляет видимостью кнопок Заполнить, Удалить и Очистить (см. рис. 7.61) процедура КнопкиВидимость(флаг)
// заполнить, удалить и очистить - идентификаторы одноименных кнопок Форма.Заполнить.Видимость(флаг);
Форма.Удалить.Видимость(флаг);
Форма.Очистить.Видимость(флаг); конецПроцедуры // КнопкиВидимость
// Управляет доступностью элемента диалога сПодр процедура Проследить()
Премия отобранным сотрудникам кто = 2
если кто = 1 тогда //
форма.СПодр.Доступность(0); иначе //
форма.СПодр .Доступность( 1); конецЕсли;
КонецПроцедуры // Проследить
//Управляет видимостью столбцов Коэф., Сумма и Премия 1234 табличной части документа // и доступностью элементов задания дат на слое ИнтервалыРасчетов
процедура Столбцы()
форма.кЗ.Видимость(коэф); // Премия коэффициентом
форма.ДатаНачКоэф.Доступность(коэф);
форма.ДатаКонКоэф.Доступность(коэф);
форма.Сумма.Видимость(сум); // Премия суммой
форма. ДатаНачСум.Доступность(сум); форма.ДатаКонСум.Доступность(сум);
форма.Премия1234.Видимость(п1234); // Премия 1234
фор'ма.ДатаНач1234.Доступность(п1234);
форма.ДатаКон1234.Доступность(п1234);
если коэф = 1 тогда // Премия коэффициентом
// Заносим в пустые столбцы ПремияКоэф равный кЗПоУмолчанию коэффициент ПремияК10(); конецЕсли;
если п1234 = 1 тогда // Премия 1234
// Заносим в пустые столбцы Премия 1234 значения Да перечисления ДаНет ПремияДа(Перечисление. ДаНет.ЗначениеПоНомеру(1)); конецЕсли;
конецПроцедуры // Столбцы
процедура ОтобразитьСПодр() // Формула элемента диалога сПодр
текСтрока = сПодр.ТекущаяСтрока(); сПодр.ПолучитьЗначение(текСтрока); конецПроцедуры // ОтобразитьСПодр
// Заносит в пустые ячейки столбца задания коэффициента к3 // равный кЗПоУмолчанию коэффициент процедура ПремияК10()
если ВыбратьСтроки() = 1 тогда
пока ПолучитьСтроку() = 1 цикл
к3 = ?(к3 = 0, кЗПоУмолчанию, к3); конецЦикла; // пока конецЕсли;
конецПроцедуры // ПремияК10
// Заносит в пустые столбцы Премия 1234 значения Да перечисления ДаНет процедура ПремияДа(пЗнач)
если ВыбратьСтроки() = 1 тогда
пока ПолучитьСтроку() = 1 цикл
если ПустоеЗначение(Премия1234) = 1 тогда Премия 1234 =пЗнач; конецЕсли; конецЦикла; // пока конецЕсли;
конецПроцедуры // ПремияДа
// Заполняет табличную часть документа Премия для одного (кто = 1)
// или группы сотрудников процедура Заполнить() перем подр;
// Удаляем, если табличная часть заполняется для подразделения // или всего предприятия, ее строки, но только с согласия пользователя если (кто > 1) и (КоличествоСтрок( ) > 0) тогда
если Вопрос("Удалить имеющиеся строки?", "Да+Нет") = "Да" тогда
УдалитьСтроки(); // Очищаем табличную часть документа
иначе
возврат; конецЕсли; конецЕсли; если кто = 1 тогда
// Указываем явно имя основной формы списка для метода ОткрытьПодбор // Задаем режим множественного выбора
// Добавляем в табличную часть в результате каждого выбора в открытой форме // данные одного сотрудника. Собственно добавление осуществляет // предопределенная процедура модуля формы ОбработкаПодбора ОткрытьПодбор("Справочник.Сотрудники_2", "ФормаСписка",, 1); иначеЕсли кто = 2 тогда // Работаем с подразделением
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Заносим в табличную часть данные о сотрудниках выбранного подразделения подр
подр = сПодр.ПолучитьЗначение(сПодр.ТекущаяСтрока());
сСотр_2.ИспользоватьРодителя(подр);
сСотр_2.ВыбратьЭлементы();
пока сСотр_2.ПолучитьЭлемент() = 1 цикл
если сСотр_2.ЭтоГруппа() = 0 тогда // Только сотрудники
// Используем уже имеющуюся процедуру ОбработкаПодбора,
// выполняющую обработку одного сотрудника ОбработкаПодбора(сСотр_2,""); конецЕсли; конецЦикла; // пока конецЕсли;
если КоличествоСтрок() > 0 тогда форма.Удалить.Доступность(1); форма.Очистить.Доступность(1); конецЕсли;
конецПроцедуры // Заполнить
процедура ОбработкаПодбора(значен, конт)
// Запрещаем, если добавляем по одному сотруднику, выбор того же лица дважды если (кто = 1) и (ВыбратьСтроки() = 1) тогда пока ПолучитьСтроку() = 1 цикл
если Сотрудник = значен.ТекущийЭлемент() тогда Предупреждение("Сотрудник уже выбран."); возврат; конецЕсли; конецЦикла; // пока конецЕсли;
НоваяСтрока(); // Новая строка в табличной части документа
Сотрудник = значен.ТекущийЭлемент();
// Премия коэффициентом или 1234 если (коэф = 1) или (п1234 = 1) тогда
к3 = кЗПоУмолчанию; // Коэффициент по умолчанию
конецЕсли;
если п1234 = 1 тогда // Премия 1234 или все премии
// Заносим в столбец Премия 1234 значение Да перечисления ДаНет Премия 1234 = Перечисление.ДаНет.ЗначениеПоНомеру(1); конецЕсли;
// Если есть хотя бы одна запись, то есть что удалять если (кто = 1) и (КоличествоСтрок() = 1) тогда форма.Удалить.Доступность(1); форма.Очистить .Доступность( 1); конецЕсли;
конецПроцедуры // ОбработкаПодбора
// Удаляет с согласия пользователя, если флаг = 1, текущую запись табличной // части документа, и, если флаг = 2, все записи процедура УдалитьЗап(флаг) перем вопр;
вопр = "Удалить " + ?(флаг = 1, "одну запись", "все записи") + "?"; если Вопрос(вопр, "Да+Нет") = "Да" тогда если флаг = 1 тогда УдалитьСтроку();
иначе // флаг = 2
УдалитьСтроки(); конецЕсли;
если КоличествоСтрок() = О тогда форма.Удалить.Доступность(О); форма.Очистить.Доступность(О); конецЕсли; конецЕсли;
конецПроцедуры // УдалитьЗап
// Выполняет проверку дат процедура ПриЗаписи() перем ош; ош = 0;
если (коэф = 1) и (датаНачКоэф > датаКонКоэф) тогда ош = 1; конецЕсли;
если (сум = 1) и (датаНачСум > датаКонСум) тогда ош = 1; конецЕсли;
если (п1234 = 1) и (датаНач1234 > датаКон1234) тогда ош= 1; конецЕсли; если ош = 1 тогда
Предупреждение("Неверный период действия расчета."); СтатусВозврата(0); // Запрещаем запись документа
конецЕсли;
конецПроцедуры // ПриЗаписи
7.9.4. МОДУЛЬ ДОКУМЕНТА
Содержит предопределенную процедуру ОбработкаПроведения. Она для каждого сотрудника табличной части заносит в ЖЗ либо выбранный расчет, либо все расчеты. Причем расчеты заносятся с вычисленными результатами.
Документ можно провести, лишь когда все заданные премии имеют ненулевое значение. В противном случае выдается сообщение; расчеты в ЖЗ не переносятся.
функция ПровершъНаНульО далее функция НайтиЧасы(жз, нтп) далее функция НайтиХозОп(хозОп, ВР) далее
процедура ВводРасчВЖЗ(жз, хозОп, ВР, датаНач, датаКон, рез) далее
процедура ОбработкаПроведения() перем жз, нтп;
перем ВР[3], рассч[3], всегоЧасов[3], рез[3], датаНач[3], датаКон[3]; перем а, б, ин;
// Объект с разновидностью типа Справочник.ХозОпДляВР перем хозОп;
датаНач[1] = датаНачКоэф; датаКон[1] = датаКонКоэф;
датаНач[2] = датаНачСум; датаКон[2] = датаКонСум;
датаНач[3] = датаНач1234; датаКон[3] =датаКон1234;
если ПроверитъНаНулъО = 1 тогда
Предупреждение("Есть расчеты с нулевой премией."); возврат; конецЕсли;
// Для поиска хозяйственных операций ВР хозОп = СоздатъОбъект("Справочник.ХозОпДляВР"); жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); нтп = жз.НачалоТекущегоПериодаО;
// ВР - массив видов премий ВР[1] = ВидРасчета.ПремияКоэф_2;
ВР[2] = ВидРасчета.ПремияСум_2;
ВР[3] = ВидРасчета.Премия1234_2;
для ин = 1 по 3 цикл // Инициализация вспомогательных массивов
// Массив рассч используется для задания значения атрибута ЖЗ Рассчитана рассч[ин] = 0; всегоЧасов[ин] = 0; рез[ин] = 0; конецЦикла; // для
ВыбратьСтроки(); // Открываем выборку строк документа
пока ПолучитьСтроку() = 1 цикл
// Устанавливаем реквизиты для каждого вводимого ВР
а = 1; б = 2; // Параметры цикла Для, вводящего расчеты в ЖЗ
если коэф = 1 тогда // Премия коэффициентом // Найдем по ЖЗ число часов, отработанных сотрудником всегоЧасов[1] = НайтиЧасы(жз, нтп); рез[1] = всегоЧасов[ 1 ] * к3; // Начисленная премия рассч[1] =1; // Запись рассчитана
конецЕсли;
|
если сум = 1 тогда |
// |
Премия суммой |
|
рез[2] = Сумма; |
// |
Начисленная премия |
|
рассч[2] = 1; |
// |
Запись рассчитана |
конецЕсли;
// Для ввода премии |
1234 (и 1234 = |
1) все готово |
|
если п1234 = 1 тогда |
// |
Премия 1234 |
|
а =1; б = 3; |
// |
Параметры цикла Для, вводящего расчеты в ЖЗ |
конецЕсли;
// Ввод расчетов для ин = а по б цикл |
|
|
|
|
если (ин < 3) и (рассч[ин] = 0) тогда |
продолжить;
конецЕсли;
жз.УстановитьРеквизит(" Рассчитана", рассч [ин]); жз.УстановитьРеквизитС'всегоЧасов'', всегоЧасов[ин]);
ВводРасчВЖЗ(жз, хозОп, ВР[ин], датаНач[ин], датаКон[ин], рез[ин]); конецЦикла // для конецЦикла; // пока
// Вычисляем результаты введенных расчетов
// Выборка записей ЖЗ по документу не дает верного результата
// Поэтому используем выбор записей текущего периода по объекту
// В данном документе нижеследующий расчет результата нужен только
//для ВР Премия 1234. Остальные премии уже подсчитаны
если п1234 = 1 тогда
ВыбратьСтроки(); // Открываем выборку строк документа
пока ПолучитьСтроку() = 1 цикл
жз.ВыбратьПериодПоОбъекту(Сотрудник, нтп); пока жз.ПолучитьЗапись() = 1 цикл
если (жз.Документ = ТекущийДокумент()) и (жз.ВидРасч = ВР[3]) тогда жз.Рассчитать(); // или жз.ВыполнитьРасчет
конецЕсли; конецЦикла; // пока конецЦикла; // пока конецЕсли;
если Проведен() = 0 тогда // Если Документ проводится впервые
// Ограничиваем время показа окна с предупреждением тремя секундами Предупреждение("Документ проведен.", 3); иначе
Предупреждение("Документ перепроведен.", 3); конецЕсли;
конецПроцедуры // ОбработкаПроведения
// Проверяет на наличие расчетов с нулевым результатом // Если таковые есть, то записи не проводятся функция ПроверитьНаНуль()
ВыбратьСтроки( ); // Открываем выборку строк документа
пока ПолучитьСтроку() = 1 цикл
// Отрицательных значений к3 и Сумма быть не может - так заданы свойства // этих элементов диалога. Кроме того, для элемента Сумма задано // свойство Разделять триады
// Премия коэффициентом если (коэф = 1) и (к3 = 0) тогда возврат 1; конецЕсли;
// Премия суммой если (сум = 1) и (Сумма = 0) тогда возврат 1; конецЕсли;
//Премия 1234
если (п1234 = 1) и (Премия 1234 = Перечисление.ДаНет.ЗначениеПоНомеру(2)) тогда возврат 1; конецЕсли; конецЦикла; // пока возврат 0;
конецФункции // ПоверитьНаНуль
// Ищет для премии коэффициентом по ЖЗ число часов, отработанных сотрудником // Это число занесено в ЖЗ вместе с расчетом, имеющим ВР Оклад_2 функция НайтиЧасы(жз, нтп)
жз. ВыбратьПериодПоОбъекту(Сотрудник, нтп); пока жз.ПолучитьЗапись() = 1 цикл
если жз.ВидРасч = ВидРасчета.Оклад_2 тогда возврат жз. ВсегоЧасов; конецЕсли; конецЦикла; // пока
возврат 0; // Расчет с ВР,Оклад_2 для сотрудника не введен конецФункции // НайтиЧасы
// Вводит новые или редактирует имеющиеся в ЖЗ расчеты с заданным ВР процедура ВводРасчВЖЗ(жз, хозОп, ВР, датаНач, датаКон, рез) жз,УстановитьРеквизит("строкаДок", НомерСтроки); жз.УстановитьРеквизит("хозОп", НайтиХозОп(хозОп, ВР)); жз.ВвестиРасчет(Сотрудник, ВР, датаНач, датаКон, рез); конецПроцедуры // ВводРасчВЖЗ
// Возвращает хозяйственную операцию ВР ,
функция НайтиХозОп(хозОп, ВР)
// Ищем простым перебором в справочнике ХозОпДляВР вид расчета ВР
хозОп.ВыбратьЭлементы();
флаг = 0;
пока хозОп.ПолучитьЭлемент() = 1 цикл если хозОп.ВР = ВР тогда флаг = 1; прервать; конецЕсли; конецЦикла; // пока если флаг = 1 тогда
возврат хозОп.хозОп; иначе
возврат ПолучитьПустоеЗначение(хозОп); конецЕсли;
конецФункции // НайтиХозОп
7.9.5. ФОРМА СПИСКА ЖУРНАЛА ДОКУМЕНТОВ РАСЧЕТЫ
Документы НачПериода_2 и Премия отображаются в журнале документов Расчеты (см. рис. 7.57). Форму списка этого журнала документов создадим такую же, как и форму списка журнала документов Табель (разд. 7.6.5).
Модуль формы списка журнала документов Расчеты содержит предопределенную процедуру ПриОткрытии. Назначение процедуры такое же, как и у одноименной процедуры модуля формы списка журнала кадровых приказов (разд. 5.8.3.2).
// Список действий по документу. Передается процедуре глобального модуля // глДействия(ТекущийДокумент, сДейст) перем сДейст;
// Формирует список действий и устанавливает интервал журнала,
// отображающий все введенные документы вида НачПериода_2 и Премия процедура ПриОткрытии()
перем дНач; // Дата начала интервала журнала Расчеты
перем флаг, док;
ОчистигьОкноСообщенийО;
// Определяем список действий для кнопки Действия сДейст.ДобавитьЗначение("Структура подчиненности"); сДейст.ДобавшъЗначение("Движения документа");
флаг = 1; // Равен единице, если удалось создать док
попытка
док = СоздатьОбъект("Документ.НачПериода_2"); исключение попытка
док = СоздатьОбъект("Документ.Премия"); исключение флаг = 0; конецПопытки; конецПопытки;
// Если документ НачПериода_2 или Премия создан если флаг = 1 тогда
// Находим документ с наименьшей датой. По умолчанию документы располагаются // в выборке по возрастанию их дат док. ВыбратьДокументы(); если док.ПолучитьДокумент() = 1 тогда дНач = док.ДатаДок; иначе
дНач = ТекущаяДата(); конецЕсли;
иначе // Искомых документов нет
дНач = ТекущаяДата(); конецЕсли;
УстановитьИнтервал(дНач, ТекущаяДата( )); конецПроцедуры // ПриОткрытии
// В основной программе модуля всего один оператор сДейст = СоздатьОбъект("СписокЗначений");
7.10. ВИДЫ РАСЧЕТОВ ДОКУМЕНТА ПРЕМИЯ
7.10.1. ПРЕМИЯ КОЭФФИЦИЕНТОМ
ВР ПремияКоэф_2 является самовытесняющимся. Включен в группу ВР ВсеНа-числения_2, которая применяется при оценке налога и размера выплат в банк. Является согласно правилам перерасчета ведущим по отношению к ВР НДФЛ2, ВБанк_2 и Премия 1234_2 (разд. 7.7). То есть при вводе расчета с ВР ПремияКоэф_2 или ручном исправлении его результата атрибут Рассчитана нефиксированных расчетов с такими ВР и не имеющих вдобавок неотмененной ручной правки становится равен нулю. Чтобы получить верные результаты, придется после ввода расчета с ВР ПремияКоэф_2 рассчитать заново либо зависимые расчеты, либо весь объект.
Важно, однако, иметь в виду, что если сначала ввести ручную правку расчета с ВР ПремияКоэф_2, затем снять флаг ручной правки и рассчитать заново запись с новым результатом, то атрибут Рассчитана зависимых расчетов не изменится, а общий результат расчета объекта окажется неверным (хотя система будет "думать", что объект рассчитан).
Напомним, что рассчитанные записи сопровождаются в ЖЗ иконкой
„ П ’
считанные - иконкой
процедура ПровестиРасчет() // Процедура модуля ВР ПремияКоэф_2 перем жз;
// Процедура выполняется при проведении расчета с ВР ПремияКоэф_2 // Имеет следующий алгоритм:
// По значению реквизита ЖЗ сторокаДок в документе-родителе ищется запись,
// породившая расчет, в этой записи читается значение реквизита к3,
//зная которое находим искомую величину премии. Переменная всего Часов,
// необходимая для расчета результата, является реквизитом ЖЗ // Если расчет вводился до ввода документа Табель, то всего Часов = 0 если всегоЧасов = 0 тогда // Найдем значение реквизита всегоЧасов
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2''); жз.ВыбратьПериодПоОбъекту(Объект, жз.НачалоТекущегоПериодаО); пока жз.ПолучитьЗапись() = 1 цикл
если жз.ВидРасч = ВидРасчета.Оклад_2 тогда всегоЧасов = жз.ВсегоЧасов; конецЕсли; конецЦикла; // пока конецЕсли;
Документ. ПолучитьСтрокуПоНомеру(строкаДок); результат = всегоЧасов * Документ.к3; конецПроцедуры // ПровестиРасчет
7.10.2. ПРЕМИЯ СУММОЙ
ВР ПремияСум_2 является самовытесняющимся. Включен в группу ВР ВсеНачис-ления_2. Является ведущим по отношению к ВР НДФЛ_2, ВБанк_2 и Премия 12342 (разд. 7.7). Вытесняет ВР ПремияКоэф_2.
процедура ПровестиРасчет( ) // Процедура модуля ВР ПремияСум_2
// Процедура выполняется при проведении расчета с ВР ПремияСум_2
// Имеет следующий алгоритм:
// По значению реквизита ЖЗ сторокаДок в документе-родителе ищется запись,
// породившая расчет, в этой записи читается значение реквизита Сумма,
// которое и является искомой величиной премии Документ. ПолучитьСтрокуПоНомеру(строкаДок); результат = Документ. Сумма; конецПроцедуры // ПровестиРасчет
7.10.3. ПРЕМИЯ 1234
. ВР Премия1234_2 является самовытесняющимся. Включен в группу ВР ВсеНа-числения_2. Является ведущим по отношению к ВР НДФЛ_2, ВБанк_2 и зависимым от ВР Оклад_2, ПремияКоэф_2, ПремияСум_2 (разд. 7.7).
процедура ПровестиРасчет() // Процедура модуля ВР Премия 1234_2 перем жз, нтп, ктп, прем 1234;
// Процедура выполняется при проведении расчета с ВР Премия1234_2 // Вычисляется по следующей формуле:
// Премия 12342 = (Оклад_2 + ПремияКоэф_2 + ПремияСум_2) * к5, где
// к5 - постоянный для всех сотрудников коэффициент
// Коэффициент к5 - берется из списка периодических констант
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
нтп = жз.НачалоТекущегоПериода();
ктп = жз.КонецТекущегоПериода();
прем 1234 = 0;
жз.ВыбратьПериодПоОбъекту(Объект, нтп); пока жз.ПолучитьЗапись() = 1 цикл
если (жз.ВидРасч = ВидРасчета.Оклад_2) или
(жз.ВидРасч = ВидРасчета.ПремияКоэф_2) или (жз.ВидРасч = ВидРасчета.ПремияСум_2) тогда прем 1234 = прем 1234 + жз.результат; конецЕсли; конецЦикла; // пока
результат = прем1234 * Константа. К5. По лучить(ктп); конецПроцедуры // ПровестиРасчет
Значение числовой константы к5, которая должна быть периодической, после ее добавления в конфигурацию определим, запустив следующую процедуру:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
Константа. К5.Установить(ТекущаяДата(), 0.5); конецПроцедуры // Выполнить
7.11. ВЗАИМОДЕЙСТВИЕ ВИДА РАСЧЕТА ПРЕДПРИЯТИЯ
Характер взаимодействия ВР предприятия представлен в табл. 7.15, где под взаимодействием понимаются такие свойства ВР, как способность вытеснять иные ВР, быть по отношению к ним зависимым или ведущим, а также очередность исполнения.
Таблица 7.15
Взаимодействие ВР предприятия |
|
Вид расчета |
Ведущий по отношению к ВР |
Зависит от ВР |
Вытесняет
ВР |
Очеред
ность |
|
НачСальдо_2 |
ВБанк_2 |
- |
- |
1 |
|
Оклад_2 |
ВР НДФЛ_2, ВБанк_2 |
- |
- |
1 |
|
ПремияКоэф_2 |
Премия1234.2, НДФЛ_2, ВБанк_2 |
- |
- |
5 |
|
ПремияСум_2 |
НДФЛ_2, ВБанк_2 |
- |
ПремияКоэф_2 |
1 |
|
Премия1234_2 |
// |
Оклад_2,
ПремияКоэф_2,
ПремияСум_2 |
|
10 |
|
НДФЛ_2 |
|
Оклад_2, ПремияКоэф_2, ПремияСум 2, Премия1234_2 |
|
15 |
|
ВБанк_2 |
- |
От всех ВР |
- |
20 |
|
|
Замечания: |
1. Это важная таблица, о составлении такой или ей подобной надлежит позаботиться лицам, сопровождающим и поддерживающим программы расчета заработной платы.
2. Все ВР табл. 7.15 являются самовытесняющимися.
3. Задание ВР ПремияСум_2 вытесняющим по отношению к ВР ПремияКоэф_2 обусловлено учебными целями. На примере взаимодействия этих двух ВР мы продемонстрируем работу алгоритма вытеснения 1С.
Напомним также, что ВР Оклад_2, ПремияКоэф_2, ПремияСум_2 и Премия 12342 входят в группу ВР ВсеНачисления_2, а группа ВР ВсеУдержания_2 содержит пока что лишь один ВР - НДФЛ_2.
Все приведенные в табл. 7.15 свойства уже введены в конфигурацию системы. Теперь посмотрим на практике, как они реализуются. Пока что можно сказать, что полностью полагаться на правила перерасчета нельзя (это уже отмечалось выше), поскольку они срабатывают при вводе ведущих ВР или при их ручной правке, но не оказывают влияния на зависимые ВР при расчете записи с ведущим ВР в результате выбора пункта меню Рассчитать запись (разд. 7.10.1).
7.12. ДЛИННЫЕ РАСЧЕТЫ.
ЭФФЕКТ ВЫТЕСНЕНИЯ РАСЧЕТА
В этом разделе мы рассмотрим поведение длинных расчетов на примере ВР Пре-мияКоэф_2 и ПремияСум_2. Первый мы удлиним вперед, в будущий период (БП), а второй назад, в прошлый период (ПП). Учитывая, что ВР ПремияСум_2 вытесняет ВР ПремияКоэф_2, действие расчета с ВР ПремияСум_2 ограничим сверху серединой текущего периода (ТП) (рис. 7.68).
 |
|
Рис. 7.68. ВРПремияСум_2 и ПремияКоэф_2 на временной оси документа по начислению премии |
После оформления документа (рис. 7.69, 7.70) и его проведения в ЖЗ на фамилию Агальцова добавятся 4 записи о премиях (рис. 7.71).
 |
|
Рис. 7.69. Премии Агальцова Ю. А. в документе Премия |
 |
|
Рис. 7.70. Интервалы действия премий Агальцова Ю. А |
|
|
Сотрудник |
ВР |
Часы |
Резчл... |
Хоз.... |
Начало |
Окота... «I |
|
|
Агальцов Юрий |
Премия с<*имой |
|
1.000 00 |
2013001 |
01.11.01 |
3011.01 |
|
ё |
Агальцов Юрий |
Начальное сальдо |
|
000 |
2013000 |
01 1201 |
31 1201 |
|
ё |
Агальцов Юрий |
Оклад |
165.0 |
2.900 00 |
2013000 |
01.1201 |
31.1201 |
|
ё |
Агальцов Юрий |
Премия суммой |
|
1.000.00 |
2013001 |
01.1201 |
15.1201 |
|
ё |
Агальцов Юрий |
Премия коэффициентом |
165.0 |
1.650.00 |
2013001 |
161201 |
31.1201 |
|
ё |
Агальцов Юрий |
Премия коэффициентом |
1650 |
1.650.00 |
2013001 |
01.01.02 |
31.01.02 |
|
|
Рис. 7.71. Расчеты-премии Агальцова Ю. А |
МЕТОДЫ ЖУРНАЛА РАСЧЕТОВ И ЕГО ПЕРИОДА
Знакомясь с новыми записями, во-первых, отметим, что в ЖЗ нет длинного заданного в документе расчета. Он разбился на обычные так, что период действия каждого лежит в пределах некоторого расчетного периода.
Во-вторых, обратим внимание, что разбиение затрагивает только временной параметр расчетов. Сумма премии переносится в каждый интервал разбиения. То есть в нашем случае 1С удваивает премии Агальцова Ю. А. по сравнению с величинами, заданными в документе.
В-третьих, как и ожидалось, расчет Премия суммой вытеснил расчет Премия коэффициентом, укоротив (на временной оси) последний на 15 дней слева. При этом вновь изменились только временные параметры расчета. Его результат сохранился. Единственный случай, когда наблюдается изменение результата, - это полное вытеснение расчета.
В-четвертых, скорректируем наши представления об упорядочении расчетов: в пределах выбранного объекта расчеты располагаются по приоритетам (очередности исполнения), в пределах одного приоритета - в порядке возрастания атрибута расчета ДатаНачала, а при равных датах - в алфавитном порядке.
Итак, на временной оси ЖЗ введенные расчеты располагаются в соответствии с рис. 7.72, а количественные характеристики каждого расчета удвоились.
|
пп т |
|
|
|
п |
БП |
ПС1
<-> |
ПС2
--> |
|
Рис. 7.72. ВРПремияСум_2 (ПС) и ПремияКоэф_2 (ПК) из приведенного на рис. 7.69 и 7. 70 документа на временной оси ЖЗ
Если рис. 7.72 закономерен, то двукратное увеличение результатов входит в противоречие с документом и реальными событиями. В самом деле, если ваш отпуск длится, скажем, 40 дней, то в документе-приказе об отпуске, в котором отпускные вводятся единой суммой, нужно указать именно эту сумму, а также даты начала и конца отпуска. После проведения документа мы получим 2 или 3 расчета (в зависимости от отпускного периода), но общая сумма отпускных должна сохраниться. То есть, разбивая длинный расчет на к частей, мы должны иметь некоторый алгоритм деления его суммы на те же к частей.
Если расчет А вытесняется расчетом Б, интервал действия которого лежит в пределах интервала действия расчета А (см. рис. 7.4, б), наблюдается та же, что и в случае длинных ВР, картина: интервал действия расчета А разбивается на 2 части, но при этом результат расчета сохраняется для каждой из частей разбиения. Это приводит к удвоению результата по сравнению со значением, определенным в документе, породившим расчет.
Этот эффект иллюстрирует рис. 7.73, в котором в качестве расчета А выступает Премия коэффициентом, а Премия суммой является расчетом Б.
|
|
Сотрудник II ВР |
Часы 1 Резу... |
Хоз.on. |
I Начало |
Окоича* |
|
9 і |
Агальцов Юрий |
Премия суммой |
11.500.00 |
2013001 |
1201.02 |
22.01.02 |
|
|
Агальцов Юрий |
Премия коэффициентом |
167.011.670.00 |
2013001 |
01.01.02 |
11.01 02 |
|
• ; |
Агальцов Юрий |
Премия коэффициентом |
1Б7 0 Н1 -670 0012013001 |
123.01.02 |
31.01.02 |
|
|
Рис. 7. 73. После разбиения результат расчета Премия коэффициентом удвоился |
В документе для расчетов Агальцова Ю. А. Премия суммой и Премия коэффициентом заданы приведенные на рис. 7.74 интервалы действия.
|
Премия коэффициентом |
|01 01.02 |
1°1 |
131.01.02 [?] |
|
Премия суммой |
jl2.01.02 |
У |
122.01.02 |п| |
Рис. 7.74. Интервал действия расчета Б (Премия суммой) лежит внутри интервала действия расчета А (Премия коэффициентом), причем расчет Б вытесняет расчет А
Ясно, что наблюдаемый эффект потребует ручной правки результата.
7.13. МЕТОДЫ ЖУРНАЛА РАСЧЕТОВ И ЕГО ПЕРИОДА
Приводятся в табл. 7.16.
Методы ЖР и его периода
|
Таблица 7.16 |
|
Метод |
Описание |
|
|
Метод периода ЖР |
|
пер = пер.ПрибавитьПериод (кол); |
Прибавляет к периоду пер, где пер = жр.ПериодДействия | жр.ПериодРегистрации | жр.ТекущийПериод() или иное значение типа РасчетныйПериод, заданное параметром кол число периодов
Методы ЖР |
|
нтп = жр.НачалоТекущего Периода(); |
Возвращает дату начала текущего периода ЖР |
|
ктп = жр.КонецТекущего Периода(); |
Возвращает дату конца текущего периода ЖР |
|
нтп = жр.НачалоПериода ПоДате(дата); |
Возвращает дату начала расчетного периода ЖР, которому принадлежит заданная дата |
|
ктп = жр.КонецПериода ПоДате(дата); |
Возвращает дату конца расчетного периода ЖР, которому принадлежит заданная дата |
|
пер = жр.ПериодПоДате(дата); |
Возвращает расчетный период ЖР (объект типа РасчетныйПериод), которому принадлежит заданная дата |
|
флаг = жр.УстановитьТекущий Период(пер, [способ]); |
Устанавливает в качестве текущего период пер, где пер -значение типа РасчетныйПериод. Если способ= 1, то при смене периода отрабатываются ее сопровождающие системные действия, то есть смена периода осуществляется так же, как и при ее интерактивном выполнении. Если способ = 0, то системные действия не отрабатываются, в частности не производится архивация документов при смене периода вперед и не изменяется значение атрибута записей Рассчитана при смене назад |
|
пер = жр.ТекущийПериод(); |
Возвращает текущий расчетный период - значение типа РасчетныйПериод |
|
флаг = жр.ПолучитьЗапись(); |
Позиционирует выборку на ее следующей записи и возвращает 1 или за пределами выборки и возвращает 0, если выборка пуста или исчерпана |
|
флаг = жр.ВыполнитьРасчет(); |
Рассчитывает текущую запись ЖР, обращаясь к процедуре ПровестиРасчет, которой снабжен ВР этой записи |
|
on = жр.ОписательПериода (дата); |
Возвращает строку, описывающую расчетный период, содержащий дату, заданную параметром дата. Формат строки зависит от продолжительности расчетного периода. Если продолжительность - месяц, то результат имеет, например, следующий вид: Январь 2002 г. |
|
зап = жр.ТекущаяЗапись(); |
Возвращает текущую запись ЖР - значение типа Запись-Журнал аРасчетов |
|
|
Метод |
Описание |
|
флаг = жр.НайтиЗапись(зап); |
Осуществляет в ЖР поиск записи зап. Переменная зап должна иметь тип ЗаписьЖурналаРасчетов |
флаг = жр. Фиксировать
Запись(); |
Устанавливает в атрибут Фиксирована текущей записи ЖР значение, равное единице |
|
флаг = жр.ОсвободитьЗапись(); |
Устанавливает в атрибут Фиксирована текущей записи ЖР значение, равное нулю |
|
флаг = жр.ВвестиПерерасчет(); |
Вводит в текущий период запись, которая является копией текущей записи одного из прошлых периодов, обнуляя ее результат. Введенная запись называется перерасчетом, и ее атрибут Перерасчет равен единице. Результат перерасчета уменьшается на значение атрибута Результат первичной записи. Перерасчет нельзя ввести, если первичная запись сама является перерасчетом |
|
флаг = жр.ВвестиПерерасчет НаОсновании(док); |
Метод выполняет те же действия, что и метод ВвестиПере-расчет, с той лишь разницей, что перерасчет вводится на основании документа док |
|
названиеЖР = жр.Вид(); |
Возвращает заданный в конфигурации идентификатор ЖР, например Зарплата_2. Результат имеет символьный тип |
|
предстЖР = жр.Представление Вида(); |
Возвращает заданный в конфигурации синоним ЖР, а при отсутствии синонима - идентификатор ЖР. Результат имеет символьный тип |
|
жр.НазначитьТип(рекв, тип, длина, точность); |
Назначает тип или разновидность типа, заданную параметром тип, реквизиту рекв неопределенного типа. Символьный параметр тип может принимать значение базового типа ("Число", "Строка", "Дата"), любой определенной в конфигурации разновидности типа, например "Справочник.Дети", или "Документ.ИзменениеОклада", или значение вида субконто |
|
жр.УстановитьРеквизит (рекв, знач); |
Устанавливает значение реквизита ЖР. Для сохранения значения после применения метода вызывается один из следующих методов: ВвестиРасчет, ВвестиРасчетНаОсновании, ЗаписатьРасчет или ЗаписатьРасчетНаОсновании. При этом если расчет вводится в документе, то в нем эти методы записывают дополнительные реквизиты ЖР, а также (по мере необходимости) атрибуты Сторно, Рассчитана, Исправлена, Фиксирована, Перерасчет и Результат; значения атрибутов Документ, РодительскийДокумент, Объект, ВидРасч, Дата-Начала, ДатаОкончания и ПервичнаяЗапись в этом случае методом УстановитьРеквизит не задаются.
Также метод УстановитьРеквизит употребляется с методами Новая и Записать. Причем метод Новая предшествует вызову метода УстановитьРеквизит. Методы могут применяться как в документах, так и в модулях иных объектов. При этом Ус-тановитьРеквизит должен определить значения обязательных атрибутов (Документ, РодительскийДокумент, Объект, ВидРасч, ДатаНачала и ДатаОкончания). Другие атрибуты и дополнительные реквизиты ЖР определяются по мере необходимости. Атрибуты ЖР ПериодДействия и ПериодРегист-рации пользователем не устанавливаются |
|
Метод |
Описание |
|
*флаг = жр.ВвестиРасчет (объект, видРасч, датаНачала, датаОкончания, [результат]); |
Вводит расчет в ЖР. При вводе длинных расчетов метод вводит в ЖР несколько расчетов. Также несколько записей может быть введено при вводе вытесняющих расчетов. Может быть вызван в модуле документа или в модуле ВР. В первом случае атрибуты Документ и РодительскийДокумент принимают значение текущего документа (возвращается методом ТекущийДокумент). Во втором значения этих атрибутов вновь введенных расчетов становятся равными соответствующим значениям текущего расчета, то есть расчета, результат которого определяется. Параметры метода определяют значения одноименных атрибутов вводимого расчета |
|
*флаг = жр.ВвестиРасчетНа Основании(документ, (объект, видРасч, датаНачала, датаОкончания, [результат]); |
Выполняет те же действия, что и метод ВвестиРасчет, за тем исключением, что атрибут Документ введенного расчета заполняется значением параметра документ, указывающим на документ-основание. Атрибут РодительскийДокумент принимает, как и в методе ВвестиРасчет, значение текущего документа |
|
*флаг — жр. ЗаписатьРасчет (объект, ВР, датаНач, датаКон, [результат]); |
Выполняет те же действия, что и метод ВвестиРасчет, за тем исключением, что расчет не вытесняет сам себя, даже если он является самовытесняющимся |
*флаг = жр.ЗаписатьРасчетНа Основании(док, объект, ВР, датаНач, датаКон,
[результат]); |
Выполняет те же действия, что и метод ВвестиРасчетНаОс-новании, за тем исключением, что расчет не вытесняет сам себя, даже если он является самовытесняющимся |
|
*жр.Рассчитать(); |
Вычисляется результат расчета. Результат возвращается предопределенной процедурой ПровестиРасчет модуля соответствующего ВР. Если рассчитываемая запись фиксирована или скорректирована вручную и ее атрибут Исправлена = 1, результат расчета не изменяется. Расчет не выполнятся, если ЖР позиционирован на записи прошлого периода • |
|
*флаг = жр.ВыбратьЗаписи ([датаНач], [датаКон]); |
Открывает выборку записей ЖР, период действия которых пересекается с периодом, заданным параметрами типа Дата датаНач и датаКон. Если параметры опущены, то открывается выборка всех расчетов ЖР |
|
*флаг = жр.ВыбратьПериод ([дата]); |
Открывает выборку записей ЖР, период регистрации которых совпадает с периодом, в котором лежит параметр метода дата. Если параметр дата опущен, то открывается выборка расчетов, зарегистрированных в текущем периоде |
*флаг = жр.ВыбратьЗаписиПо Объекту(объект, [датаНач],
[датаКон]); |
Открывает выборку записей ЖР, принадлежащих объекту, заданному параметром объект, и период действия которых пересекается с периодом, заданным параметрами типа Дата датаНач и датаКон. Если параметры датаНач и датаКон опущены, то выбираются все принадлежащие заданному объекту расчеты ЖР, период действия которых пересекается с текущим периодом |
|
Метод |
Описание |
|
*флаг = жр.ВыбратьЗаписиПо Документу(док); |
Открывает выборку записей ЖР, атрибут Документ которых равен значению параметра док, имеющему тип Документ |
|
*флаг = жр.ВыбратьПериодПо Объекту(объект, [дата]); |
Открывает выборку записей ЖР, принадлежащих объекту, заданному параметром объект, и период регистрации которых совпадает с периодом, в котором лежит параметр дата. Если параметр дата опущен, то открывается выборка расчетов, зарегистрированных в текущем периоде |
|
*флаг = жр.ВыбратьПо Значению (графаОтбора, значОтбора, перНач, пер Кон); |
Открывает выборку записей ЖР по отбору, заданному символьным параметром графаОтбора, со значением значОтбора. Период регистрации выбираемых расчетов принадлежит временному интервалу, заданному параметрами перНач и перКон, имеющими тип РасчетныйПериод |
|
жр.Новая(); |
Создает новую запись ЖР. Добавление записи в ЖР осуществляется методом Записать |
|
жр.3аписать(); |
Добавляет или изменяет текущую запись ЖР. Добавлению записи предшествует вызов метода Новая. Изменение значений реквизитов ЖР выполняется методом УстановитьРекви-зит, вызываемым до метода Записать, но после метода Новая (если добавляется новая запись). При добавлении записи в обязательном порядке устанавливаются значения реквизитов Объект, Документ, РодительскийДокумент и ВидРасч. Следует помнить, что метод Записать не отрабатывает заданные правила перерасчета и вытеснения ВР |
|
*флаг = жр.УдалитьЗапись(); |
Удаляет текущую запись ЖР (проставляет DBF-пометку удаления записи) |
|
жр.Исправить(новРез); |
Заменяет существующий результат текущей записи ЖР на нов-Рез, устанавливая в атрибут Исправлена значение 1. Исправленная запись помечается иконкой СО. Результаты таких записей не изменяются при исполнении метода ВыполнитьРасчет или Рассчитать. Параметр новРез имеет числовой тип |
|
жр. ОтменитьИсправление(); |
Устанавливает в атрибут Исправлена текущей записи ЖР значение 0
Методы модуля формы ЖР |
|
списокВидовТек - ВидыОтбора ([списокВидовНов]); |
Устанавливает для интерактивного режима работы доступные виды отбора ЖР. Новые виды отбора задаются строкой списокВидовНов, содержащей перечисление имен граф отбора, например "Родитель, Образование". Возвращает строку с именами видов отбороэ, доступных до вызова метода. По умолчанию доступны все заданные при создании ЖР виды отбора |
|
флаг = УстановитьОтбор (графаОтбора, значениеОтбора); |
Устанавливает режим отображения записей ЖР по отбору. Заданному символьным параметром графаОтбора. В ЖР будут отображаться лишь те записи, объекты которых имеют реквизит, заданный параметром графаОтбора, например Образование, равный величине, заданной параметром значе-ниеОтбора. Тип параметра значениеОтбора должен совпадать с типом соответствующего реквизита объекта. Чтобы вновь вернуться в режим вывода всех записей ЖР, следует сделать следующий вызов:
УстановитьОтбор(""); |
|
Метод |
Описание |
флаг = ПолучитьОтбор
(графаОтбора,
значениеОтбора); |
Возвращает в символьную переменную графаОтбора текущий вид отбора, а в переменную значениеОтбора - его значение. Вид отбора задается методом УстановитьОтбор. Если отбор не установлен (отображаются все записи), то переменная флаг получит значение 0 |
|
флаг = ЗакладкиОтбора (графаОтбора, [значениеОтбора]); |
Устанавливает режим отображения закладок отбора, заданного символьным параметром графаОтбора, открывая закладку со значением значениеОтбора. Если второй параметр опущен, то активизируется первая закладка. Если первый параметр равен пустой строке, то закладки отбора не отображаются |
|
периодТек = Г раницаПросмотра ([период Нов])\ |
Устанавливает, если задан параметр периодНов, границу просмотра ЖР. Возвращает значение границы просмотра, существовавшее до вызова метода. Тип параметра и результата - РасчетныйПериод. Интерактивно границы просмотра устанавливаются цепочкой Действия - Задать глубину просмотра архива или после выбора иконки на панели инструментов диалогафо?мь^Ж^_ |
флаг = Установить
Представление (режим, [объект]); |
Устанавливает режим вывода записей ЖР. Если режим равен:
• 1, выводятся все записи ЖР, параметр объект не используется;
• 2, выводятся записи, имеющие атрибут Объект, равный значению параметра объект;
• 3, выводятся записи, имеющие атрибут Документ, равный значению параметра объект |
|
флаг = ПолучитьПредставление (режим, объект); |
Возвращает в параметры режим и объект текущие значения режима представления записей ЖР, заданного методом УстановитьПредставление. Переменная флаг примет значение 1, если представление установлено, или 0 -в противном случае |
|
флагТек = РассчитыватьПри ОтменеИсправления ([флагНов]); |
Устанавливает, если флагНов = 1, режим автоматического расчета записей при интерактивной отмене ручной правки.
По умолчанию флагНов = 0 и автоматического расчета записей при интерактивной отмене ручной правки не производится. Возвращает значение флага расчета, действующее в системе на момент вызова метода |
Замечания:
1. Префикс жр, употребленный с методами ЖР и его периодом, может быть произвольным.
2. Методы, отмеченные звездочкой (*), применяются только с переменными, определяемыми функций СоздатьОбъект. Прочие методы, если они находятся в модуле формы ЖР и применяются для текущего журнала, употребляются без префикса.
3. Появляющаяся в таблице переменная флаг равна единице, если метод выполнен удачно, и нулю - в противном случае.
Пример 1 для метода периода ЖР. Выводятся текущий, следующий и предшествующие периоды журнала Зарплата_2.
процедура Выполнил^ ) // Связана с кнопкой Пуск обработки Проба
перем жз, перТек, пер;
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2''); пер = жз.ТекущийПериодО;
Сообщить(''Текущий период:" + Символ Табуляции + пер); пер = пер.ПрибавитьПериод(1);
Сообщить("Период после:" + СимволТабуляции + пер); пер = пер.ПрибавитьПериод(-2);
Сообщить("Период до:" + СимволТабуляции + пер); кОнецПроцедуры // Выполнить
Результат:
Текущий период: Декабрь 2001 г.
Период после: Январь 2002 г.
Период до: Ноябрь 2001 г.
Пример 2 для метода периода ЖР. Выводятся текущий, следующий и предшествующие периоды регистрации.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем жз, перТек, пер;
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2'');
' жз.ВыбратьЗаписи(); // Позиционируемся на первом расчете ЖЗ
пер = жз.ПериодРегистрации; // или жз.ПериодДействия;
Сообщить("Период регистрации:" + СимволТабуляции + пер); пер = пер.ПрибавитьПериод(1);
Сообщить("Период после:" + СимволТабуляции + пер); пер = пер.ПрибавитьПериод(-2);
Сообщить("Период до:" + СимволТабуляции + пер); конецПроцедуры // Выполнить
Результат тот же, что и в примере 1.
Пример 3. Выводится вид и представление вида ЖЗ Зарплата_2.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем жз;
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
// Идентификатор ЖЗ
Сообщить(жз.Вид()); // Зарплата_2
// Синоним ЖЗ
Сообщить(жз.ПредставлениеВида()); // Журнал заработной платы конецПроцедуры // Выполнить
Пример 4. В окно сообщений выводятся все расчеты ЖЗ, относящиеся к выбранному сотруднику.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, жз;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Метод Выбрать вызывает диалог для выбора элемента справочника
// Если сотрудник не выбран
если сСотр_2.Выбрать("Выберите сотрудника", "ФормаСписка") = 0 тогда Предупреждение("Сотрудник не выбран."); возврат; конецЕсли;
// Выбран Добрецов Б. Ю.
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьЗаписиПоОбьекту(сСотр_2.ТекущийЭлемент()); пока жз.ПолучитьЗапись() = 1 цикл
Сообщить("" + жз.Объект + СимволТабуляции + жз.ВидРасч + Символ Табуляции + жз.Результат); конецЦикла; // пока конецПроцедуры // Выполнить
|
Результат: |
|
Добрецов Борис Юрьевич |
Начальное сальдо |
0.75 |
|
Добрецов Борис Юрьевич |
Премия коэффициентом |
1670 |
|
Добрецов Борис Юрьевич |
Премия суммой |
2000 |
|
Добрецов Борис Юрьевич |
Перечисление в банк |
8444 |
|
Добрецов Борис Юрьевич |
НДФЛ |
1261.65 |
|
Добрецов Борис Юрьевич |
Оклад |
2800 |
|
Добрецов Борис Юрьевич |
Премия 1234 |
3235 |
|
Пример 5. В окно сообщений выводятся все расчеты ЖЗ, относящиеся к выбранному документу.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем док, жз;
док = СоздатъОбъект("Документ.Премия");
// Метод Выбрать вызывает диалог для выбора документа // Если документ не выбран
если док.Выбрать("Выберите документ") = 0 тогда Предупреждение("Документ не выбран."); возврат; конецЕсли;
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьЗаписиПоДокументу(док.ТекущиЙДокумент()); пока жз.ПолучитьЗапись() = 1 цикл
Сообщить("" + жз.Объект + СимволТабуляции + жз.ВидРасч +
СимволТабуляции + жз.Результат); конецЦикла; // пока конецПроцедуры // Выполнить
Результат:
Пример 6. В окно сообщений выводятся все зарегистрированные в текущем периоде расчеты ЖЗ (объект, ВР и результат) сотрудников второго цеха.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, жз, пер, подр;
сСотр_2 = СоздатьО6ъект(''СправочникСотрудники_2''); если сСотр_2.НайтиПоНаименованию(”02 Цех”, 0) = 0 тогда Предупреждение(''Второй цех не найден.”); возврат; конецЕсли;
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2''); пер = жз.ТекущийПериод();
// Подразделение предприятия (найденная выше группа справочника Сотрудники_2) подр = сСотр_2.ТекущийЭлемент(); жз.ВыбратьПоЗначению(''Родитель'', подр, пер, пер); пока жз.ПолучитьЗапись() = 1 цикл
Сообщить(”” + жз.Объект + СимволТабуляции + жз.ВидРасч +
СимволТабуляции + жз.Результат); конецЦикла; // пока конецПроцедуры // Выполнить
|
Результат: |
|
Абрамова Лариса Сергеевна |
Начальное сальдо |
2.6 |
|
Абрамова Лариса Сергеевна |
Оклад |
2500 |
|
Абрамова Лариса Сергеевна |
НДФЛ |
325 |
|
Абрамова Лариса Сергеевна |
Перечисление в банк |
2177 |
|
Пример 7. Удаляются все расчеты ЖЗ, относящиеся к выбранному документу, и сам документ. Записи получают DBF-пометку удаления, а документу проставляется 1С-пометка удаления.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем док, жз;
док = СоздатьОбъект(”Документ.Премия”);
// Метод Выбрать вызывает диалог для выбора документа // Если документ не выбран если док.Выбрать(''Выберите документ”) = 0 тогда Предупреждение(”Документ не выбран.”); возврат; конецЕсли;
жз = СоздатьОбъект(”ЖурналРасчетов.Зарплата_2”); жз.ВыбратьЗаписиПоДокументу(док.ТекущийДокумент()); пока жз.ПолучитьЗапись() = 1 цикл
жз.УдалитьЗапись(); // Удаляем расчет (ставим DBF-пометку удаления) конецЦикла; // пока
док.Удалить(О); // Удаляем документ (ставим 1С-пометку удаления)
конецПроцедуры // Выполнить
Пример 8. Обнуляется флаг ручной правки расчетов выбранного сотрудника, кроме расчетов с ВР ПремияСум_2, для которых, наоборот, вносится ручная правка результата. Новая величина премии равна 1250 руб. Попутно выполняется расчет записей, с которых снимется флаг ручной правки.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, жз, ВР;
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
// Метод Выбрать вызывает диалог для выбора элемента справочника // Если сотрудник не выбран
если сСотр_2.Выбрать(''Выберите сотрудника", "ФормаДляВыбора") = 0 тогда Предупреждение("Сотрудник не выбран."); возврат; конецЕсли;
// Выбран Агальцов Ю. А.
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьПериодП0Объекту(сСотр_2.ТекущийЭлемент());
ВР = ВидРасчета.ПремияСум_2; пока жз.ПолучитьЗапись() = 1 цикл
если (жз.Исправлена =1) и (жз.ВидРасч о ВР) тогда
жз.ОтменитьИсправление(); // Снимаем флаг ручной правки результата жз.Рассчитать(); // Рассчитываем запись
конецЕсли;
если жз.ВидРасч = ВР тогда жз.Исправить( 1250.0); конецЕсли; конецЦикла; // пока Предупреждение('Тотово."); конецПроцедуры // Выполнить
Для иллюстрации методов модуля формы ЖР войдем в конфигурацию, раскроем ее пункт Журналы расчетов и в ЖЗ Зарплата_2 установим еще один вид (графу) отбора - Образование (рис. 7.75).
 |
|
Рис. 7. 75. В ЖЗ Зарплата_2 доступны отборы по графам Родитель и Образование |
Пример 9. В форме списка ЖЗ Зарплата_2 устанавливается отбор по графе Образование. Это выполняется в предопределенной процедуре ПриОткрытии модуля формы списка ЖЗ.
процедура ПриОткрытии() // Предопределенная процедура
перем обр, флаг, сСотр_2, сОбр_2;
// Задаем доступные виды отбора (этот вызов может быть опущен) ВидыОтбора("Родитель, Образование");
// Отображаем закладки отбора по реквизиту Образование ЗакладкиОтбора("Образование");
// Установим представление по одному объекту // Найдем для этого сотрудника, имеющего высшее образование сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сОбр_2 = СоздатьОбъект("Справочник.Образование_2");
// Выбираем вид образования обр
флаг = сОбр_2.Выбрать("Выберите вид образования",""); если флаг = 1 тогда
обр = сОбр_2.ТекущийЭлемент();
если сСотр_2.НайтиПоРеквизиту("Образование", обр, 1) = 1 тогда // Отображаем записи по одному объекту УстановитьПредставление(2, сСотр_2.ТекущийЭлемент()); конецЕсли; конецЕсли; сСотр_2 = 0; сОбр_2 = 0;
// Для иных процедур модуля определим нтп нтп = НачалоТекущегоПериода(); конецПроцедуры
|
Результат после открытия формы ЖЗ см. на рис. 7.76. |
|
Высшее 1 Начальное Неоконченное высшее I Среднее | |
|
Г- По цехам |
|
Jt) Д] о| |
|
ВСотрчдник ||ВР ВЧа... (Резчл... |Хоз.... 1 |
IНачало ІОконч... ^ | |
|
1 1 |
Добрецов Борис |
(Начальное сальдо |
0.101201300С |
01.1201 |
31.1201 |
|
|
Добрецов Борис |
Оклад |
165.0 |
2.800.00|201300С |
01.1201 |
31.1201 |
|
р |
Добрецов Борис |
Премия суммой |
|
500.0012013001 |
12.12.01 |
221201 |
|
4 1 |
Добрецов Борис |
Премия коэффициентом |
165.0 |
1.650.00J 2013001 |
01.12.01 |
11.12.01 |
|
|
Премия 1234 |
|
2,475.00| 2013001 |
23.12.01 |
31.1201 |
|
1 Добрецов Борис |
НДФЛ |
|
965.251201700: |
01.12.01 |
31.1201 |
|
\ 1<Н Добрецов Борис |
Перечисление в банк |
II 6.459.001230010(1 |
01.12.01 |
31.12.01 . |
|
Рис. 7.76. Установлены отбор по графе Образование и режим представления по одному объекту
Замечание. Чтобы полноценно использовать отбор по графе Образование, нужно внести соответствующие изменения и в диалог формы списка ЖЗ Зарплата 2, и в модуль формы. В частности, флажок придется заменить на приведенный
на рис. 7.77 переключатель.
Установить отбор------—
С По цехам С По образованию
Рис. 7.77. Переключатель видов отборов
Пример 10. В форме списка ЖЗ Зарплата_2 выводятся только сотрудники с заданным образованием.
процедура ПриОткрытии() // Предопределенная процедура
перем обр, флаг, сОбр_2, графаОтбора, значениеОтбора;
// Выбираем вид образования обр
сОбр_2 = СоздатьОбъект(''Справочник.Образование_2''); флаг = сОбр_2.Выбрать(''Выберите вид образования",""); если флаг = 1 тогда
обр = сОбр_2.ТекущийЭлементО;
// Задаем режим вывода записей о сотрудниках с образованием обр УстановитьОтбор("Образование", обр); конецЕсли;
// Контрольный вывод
если ПолучитьОтбор(графаОтбора, значениеОтбора) = 1 тогда Сообщить("Установлен отбор по графе " + графаОтбора +
" со значением " + значениеОтбора); конецЕсли;
УстановитьПредставление(І); // Вывод списка сотрудников
// Для иных процедур модуля определим нтп нтп = НачалоТекущегоПериодаО; конецПроцедуры // ПриОткрытии
Результат:
Установлен отбор по графе Образование со значением Среднее
Пример 11.В форме списка ЖЗ Зарплата_2 выводятся только записи, относящиеся к документу, выбранному в предопределенной процедуре ПриОткрытии.
процедура ПриОткрытии() // Предопределенная процедура
перем док;
док = СоздатьОбъект("Документ.Премия");
// Метод Выбрать вызывает диалог для выбора документа // Если документ не выбран
если док.Выбрать("Выберите документ") = 0 тогда Предупреждение("Документ не выбран."); возврат; конецЕсли;
// Вывод расчетов, порожденных выбранным ранее документом УстановитьПредставление(3, док. ТекущийД окумент());
// Для иных процедур модуля определим нтп нтп = НачалоТекущегоПериода(); конецПроцедуры // ПриОткрытии
7.14. ПРЕДОПРЕДЕЛЕННЫЕ ПРОЦЕДУРЫ МОДУЛЯ ФОРМЫ ЖУРНАЛА РАСЧЕТОВ
Приведены в табл. 7.17.
Предопределенные процедуры модуля формы ЖР
Процедур*
ПриИсправлении
Результата
(запись)
ПриОтмене
Исправления
(запись)
ПриРасчете
(объектРасчета)
ПриВыбореВладельца
(владелец)
ПриУ становкеОтбора
(графаОтбора, значениеОтбора)
Описание
Таблица 7.17
Вызывается при попытке ручного исправления результата расчета (после нажатия на ОК в приведенном на рис. 7.78 диалоге).
ние результат;
Исправить не [
1Л2О00І
Cancel
Рис. 7.78. Ручная правка результата
Параметр запись имеет тип ЗалисьЖурналаРасчетов и является ссылкой на исправляемую запись ЖР. Диалог ввода ручной
М2
правки вызывается при нажатии на иконку панели управления ЖР
Вызывается при интерактивной попытке отмены ручной правки результата расчета. Параметр запись имеет тип ЗаписьЖурналаРасчетов и является ссылкой на текущую запись ЖР
Вызывается при попытке интерактивно инициировать расчет записи, документа или объекта. При расчете записи объектРасчета - это текущая запись ЖР, при расчете объекта - элемент справочника-владельца ЖР, при расчете документа - документ, породивший записи ЖР. Расчет записи, объекта и документа инициируются иконками k І Ь панели управления ЖР или соответствующими пунктами меню
Вызывается при интерактивном переходе в справочнике-владельце ЖР от одного элемента к другому. Формальный параметр владелец является ссылкой на выбираемый элемент-владелец. Выполняется только в режиме вывода расчетов по одному объекту. Справочник-владелец можно,
в частности, открыть, нажав на иконку ления ЖР
I панели управ-
Вызывается при интерактивной установке отбора в ЖР. Напомним, что ніггерактнвно отбор управляется диалогами, вызываемыми
иконками-* ^ или соответствующими командами меню. Параметр графаОтбора является символьным и содержит имя графы отбора. Тип параметра значениеОтбора совпадает с типом используемого в качестве графы отбора реквизита справочника-владельца ЖР
|
Процедура |
Описание |
|
ПриУстановкеГ раницы Просмотра (период) |
Вызывается при интерактивной смене границы просмотра ЖР. Интерактивно граница просмотра задается в диалоге, вызываемом при помощи иконки панели управления ЖР, или при выборе соответствующего пункта меню. Параметр период имеет тип РасчетныйПериод и содержит значение периода, задающего границу просмотра ЖР |
ПриУстановке
Представления
(режим) |
Вызывается при иігтеракіивной смене режима представления ЖР. Интерактивно режим представления задается на панели управления
ЖР иконками •= (все объекты), ~ (один объект) и = (один документ). Числовой параметр режим имеет значение:
• 1, если осуществляется переход к просмотру всех записей ЖР;
• 2, если устанавливается просмотр одного объекта;
• 3, если планируется просматривать записи по одному документу-основанию |
|
|
Пример. Запрещается ручное исправление результатов во всем ЖР. |
// Процедура входит в состав модуля формы списка ЖР процедура ПриИсправленииРезультата(запись)
Предупреждение(''Ручная правка невозможна.");
СтатусВозврата(0);
конецПроцедуры
7.15. ВИДЫ РАСЧЕТОВ И ИХ ГРУППЫ
7.15.1. ВЫВОД СПИСКОВ ВИДОВ РАСЧЕТОВ И ИХ ГРУПП
С ВР и группами ВР мы уже имели возможность ознакомиться весьма плотно. Те- | перь наша задача - привести достаточные для активного употребления этих объектов справочные сведения.
Приведем, однако, прежде коды, выводящие список ВР и групп ВР конфигурации.
// Процедура вывода списка ВР конфигурации
// Выводит для каждого ВР его атрибуты: код (идентификатор),
// наименование (комментарий), очередность и приоритет, а также его синоним процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем всегоВР; // Число ВР в конфигурации
перем ин, код, ВР, наим, очер, приорВыт, синоним;
ОчиститьОкноСообщений(); // Очищаем окно сообщений
всегоВР = Метаданные.ВидРасчета(); для ин = 1 по всегоВР цикл
код = Метаданные.ВидРасчета(ин).Идентификатор;
// ВР имеет тип ВидРасчета
ВР = ВидРасчета.ПолучитьАтрибут(код);
наим = ВР.Наименование;
// или наим = Метаданные.ВидРасчета(ин).Комментарий; очер = ВР.Очередность;
приорВыт = ВР.ПриоритетВытеснения; синоним = Метаданные. ВидРасчета(ин). Синоним;
Сообщить(код + " - " + наим + " - " + очер + " - " + приорВыт + " - " + синоним); конецЦикла; // для конецПроцедуры // Выполнить
Фрагмент результата:
Авторские - Другие авторские вознаграждения - 30 - 0 - Др. авторские возн-ия АвторскиеЗаНП - Авторские за создание произведений науки - 30 - 0 - Авт. за науку БанковскиеИздержки - Банковские издержки - 152 - 0 - Банковские издержки
// Процедура вывода списка групп ВР конфигурации
// Выводит для каждой группы ВР ее атрибуты: код (идентификатор)
// и наименование (комментарий), а также синоним
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем всегоГруппВР; // Число групп ВР в конфигурации
перем ин, код, наим, синоним;
ОчиститьОкноСообщений(); // Очищаем окно сообщений
всегоГруппВР = Метаданные.ГруппаРасчетов(); для ин = 1 по всегоГруппВР цикл
код = Мегаданные.ГруппаРасчетов(ин).Иденіификатор; наим = Метаданные.ГруппаРасчетов(ин).Комментарий; синоним = Метаданные.ГруппаРасчетов(ин). Синоним;
Сообщить(код + "-." + наим + " - " + синоним); конецЦикла; // для конецПроцедуры // Выполнить
Фрагмент результата:
ВсеНачисления - Группа, в которую входят начисления - Все начисления ВсеУдержания - Группа, в которую входят все удержания - Все удержания ВсеНачисления_2 - Для сотрудников из справочника Сотрудники_2 - Все начисления
7.15.2. АТРИБУТЫ ВИДОВ РАСЧЕТОВ И ИХ ГРУПП
Приводятся в табл. 7.18.
Таблица 7.18
Атрибуты ВР и их групп |
|
Атрибут |
Описание |
|
Атрибуты ВР и групп ВР |
|
Код |
Строка, содержащая идентификатор ВР или группы ВР |
|
Наименование |
Строка, содержащая комментарий ВР или группы ВР |
|
Атрибуты ВР |
|
Очередность |
Число, задающее очередность (приоритет) выполнения ВР (см. разд. 7.3.4) |
Приоритет
Вытеснения |
Число, задающее приоритет вытеснения ВР. Не рекомендован для употребления и сохранен для поддержания совместимости с прежними версиями 1С |
|
7.15.3. МЕТОДЫ ВИДОВ РАСЧЕТОВ И ИХ ГРУПП
Приводятся в табл. 7.19.
Таблица 7.19
Методы ВР и групп ВР |
|
Метод |
Описание |
|
Методы ВР |
ВР = ВидРасчета.
ПолучитьАтрибут
(код); |
Возвращает объект типа ВидРасчета, идентификатор которого равен символьному параметру код |
флаг = <ВР>Входит
ВГругппу(группа); |
Возвращает 1, если вид расчета ВР входит в группу ВР, заданную параметром группа типа ГруппаРасчетов |
флаг = <ВР.>
Выбран(); |
Возвращает 1, если ВР - объект типа ВидРасчета - имеет значение, или О-в противном случае. Употребляется, в частности, для реквизитов типа ВидРасчета объектов 1С, например справочников или документов, с целью узнать, задан ли для реквизита ВР или реквизит имеет пустое
значение |
флаг = ВР1.Вытесняет
ВидРасчета(ВР2); |
Возвращает 1, если вид расчета ВР1 вытесняет вид расчета ВР2, или О-в противном случае |
|
флаг = ВР1.Вытесняется ВидомРасчета (ВР2); |
Возвращает 1, если вид расчета ВР1 вытесняется видом расчета ВР2, или О-в противном случае |
|
Методы групп ВР |
флаг = ГВР.Содержит
ВидРасчета(ВР); |
Вернет 1, если группа видов расчетов ГВР содержит вид расчета ВР, или О-в противном случае |
|
кол = ГВР.Количество(); |
Возвращает число ВР, входящих в группу расчетов ГВР |
|
ВР = ГВР.Получить Расчет(ном); |
Вернет объект типа ВидРасчета, входящий в группу расчетов ГВР под номером ном. Если номер ном больше числа расчетов в группе, то возникнет завершающая ошибка, сопровождаемая сообщением "Выход за границы группы расчетов" |
|
|
Примеры для методов ВР: |
процедура ВыполнитьО // Связана с кнопкой Пуск обработки Проба
перем ВР1,ВР2; перем ин, код, наим, синоним;
ОчиститьОкноСообщений( ); // Очищаем окно сообщений
ВР1 = ВидРасчета.ПремияСум_2;
ВР2 = ВидРасчета.ПремияКоэф_2;
если ВР1.ВытесняетВидРасчета(ВР2) = 1 тогда
Сообщить("ВР Премия суммой вытесняет ВР Премия коэффициентом."); конецЕсли;
// Определим переменные ВР типа ВидРасчета иным способом ВР1 = ВидРасчета. ПолучшъАтрибуг("ПремияСум_2");
ВР2 = ВидРасчета.ПолучшъАтрибут("ПремияКоэф_2"); если ВР1.ВытесняетсяВидомРасчега(ВР2) = 1 тогда
Сообщить("ВР Премия суммой вытесняется ВР Премия коэффициентом."); иначе
Сообщить("ВР Премия коэффициентом вытесняется ВР Премия суммой."); конецЕсли;
конецПроцедуры // Выполнить Результат:
ВР Премия суммой вытесняет ВР Премия коэффициентом.
ВР Премия коэффициентом вытесняется ВР Премия суммой.
Примеры для методов групп ВР:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем ВР, ГВР, кол, ном;
ОчиститьОкноСообщений(); // Очищаем окно сообщений
ВР = ВидРасчета.ПремияСум_2;
ГВР = ГруппаРасчетов.ВсеНачисления_2; если ГВР.СодержитВидРасчета(ВР) = 1 тогда
Сообщшъ('Труппа ВР " + ГВР.Код + " содержит ВР " + ВР.Код); иначе
Сообщигъ("Группа ВР " + ГВР.Код + " не содержит ВР " + ВР.Код); конецЕсли;
кол = ГВР.Количество();
Сообщигъ("В группу ВР " + ГВР.Код + " входит" + кол + " ВР"); ном = 2;
ВР = ГВР.ПолучитъРасчет(ном);
Сообщитъ("В группе ВР " + ГВР.Код + " под номером " + ном +
" расположен расчет " + ВР.Код); конецПроцедуры // Выполнитъ
Результат:
Группа ВР ВсеНачисления_2 содержит ВР ПремияСум_2 В группу ВР ВсеНачисления_2 входит 4 ВР
В группе ВР ВсеНачисления_2 под номером 2 расположен расчет ПремияКоэф_2
7.16. АТРИБУТЫ И МЕТОДЫ ПРАВИЛ ПЕРЕРАСЧЕТА
7.16.1. АТРИБУТЫ ПРАВИЛ ПЕРЕРАСЧЕТА
Правило перерасчета, как отмечено в разд. 7.7, при вводе ведущего расчета обнуляет значение атрибута Рассчитана у зависимых расчетов.
Каждое правило имеет 4 атрибута: Код, Наименование, Тип и КоличествоПерио-дов. Их описание дано в табл. 7.20.
Таблица 7.20
Атрибуты правил перерасчета |
|
Атрибут |
Описание |
|
Код |
Строка, содержащая идентификатор правила перерасчета (разд. 7.7) |
|
Наименование |
Строка, содержащая комментарий правила перерасчета |
|
Тип |
Зависимые расчеты должны быть перерассчитаны:
• если Тип = 0 - в текущем расчетном периоде ЖР;
• если Тип = 1 - в том же расчетном периоде, к которому принадлежит вводимый ведущий расчет;
• если Тип = 2 - в нескольких периодах, следующих за периодом, к которому принадлежит вводимый ведущий расчет (разд. 7.7).
Число периодов, Охватываемых правилом, заносится в атрибут Коли-чествоПериодов правила перерасчета |
|
КоличествоПериодов |
Число периодов, охватываемых правилом перерасчета. Может быть больше единицы, только когда Тип = 2 |
|
|
Пример. Выводятся атрибуты правила перерасчета КвартальнаяПремия. |
процедура Выполншъ() // Связана с кнопкой Пуск обработки Проба
перем ПП;
ОчиститьОкноСообщений(); // Очищаем окно сообщений
ПП = ПравилоПерерасчета.КвартальнаяПремия;
Сообщить(''Код (идентификатор): " + ПП.Код);
СообщитьС'Наименование (комментарий):" + ПП.Наименование);
Сообщить("Тип = " + ПравилоПерерасчета.КвартальнаяПремия.Тип); Сообщить("КоЛичествоПериодов = " + ПП.КоличествоПериодов); конецПроцедуры // Выполнить
Результат:
Код (идентификатор): КвартальнаяПремия Наименование (комментарий): Для квартальной премии Тип = 2
КоличествоПериодов = 3
7.16.2. МЕТОДЫ ПРАВИЛ ПЕРЕРАСЧЕТА
Находятся в табл. 7.21.
Таблица 7.21
Методы правил перерасчета |
|
Метод |
Описание |
|
колВед = ПП.КоличествоВедущих(); |
Возвращает количество ведущих ВР в правиле перерасчета ПП |
|
флаг = ПП.ИмеетВедущий(ВР); |
Вернет 1, если вид расчета ВР входит в правило перерасчета ПП как ведущий |
|
ВР = ПП.ПолучитьВедущий(ном); |
Возвращает вид расчета ВР, входящий в правило перерасчета ПП как ведущий под номером ном |
|
ПП.ДобавитьКакВедущий(ВР); |
Добавляет в правило перерасчета ПП вид расчета
ВР в качестве ведущего |
|
|
Метод |
Описание |
|
ПП.УдалитьВсеВедущие(); |
Удаляет из правила перерасчета ПП все ведущие
ВР |
|
колПод = ПП.КоличествоПодчиненных(); |
Возвращает количество подчиненных (зависимых) ВР в правиле перерасчета ПП |
|
флаг = ПП.ИмеетПодчиненный(); |
Вернет 1, если вид расчета ВР входит в правило перерасчета ПП как подчиненный |
|
ВР = ПП.ПолучитъПодчиненный(ном); |
Возвращает вид расчета ВР, входящий в правило перерасчета ПП как подчиненный под номером
ном |
|
ПП.ДобавитьКакПодчиненный(); |
Добавляет в правило перерасчета ПП вид расчета ВР в качестве подчиненного |
|
П П .УдалитьВсеПодчиненные(); |
Удаляет из правила перерасчета ПП все зависимые ВР |
флагТек =
ПравилоПерерасчета.Применять ' ([флагНов]); |
При вводе ведущих ВР правила перерасчета применяются, если флагНов = 1, и не применяются, если флагНов = 0. По умолчанию флагНов = 1. Возвращает текущее, до вызова метода значение флага применения правил перерасчета |
Замечание. Префикс ПП, употребленный с методами правил перерасчета, может быть произвольным.
Пример 1:
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем ПП, колВед, колПод, ин;
ОчиститьОкноСообщений(); // Очищаем окно сообщений
ПП = ПравилоПерерасчета.ВБанк_2; колВед = ПП.КоличествоВедущихО; колПод = ПП.КоличествоПодчиненных();
Сообщить("Правило перерасчета " + ПП.Код);
Сообщить("Число ведущих ВР:" + колВед);
Сообщить("Число зависимых ВР: " + колПод);
Сообщить("Список ведущих ВР:"); для ин = 1 по колВед цикл
Сообщить(ПП.ПолучитьВедущий(ин). Код); конецЦикла; // для Сообщить("Список зависимых ВР:"); для ин = 1 по колПод цикл
Сообщигь(ПП.ПолучиіъПодчиненный(ин). Код); конецЦикла; // для конецПроцедуры // Выполнить
Результат:
Правило перерасчета ВБанк_2 Число ведущих ВР: 6 Число зависимых ВР: 1 Список ведущих ВР:
НачСальдо_2
Оклад_2
ПремияКоэф_2
ПремияСум_2
Премия1234_2
НДФЛ_2
Список зависимых ВР: ВБанк 2
Пример 2. В правиле перерасчета ВБанк_2 первоначально удаляются все ведущие и подчиненные ВР, а затем оно формируется заново.
Связана с кнопкой Пуск обработки Проба
процедура Выполнить() //
перем ПП, ВРВед[6], ВРПод, ин;
Очищаем окно сообщений
ОчиститьОкноСообщений(); //
ПП = ПравилоПерерасчета.ВБанк_2;
ВРВед[1] = ВидРасчета.НачСальдо_2;
ВРВед[2] = ВидРасчета.Оклад_2;
ВРВед[3] = ВидРасчета.ПремияКоэф_2;
ВРВед[4] = ВидРасчета.ПремияСум_2;
ВРВед[5] = ВидРасчета.Премия1234_2;
ВРВед[6] = ВидРасчета.НДФЛ_2;
ВРПод = ВидРасчета.ВБанк_2;
Удаляем ведущие ВР Удаляем подчиненные ВР
ПП.УдалитьВсеВедущиеО; //
ПП.УдалитьВсеПодчиненные(); //
// Контроль
Сообщить("Число ведущих ВР: " + ПП.КоличествоВедущихО); Сообщить("Число подчиненных ВР: " + ПП.КоличествоПод4иненныхО); для ин = 1 по 6 цикл
ПП.ДобавитьКакВедущий(ВРВед[ин]); конецЦикла; // для
ПП.ДобавитьКакПодчиненный(ВРПод);
// Контроль
Сообщить("Число ведущих ВР: " + ПП.КоличествоВедущихО); Сообщить("Число подчиненных ВР: " + ПП.КоличествоПодчиненныхО); конецПроцедуры // Выполнить
7.17. ЗАВЕРШАЕМ КОДИРОВАНИЕ ПРОЦЕДУР МОДУЛЯ ФОРМЫ СПИСКА ЖУРНАЛА ЗАРПЛАТА_2
После ввода расчетов интерфейс ЖЗ предоставляет возможность рассчитать зарплату сотрудников, сформировать их расчетные листки и ведомость о перечислениях
в банк. Для этих целей с кнопками диалога (рис. 7.21) Расчет зарплаты, О и ^
связаны соответственно процедуры РасчетЗП, ПечатьРЛ и ВедомостьБанк. Это простые процедуры, но для полноты изложения мы напишем и приведем их код. Дополнительно рассмотрим запрос, возвращающий распределение результатов расчетов ЖЗ по хозяйственным операциям.
7.17.1. РАСЧЕТ ЗАРПЛАТЫ
Процедура РасчетЗП для выбранного сотрудника или сотрудников заданного подразделения выполняет расчет его начислений и удержаний, включая перечисление п банк. То есть в первом случае она повторяет действия процедуры, запускаемой иконкой >' или соответствующим ей пунктом меню, во втором - эти действия повторяются для каждого сотрудника выоранного подразделения. 1аким ооразом, наша задача - написать процедуру расчета объекта, а затем вызвать ее необходимое число раз.
Поскольку расчет с ВР НачСальдо_2 фиксирован, то в создаваемой процедуре записи с таким ВР не будут рассчитываться вовсе. Также не рассчитываются записи с неотмененной ручной правкой. Кроме того, заложим в процедуру код, проверяющий присутствие у объекта обязательного расчета с ВР НДФЛ2. В соответствии с документом Табель наличие одного обязательного расчета, например НДФЛ_2, говорит о том, что в ЖЗ есть и все иные обязательные расчеты объекта, то есть расчеты с ВР Оклад_2 и ВБанк_2.
После всего сказанного текст процедур расчета зарплаты может быть таким:
// Процедура РасчетОбъекта рассчитывает все записи объекта ЖЗ,
// кроме расчета с ВР НачСальдо_2
// Поскольку процедура присутствует в модуле формы списка ЖЗ,
// то все методы ЖР вызываются без префикса процедура РасчетОбъекта(сотр) перем флаг, сотр2;
// Флаг будет равен единице, если у сотрудника есть расчет с ВР Оклад_2 флаг = 0;
сотр2 = сотр; // Запоминаем для вывода сообщения
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде ВыбратьПериодПоОбъекту(сотр); пока ПолучитьЗапись() = 1 цикл
если видРасч = ВидРасчета.НДФЛ_2 тогда флаг = 1; конецЕсли;
// Фиксированные и исправленные записи рассчитывать нет смысла если Фиксирована + Исправлена = 0 тогда Рассчитать(); конецЕсли; конецЦикла; // пока если флаг = 0 тогда
Сообщить(''Оформите табель сотруднику " + сотр2.Наименование); конецЕсли;
конецПроцедуры // РасчетОбъекта
процедура СоздатьСЗнач(сЗначСотр) далее
процедура РасчетЗП( )
перем сотр, сЗначСотр, ин;
ОчиститьОкноСообщений();
если кто = 1 тогда // Расчет зарплаты выбранного сотрудника
Состояние("Расчет зарплаты сотрудника " + Объект.Наименование); РасчетОбъекта(Объект);
// Расчет заплаты сотрудников выбранного подразделения // Используя метод ЖР ВыбратьПоЗначению, занесем (без повторов) значение // атрибута Объект расчетов выбранного подразделения в список сЗначСотр иначе
Состояние(''Формируем список сотрудников подразделения " + Объект.Родитель); СоздатьСЗнач(сЗначСотр); // Формируем список сотрудников подразделения для ин = 1 по сЗначСотр.РазмерСписка() цикл сотр = сЗначСотр.ПолучитъЗначение(ин);
Состояние(''Расчет зарплаты сотрудника " + сотр.Наименование); РасчетОбъекта(сотр); конецЦикла; // для // Поправляем закладку отбора УстановитьОтбор("Родитель", сотр.Родитель); конецЕсли;
конецПроцедуры // РасчетЗП
процедура СоздатьСЗнач(сЗначСотр) // Формируем список сотрудников подразделения перем сотр, пер;
сЗначСотр = СоздатьОбъект("СписокЗначений"); пер = ТекущийПериод();
ВыбратаПоЗначениюСРодитель'', Объект.Родитель, пер, пер);
сотр = Объект; // Первый объект выборки
пока ПолучитьЗапись() = 1 цикл
// Значения в список сЗначСотр заносятся без повторов если сотр = Объект тогда продолжить; иначе
сЗначСотр.ДобавитьЗначение(сотр); сотр = Объект; конецЕсли; конецЦикла; // пока
// Добавляем ссылку на последнего сотрудника выбранного подразделения сЗначСотр.ДобавитьЗначение(сотр); конецПроцедуры // СоздатьСЗнач
Замечания:
1. Созданный код работает существенно быстрее, чем аналогичный встроенный в 1С.
2. Процедуры РасчетОбъекта и РасчетЗП добавляются в модуль формы списка ЖЗ Зарплата_2.
3. Встроенная процедура Состояние выводит в строку состояний, расположенную в нижней левой части экрана, занесенное в символьный параметр процедуры сообщение.
4. Сотрудников выбранного подразделения можно было бы извлечь из справочника Сотрудники_2 и затем передать их процедуре РасчетОбъекта, употребив, например, следующий код:
процедура РасчетЗЩ )
перем пер, сотр, сСотр_2;
ОчиститьОкноСообщений();
если кто = 1 тогда // Расчет зарплаты выбранного сотрудника
Состояние("Расчет зарплаты сотрудника " + Объект.Наименование); РасчетОбъекта(Объект); иначе
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сСотр_2.ИспользоватьРодителя(Объект.Родигель); сСотр_2.ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл сотр = сСотр_2.ТекущийЭлемент();
Состояние("Расчет зарплаты сотрудника " + сотр);
РасчетОбъекта(сотр); конецЦикла; // пока // Поправляем закладку отбора УстановитьОтбор("Родитель", сотр.Родитель); конецЕсли;
конецПроцедуры // РасчетЗП
Критерий выбора кода в данном случае - его быстродействие. Вопрос замера времени вычислений обсуждается в разд. 2.8.3.
5. На период отладки вам может понадобиться приводимый ниже код, отменяющий ручную правку и обнуляющий результат расчета с ВР ВБанк_2 (перечисление в банк):
// Отменяет ручную правку и заносит 0 в результат расчета с ВР ВБанк_2
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем жз, перТек, пер;
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьПериод(жз.НачалоТекущегоПериода()); пока жз.ПолучитьЗапись() = 1 цикл если жз.Исправлена = 1 тогда
жз.ОтменитьИсправление(); // Обнуляем флаг ручной правки конецЕсли;
если жз.ВидРасч = ВидРасчета.ВБанк_2 тогда жз.Результат = 0; конецЕсли; конецЦикла; // пока конецПроцедуры // Выполнить
ФОРМИРОВАНИЕ РАСЧЕТНОГО ЛИСТКА
Так же как и при расчете зарплаты, мы создадим процедуру ЛистокСотрудника, формирующую расчетный листок (РЛ) для одного сотрудника, и будем использовать ее нужное число раз, когда задача решается для выбранного подразделения.
Вывод РЛ будем осуществлять в специально созданную в форме списка ЖЗ таблицу, которой дадим имя РЛ (рис. 7.79).
|
|
|
1 |
2 |
3 |
4 |
s |
|
Заголовок |
1 |
|
|
Расчетный листок |
|
|
|
|
2 |
|
Предприятие [Константа.Название0рганиэации[> |
|
|
|
3 |
|
«"Подразделение * ¦ Объект Родитель ¦ Обь?кт.Наименование» |
|
|
4 |
|
«Табельный номер" ¦ Обьект.Код ¦Оклад" ¦ окл |
¦¦руб"» |
|
|
твбЗаг |
5 |
|
«?(начУд = 1, "Начисления". "Удержания")» |
|
|
9 |
|
Мес. |
"Вид" ¦ ?(начУд= 1 ."начисления", "удержания") |
Сумма |
Часы |
|
Расчет |
7 |
|
<мес> |
«ВР» |
« рез> |
«часы» |
|
Пусто |
1 |
|
|
|
сНач |
9 |
|
|
Остаток прошлого месяца |
сальдоНач» |
|
|
Итог |
19 |
|
|
Начислено |
<нач> |
|
|
|
'11 |
|
|
Удержано |
«УД* |
|
|
|
12 |
|
|
Полагается к выплате: |
<вып> |
|
|
|
13 |
|
|
Перечислено в банк |
«вБанк» |
|
|
сКон |
14 |
|
|
Остаток на конец месяца |
«сальдоКон» |
|
|
|
t~~] Диалог 1 f J Монель / А]РЛ * ~f |
Рис. 7. 79. Образец для расчетного листка
Из образца видно, что для вывода нам понадобятся переменные окл, мес, ВР, рез, часы, начУд, нач, уд, вып, вБанк, сальдоНач и сальдоКон. Их смысл разъясняет рис. 7.79.
Алгоритм получения РЛ следующий:
1. Вывести заголовок РЛ и заголовок таблицы начислений.
2. Сформировать списки тЗначНач и тЗначУд с начислениями и удержаниями сотрудника, попутно вычисляя значения переменных нач, уд, вып, вБанк, сальдоНач и сальдоКон.
3. Вывести заголовок таблицы начислений, а затем, используя таблицу тЗначНач, и сами начисления.
4. Вывести заголовок таблицы удержаний, а затем, используя таблицу тЗначУд, и сами удержания.
5. Вывести итоговую часть РЛ.
Этот алгоритм реализует процедура ЛистокСотрудника, вызываемая из процедуры ПечатьРЛ. После программ на рис. 7.80 приведен пример сформированного РЛ.
процедура СоздатьТЗнач(тЗнач) далее // Вспомогательные процедуры формирования РЛ процедура НовСтрокаВТЗнач(тЗнач, мес) далее процедура ВыводНачУд(табл, тЗнач, начУд) далее
// Процедура ЛистокСотрудника формирует РЛ одного сотрудника // Поскольку процедура присутствует в модуле формы списка ЖЗ,
// то все методы ЖР вызываются без префикса процедура ЛистокСотрудника(Объект, табл, тЗначНач, тЗначУд) перем нач, уд, вып, вБанк, сальдоНач, сальдоКон, мес;
// Инициализация переменных
нач = 0; уд = 0; вып = 0; вБанк = 0; сальдоНач = 0; сальдоКон = 0;
// Помним, что Оклад - это периодический реквизит справочника Сотрудники_2 окл = Объект.Оклад.Получить(КонецТекущегоПериода());
// При выводе применяем заданные по умолчанию параметры таблицы;
// для их изменения следует обратиться к методу Опции // Выводим секцию Заголовок табл.ВывестиСекцию("Заголовок");
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде ВыбратьПериодПоОбъекту(Объект); пока ПолучитьЗапись( ) = 1 цикл мес = ДатаМесяц(ДатаНачала);
если ВидРасч.ВходитВГруппу(ГруппаРасчетов.ВсеНачисления_2) = 1 тогда нач = нач + Результат;
// Добавляем в тЗначНач номер месяца, ВидРасч, Результат и ВсегоЧасов НовСтрокаВТЗнач(тЗначНач, мес);
иначеЕсли ВидРасч.ВходитВГруппу(ГруппаРасчетов.ВсеУдержания_2) = 1 тогда уд = уд + Результат;
// Добавляем в тЗначУд номер месяца, ВидРасч, Результат и ВсегоЧасов НовСтрокаВТЗнач(тЗначУд, мес); иначеЕсли ВидРасч = ВидРасчета.НачСальдо_2 тогда сальдоНач = Результат;
Вид расчета ВБанк_2
Пустая строка в РЛ
Выводим сальдо на начало месяца Форматируем данные
вБанк = Результат; конецЕсли; конецЦикла; // пока
Полагается к выплате Сальдо на конец месяца //Вывод начислений
//Вывод удержаний
нач = Формат(нач, "4-10.2"); уд = Формат(уд, "4-10.2"); вБанк = Формат(вБанк, "Ч-10.2"); табл.ВывестиСекцию("Итог"); сальдоКон = Формат(сальдоКон, "4-10.2");
табл.ВывестиСекцию("сКон"); // Вывод сальдо на конец месяца
// Запрещаем редактирование результирующей таблицы табл.ТолькоПросмотр(1);
// В методе Показать задаем пустой заголовок окна с результирующей таблицей табл.Показать("");
конецПроцедуры // ЛистокСотрудника процедура ПечатьРЛ()
перем сотр, сЗначСотр, ин, табл, тЗначНач, тЗначУд;
// тЗначНач, тЗначУд - таблицы значений для начислений и удержаний сотрудника ОчиститьОкноСообщений();
СоздатьТЗнач(тЗначНач);
СоздатьТЗ нач(тЗ начУ д);
табл = СоздатьОбъект("Таблица");
// Свяжем переменную табл с таблицей РЛ, содержащей макет расчетного листка табл.ИсходнаяТ аблица("РЛ");
если кто = 1 тогда // РЛ выбранного сотрудника
Состояние("Формируем расчетный листок сотрудника " + Объект.Наименование); ЛистокСотрудника(Объект, табл, тЗначНач, тЗначУд);
// Вывод РЛ сотрудников выбранного подразделения
// Используя метод ЖР ВыбратьПоЗначению, занесем (без повторов) значение // атрибута Объект расчетов выбранного подразделения в список сЗначСотр
иначе
Состояние("Формируем список сотрудников подразделения " + Обьект.Родитель);
// Код процедуры СоздатьСЗнач см. в предшествующем разделе СоздатьСЗнач(сЗначСотр); // Формируем список сотрудников подразделения для ин = 1 по сЗначСотр.РазмерСписка() цикл сотр = сЗначСотр.ПолучитьЗначение(ин);
Состояние("Формируем расчетный листок сотрудника " + сотр.Наименование); ЛистокСотрудника(сотр, табл, тЗначНач, тЗначУд);
// Подготовка таблиц значений для РЛ следующего сотрудника тЗначНач.УдалитьСтроки(); тЗначУд.УдалитьСтроки(); конецЦикла; // для // Поправляем закладку отбора УстановитьОтбор("Родитель", сотр.Родитель); конецЕсли;
конецПроцедуры // ПечатьРЛ
// Создает таблицу значений с четырьмя столбцами процедура СоздатьТЗнач(тЗнач)
// Таблица значений для начислений (удержаний) сотрудника тЗнач = СоздатьОбъект("ТаблицаЗначений");
// Формируем столбцы таблицы значений. Опуская имена необязательных параметров,
// сохраняем разделяющие их запятые тЗнач.НоваяКолонка("Месяц", "Число",,,, 2); тЗнач.НоваяКолонка("ВидРасчета", "Вид Расчета",,,,); тЗнач.НоваяКолонка("Сумма", "Строка",,,, 10); тЗнач.НоваяКолонка("Часы", "Строка",,,, 3); конецПроцедуры // СоздатьТЗнач
// Добавляем в таблицу значений номер месяца, ВР, Результат и ВсегоЧасов процедура НовСтрокаВТЗнач(тЗнач, мес)
тЗнач.НоваяСтрока(); // Добавляем новую строку
// Определяем, используя атрибут идентификатор столбца, ячейки новой строки тЗнач.Месяц = мес; тЗнач.ВидРасчета = ВидРасч;
// Форматируем данные тЗнач.Сумма = Формат(Результат, "Ч-10.2"); тЗнач.Часы = Формат(ВсегоЧасов, "Ч-3.0"); конецПроцедуры // НовСтрокаВТЗнач
// Выводит в РЛ, если начУд = 1, таблицу с начислениями или с удержаниями, если начУд = 2 процедура ВыводНачУд(табл, тЗнач, начУд)
// Выводим секцию табЗаг с заголовком для таблицы начислений (удержаний) табл.ВывестиСекцию("табЗаг"); тЗнач.ВыбратьСтроки( ); пока тЗнач.ПолучитьСтроку() = 1 цикл мес = тЗнач.Месяц;
ВР = тЗнач.ВидРасчета; рез = тЗнач.Сумма; часы = тЗнач.Часы; табл.ВывестиСекцию("Расчет"); конецЦикла; // пока конецПроцедуры // ВыводНачУд
Расчетный листок
Предприятие АО ТриТ
Подразделение 03 Цех; Безверхний Игорь Петрович Табельный номер 301;' Оклад 3100 руб._ |
|
Начисления |
|
Мес. |
Вид начисления |
Сумма |
Часы |
|
12 |
Оклад |
3100.00 |
165 |
|
12 |
Премия суммой |
700.00 |
|
|
12 |
Премия коэффициентом |
1650.00 |
165 |
|
1 |
Премия коэффициентом |
1650.00 |
165 |
|
12 |
Премия 1234 |
3550.00 |
|
|
Удержания |
|
Мес. |
Видудержания |
Сумма |
Часы |
|
12 |
НДФЛ |
1384.50 |
_ |
|
|
Остаток прошлого месяца |
0.20 |
|
|
|
Начислено |
10650.00 |
|
|
|
Удержано |
1384.50 |
|
|
|
Полагается к выплате: |
9265.70 |
|
|
|
Перечислено в банк |
9265.00 |
|
|
|
Остаток на конец месяца |
0.70 |
|
|
|
Рис. 7.80. Расчетный листок Безверхнего И. П. |
Замечание. Формат "Ч-10.2", употребленный во встроенной функции Формат, обеспечит вывод ненулевого значения на поле длиной в 10 символов с двумя знаками после десятичной точки. Если первый параметр функции Формат равен нулю, то вместо нуля согласно формату "Ч-10.2" будет выводиться символ -.
7.17.3. ВЕДОМОСТЬ ПЕРЕЧИСЛЕНИЙ В БАНК
Формируется в виде текстового файла, который затем можно отправить по электронной почте в банк назначения. Содержит для каждого сотрудника его ФИО, табельный номер, номер счета в банке и перечисленную сумму. При этом мы предполагаем, что номер счета отличается от табельного номера сотрудника только префиксом Б-. Если это не так, то в справочник Сотрудники_2 придется добавить новое поле для хранения в нем номера счета сотрудника.
процедура СтрокаВТекст(сотр, текст, ном, всего) далее
// Ведомость перечислений в банк для одного сотрудника или сотрудников // выбранного подразделения. Формируется как текстовый файл // Поскольку процедура присутствует в модуле формы списка ЖЗ,
//то все методы ЖР вызываются без префикса процедура ВедомостьБанк()
перем текст, всего, сЗначСотр, ин, сотр; перем сообщение;
сообщение = "Формируем ведомость перечислений сотрудника "; всего = 0; // Общая сумма перечислений в банк
текст = СоздатьОбъект("Текст"); // Направляем вывод в текстовый файл текст.КодоваяСтраница(1); // Используем DOS-кодировку текста
текст.ДобавитьСтроку(" Список перечислений во вклады из заработной платы на лицевые счета рабочих и служащих"); текст.ДобавитьСтроку(" " + Объект.Родитель + "," +
Константа. НазваниеОрганизации);
текст.ДобавитьСтроку(" за " + ПериодРегистрации.ОписательПериода + " в " + Константа. БанкОрганизации);
|
текст.ДобавшъСтроку(" |
 |
если кто — 1 тогда // Ведомость для выбранного сотрудника
Состояние(сообщение + Объект.Наименование);
СтрокаВТекст(Объект, текст, 1, всего);
// Вывод РЛ сотрудников выбранного подразделения
// Используя метод ЖР ВыбратьПоЗначению, занесем (без повторов) значение // атрибута Объект расчетов выбранного подразделения в список сЗначСотр иначе
Состояние("Формируем список сотрудников подразделения " + Объект.Родитель);
// Код процедуры СоздатьСЗнач см. в предшествующем разделе
СоздатьСЗнач(сЗначСотр); // Формируем список сотрудников подразделения для ин = 1 по сЗначСотр.РазмерСписка() цикл сотр = сЗначСотр.ПолучитьЗначение(ин);
Состояние(сообщение + сотр.Наименование);
СтрокаВТекст(сотр, текст, ин, всего); конецЦикла; // для // Поправляем закладку отбора УстановитьОтбор(" Родитель", сотр. Родитель); конецЕсли;
// Завершаем вывод ведомости перечислений в банк текст.ДобавитьСтроку(""); // Пустая строка
// Формат "ЧПД" обеспечит вывод итоговой суммы перечислений прописью текст.ДобавитьСтроку(" Итого: " + Формат(всего, "ЧПД")); текст.ДобавитьСтроку(""); // Пустая строка
текст.ДобавитьСтроку(" Гл. бухгалтер" + СимволТабуляции +
Символ Табуляции + СимволТабуляции + СимволТабуляции +
Константа.Г лБухгалтер .Получить(Т екущаяДата())); текст.ТолькоПросмотр(1); // Запрещаем редактирование текста
текст.Показать("Ведомость перечислений в банк"); конецПроцедуры // ВедомостьБанк
// Добавляет в ведомость строку под номером ном и корректирует значение переменной всего процедура СтрокаВТекст(сотр, текст, ном, всего)
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде
ВыбратьПериодПоОбъекту(сотр);
пока ПолучитьЗапись() = 1 цикл
если видРасч = ВидРасчета.ВБанк_2 тогда всего = всего + Результат;
// Форматируем данные в соответствии с заголовком табличной части ведомости текст.ДобавитьСтроку(" " + Формат(ном, "С5") + ":" + Формат(Объект.Наименование, "С27") + ": " +
Формат(Объект.Код, "С9") + ":" +
Формат(Результат, "410.2") + " : " +
Формат("Б-" + Строка(Объект.Код), "С9")); возврат; конецЕсли; конецЦикла; // пока конецПроцедуры // СтрокаВТекст
Результат для третьего цеха приведен на рис. 7.81.
 |
|
Рис. 7.81. Ведомость для третьего цеха |
Замечание. Чтобы получить отображение ведомости перечислений в банк равномерным шрифтом, была выполнена цепочка Текст - Текст модуля.
7.17.4. СВЕДЕНИЯ ДЛЯ БУХГАЛТЕРСКОГО УЧЕТА ЗАРПЛАТЫ
Эти сведения нам предоставит запрос, вычисляющий в заданном периоде для каждой хозяйственной операции суммарные значения результатов относящихся к ней расчетов.
Запрос запустим из обработки Проба. Для просмотра результатов запроса выгрузим его в таблицу значений.
// Формирует и выполняет запрос по хозяйственным операциям,
// суммируя относящиеся к ним результаты // Параметр зХозОп типа Запрос является входным/выходным функция ЗапрХозОп(зХозОп)
перем текстЗапХозОп; // Содержание запроса
перем жз, нтп, ктп;
жз = СоздатьОбъект(''ЖурналРасчетов.Зарплата_2'');
// Начало и конец текущего периода ЖЗ нтп = жз.НачалоТекущегоПериода(); ктп = жз.КонецТекущегоПериода(); текстЗапХозОп = "
| период с нтп по ктп; // Период запроса
// Переменные запроса | хозОп = журналРасчетов.Зарплата_2.ХозОп;
| рез = журналРасчетов.Зарплата_2.Результат;
// Функция запроса | функция сумХозОп = сумма(рез);
// Задаем порядок выборки данных
| группировка хозОп упорядочить по хозОп.Наименование;";
// Выполняем запрос и возвращаем 1 в случае удачи, или 0, если есть проблемы возврат зХозОп. Выполнить(текстЗапХозОп); конецфункции // ЗапрХозОп
// Запускает запрос зХозОп о хозяйственных операциях и выгружает // его результат для последующего просмотра в таблицу значений тЗнач процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем зХозОп, тЗнач;
// Создаем объекты зХозОп и тЗнач зХозОп = СоздатьОбъект("Запрос"); если ЗапрХозОп(зХозОп) = 0 тогда
возврат; // Запрос не выполнен
конецЕсли;
// Создаем объект тЗнач для промежуточной демонстрации выборки запроса тЗнач = СоздатьОбъекг("ТаблицаЗначений");
// Выгружаем все переменные запроса в таблицу значений тЗнач // для его предварительного просмотра зХозОп.Выгрузить(тЗнач, 1);
// Просмотр .таблицы значений
тЗнач.ВыбратьСтроку(, "Запрос о хозяйственных операциях в таблице значений"); конецПроцедуры // Выполнить
Результат приведен на рис. 7.82.
 |
|
Рис. 7.82. Распределение расчетов по хозяйственным операциям Имеющаяся в тексте запроса строка-функция | функция сумХозОп = сумма(рез); |
задает в результирующей таблице поле сумХозОп, в которое для каждой группы, а группировка выполняется по переменной запроса хозОп, заносится сумма результатов всех расчетов, отнесенных на текущую хозяйственную операцию.
Код, повторяющий действия функции сумХозОп, может быть таким:
// Возвращает в заданном периоде для заданной хозяйственной операции хозОп // сумму результатов относящихся к ней расчетов функция сумХозОп2(хозОп, жз, нтп) жз.ВыбратьПериод(нтп);
схо = 0; // Искомый результат
пока жз.ПолучитьЗапись() = 1 цикл если жз.ХозОп = хозОп тогда схо = схо + жз.Результат; конецЕсли; конецЦикла; // пока возврат схо;
конецФункции // сумХозОп2
Запустим функцию сумХозОп2 для всех хозяйственных операций текущего расчетного периода из обработки Проба. Перечень хозяйственных операций нам даст запрос зХозОп.
// Формирует список использованных в текущем периоде ЖЗ хозяйственных операций // Вызывает затем функцию сумХозОп2 для каждой хозяйственной операции // и печатает возвращенный функцией результат
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем зХозОп, текстЗапХ; // Содержание запроса
перем жз, нтп, ктп, сумРез;
ОчиститьОкноСообщенийО;
// Создаем объекты зХозОп и жз
зХозОп = СоздатьОбъект("Запрос");
жз = СоздатъОбъект('ЖурналРасчетов.Зарплата_2");
// Начало и конец текущего периода ЖЗ нтп = жз.НачалоТекущегоПериодаО; ктп - жз.КонецТекущегоПериода(); текстЗапХ = "
| период с нтп по ктп; // Период запроса
// Переменная запроса
[ хозОп = журналРасчетов.Зарплата_2.ХозОп;
| группировка хозОп упорядочить по хозОп.Наименование;";
// Выполняем запрос и возвращаем 1 в случае удачи, или 0, если есть проблемы если зХозОп.Выполнить(текстЗапХ) = 0 тогда
возврат; // Запрос не выполнен
конецЕсли; всего = 0;
пока зХозОп.Группировка("хозОп") = 1 цикл
сумРез = сумХозОп2(зХозОп.хозОп, жз, нтп); всего = всего + сумРез;
Сообщить("Сумма результатов по операции " + СокрП(зХозОп.хозОп) +
" равна " + символТабуляции + сумРез); конецЦикла; // пока
Сообщить("Всего по всем операциям: " + всего); конецПроцедуры // Выполнить
Результат:
Сумма результатов по операции 2017002 равна 13642.6
Всего по всем операциям: 209892.1
Если нужно просмотреть отдельные составляющие каждой группы с указанием объекта, текст запроса нужно сформировать следующим образом:
текстЗапХозОп ="
| период с нтп по ктп; // Период запроса
// Переменные запроса; добавляем переменную сотр | сотр = журналРасчетов.Зарплата_2.Объект;
| хозОп = журналРасчетов.Зарплата_2.ХозОп;
| рез = журналРасчетов.Зарплата_2.Результат;
// Функция запроса | функция сумХозОп = сумма(рез);
// Задаем порядок выборки данных
| группировка хозОп упорядочить по хозОп.Наименование;
| группировка рез;"; // Добавленная строка
|
Тогда в таблице результатов мы будем наблюдать приведенные на рис. 7.83 данные. |
 |
|
Рис. 7.83. Фрагмент результата запроса для группы хозОп =20130000 |
7.18. ПЕРВЫЙ РАСЧЕТНЫЙ ПЕРИОД НОВОГО ГОДА
Теперь, когда выполнены расчеты и выпущены все необходимые документы, можно перейти к следующему расчетному периоду. Это можно сделать интерактивно, выбрав
_о*
на панели инструментов диалога формы списка ЖЗ Зарплата 2 иконку ЭІЛ. В
этом слу
чае будут отработаны сопровождающие смену системные действия, предопределенная процедура глобального модуля ПриСменеРасчетногоПериода и, следовательно, добавленная нами в глобальный модуль процедура ФиксироватьСменуРП (разд. 7.3.6.3). В результате ее исполнения в документе Начало периода № 1 появится новая запись, напоминающая о произошедшем событии (рис. 7.84).
 |
|
Рис. 7.84. Новый расчетный период |
Вспомним, что архивные записи ЖЗ (кроме фиксированных) имеют иной цвет фона сопровождающих их иконок - голубой. Изменяется и фон иконок в журнале документов: иконки, сопровождающие документы, соответствующие архивным расчетам, располагаются на темно-синем фоне.
В новом периоде нет пока что ни одного расчета. Но не следует торопиться с их вводом, поскольку период открывает новый год и скорее всего для него не определены используемые справочником Сотрудники_2 календари и праздники. Поэтому предварим ввод расчетов заданием праздников, а вслед выполним автозаполнение календарей. Все необходимые средства для выполнения этих действий у нас есть, доступ к ним осуществляется посредством пунктов Календари и Праздники, расположенных в колонке Календари меню интерфейса Ученик.
7.19. ВЫВОДЫ
1. ЖР состоит из записей, называемых расчетами; они попадают в журнал в результате проведения соответствующих документов.
2. Расчеты могут быть обязательными, дополнительными, вытесняющими, длинными, перерасчетами, зависимыми и обычными. Полезно контролировать, имеют ли объекты ЖЗ все обязательные расчеты.
3. Длинные расчеты могут существовать только в документах. В ЖЗ длинный расчет разбивается на соответствующее число обычных расчетов.
4. В описание группы ВР следует помещать информацию о программах, в которых группа используется.
5. Перенос данных в 1С из других программ можно выполнить, употребляя объекты типа XBase.
6. Основное назначение объектов типа Календарь и Праздники - предоставлять данные для вычисления числа рабочих часов и дней в заданном временном интервале.
7. Сложные документы, журналы и обработки 1С, учитывающие многие случаи жизни, целесообразно заменять на аналогичные по назначению, отвечающие потребностям предприятия более простые и, следовательно, эффективные программы.
8. В окне задания свойств документа, вводящего расчеты, нужно активизировать флажок Расчет.
9. Методы ВвестиРасчет и ЗаписатьРасчет могут быть вызваны только в модулях документов, вводящих расчеты. Вызвать эти методы в модулях иных объектов, например в модуле формы списка ЖЗ или в модуле отчета (обработки), нельзя.
10. Расчеты одного объекта располагаются в ЖЗ в порядке очередности их исполнения;
11. Команда проведения документа при выполнении перепроведения отслеживает все возможные произошедшие в документе изменения.
12. Для обновления самовытесняющего расчета при его повторном вводе другим документом вместо метода ЗаписатьРасчет используется метод ВвестиРасчет.
13. Правила перерасчета обнуляют значение атрибута Рассчитана у зависимых расчетов.
14. Правила перерасчета не срабатывают при расчете записи в результате выбора пункта меню Рассчитать запись.
15. Разбивая длинный расчет на части, 1С сохраняет вычисленный в соответствии с документом, порождающим расчет, результат для каждой из частей разбиения.
16. Если в результате вытеснения расчет разбивается на к частей, то каждая из этих частей наследует общий результат, то есть общий результат исходного расчета увеличивается в к раз, что входит в противоречие с документом; создавшим расчет.
17. Предопределенные процедуры модуля формы ЖР позволяют эффективно управлять правами доступа пользователей.
8. ПОВЫШЕНИЕ ЭФФЕКТИВНОСТИ ФУНКЦИОНИРОВАНИЯ СИСТЕМЫ
8.1. КРИТЕРИИ ЭФФЕКТИВНОСТИ
Эффективность функционирования системы будем оценивать быстродействием программ, временным промежутком, необходимым для ввода, редактирования данных, поиска ошибок и получения результата, качеством пользовательского интерфейса, надежностью вычислений и степенью защищенности данных.
На первый взгляд мы не можем повлиять на эти характеристики, поскольку они заложены в систему ее разработчиками. Это действительно так, если эксплуатировать систему как она есть. Но теперь, когда мы понимаем ее узкие звенья, знаем, как их преобразовать, и умеем делать это, некоторые параметры эффективности можно улучшить.
8.2. УВЕЛИЧЕНИЕ БЫСТРОДЕЙСТВИЯ
Частично эта задача решена. Так, программы расчета зарплаты, формирования расчетных листков и ведомостей перечислений в банк, которые мы разместили в модуле формы списка ЖЗ Зарплата_2 и привели разд. 7.17.1-7.17.3, работают существенно быстрее, чем аналогичные встроенные в 1С процедуры. Это достигнуто за счет утраты универсальности, но нам она в нашей задаче и не нужна.
В этом направлении заинтересованные пользователи могут сделать и иные продуктивные шаги.
Иной способ повышения быстродействия - удаление из конфигурации ненужных вам объектов. Сразу это может не получиться. Так, если вы хотите удалить ВР Опла-таБЛ_Северн (больничный для северных регионов), то система выдаст предупреждение "Объект не может быть удален", а в окне сообщений выведет следующие текст:
Данный объект использован в:
ПравилоПерерасчета.ОсновныеУдержания
ПравилоПерерасчетаБольничныеЛисты
ПравилоПерерасчетаНДФЛ_по_13
Однако после устранения объекта из этих правил удаление ВР ОплатаБЛСеверн станет возможным.
8.3. УЛУЧШЕНИЕ КАЧЕСТВА ИНТЕРФЕЙСА
В формах 1С или в созданных взамен их своих формах вы можете разместить облегчающие обработку данных элементы управления. Что мы, собственно, и сделали, например, в форме списка ЖЗ Зарплата_2. Элементы диалога этой формы позволяют ввести все записи, провести их расчеты и выпустить необходимые сопровождающие расчеты документы, не покидая формы списка ЖЗ.
Кроме размещения дополнительных элементов управления, можно произвести ревизию существующих и удалить перегружающие интерфейс элементы. Однако это не всегда просто сделать.
Возьмем, к примеру, иконку ^ на панели инструментов ЖЗ, предлагающую создать новый документ. В нашем случае ее желательно убрать, поскольку список предлагаемых для выбора документов содержит много лишних позиций (рис. 8.1).
Выбор вида документа
БОЛЬНИЧНЫЙ ЛИСТ
Кн. делом (Ввод начальных данных по сотрут' Прочие нач (Ввод вспомогательных начисле. Нал льготы (Редактирование затеей справ Нач. сальдо (Ввод начального сальдо по сог[ Устаревший документ
Возвр. в кассу (Регистрц>ует Факт погашет Возвр нал на доходы (Регистрирует факт вс Выг. по вкл (Ввод материальной вьгоды по Выпл делом (Списание выданных депонироі Дивиденды (Приказ на выплату дивидендов
Пдплыыгweewxa fPenjr
ii_____I
ок
Отмена
Помошь
ьнаов і *лв I
±г
Рис. 8.1. Список, открываемый иконкой панели инструментов ЖЗ
Мы заменили эту иконку кнопкой Ввод расчета, показывающей для выбора список документов (см. рис. 7.25), вводящих расчеты в ЖЗ Зарплата_2. Их перечень, напомним, мы внесли в перечисление ВР 2 (разд. 7.3.3).
Однако удалить иконку из панели инструментов можно, только убрав всю панель инструментов (Сервис - Панели инструментов - Дополнительные - Инструментальные панели окон - <Отключены>). Но даже после этого аналогичный пункт останется в колонке Действия меню системы.
В большей мере нежелательно присутствие на панели инструментов ЖЗ иконки , предлагающей удалить документ. Для этого есть по меньшей мере три причины.
Во-первых, пользователь, наблюдая ЖЗ, не видит документа, который ему предлагают удалить, - перед ним лишь часть расчетов, порожденных документом (а эти расчеты могут быть рассыпаны по всему ЖЗ), а чтобы принять решение, нужно иметь перед глазами объект, а не его производные.
Во-вторых, пользователь, находясь в ЖЗ, наблюдает удаление не документа, а записей ЖЗ. Такая рассогласованность намерений и визуального результата несколько обескураживает.
В-третьих, расчеты, порожденные удаляемым документом, могут иметь неотме-ненную ручную правку. И если ошибочное удаление документа, расчеты которого не имеют ручной правки, - дело поправимое (для преодоления ошибки нужно снять пометку удаления документа в соответствующем журнале документов и провести документ заново), то расчеты с ручной правкой после восстановления ошибочно удаленного документа придется произвести заново.
Ситуацию можно поправить, если в предопределенную процедуру ПриУдалении-Документа, которую нужно расположить в глобальном модуле, добавить вызов нижеприводимой функции ЕстьЛиРучнаяПравка, которая как раз-то и фиксирует наличие расчета с ручной правкой и запрещает при наличии такового удаление породившего его документа. Функцию придется разместить в глобальном модуле, поскольку оттуда осуществляется ее вызов.
// Вернет 0, если хотя бы один расчет удаляемого документа имеет ручную правку функция ЕстьЛиРучнаяПравка(док) перем жз;
жз = СоздатьОбъект('ЖурналРасчетов.Зарплата_2''); жз.ВыбратьЗаписиПоДокументу(док);
// Просматриваем все расчеты, порожденные документом док пока жз.ПолучитьЗапись() = 1 цикл если жз.Исправлена = 1 тогда
возврат 0; // Есть ручная правка
конецЕсли; конецЦикла; // пока
возврат 1; // Нет расчетов с ручной правкой
конецФункции // ЕстьЛиРучнаяПравка
Саму же предопределенную процедуру ПриУдаленииДокумента можно записать следующим образом:
// Предопределенная процедура глобального модуля
// Интерфейс процедуры задан в системе и содержит два входных параметра: док и режим // док - удаляемый документ
// Параметр режим равен единице, если проставляется DBF-пометка удаления,
// и равен нулю, если документ получает Ю-пометку удаления // В нашей проблеме этот параметр неинтересен процедура ПриУдаленииДокумента(док, режим) если док.ПометкаУдаленияО = 1 тогда
возврат; // Если снимается пометка удаления,
конецЕсли; // то никаких проверок не выполняем
// Исследуем документы, порождающие расчеты // Иные документы в этом исследовании не участвуют если (док.ВидО = "Табель") или (док.Вид() = "Премия") или (док.ВидО = "НачПериода_2") тогда
// Статус возврата будет равен нулю, если расчеты документа док имеют ручную // правку. При таком статусе возврата документ удален не будет если ЕстьЛиРучнаяПравка(док) = 0 тогда СтатусВозврата(0);
Предупреждение("Нельзя удалить документ с ручной правкой."); конецЕсли; конецЕсли;
конецПроцедуры // ПриУдаленииДокумента
Подобного рода модификации заинтересованный пользователь может осуществить в великом множестве.
8.4. НАДЕЖНОСТЬ ПРОГРАММ
Мы рассмотрим один аспект надежности - вероятность получения ожидаемого результата. Ниже мы обсудим ряд мероприятий, позволяющих повысить эту вероятность и, следовательно, надежность вычислений.
8.4.1. ПРОВЕРКА ДАННЫХ
В любой задаче мы планируем получить некоторый результат. Так, нажав на иконку ®, размещенную в диалоге формы списка ЖЗ Зарплата_2, мы рассчитываем получить ведомость перечислении в банк для выбранного сотрудника или подразделения.
Видимых препятствий для получения такого результата нет, и если нет ошибок в расчетах и коде, формирующем ведомость, то будет верен и документ. В то же время в программу, выводящую ведомость, можно добавить функцию, проверяющую, точно ли подсчитан размер перечисляемой в банк суммы. Ошибка, как мы уже отмечали (разд. 7.10.1), может возникнуть, когда после отмены ручной правки какой-либо записи, имеющей зависимые ВР, выполнен ее перерасчет (иконка ^
панели инстру
ментов ЖЗ), при этом атрибут Рассчитана зависимых ВР остается равным единице, а пользователь забывает выполнить их перерасчет. (Напомним, что ВР ВБанк_2 зависит от всех иных ВР.)
Код такой проверочной функции прост:
// Выполняет сравнение размеров перечислений в банк. Возвращает нуль,
// если перечисления верны, и отличное от нуля число - в противном случае // При ошибке функция выдает соответствующее предупреждение функция СовпадениеПеречислений(сотр, перечислено)
// перечислено = Целая часть(Начальное сальдо + Все начисления - Все удержания) перем ВР, банк; банк = перечислено;
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде ВыбратьПериодПоОбъекту(сотр); пока ПолучитьЗапись() = 1 цикл ВР - ВидРасч;
если (ВР.ВходитВГруппу(ГруппаРасчетов.ВсеНачисления_2) = 1) или (ВР = ВидРасчета.НачСальдо_2) тогда банк = банк - результат;
иначеЕсли ВР.ВходитВГруппу(ГруппаРасчетов.ВсеУдержания_2) = 1 тогда банк = банк + результат; конецЕсли; конецЦикла; // пока
возврат Цел(банк); // Берем целую часть результата
конецФункции // СовпадениеПеречислений
Тогда приведенная в разд. 7.17.3 процедура СтрокаВТекст, добавляющая строку в ведомость перечислений в банк, примет следующий вид:
// Добавляет в ведомость строку под номером ном и корректирует значение переменной всего процедура СтрокаВТекст(сотр, текст, ном, всего)
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде
ВыбратьПериодПоОбъекту(сотр);
пока ПолучитьЗапись( ) = 1 цикл
если видРасч = ВидРасчета.ВБанк_2 тогда всего = всего + Результат;
// Форматируем данные в соответствии с заголовком табличной части ведомости текст.ДобавитьСтроку(Формат(ном, "С5") + +
Формат(Объект.Наименование, "С27") + ":" +
Формат(Объект.Код, "С9") + ":" +
Формат(Результат, ”410.2”) + ”: ” +
Формат(Объект.Код, ”С9”)); прервать; конецЕсли; конецЦикла; // пока
// Добавляем вызов проверяющей функции СовпадениеПеречислений если СовпадениеПеречислений(сотр, Результат) о 0 тогда
Сообщить(''Ошибка в размере перечислений сотрудника ” + сотр.Наименование); Предупреждение(''Ошибка в размере перечислений сотрудника ” +
РазделительСтрок + сотр.Наименование); конецЕсли;
конецПроцедуры // СтрокаВТекст
Такой подход, правда, тоже имеет недостаток. Ведь если изменится алгоритм расчета перечислений в банк, то код придется менять в двух местах: в ВР ВБанк_2 и в вышеприведенной функции СовпадениеПеречислений. Дублирования кода, впрочем, можно избежать, если разместить его в глобальном модуле.
8.4.2. ПРЕОДОЛЕНИЕ КОНФЛИКТОВ
До сих пор мы предполагали, что с программой работает один пользователь. В этом случае обработка данных выполняется без конфликтов. Они возникают в многопользовательском режиме, когда несколько пользователей одновременно пытаются обновить записи одной и той же DBF-таблицы информационной базы данных. При этом оказывается, что DBF-таблица доступна только пользователю, первому получившему к ней доступ. В этом случае говорят, что произошел захват таблицы. При единичных записях время захвата таблицы непродолжительно, и если программы других пользователей могут ждать освобождения таблицы, то конфликт через некоторое время будет исчерпан. Если же программы не содержат кода, обеспечивающего режим ожидания, то при попытке обновления захваченной таблицы произойдет завершающая исполнение ошибка, сопровождаемая, например, таким сообщением:
жз.3аписать();
^:\ПРОБАБКТ(20)}: Объект заблокирован: Журнал расчетов Журнал заработной платы
Чтобы промоделировать такую ситуацию, напишем следующий код:
процедура Выполнить( ) // Связана с кнопкой Пуск обработки Проба
перем сСотр_2, сотр, жз, рез, флаг;
ОчиститьОкноСообщений( );
сСотр_2 = СоздатьОбъект(”Справочник.Сотрудники_2”);
// Ищем во всем справочнике сотрудника с кодом 301
сСотр_2.НайтиПоКоду(301,0);
сотр = сСотр_2.ТекущийЭлемент( );
жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2");
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде
жз.ВыбратьПериодПоОбъекту(сотр);
пока жз.ПолучитьЗапись( ) = 1 цикл
// Пропускаем фиксированные и исправленные расчеты если жз. Фиксирована + жз.Исправлена о 0 тогда продолжить; конецЕсли; рез = жз.Результат;
// Начинаем бесконечный цикл // Чтобы цикл прервать, нужно нажать клавишу Esc // В этом цикле время от времени захватывается ЖЗ флаг= 1;
пока флаг = 1 цикл
// Значение реквизита Результат не меняется жз.УстановитьРеквизит("Результат", рез); жз.3аписать(); конецЦикла; // пока флаг = 1 конецЦикла; // пока жз.ПолучитьЗапись() = 1 конецПроцедуры // Выполнить
Эта программа никаких изменений в ЖЗ не производит, но время от времени, выполняя оператор
жз.3аписать();
захватывает журнал расчетов Зарплата_2.
Пусть 1С:Предприятие откроют два пользователя (в этом эксперименте число пользователей при желании можно сделать и большим). Первый запустит приведенную программу, а второй - ту же программу, но вместо оператора
// Ищем во всем справочнике сотрудника с кодом 301 сСотр_2.НайтиПоКоду(301,0);
имеющую оператор
// Ищем во всем справочнике сотрудника с кедом 302 сСотр_2.НайіиПоКоду(302, 0);
То есть в ЖЗ мы будем обновлять результат другой записи, отвечающей объекту с кодом 302.
Тогда если сотрудники с кодами 301 и 302 в справочнике Сотрудники_2 есть и если в текущем периоде ЖЗ каждый из этих сотрудников имеет нефиксированный и неисправленный расчет, то неизбежно в работе одного из пользователей возникнет завершающая ошибка исполнения и приведенное выше сообщение об этой ошибке.
Если же в этом эксперименте вместо операторов
жз.УстановтъРеквизит("Резулкгат", рез); жз.3аписать();
записать оператор
жз.Результат = рез;
то ошибка возникнет сразу у двух пользователей (поскольку имеем дело с бесконечным циклом). Сообщение, которое они смогут наблюдать, будет таким:
жз.Результат = рез;
{D:\ПPOБA.ERT(21)}: Запись заблокирована!
Причем ошибка будет не завершающей, а информационной и сообщение о ней будет воспроизводиться вплоть до прерывания обработки, выполняемого клавишей Esc. После прерывания одной из обработок блокировка будет снята и оставшаяся обработка продолжит вычисления.
В чистом виде на практике такая ситуация может возникнуть лишь при наличии в программе ошибки, приводящей к бесконечному циклу. Но описанные пользовательские конфликты будут происходить и в правильно написанной (с позиции одного пользователя) программе при интенсивных модификациях таблиц базы данных.
Чтобы продемонстрировать метод устранения такой ошибки, продолжим начатый пример, модифицировав в нем бесконечный цикл Пока флаг = 1, введя в него управляющую конструкцию Попытка.
// Начинаем бесконечный цикл // Чтобы цикл прервать, нужно нажать клавишу Esc // В этом цикле время от времени захватывается ЖЗ флаг = 1;
пока флаг = 1 цикл // Этот цикл подлежит модификации
// Значение реквизита Результат не меняется жз.УстановитьРеквизит("Результат", рез);
// Начало добавляемого кода
// Вводим в цикле Пока флагПопытки - 1 управляющую конструкцию Попытка // Цикл прервется после удачного исполнения метода Записать флагПопытки = 1; пока флагПопытки = 1 цикл
попытка // Управляющая конструкция Попытка
жз.3аписать(); // Этот оператор из старого кода
флагПопытки = 0;
Сообщить("Запись выполнена."); исключение
Сообщить("Ожидаю освобождения таблицы."); конецПопытки;
конецЦикла; // пока флагПопытки = 1 // Конец добавляемого кода
конецЦикла; // пока флаг = 1
Внесем соответствующие изменения в обработки двух наших пользователей и запустим их процедуры Выполнить. Внешний цикл по-прежнему будет бесконечным, но благодаря управляющей конструкции Попытка завершающих ошибок по причине блокировки DBF-таблицы происходить не будет и соответствующие ее записи будут обновляться. Добавленные вызовы встроенной процедуры Сообщить привнесут в окно сообщений (в многопользовательском режиме) следующий код:
Запись выполнена.
Запись выполнена.
Ожидаю освобождения таблицы. Ожидаю освобождения таблицы. Запись выполнена.
Продемонстрированный метод преодоления конфликтов при помощи управляющей конструкции Попытка нужно применять каждый раз, когда есть угроза пользовательских конфликтов на почве захвата DBF-таблиц. В частности, при работе такая угроза существует при употреблении методов, выполняющих модификацию ЖЗ, а именно: ВыполнитьРасчет, Рассчитать, ВвестиРасчет, ЗаписатьРасчет, ВвестиПерерасчет, Записать, ФиксироватьЗапись, ОсвободитьЗапись, Исправить, ОтменитьИсправление и УдалитьЗапись.
С учетом сказанного процедура РасчетОбъекта, рассчитывающая записи сотрудника, вызываемая из процедуры РасчетЗП (разд. 7.17.1), должна быть усовершенствована следующим образом:
// Обновленная процедура РасчетОбъекта
// Рассчитывает все записи объекта ЖЗ кроме расчета с ВР НачСальдо_2 // Поскольку процедура присутствует в модуле формы списка ЖЗ,
// то все методы ЖР вызываются без префикса процедура РасчетОбъекта(сотр)
перем флаг, сотр2, флагПопытки;
// Флаг будет равен единице, если у сотрудника есть расчет с ВР Оклад_2 флаг = 0;
сотр2 = сотр; // Запоминаем для вывода сообщения
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде ВыбратьПериодПоОбъекту(сотр); пока ПолучитьЗапись() = 1 цикл
если видРасч = ВидРасчета.НДФЛ_2 тогда флаг = 1; конецЕсли;
// Фиксированные и исправленные записи рассчитывать нет смысла если Фиксирована + Исправлена = 0 тогда
// Начало добавляемого кода
// Вводим в цикле Пока флагПопытки = 1 управляющую конструкцию Попытка // Цикл прервется после удачного исполнения метода Рассчитать флагПопытки = 1; пока флагПопытки = 1 цикл
попытка //
Управляющая конструкция Попытка Этот оператор из старого кода
//
Рассчитать(); //
флагПопытки = 0;
Состояние ("Выполнен расчет сотрудника " + сотр.Наименование); исключение
Состояние(''Ожидаю освобождения таблицы."); конецПопытки;
конецЦикла; // пока флагПопытки = 1 // Конец добавляемого кода
конецЕсли; конецЦикла; // пока если флаг = 0 тогда
Сообщить(''Оформите табель сотруднику " + сотр2.Наименование); конецЕсли;
конецПроцедуры // РасчетОбъекта
Аналогичные изменения должны быть внесены и в другие процедуры модуля формы списка ЖЗ Зарплата_2, а также в модули форм созданных нами документов и справочников, хотя степень их конфликтности по сравнению с ЖЗ существенно ниже.
Вопрос надежности исполнения предопределенных процедур модуля документа ОбработкаПроведения и ОбработкаУдаленияПроведения обсуждается в следующем разделе. Здесь же заметим, что в периоды расчета зарплаты, продолжительность которых в силу организационных причин невелика (чуть более недели), эти процедуры (особенно ОбработкаПроведения), вызываемые в создающих расчеты ЖЗ документах, интенсивно модифицируют базу данных и, следовательно, обладают повышенной конфликтностью.
8.4.3. ТРАНЗАКЦИИ
Транзакция - это механизм обновления таблиц базы данных, обеспечивающий при отсутствии внешних воздействий получение ожидаемого результата. В случае невозможности обновления таблиц в соответствии с установленными правилами транзакцию можно отменить, не производя каких-либо модификаций данных. (Под внешними воздействиями понимаются факторы, возникающие не в результате исполнения программы, а по иным причинам, например при сбоях в энергоснабжении, вирусной атаке и др.)
Если речь идет о единичном обновлении базы данных, например в результате выполнения метода Записать, то гарантии получения ожидаемого результата нам дает управляющая конструкция Попытка. При пакетном обновлении базы данных, например в результате проведения документа, порождающего многочисленные расчеты ЖЗ, нужно применять транзакцию.
Надо сказать, что в модуле документа в предопределенных процедурах Обработка-Проведения и ОбработкаУдаленияПроведения 1С выполняет предусмотренные в этих процедурах действия, употребляя транзакцию. Поэтому добавлять в них свои транзакции нет необходимости.
Известно, что транзакции блокируют используемые в них DBF-файлы, поэтому необходимо максимально содействовать их успешному завершению. В частности,
предопределенные процедуры ОбработкаПроведения и ОбработкаУдаленияПрове-дения не следует включать приостанавливающие до отклика пользователя процедуры Вопрос, Предупреждение, функции, вызывающие диалог ввода данных, например ВвестиЗначение, и другие открывающие диалоги команды.
В решаемых нами задачах, кроме упомянутых процессов проведения документов, транзакцию можно было бы применить при расчете зарплаты объекта, записав код процедуры РасчетОбъекта следующим образом:
// Еще один вариант процедуры РасчетОбъекта, на этот раз использующий транзакцию процедура РасчетОбъекта(сотр) перем флаг, сотр2;
// Флаг будет равен единице, если у сотрудника есть расчет с ВР Оклад_2 флаг = 0;
сотр2 = сотр; // Запоминаем для вывода сообщения
// Открываем выборку расчетов объекта, зарегистрированных в текущем периоде если ВыбратьПериодПоОбъекту(сотр) = 0 тогда возврат; конецЕсли;
НачатьТранзакцию(); // Первый добавленный оператор..
пока ПолучитьЗапись() = 1 цикл
если видРасч = ВидРасчета.НДФЛ_2 тогда флаг = 1; конецЕсли;
// Фиксированные и исправленные записи рассчитывать нет смысла если Фиксирована + Исправлена = 0 тогда Рассчитать( ); конецЕсли; конецЦикла; // пока
если флаг = 1 тогда // Транзакция фиксируется, если проведен Табель
ЗафиксироватьТранзакцию(); // Второй добавленный оператор
иначе // флаг = 0
Отменить Транзакцию^); // Третий добавленный оператор
Сообщить("Оформите табель сотруднику " + сотр2.Наименование); конецЕсли;
конецПроцедуры // РасчетОбъекта
В этом обновленном коде 3 новые (для нас) встроенные в 1С процедуры: Начать-Транзакцию, ЗафиксироватьТранзакцию и ОтменитьТранзакцию. Назначение процедур понятно из их названий. Остановимся на особенностях их исполнения.
Во-первых, пользователь, начавший транзакцию, захватывает одну или несколько DBF-таблиц, участвующих в транзакции, и тем самым Не дает работать другим участникам процесса. При длительном захвате таблицы ждущая процедура может завершиться аварийно, о чем пользователь получит соответствующее сообщение, например такое:
пока ПолучиіьЗапись( ) = 1 цикл
{ЖурнапРасчетов.Зарплага_2.Форма.ФормаСписка.Форма.Модуль(250)}:Таблица: CJ4287 Ошибка обращения к данным при транзакции, выполняемой другим пользователем
Если захват непродолжительный, то после завершения транзакции ждущий пользователь благополучно продолжит вычисления.
Во-вторых, обновление захваченных таблиц во время транзакции не производится, но необходимые для обновления сведения накапливаются в надлежащем виде для последующего использования.
Если в результате транзакции получены правильные результаты, то следует вызвать процедуру ЗафиксироватьТранзакцию, которая, собственно, и выполняет обновление базы данных и завершает транзакцию. Если обнаружены ошибки, то вызов процедуры ОтменитьТранзакцию завершит транзакцию, но никаких модификаций данных произведено не будет. Об обнаружении ошибок должен позаботиться программист, встроив в процедуру с транзакцией соответствующий код.
В нашем примере осуществлены вызовы всех трех процедур, что несколько изменило характер получаемого результата. Так, если ранее процедура РасчетОбъекта модифицировала результаты расчетов и при отсутствии расчета с ВР Оклад_2, то теперь в такой ситуации данные не меняются, поскольку вызывается .процедура ОтменитьТранзакцию.
Если сравнивать две модификации процедуры РасчетОбъекта (первая с управляющей конструкцией Попытка, а вторая с транзакцией), то предпочтение следует, видимо, отдать первому варианту. На этот счет есть по меньшей мере 3 причины. Первая в том, что нет необходимости рассматривать расчет объекта как единое целое и употреблять для него транзакцию; вполне приемлемо, если расчеты будут выполняться последовательно в соответствии с установленной очередностью, и нет трагедии, если между двумя вашими расчетами выполнится один-другой расчет иного пользователя. Во-вторых, как мы убедились, при длительных транзакциях ждущие процедуры могут завершаться аварийно. И наконец, транзакция может потребовать дополнительных ресурсов (пространственных, например в виде области памяти на диске, и временных), снижающих эффективность исполнения программы.
8.5. ЗАЩИТА ДАННЫХ
8.5.1. ПОСТАНОВКА ЗАДАЧИ
Защита данных - это также многогранная задача, включающая такие подзадачи, как физическое сохранение данных, обеспечение их целостности и непротиворечивости, верификация данных, ограничение прав доступа и др.
В целом в 1С достаточно средств для защиты данных. Однако в ряде случаев для упрочнения защиты требуется вмешательство программиста.
Остановимся на проблеме ограничения прав доступа. (Иные проблемы либо частично затрагивались по мере изложения материала, либо находятся за пределами настоящего пособия.)
Изначально пользователю можно присвоить имя, назначить интерфейс, пароль и снабдить определенными правами доступа (разд. 1.2, 1.3).
Наборы прав задаются на закладке Права окна Конфигурация (рис. 8.2).
 |
|
Рис. 8.2. Задание набора прав выполняется на этой закладке |
Для заданного набора прав, если по строке с именем набора дважды ударить мышью, откроется редактор прав (рис. 8.3).
Y Ученик. - Редактор пользе
|Я i^j} Конфигурация Зарплата ¦ Кадры (от 15.01.200
> аіиаия
К Я Слраео’аыки К CJ Докірлвмты к ы Журналы В К] Отчеты № ,sj Обработки "Y План счетов ^ Операция % Проводка & Т иловая операция Я) Регистры ?© Журналы расчетов Ж Ц Календари
Рис. 8.3. Редактор пользовательских прав
В этом редакторе для выбранного набора прав (в нашем случае - Ученик) можно определить права Ученика в отношении каждого класса объектов в целом (рис. 8.4) и отдельных представителей классов (рис. 8.5).
Y Ученик - Редактор пользовательски» прав
Конфигурация Зарплата * Кадры (от 15 01.2001)
>’ S Константы
іпраеочниг И
свойства элемента прав
_іЫ
Достиг I
? Чтение
Любые изменения
Ввод нового
удаление
Пометка ма удаление
Отмена
Снятие пометки на удаление
) осре»тмрое* а
Обновить
Рис. 8.4. Задание прав доступа Ученика ко всем справочникам системы
 |
|
Рис. 8.5. Детализация прав Ученика в отношении справочника Сотрудники_2 |
Напоследок надо не забыть задать права по управлению конфигурацией системы (рис. 8.6).
 |
|
Рис. 8.6. Задание прав по управлению системой |
Далее встает проблема ограничения прав доступа в пределах справочника Сотрудники_2, журнала Зарплата_2 и других журналов. Суть проблемы в том, что начисление зарплаты осуществляется несколькими расчетчиками, которые, разумеются, используют один и тот же справочник сотрудников, журнал расчетов и одинаковые журналы документов. И в отношении к имеющимся в этих объектах данным расчетчики обладают равными правами. Более того, они, как правило, пользуются единым по своему содержанию интерфейсом.
Положим, что на нашем предприятии зарплатой занимаются 3 расчетчика, обслуживающие соответственно цехи 1, 2 и 3. Тогда полезно ввести дополнительные ограничения, запретив расчетчику цеха 1 доступ к данным расчетчиков цехов 2 и 3. Аналогичные ограничения распространим и на других расчетчиков.
Реализация этих ограничений проста. Создается справочник ПраваРасчетчика; в нем для каждого расчетчика указываются подразделения, к которым он имеет доступ. Далее эта информация используется при работе со справочниками и журналами 1С.
Используется следующим образом. В модуль формы списка справочника Сотруд-ники_2 мы добавим две предопределенные процедуры - ПриВыбореРодителя и При-СменеИерархии. В первой мы разрешим каждому расчетчику открывать только доступные ему в соответствии со справочником ПраваРасчетчика группы (подразделения), а во второй запретим всем расчетчикам переходить в режим просмотра всего справочника. При открытии справочника мы зададим режим отображения данных справочника с учетом имеющейся иерархии (см. рис. 5.1).
В модуль формы списка журнала Зарплата_2 добавляется предопределенная процедура ПриУстановкеОтбора, позволяющую расчетчику работать только с подразделениями, назначенными ему справочником ПраваРасчетчика.
В модуле формы списка журнала Зарплата_2 придется также модифицировать процедуру ПриОткрытии, которая теперь, если ЖЗ открывает расчетчик, будет подбирать для работы соответствующие ему подразделения.
Замечание. Рассматриваемые мероприятия по ограничению доступа к данным не являются исчерпывающими, но раскрывают механизм решения этой проблемы.
8.5.2. СПРАВОЧНИК ПраваРасчетчика
Реквизиты и свойства справочника задаются в соответствии с рис. 8.7, а описание реквизитов см. в табл. 8.1.
 |
|
Рис. 8.7. Свойства и реквизиты справочника ПраваРасчетчика |
Таблица 8.1
Реквизиты справочника ПраваРасчетчика |
|
Реквизит |
Описание |
Примечание |
|
имяПользователя |
Имя, с которым расчетчик входит в систему. Задается в конфигурации |
Строка длиной в 15 символов |
|
подразделение |
Подразделение, с которым может работать расчетчик. Вводится как группа справочника Сотрудники_2 |
Имеет разновидность типа Справочник.Сотрудники_2 |
|
Правами ввода и редактирования данных справочника обладает только администратор системы.
Редактирование данных осуществляется в форме списка, и после заполнения справочник будет содержать отображенные на рис.'8.8 сведения.
 |
|
Рис. 8.8. Имена пользователей предприятия и обслуживаемые ими подразделения |
Чтобы в справочнике Сотрудники_2 можно было выбирать группы (подразделения), в модуль формы ФормаДляВыбора мы добавили следующий код:
// Предопределенная процедура ПриОткрытии процедура ПриОткрытии()
ВыборГруппы(1); конецПроцедуры // ПриОткрытии-
Сами же имена пользователей определим в конфигурации в соответствии с рис. 8.9, задав им одинаковые права, интерфейс и рабочий каталог.
 |
|
Рис. 8.9. Задание имен пользователей и их прав в конфигурации системы |
8.5.3. МЕНЮ И ПРАВА ПОЛЬЗОВАТЕЛЕЙ
В меню пользователя Ученик добавим возможность вызова вновь созданного справочника ПраваРасчетчика, оставив иные пункты меню без изменений. Для работника, отвечающего за кадры, создадим интерфейс Кадры, меню которого построим в соответствии с рис. 8.10.
‘Щэ Документы '—В Приказ о приеме -В Изменение оклада
j=j Справочники —0 Сотрудники_2 —В 0бразование_2
^ Журналы документов 'Щ} Отчеты «• В Кадровые приказы "В Список сотрудкмкое
Рис. 8.10. Меню для лица, регистрирующего кадровые изменения
Также работнику отдела кадров доступен справочник Дети, подчиненный справочнику Сотруцники_2. В отношении указанных в меню объектов пользователь под именем Кадры имеет полные права.
Расчетчик сможет работать с объектами, показанными на рис. 8.11. |
 |
|
Рис. 8.11. Меню расчетчика |
Причем справочник Сотрудники_2 доступен расчетчику только в режиме чтения.
Замечание. Колонка Операции меню системы отключается в обоих создаваемых пользовательских меню. Порядок ее отключения иллюстрирует рис. 1.4.
Иные введенные нами операции, такие, как удаление помеченных объектов, модификация констант, редактирование справочников ПраваРасчетчика, хозяйственных операций и ХозОпДляВР, управление календарями и праздниками, возложим на лицо, выполняющее функции администрирования системы. Для этих целей у нас имеется интерфейс Ученик. В то же время необходимо ограничить права этого лица по отношению к данным, создаваемым в отделе кадров и расчетном отделе. Эти данные должны быть доступны ему только в режиме просмотра.
8.5.4. МОДИФИКАЦИЯ МОДУЛЯ ФОРМЫ СПИСКА ЖУРНАЛА ЗАРПЛАТА_2
Суть вносимых изменений отражена в разд. 8.5.1. Однако, прежде чем заняться кодированием, несколько слов придется сказать об изменениях интерфейса ЖЗ. Во-первых, если работает расчетчик, то нужно отключить возможность вывода ЖЗ с применением закладок отбора 01/1,01/2, 01/3, 02 Цех и 03 Цех (см. рис. 7.26). Дело втом, что ограничить доступ к закладке отбора встроенными средствами 1С нельзя. Это выясняется, когда пытаешься применить предопределенную процедуру модуля формы ПриВыбореЗакладки: она работает лишь с атрибутом формы Закладки, имеющим тип Список значений. Метод ЗакладкиОтбора этот атрибут не изменяет. Так, после применения метода
ЗаклацкиОтбораС'Родитель");
формирующего в случае ЖЗ вышеперечисленные закладки отбора, процедура Сообщить(ТипЗначения(Форма. Закладки));
напечатает в окне сообщений 0 - число, выдаваемое встроенной функцией ТипЗначе-ния для неопределенного типа данных.
Во-вторых, нужно позаботиться о том, чтобы не изменились функции радиокнопок с идентификатором кто группы Режим расчета.
Таким образом, переменная закл при входе расчетчика должна быть равна единице, но закладки отбора отображаться не должны и, конечно же, должны быть в соответствии со справочником ПраваРасчетчика введены ограничения на рабочее пространство расчетчика. Если в систему входит пользователь с правами Ученика, то ее функционирование должно отвечать привычной, изложенной в разд. 7.4.3 схеме. Озвученные изменения поддерживаются следующим кодом:
// Определяем сПраваРасч, расч, значениеОтбора и флагРасч как переменные модуля перем сПраваРасч, расч, значениеОтбора, флагРасч;
// Следует уже имеющийся в модуле код (разд. 7.4.4.1) // Предопределенная процедура модуля формы ЖР
// Эта процедура добавляется в модуль формы списка ЖЗ Зарплата_2
// Интерактивно отбор управляется иконками 5* У*
// лежащими на панели управления ЖЗ
процедура ПриУстановкеОтбора(графаОтбора, значениеОтбора)
если флагРасч = 0 тогда // Если работает не расчетчик, то
возврат; // контроль прав не осуществляется
конецЕсли;
// Простым перебором устанавливаем, можно ли расчетчику расч работать // с интерактивно выбираемым им подразделением сПраваРасч.ВыбратьЭлементы(); пока сПраваРасч.ПолучитьЭлемент() = 1 цикл
если (расч = СокрЛП(сПраваРасч.ИмяПользователя)) и
(сПраваРасч.Подразделение = значениеОтбора) тогда СтатусВозврата(1); // Работать можно
возврат; // Выход из процедуры
конецЕсли; конецЦикла; / / пока
СтатусВозврата(0); // Работать нельзя
Предупреждение("Это не Ваше подразделение."); конецПроцедуры // ПриУстановкеОтбора
процедура При6ткрытии() // Предопределенная процедура
перем реж, значРеж;
// Восстанавливаем с диска значения переменных диалога закл и кто // для текущего сеанса работы
закл = ВосстановитьЗначение("ЗакладкиВЗарплате");
если ТипЗначения(закл) = 0 тогда // Если значение переменной закл не восстановлено закл = 1; кто = 1; иначе
кто = ВосстановитьЗначение("КтоВЗарплате"); конецЕсли; ктоСтар = кто;
ПоЦехам( );
если флагРасч = 0 тогда // Добавленная строка кода
если закл = 1 тогда
значОтбора = ВосстановитьЗначение("ЗначениеОтбора"); ЗакладкиОтбора("Родитель", значОтбора); конецЕсли;
иначе // Еще 5 добавленных строк кода
Форма.Закл.Видимость(О); // Элемент диалога закл расчетчику не нужен
// Установим разрешенный для расчетчика расч отбор УстановитьОтбор(''Родитель'', значениеОтбора); конецЕсли;
реж = ВосстановитьЗначение(''РежимПредставления''); значРеж = ВосстановитьЗначение("ЗначениеПредставления"); если реж = 1 тогда
УстановитьПредставление( 1); иначе
УстановитьПредставление(реж, значРеж); конецЕсли;
нтп = НачалоТекущегоПериода(); конецПроцедуры // ПриОткрытии
// Включает/отключает режим вывода по цехам. Если закл = 0, то устанавливает // кто = 1 и делает недоступными радиокнопки группы Режим расчета процедура ПоЦехам()
// Эти 3 строчки добавляются в прежнюю процедуру ПоЦехам (разд. 7.4.4.1) если флагРасч = 1 тогда // Начало добавляемого кода
возврат;
конецЕсли; // Конец добавляемого кода
если закл = 1 тогда // Если используются закладки отбора
ЗакладкиОтбора("Родитель"); кто = ктоСтар;
Форма. Кто.Доступность( 1);
Форма. Кто2.Доступность( 1); иначе
ЗакладкиОтбора(""); кто= 1;
Форма. Кто.Доступность(0);
Форма. Кто2 .Доступность(0); конецЕсли;
конецПроцедуры // ПоЦехам()
// А это оператор основной программы модуля формы списка ЖЗ // Переменная модуля флагРасч получит значение 1, если в системе расчетчик, .
// или О-в противном случае. Функция ЕстьЛиРасчетчик включена в глобальный модуль флагРасч = ЕстьЛиРасчетчик(расч, сПраваРасч, значениеОтбора);
Замечания:
1. Функция ЕстьЛиРасчетчик включается в глобальный модуль. Это целесообразно, потому что проверка наличия расчетчика в системе выполняется неоднократно. Можно было бы пойти дальше - включить в глобальный модуль переменную флагРасч, дать ей атрибут Экспорт и вычислять ее значение при загрузке системы, вызывая функцию ЕстьЛиРасчетчик в предопределенной процедуре глобального модуля ПриНачалеРаботыСистемы, но мы остановимся на первом варианте. Функция ЕстьЛиРасчетчик имеет следующий код: // А это функция, которую мы включаем в глобальный модуль
// Следует после всех его программных компонентов
функция ЕстьЛиРасчетчик(расч, сПраваРасч, значениеОтбора) экспорт
// Этот пользователь работает в системе и открывает форму списка ЖЗ Зарплата 2
расч = ИмяПользователя();
сПраваРасч = СоздатьОбьект(''Справочник.ПраваРасчетчика'');
// Смотрим, является ли этот пользователем расчетчиком. Если да, то флагРасч получит // значение 1, или 0 - в противном случае. Проверку осуществляем простым перебором сПраваРасч.ВыбратьЭлементыО;
флагРасч = 0; // Первоначальное предположение
пока сПраваРасч.ПолучитьЭлемент() = 1 цикл
если расч = СокрЛП(сПраваРасч.имяПользователя) тогда флагРасч =1; // В системе расчетчик
значениеОтбора = сПраваРасч.Подразделение; прервать; // Прерываем цикл
конецЕсли; конецЦикла; // пока возврат флагРасч; конецФункции // ЕстьЛиРасчетчик
2.
3.
Если бы мы хотели избежать переборных операций при поиске пользователя или подразделения в справочнике ПраваРасчетчика, то нам пришлось бы задать свойство Сортировка соответствующим реквизитам справочника. Однако используемый перебор вследствие ничтожного объема просматриваемых значений не приведет к замедлению вычислений, поэтому нужды в задании обозначенного свойства нет.
Напомним, что возможные отборы отображаются и становятся доступными после выбора иконки в приведенном на рис. 8.12 фрагменте диалога Отбор записей.
 |
|
Рис. 8.12. Фрагмент диалога Отбор записей: возможные отборы ЖЗ Зарплата_2 Подробнее об управлении отборами см. в разд. 5.9.1. |
8.5.5. МОДИФИКАЦИЯ МОДУЛЯ ФОРМЫ СПИСКА СПРАВОЧНИКА СОТРУДНИКИ_2
Аналогичные дополнения следует сделать в модулях форм списка и для выбора справочника Сотрудники_2. Наша задача в том, чтобы запретить расчетчику переход в режим просмотра списка всех сотрудников, а также не допускать проникновения в запрещенные для него подразделения. В отличие от ЖЗ используемый в справочнике Сотрудники_2 отбор по реквизиту Образование отключать не надо, поскольку отбор осуществляется в пределах выбранного родителя. (Напомним, что расчетчику справочник Сотрудники_2 доступен только в режиме чтения.)
I// Определяем сПраваРасч, расч, родитель и флагРасч как переменные модуля перем сПраваРасч, расч, родитель, флагРасч;
// Следует уже имеющийся в модуле код (разд. 5.12.6)
// Предопределенная процедура модуля формы справочника // Эта процедура добавляется в модули форм списка // (основной и для выбора) справочника Сотрудники_2 процедура ПриВыбореРодителя(родитель)
если флагРасч = 0 тогда // Если работает не расчетчик, то
возврат; // контроль прав не осуществляется
конецЕсли;
// Простым перебором устанавливаем, можно ли расчетчику расч работать // с интерактивно выбираемым им подразделением сПраваРасч.ВыбратьЭлементы(); пока сПраваРасч.ПолучитьЭлемент() = 1 цикл
если (расч = СокрЛП(сПраваРасч.ИмяПользователя)) и (сПраваРасч.Подразделение = родитель) тогда
|
СтатусВозврата(1); |
// |
Можно менять родителя |
|
возврат; |
//Выход |
из процедуры |
|
конецЕсли; |
|
|
|
конецЦикла; // пока |
|
|
|
СтатусВозврата(0); |
// |
Родителя менять нельзя |
|
|
Предупреждение("Это не Ваше подразделение."); конецПроцедуры // ПриВыбореРодителя |
|
// Предопределенная процедура модуля формы справочника // Эта процедура добавляется в модули форм списка // (основной и для выбора) справочника Сотрудники_2 |
|
процедура ПриСменеИерархии(иерарх) |
|
|
если флагРасч = 0 тогда |
// |
Если работает не расчетчик, то |
|
возврат; |
// |
контроль прав не осуществляется |
конецЕсли;
если иерарх = 1 тогда |
// |
Разрешим устанавливать режим |
|
возврат; |
// |
иерархического доступа к записям |
|
конецЕсли; |
// |
справочника Сотрудники_2 |
|
СтатусВозврата(0); |
// |
Нельзя просматривать весь список |
|
Предупреждение("Доступ к списку всех сотрудников невозможен."); |
|
конецПроцедуры // ПриСменеИерархии |
|
|
процедура ПриОткрытии() |
// |
Предопределенная процедура |
|
// Этот оператор нужен в форме списка для выбора (разд. 8.5.2);
// в основной форме списка его нужно опустить ВыборГруппы(1);
// Если работает расчетчик, то отображаем справочник Сотрудники_2 // в виде иерархического списка если флагРасч = 1 тогда
ИерархическийСписок(1);
// Позиционируемся в первой разрешенной для расчетчика/?асч группе ИспользоватьРодителя(родитель); конецЕсли;
конецПроцедуры // ПриОткрытии
// А это оператор основной программы модуля формы списка справочника // Переменная модуля флагРасч получит значение 1, если в системе расчетчик,
// или О-в противном случае. Функция ЕстьЛиРасчетчик включена в глобальный модуль флагРасч = ЕстьЛиРасчетчик(расч, сПраваРасч, родитель);
Замечание. Процедуру ПриСменеИерархии лучше изъять из кода, а в предопределенной процедуре ПриОткрытии метод ИерархическийСписок вызвать следующим образом:
если флагРасч = 1 тогда // Нельзя менять режим отображения
ИерархическийСписок(1, 0); //справочника Сотрудники_2
// Позиционируемся в первой разрешенной для расчетчика расч группе ИспользоватьРодителя(родитель); иначе
ИерархическийСписок(1, 1); // Можно менять режим отображения
конецЕсли;
Когда второй параметр метода ИерархическийСписок равен нулю, смена режима отображения справочника (в нашем случае переход к неиерархическому списку) невозможна.
СОПРОВОЖДЕНИЕ СИСТЕМЫ. ОБНОВЛЕНИЕ КОНФИГУРАЦИИ
Задачами сопровождения системы являются поддержание ее работоспособности и повышение эффективности ее функционирования.
В комплексе мероприятий по сопровождению можно выделить два вида работ: регламентные и инициативные.
8.6.1. РЕГЛАМЕНТНЫЕ РАБОТЫ
Регламентные работы состоят в администрировании данных и системы. Цель администрирования данных - обеспечение сохранности данных, их проверка и в случае обнаружения ошибок принятие необходимых для их устранения мер. Это большая работа, требующая высокой квалификации.
При администрировании системы решаются задачи организации рабочих мест и обновления системы по мере поступления новых версий.
Перечень названных и иных работ, направленных на поддержание работоспособности системы, определяется, как известно, особым документом - регламентом. В нем же содержатся указания о периодичности работ и о порядке их регистрации, а также упоминание об инстанции, контролирующей выполнение регламента. ,
В число регламентных работ входит регистрация произведенных изменений конфигурации и внешних отчетов и обработок. Сведения об изменениях разместим в табл. 8.2.
Таблица 8.2
Изменения, произведенные в системе |
|
Изменение |
Описание |
|
Внешние отчеты и обработки |
|
Создана внешняя обработка Проба |
Файл Ilpo6a.ert. Предназначена для запуска произвольных обработок, например процедур удаления записей ЖЗ, мягкой смены расчетного периода (разд. 7.4.5), отчета по константам (разд. 1.9 и 6.1), по справочнику Сотрудники_2 (разд. 5.11), начальному сальдо (разд. 7.4.7), программной обработки удаляемых записей (разд. 5.14), загрузки начального сальдо из DBF-файла (разд. 7.4.6) и т. д. |
|
Изменения конфигурации системы |
|
Константы (файл 1SC0NST.DBF) |
|
Добавлена периодическая константа к5 |
Коэффициент, используемый в ВР Премия_1234, равной (Оклад_2 + ПремияКоэф_2 + ПремияСум_2) * к5 |
|
Добавлена периодическая константа СтавкаНалога |
Используется при вычислении результата ВР НДФЛ_2 |
|
Обработки |
|
Удалено две обработки |
РасчетЗарплаты и РасчетЗарплаты! |
|
Отчеты |
|
Удален один отчет |
ПеречисленияВБанки |
|
Виды расчетов (хранятся в конфигурации, файл ICV7.MD) |
|
Добавлено 7 ВР |
НачСальдо_2, Оклад_2, ПремияКоэф_2, ПремияСум_2,
Премия 1234_2, НДФЛ_2, ВБанк_2. Описание ВР см.
в разд. 7.3.2 (табл. 7.2) и 7.11 (табл. 7.15) |
|
Удалено два ВР |
АвторскиеЗаСк и ОплатаБЛ_Северн. Порядок удаления ВР см. в разд. 8.2 |
|
Правила перерасчетов (хранятся в конфигурации, файл 1CV7.MD) |
|
Добавлено 3 правила перерасчета |
Премия 1234_2, НДФЛ_2, ВБанк_2. Описание правил см. в разд. 7.7 (табл. 7.12) |
|
Группы расчетов (хранятся в конфигурации, файл 1CV7.MD) |
|
Добавлено две группы расчетов |
ВсеУдержания 2 (разд. 7.3.6.2) и ВсеНачисления 2 (разд. 7.8.1) |
|
Справочники |
|
Добавлено 5 справочников |
Сотрудники_2 (разд. 5.1 и 5.2, файл SC4194.DBF),
Образование 2 (разд. 5.7, файл SC4214.DBF), Дети (разд.
5.10.1, файл SC4233.DBF), ХозОпДляВР (разд. 7.3.7, файл SC4326.DBF), ПраваРасчетчика (разд. 8.5.2, файл SC4355.DBF) |
|
Документы |
|
Добавлено 5 документов. Для документа, если он имеет и заголовок и табличную часть, создаются 2 DBF-файла, или 1 - в противном случае |
ПриказОПриеме (разд. 5.8.2, файл DH4216.DBF), ИзменениеОклада (разд. 5.8.4, файлы DH4226.DBF и DT4226.DBF), Табель (разд. 7.6, файлы DH4244.DBF и DT4244.DBF), Премия (разд. 7.9, файлы DH4293.DBF и DT4293.DBF), НачПериода 2 (разд. 7.3.6.3, файл DT4321.DBF) |
|
|
Изменение |
Описание |
|
Удален один документ |
ВводОтработанногоВремени (файлы DH3061.DBF HDT3061.DBF) |
|
Журналы документов |
|
Добавлено два журнала документов |
Табель (разд. 7.6.5), Расчеты (разд. 7.9.5). Все журналы документов хранятся в файле 1 SJOURN.DBF |
|
Журнал расчетов |
|
Добавлен один ЖЗ |
Зарплата_2 (разд. 7.4.2, файл CJ4287.DBF) |
|
Удален один ЖЗ |
Зарплата (файл CJ209.DBF) |
|
Календари |
|
Добавлено два календаря |
Служащие_2, Рабочие_2 (разд. 7.5.1, файл CL.DBF) |
|
Перечисления |
|
Добавлено два перечисления |
Скидки (разд. 4.2), ВР_2 (разд. 7.3.3). Хранятся в конфигурации, файл 1CV7.MD |
Замечания:
1. Подобную таблицу следует иметь каждому лицу, сопровождающему систему.
2. При попытке удалении документа 1С может возникнуть предупреждение (рис. 8.13)
 |
|
Рис. 8.13. Предупреждение при попытке удаления документа ВводОтработанногоВремени. |
и поясняющее его сообщение
Данный объект использован в:
ГрафаОтбора. Сотрудник
Чтобы это препятствие преодолеть, следует в конфигурации открыть указанные на рис. 8.14 пункты меню, а затем дважды ударить мышью по подпункту Сотрудник.
в М Журналы документов В = Г рафы отбора — Сотрудник — Подразделение
Рис. 8.14. Графы отбора журнала документов
В появившемся диалоге (рис. 8.15) перенести вправо элемент левого списка Доку-мент.ВводОтработанногоВремени.
Теперь документ ВводОтработанногоВремени может быть удален.
3. При удалении документа система удаляет CDX- и DBF-файлы, созданные ей для документа.
4. На самом деле с целью ускорения работы системы из конфигурации удалены все, кроме созданных нами и используемых в работе, ВР, правила перерасчето в, группы ВР, перечисления, документы, справочники, перечисления, отчеты и обработки. В результате таких манипуляций файл конфигурации 1CV7.MD уменьшился почти в 6 раз до 1,3 Мбайт.
5. Получить список введенных в конфигурацию изменений можно, загрузив прежде копию неизмененной конфигурации, а затем, имитируя попытку объединения ее с модифицированной (разд. 8.6.4), выпустить отчет об изменениях. В нашем случае он будет содержать следующий текст:
Задача
 |
|
Рис. 8.15. Устраняем препятствие для удаления документа ВводОтработанногоВремени |
- Объект изменен
- Объект изменен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
- Объект добавлен
Библиотека Картинок Глобальный модуль Справочник. Сотрудники_2 Справочник. Образование_2 Справочник.Дети Справочник.ХозОпДляВР Справочник. ПраваРасчетчика Документ. ПриказОПриеме Документ. ИзменениеОклада Документ.Табель Документ. Премия Документ. НачПериода_2 Перечисление. Скидки
|
Перечисление. ВР_2 |
- Объект добавлен |
|
ГрафаОтбора. Сотрудник |
- Объект изменен |
|
ГрафаОтбора.Подразделение |
- Объект изменен |
|
Журнал. ПриказыКадровые |
- Объект изменен |
|
Журнал.Табель |
- Объект добавлен |
|
Журнал. Расчеты |
- Объект добавлен |
|
ЖурналРасчетов.Зарплата_2 |
- Объект добавлен |
|
ПравилоПерерасчета. НДФЛ_2 |
- Объект добавлен |
|
ПравилоПерерасчета.ВБанк_2 |
- Объект добавлен |
|
ПравилоПерерасчета. Премия1234_2 |
- Объект добавлен |
|
ВидРасчета. НачСальдо_2 |
- Объект добавлен |
|
ВидРасчета. Оклад_2 |
- Объект добавлен |
|
ВидРасчета.ПремияКоэф_2 |
- Объект добавлен |
|
ВидРасчета. ПремияСум_2 |
- Объект добавлен |
|
ВидРасчета. Премия1234_2 |
- Объект добавлен |
|
ВидРасчета.ВБанк_2 |
- Объект добавлен |
|
ВидРасчета. НДФЛ_2 |
- Объект добавлен |
|
ГруппаРасчетов.ВсеУдержания_2 |
- Объект добавлен |
|
ГруппаРасчетов. ВсеНачисления_2 |
- Объект добавлен |
|
Календарь. Служащие_2 |
- Объект добавлен |
|
Календарь. Рабочие_2 |
- Объект добавлен |
|
Права |
|
|
ПолныеПрава |
- Объект изменен |
|
РасчетЗП |
- Объект добавлен |
|
Кадры |
- Объект добавлен |
|
Ученик |
- Объект добавлен |
|
Интерфейсы |
|
|
РасчетЗП |
- Объект добавлен |
|
Кадры |
- Объект добавлен |
|
Ученик |
- Объект добавлен |
8.6.2. ИНИЦИАТИВНЫЕ РАБОТЫ
Инициативные работы направлены на повышение качества системы, то есть на оптимизацию системы по перечисленным в разд. 8.1 критериям.
Часть оптимизирующих мероприятий мы уже упомянули. Здесь же остановимся на еще одной стороне вопроса - скорости получения результата, которым в нашей задаче является расчет зарплаты всем сотрудникам и выпуск сопровождающих этот расчет документов. В этом плане лицо, сопровождающее систему, будучи осведомленным об особенностях ее работы, может дать полезные рекомендации и при необходимости произвести необходимые модификации программы с целью практической реализации принятых рекомендаций.
К примеру, полезно минимизировать число вводимых документов. Это повысит быстродействие системы и снизит время ввода и редактирования данных. Эта задача, с одной стороны, решается организационными мероприятиями, например по каждому ВР для цеха оформляется один документ. С другой стороны, некоторые меры по снижению числа документов может предпринять и программист.
Так, после незначительных преобразований мы научились вводить начало расчетного периода на основе одного документа для всего предприятия. Причем каждый расчетный период вводится одним и тем же документом НачПериода_2 под номером 1, в который при начале нового периода добавляется одна строка табличной части (см. рис. 7.82).
Этот документ удалять нельзя. Защиту от удаления мы поставим в предопределенной процедуре глобального модуля ПриУдаленииДокументд, добавив в нее следующий код:
если док.Вид() = "НачПериода_2" тогда
СтатусВозврата(0);
Предупреждение("Нельзя удалять документ Начало расчетного периода.");
возврат;
конецЕсли;
Еще один шаг в направлении снижения числа документов мы сделали, создав д о-кументы Табель и Премия, вводящие по несколько ВР каждый. Таким образом, чтобы ввести все расчеты с приведенными в табл. 7.2 ВР предприятия (разд. 7.3.2), мы можем обойтись всего двумя документами на цех (Табель и Премия). Схожие решения могут быть приняты и для других ВР, даже таких, как оплата больничных или расчет отпуска. Программная реализация таких подходов, как мы убедились, не представляет ос о-бых затруднений.
Другая оптимизационная ниша - это исключение повторных операций по вводу данных и их обработке. Известно, что на предприятиях многие виды оплат начисляются в подразделениях, например премиальные, простои, всевозможные доплаты (за р а-боту в ночь, в праздник и др.). Там же ведется учет отработанного времени. Поэтому логично разработать и поставить в подразделения облегченные конфигурации 1С, позволяющие выполнять присущие им расчеты. Тогда задачи расчетного отдела предпр и-ятия существенно упростятся и будут состоять в импорте подготовленных в подразделениях документов, выполнении сложных расчетов, например отпускных, бухгалтерском учете заработной платы и выпуске необходимых отчетов, в том числе и для внешних организаций, налоговых, пенсионных и др.
Третья сфера инициативных работ - это выработка предложений по оптимизация производственных процессов и согласование их с моделями, реализуемыми средствами 1С.
Словом, пространство для инициативных работ велико. Будут ли выполняться эти работы или нет, от 1С не зависит, и поэтому этот вопрос здесь не обсуждается. В то же время все необходимые для реализации подобных мероприятий средства в 1С имеются, в чем читатель мог убедиться, просматривая предшествующие разделы пособия.
8.6.3. ОПТИМИЗАЦИЯ КОНФИГУРАЦИИ И ИНФОРМАЦИОННОЙ БАЗЫ
Оптимизация достигается за счет удаления из конфигурации и базы данных неиспользуемых объектов и файлов. Для этого прежде составляется свод применяемых объектов (табл. 8.3).
Используемые объекты конфигурации
|
Таблица 8.3 |
|
Объект |
Описание |
|
Константы |
|
НазваниеОрганизации |
Используется в расчетном листке и в ведомости перечислений в банк (процедура ВедомостьБанк формы списка ЖЗ Зарплата_2) |
|
БанкОрганизации |
Используется в ведомости перечислений в банк |
|
ГлБухгалтер |
” |
|
СтавкаНалога |
Используется в ВР НДФЛ_2 |
|
к5 |
Используется в ВР Премия_1234 |
|
Справочники |
|
Банки |
Используется в объекте Константа.БанкОрганизации |
|
Счета |
Используется в объекте Справочник.ХозяйственнаяОперация |
|
ХозяйственнаяОпера- |
Используется в объектах Справочник.ХозОпДляВР, |
|
ция |
ЖурналРасчетов.Зарплата_2 |
|
ВидыАналитики |
Используется в объекте Справочник.Счета |
|
Сотрудники_2 |
Используется в объектах Константа. ГлБухгалтер, Справочник.Дети, Справочник.ПраваРасчетчика, Документ.ПриказОПриеме, Документ.ИзменениеОклада, Документ.Табель, Документ.Премия, ЖурналРасчетов.Зарплата_2 |
|
Образование_2 |
Используется в объектах Справочник.Сотрудники_2, Документ. ПриказОПриеме |
|
Дети |
Хранит сведения о детях сотрудников |
|
ХозОпДляВР |
Хранит связанные с ВР хозяйственные операции |
|
ПраваРасчетчика |
Содержит перечень доступных расчетчику подразделений |
|
Документы |
|
ПриказОПриеме |
Используется в объекте Журнал.ПриказыКадровые |
|
ИзменениеОклада |
Используется в объекте Документ.ПриказОПриеме |
|
Табель |
Создает ВР Оклад_2, НДФЛ_2, ВБанк_2 |
|
Премия |
Создает ВР ПремияКоэф_2, ПремияСум_2, Премия_1234 |
|
НачПериода_2 |
Фиксирует смену расчетного периода |
|
Журналы документов |
|
ПриказыКадровые |
Содержит документы ПриказОПриеме и ИзменениеОклада |
|
Расчеты |
Содержит документы НачПериода_2 и Премия |
|
Табель |
Содержит документ Табель |
|
|
Объект |
Описание |
|
|
Перечисления |
|
ДаНет |
Используется в объекте Документ.Премия.Премия1234 |
|
ВР_2 |
Используется в модуле формы списка ЖЗ Зарплата_2
Журналы расчетов |
|
Зарплата_2 |
Содержит расчеты зарплаты сотрудников из справочника Сотрудники_2
Правила перерасчета |
|
НДФЛ_2 |
При вводе расчетов с ВР Оклад_2, ПремияКоэф_2, ПремияСум_2 и Премия_1234 нужно пересчитать расчеты с ВР НДФЛ_2 |
|
ВБанк_2 |
При вводе расчетов с ВР НачСальдо_2, Оклад_2, ПремияКоэф_2, ПремияСум_2, Премия_1234 и НДФЛ_2 нужно пересчитать расчеты с ВР ВБанк_2 |
|
Премия_1234 |
При вводе расчетов с ВР Оклад_2, ПремияКоэф_2 и ПремияСум_2 нужно пересчитать расчеты с ВР Премия_1234
Виды расчетов (см. табл. 7.2 и 7.11)
Группы видов расчетов |
|
ВсеУдержания_2 |
Включает ВР НДФЛ_2 |
|
ВсеНачисления_2 |
Включает ВР Оклад_2, ПремияКоэф_2, ПремияСум_2 и
Премйя_1234
Календари |
|
Служащие_2 |
Календарь для служащих |
|
Рабочие_2 |
Календарь для рабочих
Процедуры и функции глобального модуля |
ПриНачале
РаботыСистемы |
Предопределенная процедура глобального модуля. Выполняет инициализацию переменных и проверку, можно ли создать ЖР Зарплата_2 |
|
глДействия |
Вызывается в документе Табель |
ПриСмене
РасчетногоПериода |
Предопределенная процедура глобального модуля. Вызывает процедуру ФиксироватьСменуРП |
Фиксировать
СменуРП |
Заносит данные о смене расчетного периода в документ НачПериода_2 |
ЕстьЛиРучная
Правка |
Функция вернет 0, если хотя бы один расчет удаляемого документа имеет ручную правку |
ПриУдалении
Документа |
Предопределенная процедура глобального модуля. Вызывает функцию ЕстьЛиРучнаяПравка и не позволяет удалять документ с ручной правкой. Не позволяет также удалять документ НачПериода_2 |
|
ЕстьЛиРасчетчик |
Функция вернет 1, если в систему вошел расчетчик, или 0 -в противном случае. Используется в ЖЗ Зарплата_2 и в справочнике Сотрудники_2 для ограничения прав доступа |
Все остальные объекты из конфигурации можно удалить, сохранив предварительно копию исходного файла. А в глобальном модуле облегченного варианта системы, предназначенного, скажем, для подразделений предприятия, следует оставить ограниченное число процедур и функций, например приведенных на рис. 8.16.
 |
|
Рис. 8.16. Сохраняемые процедуры и функции глобального модуля |
В оставшемся коде глобального модуля нужно не забыть убрать ссылки на удаленные из конфигурации объекты.
Удаление ненужных объектов, таких, как справочники, документы и журналы, повлечет удаление соответствующих им DBF- и CDX-файлов. Тогда, запуская облегченную систему, мы снизим и число открываемых файлов (система открывает все файлы в момент ее загрузки), и число операций на поиск нужных объектов, например групп ВР или перечислений.
Чтобы сохранить работоспособность модифицированной конфигурации без журнала Зарплата, в предопределенной процедуре глобального модуля ПриНачалеРаботы-Системы в операторе
ЖЗ = СоздатьОбъект("ЖурналРасчетов.Зарплата");
объект Зарплата нужно заменить на объект Зарплата_2:
ЖЗ = СоздатьОбъект("ЖурналРасчеюв.Зарплата_2");
Аналогичные изменения следует сделать и в других оставляемых процедурах глобального модуля. Впрочем, можно от имени ЖЗ Зарплата_2 вернуться к имени Зарплата.
Перед удалением документов из конфигурации можно, находясь в 1С:Предприятии, употреблять следующую процедуру (на примере документа НачалоМесящ):
процедура Выполнить()
док = СоздатьОбъект("Документ.НачалоМесяца");
док.ВыбратьДокументы( );
пока док.ПолучитьДокумент( ) = 1 цикл
// Проставляем 1 С-пометку удаления
// Затем придется выполнить удаление помеченных объектов док.Удалить(0);
конецЦикла; // пока
ОткрытьФормуС'Журнал.Общий"); // Контрольный просмотр результата
конецПроцедуры // Выполнить
Удаленные из конфигурации объекты всегда можно добавить из ее сохраненной копии (файл 1 CV7.MD), если воспользоваться режимом Объединение конфигураций.
8.6.4. ОБНОВЛЕНИЕ КОНФИГУРАЦИИ
Время от времени 1С поставляет новые версии конфигураций, содержащие свежие наработки фирмы. Ваша задача - добавить из обновленной конфигурации в рабочую нужные фрагменты и при этом сохранить все привнесенные модификации (см. табл. 8.2).
Задача решается следующим образом. Находясь в конфигураторе, выберем пункт Объединение конфигураций колонки Конфигурация. Далее откроем файл с новой конфигурацией. Его имя скорее всего будет совпадать с именем файла текущей конфигурации (1CV7.MD), а расположение, естественно, - нет.
После сравнения текущей и новой конфигураций 1С откроет диалог, представленный на рис. 8.17.
 |
|
Рис. 8.17. Результаты сравнения конфигураций |
В диалоге выберем в группе Приоритет конфигурации переключатель Текущая конфигурация и нажмем на кнопку Выкл. все. Последнее действие погасит все флажки в столбце Объект. То есть, если нажать ОК, никаких изменений произведено не будет.
Выбор метода объединения зависит от объединяемых объектов. Если он не может быть задан одинаковым для всех объектов, то объединение конфигураций придется выполнить дважды. Впрочем, число производимых объединений может быть и большим, если использовать разные приоритеты конфигураций.
Теперь, употребляя элементы диалога Открыть, Сравнить и Отчет, следует принять решение в отношении каждого объекта, после чего нажать ОК.
Процесс изменения будет сопровождаться сообщениями следующего вида:
Начало процесса объединения конфигураций
- Режим замещения ведущих объектов
- Текущая конфигурация является приоритетной
- Добавление Объекта: "’Константа.НашБанк"
Окончание процесса объединения конфигураций
После объединения выполняется сохранение полученной конфигурации.
Замечание. Обновляя конфигурацию, не забываете вносить соответствующие изменения в глобальный модуль, добавляя в него вновь появившиеся переменные и программные компоненты, удаляя или модифицируя устаревшие.
8.7. ВЫВОДЫ
1. Настройку 1С следует выполнять на основе комплексной программы, ориентированной на повышение эффективности функционирования системы.
2. Критериями эффективности являются время ввода и редактирования данных, время вычислений, качество пользовательского интерфейса, надежность вычислений и степень защищенности данных.
3. При многопользовательском доступе возможные конфликты преодолеваются при помощи конструкции Попытка или процедур для транзакций. Там, где возможно, транзакции нужно замещать конструкцией Попытка.
4. По умолчанию предопределенные процедуры модуля документа ОбработкаПрове-дения и ОбработкаУдаленияПроведения выполняются с применением транзакции.
5. После введения справочника ПраваРасчетчика ограничение доступа данных становится легко решаемой задачей.
6. Специалист, сопровождающий систему, должен выполнять не только регламентные, но и инициативные работы, направленные на оптимизацию программы и процессов, модели которых программа реализует.
7. Быстродействие системы повысится, а задачи ее сопровождения существенно упростятся, если перейти от полного к облегченному варианту системы, удалив из нее неиспользуемые объекты.
8. Удалению объектов должно предшествовать детальное описание используемых в работе объектов, процедур и функций.
9. Для подразделений предприятия, выполняющих частичный расчет зарплаты своих сотрудников, создаются максимально легкие версии программы.
10. Удаленные объекты всегда можно добавить в текущую конфигурацию из ранее сохраненной копии.
9. ОБМЕН ДАННЫМИ
С другими системами 1С обменивается данными преимущественно посредством текстовых и DBF-файлов. В этой главе мы рассмотрим вторую возможность, предварительно сообщив базовые сведения об алгоритмах сортировки и поиска данных.
9.1. МЕТОДЫ СОРТИРОВКИ ДАННЫХ
Основное назначение сортировки - обеспечить быстрый поиск данных. Помимо этого в отсортированном файле или массиве гораздо быстрее выполнять многие вычисления. Например, существенно быстрее подсчитывается число элементов, равных заданному значению. Также во многих случаях отсортированный файл более удобен для просмотра и визуального анализа данных.
9.1.1. ВНЕШНЯЯ И ВНУТРЕННЯЯ СОРТИРОВКА
Данные в файле можно отсортировать, применяя следующий порядок действий: а) ввести данные в массив; б) выполнить его сортировку; в) переместиться в начало файла; г) перенести данные из отсортированного массива в файл. Такая сортировка файла называется внутренней - все данные файла одновременно находятся в выделенной под процесс памяти.
Сортировка, при которой часть данных находится в принадлежащей программе памяти, а часть во внешней памяти, называется внешней. Крайним проявлением внешней сортировки является непосредственная сортировка DBF-файла, в котором, как известно, можно редактировать отдельные записи.
9.1.2. ПОНЯТИЕ КЛЮЧА
Пусть файл данных содержит некоторую последовательность из п элементов: г,, г,..., г. Каждый элемент файла будем называть записью. Как правило, записи файла состоят из одинакового числа компонентов, называемых полями записи. В общем случае компоненты записи могут быть разного типа.
Пример. В табл. 9.1 приводится фрагмент DBF-файла, содержащего данные о сотрудниках предприятия; строка таблиц является записью, а отдельная ячейка -ее полем.
Таблица 9.1
Фрагмевт файла SC4194.DBF |
|
Группа |
СсылкаНа
Группу |
Код |
Наименование |
Флаг
Папки |
Другие
поля |
|
6 |
2 |
201 |
Абрамова Лариса Сергеевна |
2 |
|
|
7 |
2 |
202 |
Куприкова Людмила Сергеевна |
2 |
|
|
8 |
2 |
203 |
Митина Ольга Владимировна |
2 |
|
|
|
Группа |
СсылкаНа
Группу |
Код |
Наименование |
Флаг
Папки |
Другие
поля |
|
9 |
3 |
111 |
Агальцов Юрий Алексеевич |
2 |
|
|
10 |
3 |
112 |
Добрецов Борис Юрьевич |
2 |
|
|
11 |
4 |
121 |
Волосков Михаил Андреевич |
2 |
|
|
12 |
4 |
122 |
Кузьмина Раиса Николаевна |
2 |
|
|
13 |
5 |
131 |
Васильева Елена Ивановна |
2 |
|
|
15 |
5 |
132 |
Смирнова Нина Федоровна |
2 |
|
|
16 |
5 |
133 |
Хохлов Евгений Николаевич |
2 |
|
Свяжем с. каждой записью файлов г ключ к, понимая под ключом одно из полей записи. Правда, такое понятие ключа является узким: в общем случае ключом записи r
t является некоторое выражение, среди операндов которого присутствует одно или несколько полей записи. Так, в приведенной таблице данные упорядочены по выражению СсылкаНаГруппу + Наименование (знак сложения в выражении уместен, поскольку поле СсылкаНаГруппу имеет символьный тип).
Выбор ключа диктуется практическими целями поиска и представления данных. Так, в приведенной таблице естественно для просмотра упорядочить данные по номеру цеха (группы), а в пределах каждого цеха разместить фамилии сотрудников в алфавитном порядке.
Файл отсортирован по ключу, если для любых k
t < к запись г. всегда предшествует г, где t и j - номера записей в файле до выполнения сортировки. (Первая запись файла имеет номер 1.)
Вполне возможно, что две записи имеют в некотором файле одинаковый ключ. Метод сортировки называется устойчивым, если для всех записей г, и г, таких, что к. = к,, выполняется условие: в отсортированном файле г, предшествует г , если г,-предшествует г, в первоначальном файле.
9.1.3. СОРТИРОВКА ТАБЛИЦЫ УКАЗАТЕЛЕЙ
Сортировать можно или сами записи файла, или указатели некоторой вспомогательной таблицы. Пример первого случая приведен на рис. 9.1.
Номер
записи |
Ключ |
Другие поля |
|
1 |
8 |
|
|
2 |
20 |
|
|
3 |
15 |
|
|
4 |
4 |
|
|
5 |
10 |
|
|
|
а |
|
Ключ |
Другие
поля |
|
4 |
|
|
8 |
|
|
10 |
|
|
15 |
|
|
20 |
|
|
|
б |
Рис. 9.1. Сортировка записей: а - исходный файл; б - отсортированный файл
Если объем данных в каждой записи файла велик, то сортировка самих записей является нецелесообразной, в частности по причине больших временных затрат на перемещение записей в процессе сортировки. Кроме того, часто файл имеет не один, а несколько ключей. В этом случае можно ввести вспомогательную таблицу указателей или несколько таких таблиц и перемещать при сортировке не записи, а указатели на записи (рис. 9.2). Такая сортировка называется сортировкой таблицы адресов (указателей). В базах данных таблица указателей может размещаться в отдельном индексном файле.
Таблица указателей может содержать два поля: ключ и номер соответствующей записи исходного файла.
Отсортированная таблица указателей
Номер
записи
Файл
Ключ
Другие
поля
Ключ
Номер
записи
Рис. 9.2. Отсортированная таблица указателей
При работе с таблицами указателей задача поиска записи решается в два этапа: 1) в таблице указателей ищется ключ; 2) в файле данных ищется запись (по ее номеру), с которой связан найденный в таблице указателей ключ.
Рассмотрим теперь алгоритмы внутренней пузырьковой и быстрой сортировки ключей. Расширение этих методов для сортировки записей файла или таблицы указателей представляется очевидным.
9.1.4. СОРТИРОВКА МАССИВА МЕТОДОМ ПУЗЫРЬКА
Сортировка методом пузырька наиболее проста для реализации, но имеет незначительную вычислительную эффективность.
Не теряя общности, будем для простоты изложения в дальнейшем рассматривать задачу сортировки массива х целых чисел, в котором первые п чисел должны быть отсортированы так, чтобы х,- < Xj для 1 < i ^ п.
Идея сортировки методом пузырька в том, чтобы просмотреть массив последовательно несколько раз. Один просмотр состоит из сравнения каждого элемента массива со следующим за ним элементом (x сравнивается с x+) и обмена этих двух элементов, если они располагаются не в нужном порядке (если x> х+).
Рассмотрим массив: 25 57 48 37 12 92 86 33.
Результат сортировки: 12 25 33 37 48 57 86 92.
Проанализируем процесс сортировки.
|
На первом просмотре делаются сравнения: |
|
Xj c x2 |
|
(25 с 57) |
Нет обмена |
|
х2 с X, |
|
(57 с 48) |
Обмен |
|
х3 с |
х4 |
(57 с 37) |
Обмен |
|
х4 с |
х5 |
(57 с 12) |
Обмен |
|
Xj с |
х6 |
(57 с 92) |
Нет обмена |
|
х с |
х7 |
(92 с 86) |
Обмен |
|
х7 с |
х* |
(92 с 33) |
Обмен |
|
После первого просмотра в результате обменов элементы массива расположатся в таком порядке:
25 48 37 12 57 86 33 92
Отметим, что наибольший элемент (в данном случае 92) находится после первого просмотра в нужной позиции. В общем случае элемент x
npass+I результирующего массива будет находиться в нужной позиции после итерации pass. Отсюда и идет название метода: каждое число медленно "всплывает", как пузырек, вверх на свою конечную позицию.
После второго просмотра в результате обменов элементы массива расположатся так:
25 37 12 48 57 33 86 92
Как и ожидалось, в нужной позиции оказалось второе по величине число, 86. Поскольку каждая итерация помещает в нужную позицию очередной элемент, для сортировки массива из и чисел потребуется не более п - 1 итераций.
Полный набор итераций при сортировке методом пузырька таков:
Массив до начала сортировки
Итерация 1
Итерация 2
Итерация 3
Итерация 4
Итерация 5
Итерация 6
Итерация 7
В каждой строчке приведенного списка итераций подчеркнуты элементы массива, находящиеся в нужной позиции.
Анализ полного набора итераций подсказывает два очевидных улучшения метода.
Во-первых, поскольку все элементы в позициях к> п - pass + 1 уже находятся после итерации pass на нужных местах, их рассмотрение на последующих итерациях избыточно. Следовательно, на каждой итерации число необходимых сравнений уменьшается на единицу. Так, при первом просмотре нужно сделать п - 1 сравнений, на втором - и - 2, на просмотре с номером pass - только п - pass. To есть данный процесс ускоряется с каждым просмотром.
Во-вторых, не всегда следует выполнять все и - 1 просмотров. В частности, приведенный массив был отсортирован после пяти итераций (вместо семи). Для исключения холостых проходов нужно иметь возможность обнаружения факта завершения сортировки массива и прекращать итерации при его обнаружении. Признаком того, что массив отсортирован, является отсутствие перестановок на очередном проходе. Применительно к нашему примеру это означает, что факт завершения сортировки будет установлен только на шестом проходе.
Проанализируем вычислительную эффективность метода. Всего алгоритм (без усовершенствований) предусматривает выполнение п -1 просмотров и и -1 сравнений на каждом просмотре. Таким образом, общее число сравнений на всех возможных проходах равно (n - 1)*(n -1) = п
2 - 2n + 1, что составляет 0(п
2).
Введенные усовершенствования метода хотя и сокращают общее число сравнений, но не изменяют порядка вычислительной сложности. В самом деле, число сравнений на итерации pass равно n - pass. При наличии к итераций общее число сравнений равно (n -1) + (n - 2) + ... + (n - k) - (2к*п - к
2 - k)/2. Можно показать, что среднее число итераций к представляет собой 0(п), так что общая формула имеет по-прежнему порядок 0{п
2), хотя постоянный сомножитель теперь меньше, чем ранее.
Если массив полностью отсортирован, то вычислительная сложность метода составляет 0(п) - необходимо л - 1 сравнений, чтобы в этом убедиться.
Для улучшения метода имеются и иные способы. Один из них таков: сортировка методом пузырька может быть ускорена при помощи выполнения следующих один за другим просмотров в противоположных направлениях, так что небольшие по величине элементы быстро перемещаются в начало массива таким же способом, как большие элементы перемещаются в его конец. Это приводит к уменьшению необходимого числа просмотров.
9.1.5. БЫСТРАЯ СОРТИРОВКА
Современные процедуры сортировки используют одну из модификаций алгоритма быстрой сортировки, к изложению которого мы переходим.
Рассмотрим массив х:
25 37 12 33 48 57 92 86
В нем число 48 характеризуется тем, что, во-первых, все расположенные левее него числа меньше 48 и, во-вторых, числа, расположенные правее него, больше 48. Назовем такое число разделителем массива. Нетрудно понять, что теперь мы можем отдельно решать задачу сортировки для чисел до разделителя и для чисел после него. Кроме того, сам разделитель находится в нужной позиции, то есть в дальнейшей сортировке он уже не рассматривается.
Рассмотрим теперь массив, в котором нет разделителя:
37 25 57 48 12 92 86 33
Чтобы воспользоваться только что приведенной идеей уменьшения размерности задачи сортировки, нам надо научиться выполнять такие перестановки в массиве, после которых один из его элементов станет разделителем. Выберем для будущего разделителя первый элемент массива, то есть число 37. Разделитель окажется в нужной позиции, если разместить числа 25, 12 и 33 слева от 37. Выполним это так: будем просматривать последовательно элементы массива начиная с его первой позиции до тех пор, пока не встретим число, большее разделителя. Присвоим этой позиции имя L1. Далее просмотрим элементы массива начиная с последней позиции, останавливаясь при обнаружении числа, меньшего 37. Дадим такой позиции имя R1. В нашем случае после выполнения этих двух просмотров возникнет следующая ситуация:
37 25 57 48 12 92 86 33
L1 R1
Нетрудно предугадать следующий шаг алгоритма - числа 57 и 33 должны быть переставлены местами, тогда получится массив
37 25 33 48 12 92 86 57
L1 R1
Продолжим теперь поиск элемента, большего 37, перемещаясь вправо, начиная с позиции L1, и элемента, меньшего 37, перемещаясь влево, начиная с позиции R1. Такой поиск даст следующий результат:
|
37 25 33 |
48 |
12 |
92 |
86 |
57 |
|
|
L1 |
R1 |
|
|
|
|
Выполним и перестановку: |
|
|
|
|
|
|
37 25 33 |
12 |
48 |
92 |
86 |
57 |
|
|
L1 |
R1 |
|
|
|
Еще одна пара перемещений не изменит картины, но даст нам основание для прекращения левых и правых перемещений вдоль массива (критерий прекращения перемещений - истинность выражения L1 >= R1) и перестановки разделителя (числа 37) в его окончательную позицию. После выполнения перемещений, предшествующих перестановке разделителя, имена R1 и L1 расположатся так:
37 25 33 12 48 92 86 57
Rl L1
Сам же разделитель должен быть размещен в позиции R1, что выполняется в результате обмена элементов х[1] и х [R1], то есть чисел 12 и 37. Приведем и результат:
12 25 33 37 48 92 86 57
Итак, массив разбит на две части (до и после разделителя), которые можно сортировать отдельно, применяя к каждой из частей только что приведенную схему. Завершим же сортировку, когда длина каждой из полученных в результате разбиения частей будет равна единице.
Замечание. Выбор в качестве будущего разделителя первого элемента массива (или последующего фрагмента) необязателен и в ряде случаев неудовлетворителен. Так, в случае почти отсортированного массива будущий разделитель лучше выбирать ближе к середине рассматриваемого фрагмента.
Вычислительная сложность быстрой сортировки оценивается как 0(nlogn). Так, если сортируется массив из 1024 элементов, то пузырьковая сортировка будет в среднем выполняться в
п
г / . . 1024 ,
ТГ 1о
8,„) = —= SU
раза медленнее.
9.2. ПОИСК ДАННЫХ
Поиск данных в векторе и файле выполняется по ключу. Как и при сортировке, выделяют два метода поиска: внутренний и внешний. В первом случае весь файл находится в отведенной под программу памяти ЭВМ. В случае внешнего поиска большая часть данных находится во внешней памяти, например на жестком диске.
Рассмотрим внутренний поиск применительно к одномерному массиву.
Предположим, что х - это вектор, содержащий п ключей. Пусть key является аргументом поиска, то есть искомым значением ключа. Сформулируем задачу поиска: установить в переменную search наименьшее целое число i такое, что x[i] = key, если такое i существует, и нуль - в противном случае. (При такой постановке задачи нижняя граница массива х должна быть больше нуля.)
9.2.1. ПОСЛЕДОВАТЕЛЬНЫЙ ПОИСК
Последовательный поиск является простейшей формой поиска. В представленной формулировке запись фрагмента поиска тривиальна:
перем х[20], нашел, ключ, ин, п;
<здание значений вектора х и переменной ключ > n = 20; нашел = 0; ин= 1;
пока (ин <= п) и (нашел = 0) цикл
если х[ин] = ключ тогда нашел = ин;
конецЕсли;
ин = ин+1; конецЦикла // пока; если нашел = 0 тогда
Сообщить("Ключ не найден."); иначе
Сообщить(''Искомый элемент имеет в векторе x номер " + Строка(нашел)); конецЕсли;
Эффективность последовательного поиска оценим из предположения, что аргумент поиска может равновероятно располагаться в любой позиции массива. Подсчитаем среднее число сравнений вида х[ин] = ключ, необходимых для завершения поиска. Если аргумент является первым элементом массива, то необходимо одно сравнение; если последним, то необходимо и сравнений. То есть среднее число сравнений для успешного поиска составит (n + 1)/2. А в случае неуспешного - п. В любом случае вычислительная сложность алгоритма последовательного поиска равна 0(п).
Область применения последовательного поиска - поиск в неупорядоченных массивах (файлах). Если же данные упорядочены, то следует применять бинарный поиск, имеющий и иное название - дихотомия.
9.2.2. БИНАРНЫЙ ПОИСК
Методы поиска в отсортированных таблицах указателей основаны на алгоритме бинарного поиска.
Пусть упорядоченный массив х из п элементов содержит значения
5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179 и пусть задан аргумент поиска ключ, равный, например, 129.
Идея алгоритма бинарного поиска такова:
• сравнить аргумент поиска ключ со значением среднего элемента х[сред] массива х, где сред = [п/2], а [с] - целая часть числа с;
• если они равны, то поиск завершен, иначе, если ключ < х[сред], выполнить аналогичным образом поиск в позициях массива х, предшествующих позиции сред, в противном случае, если ключ > х[сред], выполнить аналогичным образом поиск в позициях массива х, следующих за позицией сред.
Исключить из дальнейшего рассмотрения часть массива позволяет тот факт, что массив упорядочен.
Проиллюстрируем процесс бинарного поиска. Число элементов массива п = 17, тогда [п/2] = 8. Поэтому первоначально выполняется сравнение сред с x
8 = 57. Так как сред > х, то зона поиска на следующем шаге ограничивается участком от 9-го элемента до 17-го. Этот участок состоит из девяти элементов и его серединой является элемент х
13 = 107 ([(9 + 17)/2] = 13). Поскольку сред >х
13, то зона поиска ограничивается участком от 14-го до 17-го элемента. Его серединой является элемент х
15. На этом процесс поиска завершен, так как х
15 = сред. Отобразим на рис. 9.3 процесс поиска элемента ключ = 129, выделяя посредством подчеркивания на каждом шаге зоны поиска.
Итерация 0 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179
Итерация 0 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179
Итерация 1 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179
Итерация 3 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179
Рис. 9.3. Пример дихотомии
Каждое сравнение уменьшает число возможных кандидатов в 2 раза. Максимальное число шагов поиска будет в том случае, когда аргумент поиска находится в начале или в конце массива. В этом случае потребуется log
2n + 1 итераций. Действительно, если число элементов в массиве равно п = Т, ключ будет найден, когда нерассмотренным останется только один элемент, то есть через т шагов. В свою очередь, при заданном п имеем т = log
2n. После анализа последнего элемента получаем общее число итераций log
2n + 1. Поэтому вычислительная сложность бинарного поиска составляет O(logn).
Однако приведенный алгоритм не позволяет в общем случае точно решить задачу поиска, когда файл или массив содержат повторяющиеся значения ключей. Рассмотрим, например, массив
5 7 11 18 26 32 44 57 81 90 94 97 107 129 129 147 179 в котором элемент (ключ) 129 содержится 2 раза. Тогда, если аргумент поиска будет равен 129, алгоритм, как и прежде, укажет, что ключ находится в 15-й позиции, то есть будет найдено не первое, а второе значение ключа 129 (первое значение ключа расположено в позиции 14). В ряде случаев эта ошибка принципиальна, тогда она устраняется в результате очевидной модификации алгоритма бинарного поиска.
9.2.3. СРАВНЕНИЕ ПОСЛЕДОВАТЕЛЬНОГО И БИНАРНОГО ПОИСКА
Пусть файл, в котором выполняется поиск, отсортирован и содержит 1024 (2
10) элемента. В случае последовательного поиска наибольшее число итераций будет равно 1024, а бинарного - 11. То есть разница в два порядка.
Сравним теперь временные затраты на поиск в случае неотсортированного файла. При последовательном поиске максимальное число итераций, разумеется, сохраняется. Бинарный поиск неприменим. Выполним, однако, быструю сортировку файла. В среднем для этого потребуется 1024*log
21024 = 10240 итераций. Далее выполним бинарный поиск, на который будет затрачено не более 11 итераций.
Приведенные цифры позволяют сделать вывод: если файл неотсортирован и в процессе вычислений задача поиска в файле возникает сравнительно редко (в нашем примере не более 10 раз), то можно применять последовательный поиск, в противном случае более целесообразно прежде отсортировать файл или таблицу указателей и при вычислениях применять бинарный поиск. Как правило, именно такой подход используется на практике.
9.3. ПЕРЕДАЧА ДАННЫХ ИЗ 1С В DBF-ФАЙЛЫ
9.3.1. ЭКСПОРТ ДАННЫХ ИЗ СПРАВОЧНИКА СОТРУДНИКИ_2
9.З.1.1. ПОСТАНОВКА ЗАДАЧИ
В разд. 7.4.6 мы загрузили в 1С, используя объект типа XBase, DBF-файл с данными о начальном сальдо. Объекты того же типа применяются и для выгрузки данных из 1С.
Рассмотрим задачу переноса данных из справочника Сотрудники_2 в файл еm-ployee.dbf.
Задача осложняется тем, что реквизит Оклад справочника Сотрудники_2 является периодическим. Перенос значений этого реквизита мы выполним в отдельный файл -salary.dbf, то есть поступим так же, как и 1С, которая хранит данные о периодических реквизитах в файле 1SCONST.DBF. Структуру файла salary.dbf воспроизводит табл. 9.2, в заголовках столбцов которой после символа / указано имя соответствующего поля DBF-файла.
Таблица 9.2
Структура файла salary.dbf на примере истории окладов Горюновой У. В. |
|
Код\И |
Дата/Date |
Имя документа /DocNarne |
Номер документа /Dodd |
Оклад/Salary |
|
2010 |
20.11.2001 |
ПриказОПриеме |
2 |
2500 |
|
2010 |
22.11.2001 |
ИзменениеОклада |
2 |
2700 |
|
2010 |
30.11.2001 |
- |
- |
3200 |
|
|
Характеристики полей файла salary.dbf опишем в табл. 9.3, в которой формат числовых полей определяется заданными в конфигурации 1С свойствами Длина и Точность соответствующих реквизитов. |
Таблица 9.3
Характеристики полей файла salary. dbf |
|
Имя поля |
Свойства поля |
|
Id, Docld |
Числовые поля формата 5.0 |
|
Date |
Поле типа Дата |
|
DocName |
Строка из 20 символов |
|
Salary |
Числовое поле формата 10.2 |
|
ПРОЦЕДУРЫ ПЕРЕНОСА ДАННЫХ
Вторым осложняющим обстоятельством является то, что реквизиты Образование, ПриказОклац, ПриказПрием и Календарь имеют типы, которые в чистом виде нельзя воспроизвести в DBF-файле. (Средствами 1С в DBF-файле можно определить числовые, символьные, логические поля и поля типа Дата.) Поэтому нам придется некоторым образом заменить значения этих реквизитов на значения стандартных типов, но таким образом, чтобы иметь возможность восстановить при обратном преобразовании исходные величины. Замены будем выполнять в соответствии с правилами, изложенными в табл. 9.4.
Таблица 9.4
Правила преобразования значений объектов 1С |
|
Объект 1С |
На что заменяется в DBF-файле |
|
Элемент справочника |
Идентификатор справочника и код элемента |
|
Документ |
Идентификатор документа и номер документа |
|
Календарь |
Идентификатор календаря |
|
И наконец, третий осложняющий фактор в том, что, кроме данных о сотрудниках, справочник содержит группы, отражающие имена подразделений предприятия, а также описывает иерархию групп и сотрудников (см. табл. 5.1). В создаваемом файле эти сведения также надо сохранить.
Таким образом, файл employee.dbf будет иметь отраженные в табл. 9.5 поля. |
Таблица 9.5
Поля файла employee.dbf |
Имя DBF-
поля |
Имя 1C-
реквизита |
Свойства DBF-поля |
Описание |
|
Id |
Код |
Числовое поле формата 5.0 |
Код сотрудника или группы |
|
Parentld |
- |
"" 5.0 |
Ссылка на группу, в которую входит текущий элемент |
|
IsGroup |
- |
Логическое поле |
Имеет значение истина, если элемент является группой, или ложь -в противном случае |
|
Name |
Наименование |
Строка из 30 символов |
ФИО сотрудника или имя группы |
|
Ed |
Образование |
Строка из 13 символов |
Имеет значение Образование_2 |
|
EdId |
|
Числовое поле формата 3.0 |
Код соответствующей записи в справочнике Образование_2 |
|
Имя DBF-
поля |
Имя 1C-реквизита |
Свойства DBF-поля |
Описание |
|
OrderEng |
ПриказПрием |
Строка из 15 символов |
Имеет значение ПриказОПриеме |
|
OrderEngld |
" |
Числовое поле формата 5.0 |
Номер приказа о приеме на работу |
|
OrderSal |
ПриказОклад |
Строка из 13 символов |
Имеет значение ИзменениеОклада |
|
OrderSalld |
" |
Числовое поле формата 5.0 |
Номер приказа об изменении оклада |
|
Calendar |
Календарь |
Строка из 9 символов |
Идентификатор календаря |
|
|
Очевидно, что, имея файлы employee.dbf и salary.dbf, можно полностью восстановить справочник Сотрудники_2. Правда, восстановленный справочник не будет точной копией оригинала. |
9.З.1.2.
Во-первых, нужно по известной структуре справочника Сотрудники_2 и по изложенным правилам преобразования данных создать файлы employee.dbf и salary.dbf. Предварительно, однако, мы в процедуре АтрСвойства сформируем таблицу значений, содержащую преобразованное в соответствии с табл. 9.5 описание атрибутов (реквизитов) справочника Сотрудники_2. Для этого нам придется воспользоваться объектом Метаданные. Запустим процедуру АтрСвойства из обработки Проба и просмотрим п о-лученный результат.
процедура АтрСвойства(тЗнач) далее
процедура ЕщеОднаСтрока(тЗнач, видСпр, типРек, ин, кон) далее
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем тЗнач;
ОчиститьОкноСообщений();
// Формируем таблицу с описанием реквизитов справочника Сотрудники_2 АтрСвойства(тЗнач);
// Просмотр таблицы значений. Результат см. на рис. 9.3
тЗнач.ВыбратьСтроку(, "Преобразованные реквизиты справочника Сотрудники_2"); конецПроцедуры // Выполнить
// Возвращает таблицу значений, содержащую преобразованное описание // атрибутов справочника Сотрудники_2 процедура АтрСвойства(тЗнач) перем видСпр;
тЗнач = СоздатьОбъект("ТаблицаЗначений");
видСпр = "Сотрудники_2"; // Вид справочника
// Формируем столбцы таблицы значений
тЗнач. НоваяКолонка(''Идентификатор", "Строка");
тЗнач. НоваяКолонка("Тип", "Строка");
тЗнач. НоваяКолонка("Длина", "Число");
тЗнач.НоваяКолонка(''Точность", "Число");
тЗнач.НоваяКолонка("Периодический"," Число");
// Запишем в таблицу значений идентификатор, тип, длину и точность реквизитов // справочника Сотрудники_2. Длина записывается для символьных и числовых // реквизитов, а точность - только для числовых
// Два первых реквизита - это атрибуты Код и Наименование справочника
тЗнач.НоваяСтрока(); // Добавляем новую строку в таблицу значений
// Атрибут Код
тЗнач.Идентификатор = "Код";
тЗнач.Тип = Метаданные.Справочник(видСпр).ТипКода; тЗнач.Длина = Метаданные.Справочник(видСпр).ДлинаКода; тЗнач.Точность = 0; тЗнач.Периодический = 0;
тЗнач.НоваяСтрока(); // Еще одна новая строка
// Атрибут Наименование тЗнач.Идентификатор = "Наименование"; тЗнач.Тип = "Строка";
тЗнач.Длина = Метаданные.Справочник(видСпр).ДлинаНаименования; тЗнач.Точность = 0; тЗнач.Периодический = 0;
// Реквизиты справочника Сотрудники_2
// Напоминаем, что реквизиты типа Справочник и Документ порождают 2 DBF-поля,
// поэтому для них в тЗнач выделяем две строки для ин = 1 по Метаданные.Справочник(видСпр).Реквизит() цикл // Тип реквизита
типРек = Метаданные.Справочник(видСпр).Реквизит(ин).Тип;
// Очередная новая строка
ЕщеОднаСтрока(тЗнач, видСпр, типРек, ин, ""); если (типРек = "Справочник") или (типРек = "Документ") тогда // Очередная новая строка
ЕщеОднаСтрока(тЗнач, видСпр, типРек, ин, "2"); конецЕсли; конецЦикла;
конецПроцедуры // АтрСвойства
// Добавляет новую строку в таблицу значений тЗнач процедура ЕщеОднаСтрока(тЗнач, видСпр, типРек, ин, кон)
перем обВид; // Разновидность типа объекта
// кон = "", если добавляется первая строка для справочника или документа // кон = "2", если добавляется вторая строка для справочника или документа тЗнач.НоваяСтрока();
если (типРек = "Число") или (типРек = "Строка") или (типРек = "Дата") тогда тЗнач.Идентификатор =
Метаданные.Справочник(видСпр). Реквизит(ин). Идентификатор; тЗнач.Тип = типРек;
тЗнач.Длина = Метаданные.Справочник(видСпр).Реквизит(ин).Длина; иначе // Справочник, Документ или Календарь
если типРек = "Календарь" тогда тЗнач.Идентификатор =
Метаданные.Справочник(видСпр).Реквизит(ин).Идентификатор;
иначе
обВид = Метаданные.Справочник(видСпр).Реквизит(ин).Вид; тЗнач.Идентификатор = обВид + кон; конецЕсли;
если кон = "" тогда
тЗнач.Тип - "Строка";
тЗнач.Длина = СтрДлина(тЗнач.Иденгификатор); иначе // кон = 2
тЗнач.Тип = "Число"; если типРек = "Справочник" тогда
тЗнач.Длина = Метаданные.Справочник(обВид).ДпишКода; иначе // типРек = "Документ"
тЗнач.Длина = МетаданныеДокумент(обВид)ДлинаНомера; конецЕсли; конецЕсли; конецЕсли;
тЗнач.Точность = Метаданные.Справочник(видСпр).Реквизит(ин).Точность; тЗнач.Периодический = Метаданные.Справочник(видСпр).Реквизит(ин).Периодический; конецПроцедуры // ЕщеОднаСтрока
 |
|
Рис. 9.3. Результат работы процедуры АтрСвойства |
Замечания:
1. Процедуры АтрСвойства и ЕщеОднаСтрока показывают, что объект Метаданные обеспечивает доступ к значению любого компонента структуры объекта агрегатного типа.
2. Примеры структур метаданных системы приведены в прил. 1.
Теперь таблица тЗнач содержит практически все необходимые данные для создания файла employee.dbf. Осталось только заменить значения столбца Идентификатор на соответствующие имена полей файла employee.dbf. Выполним эти замены в процедуре ДляДБФ. В процедуре СоздатьПоляДБФ подготовим, пользуясь данными таблицы значений тЗнач, поля для файла employee.dbf, а в процедуре СоздатьСотр сформируем файл employee.dbf и его индексы.
Перенос данных в файл employee.dbf выполнит процедура ПеренестиСотр, обраб а-тывающая справочник Сотрудники_2 по следующему алгоритму:
1. Начало.
2. Выполнить выборку элементов справочника Сотрудники_2.
3. Для каждого элемента найти переносимые в DBF-поля значения.
4. Создать новую запись в файле employee.dbf и перенести в нее найденные в п. 3 значения.
5. Конец.
Для выбранного сотрудника пп. 3 и 4 алгоритма реализует следующий код:
дбф.Добавить();
дбф.И = сСотр_2.Код;
дбф. ParentId= сСотр_2. Родитель. Код;
дбф.IsGroup = сСотр_2.ЭтоГруппа();
дбф.Name = сСотр_2. Наименование;
дбф.Ed = сСотр_2.0бразование.Вид();
дбф^И = сСотр_2.Образование.Код;
дбф.QrderEng = сСотр_2.ПриказПрием.Вид();
дбф.OrderEngId = сСотр_2.ПриказПрием.НомерДок;
дбф.OrderSal = сСотр_2.ПриказОклад.Вид();
дбф.OrderSalId = сСотр_2.ПриказОклад.НомерДок;
дбф.Calendar = сСотр_2.Календарь.Вид();
дбф.3аписать();
Создание файла salary. dbf осуществит процедура СоздатьОклад, принимающая объект дбф2, содержащий поля файла, сформированные в процедуре СоздатьПоля-ДБФ. Предварительно, однако, мы, как и в случае файла employee.dbf, сформируем в процедуре ДляДБФ2 таблицу значений тЗнач, на основании которой процедурой СоздатьПоляДБФ будут созданы поля файла salary.dbf.
Заполнение файла salary.dbf выполним в процедуре ПеренестиОклад по схеме, реализованной в примере 3 разд. 6.1. Процедура ПеренестиОклад вызывается для выбранного сотрудника в процедуре ПеренестиСотр.
Итоговый код переноса будет таким:
процедура АтрСвойства(тЗнач) далее
процедура ЕщеОднаСтрока(тЗнач, видСпр, типРек, ин, кон) далее
процедура ДляДБФ(тЗнач) далее
процедура СоздатьПоляДБФ(тЗнач, дбф, пРекв) далее
процедура СоздатьСотр(дбф) далее
процедура ДляДБФ2(тЗнач) далее
процедура СоздатьОклад(дбф) далее
процедура ПеренестиСотр(дбф, дбф2) далее
процедура ПеренестиОклад(сотр, оп, дбф) далее
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем тЗнач, дбф, дбф2;
ОчиститьОкноСообщений();
// Формируем таблицу с описанием реквизитов справочника Сотрудники_2 АтрСвойства(тЗнач);
// Готовим таблицу значений тЗнач для процедуры создания файла employee.dbf ДляДБФ(тЗнач);
// Просмотр таблицы значений. Результат см. на рис. 9.4 тЗнач.ВыбратьСтроку(, "Свойства полей файла employee.dbf);
СоздатьПоляДБФ(тЗнач, дбф, 0); // Создаем поля файла employee.dbf
СоздатьСотр(дбф); // Создаем файл employee.dbf
ДляДБФ2(тЗнач);
// Просмотр таблицы значений. Результат см. на рис. 9.5 тЗнач.ВыбратьСтроку(, "Свойства полей файла salary.dbf);
СоздатьПоляДБФ(тЗнач, дбф2, 1); // Создаем поля файла salary.dbf
// Готовим таблицу значений тЗнач для процедуры создания файла salary.dbf СоздатьОклад(дбф2); // Создаем файл salary.dbf
// Перенос данных в файлы employee.dbf и salary.dbf.
// Вызывает процедуру ПеренестиОклад. Результаты см. на рис. 9.6 и 9.7 ПеренестиСотр(дбф, дбф2);
Предупреждение('Тотово."); конецПроцедуры // Выполнить
// Код процедур АтрСвойства и ЕщеОднаСтрока см. выше
// Заменяет в таблице значений тЗнач данные столбца Идентификатор,
// на соответствующие имена поле файла employee.dbf. Вставляет также две // строки для полей Parentld и IsGroup файла employee.dbf процедура ДляДБФ(тЗнач)
перем сЗнач, ин, поз, имяПоля, номСтроки, колСтрок;
// Список значений сЗнач содержит перечень соответствий между именами // DBF-полей файла employee.dbf и значениями столбца Идентификатор таблицы тЗнач сЗнач = СоздатьОбъект("СписокЗначений"); сЗнач.ДобавитьЗначение("Код", " Id"); сЗнач.ДобавитьЗначение("Наименование", "Name"); сЗнач.ДобавитьЗначение("Оклад", "Salary"); сЗначДобавитьЗначение("Образование_2", "Ed"); сЗнач.ДобавитьЗначение("Образование_22"; "Edld"); сЗнач.ДобавитьЗначение("ПриказОПриеме", "OrderEng"); сЗнач.ДобавитьЗначение("ПриказОПриеме2", "OrderEngld"); сЗнач.ДобавитьЗначение("ИзменениеОклада", "OrderSal"); сЗнач.ДобавитьЗначение("ИзменениеОклада2", "OrderSalld"); сЗнач.ДобавитьЗначение("Календарь", "Calendar"); тЗнач.ВыбратьСтроки();
// Заносим вместо имеющегося в столбце Идентификатор значения имя DBF-поля пока тЗнач.ПолучитьСтроку() = 1 цикл
поз = сЗнач.НайтиЗначение(тЗнач.Идентификатор); если поз > 0 тогда
сЗнач.ПолучитьЗначение(поз, имяПоля); тЗнач.Идентификатор = имяПоля; конецЕсли; конецЦикла; // пока
// Добавляем данные для двух полей файла employee.dbf- ParentID и IsGroup,
// а затем располагаем добавленные строки вслед за первой строкой таблицы тЗнач тЗнач. НоваяСтрока(); тЗнач.Идентификатор = "ParentID"; тЗнач.Тип = "Число";
// Длина поля ParentID равна длине поля ID
тЗнач.НайтиЗначение("И", номСтроки, 1);
тЗнач.Длина = тЗнач.ПолучитьЗначение(номСтроки, 3);
тЗнач.Точность = 0;
тЗнач.Периодический = 0;
тЗнач. НоваяСтрока();
тЗнач.Идентификатор = "IsGroup";
тЗнач.Тип = "Логический"; тЗнач.Длина= 1; тЗнач.Точность - 0; тЗнач.Периодический = 0;
// Сдвигаем новые строки вверх колСтрок = тЗнач.КоличествоСтрок(); тЗнач.СдвинутьСтроку(2 - колСтрок, колСтрок); тЗнач.СдвинутьСтроку(2 - колСтрок, колСтрок); конецПроцедурЫ // ДляДБФ
// Создает на основе таблицы значений тЗнач поля DBF-файл процедура СоздатьПоляДБФ(тЗнач, дбф, пРекв)
// Формальный параметр пРекв = 1, если создается поле для периодического реквизита,
// или пРекв = 0 - в противном случае
перем имяПоля, типПоля;
дбф = СоздатьОбъект("ХВаse");
тЗнач.ВыбратьСтроки();
// Каждая строка таблицы значений тЗнач, отвечающая непериодическому реквизиту // справочника Сотрудники2, порождает одно DBF-поле пока тЗнач.ПолучитьСтроку() = 1 цикл
// Значения периодических реквизитов размещаются в отдельной таблице // (в нашем случае речь идет о периодическом реквизите Оклад) если (тЗнач.Периодический = 1) и (пРекв = 0) тогда
продолжить; // Пропускаем периодический реквизит
конецЕсли;
имяПоля = тЗнач.Идентификатор;
если (тЗнач.Тип = "Число") или (тЗнач.Тип = "Числовой") тогда типПоля = "N";
иначеЕсли тЗнач.Тип = "Строка" тогда типПоля = "S";
иначеЕсли тЗнач.Тип = "Дата" тогда типПоля = "D";
иначеЕсли тЗнач.Тип = "Логический" тогда типПоля = "L"; конецЕсли;
дбф.ДобавитьПоле(имяПоля, типПоля, тЗнач.Длина, тЗнач.Точность); конецЦикла; // пока конецПроцедуры // СоздатьПоляДБФ
процедура СоздатьСотр(дбф) // Создает файл employee. dbf
// Создаем два индекса
// Индекс Name обеспечит сортировку по значению поля Name дбф.ДобавитьИндекс("№те", "Name", 0, 0,"");
// Индекс Depart обеспечить сортировку по группам (поле Parentld),
// а в пределах групп по полю Name
дбф.ДобавитьИндекс("Depart", "trim(str(ParentId)) + Name", 0, 0, ""); дбф.СоздатьФайл("employee.dbf, "employee. cdx"); конецПроцедуры // СоздатьСотр
// Готовит таблицу значений тЗнач для создания файл salary.dbf процедура ДляДБФ2(тЗнач)
перем сЗнач, ин, значен, предст, номСтроки, тЗнач2, колСтрок;
// Модифицируем таблицу значений тЗнач в соответствии с табл. 9.2 //Для этого создадим список значений сЗнач, содержащий соответствия между // старыми и новыми значениями поля Идентификатор таблицы тЗнач // Строки таблицы значений тЗнач, не отраженные в списке сЗнач, удаляются сЗнач = СоздатьОбъект("СписокЗначений"); сЗнач.ДобавитьЗначение("Ы", "Id"); сЗнач.ДобавитьЗначение("OrderSal", "DocName"); сЗнач.ДобавитьЗначение("OrderSalId", "DocId"); сЗнач.ДобавитьЗначение("Salary", " Salary");
// Перемещаем строки, отраженные в списке сЗнач, в верх таблицы значений тЗнач // и делаем предписанные списком сЗнач замены имен для ин = 1 по сЗнач.РазмерСписка() цикл
значен = сЗнач.ПолучитьЗначение(ин, предст); номСтроки = 0;
тЗнач.НайтиЗначение(значен, номСтроки, 1);
// Изменения значения поля Идентификатор в соответствии со списком сЗнач тЗнач.УстановитьЗначение(номСтроки, 1, предст); тЗнач.СдвинутьСтроку(ин - номСтроки, номСтроки); конецЦикла; // для
// Выгружаем строки, отраженные в списке сЗнач, в таблицу тЗнач2 тЗнач2 = СоздатьОбъект("ТаблицаЗначений"); тЗнач.Выгрузить(тЗнач2, 1, сЗнач.РазмерСписка());
// Переносим таблицу тЗнач2 в таблицу тЗнач т3нач.3агрузить(т3нач2);
тЗнач2 = 0; // Более таблица значений тЗнач2 не нужна
// Добавляем в тЗнач строку для даты и перемещаем ее на вторую позицию таблицы
тЗнач.НоваяСтрока(); // Добавляем новую строку в таблицу значений
тЗнач.Идентификатор = "Date";
тЗнач.Тип = "Дата";
тЗнач.Длина = 0;
тЗнач.Точность = 0;
тЗнач.Периодический = 0;
// Ставим строку с датой на вторую позицию колСтрок = тЗнач.КоличествоСтрок(); тЗнач.СдвинутьСтроку(2 - колСтрок, колСтрок); конецПроцедуры // ДляДБФ2
процедура СоздатьОклад(дбф) // Создает файл salary.dbf
// Создаем один индекс
// Индекс IdDate обеспечит сортировку по дате в пределах заданного кода сотрудника дбф.ДобавитьИндекс("IdDate", "str(Id) + dtos(Date)", 0, 0,""); дбф.СоздатьФайл("salary.dbf, "salary. cdx"); конецПроцедуры // СоздатьОклад
// Заполняет файл employee.dbfи вызывает процедуру ПеренестиОклад, которая добавляет //данные в файл salaIy.dbfдля выбранного сотрудника процедура ПеренестиСотр(дбф, дбф2) перем сСотр_2, оп;
// Создаем объект типа Периодический для работы с файлом
оп = СоздатьОбъектС'Периодический");
сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2");
сСотр_2.ВыбратьЭлементы();
пока сСотр_2.ПолучитьЭлемент() = 1 цикл
дбф.Добавить(); // Новая запись в файле employee.dbf
дбф.Id = сСотр_2.Код;
дбф.PaгentId = сСотр_2.Родитель.Код;
дбф.ЕОгоир = сСотр_2.ЭтоГруппа();
дбф.№те = сСотр_2.Наименование;
дбф.Ed = сСотр_2.0бразование.Вид();
дбф.EdId = сСотр_2.0бразование.Код;
дбф.OгdeгEng = сСотр_2.ПриказПрием.Вид();
дбф.OгdeгEngId = сСотр_2.ПриказПрием.НомерДок;
дбф.OгdeгSal = сСотр_2.ПриказОклад.Вид();
дбф.ОМейаІИ = сСотр_2.ПриказОклад.НомерДок;
дбф.Calendaг = сСотр_2.Календарь.Вид();
дбф.3аписать(); // Сохраняем данные
// Если выбран сотрудник, а не группа если сСотр_2.ЭтоГруппа() = 0 тогда
// Добавляем данные об окладе текущего сотрудника в файл salary.dbf ПеренестиОклад(сСотр_2, оп, дбф2); конецЕсли; конецЦикла // пока конецПроцедуры // ПеренестиСотр
// Добавляет для сотрудника сотр записи в файл salary.dbf процедура ПеренестиОклад(сотр, оп, дбф) перем док;
// Прикрепляем ОП к периодическому реквизиту Оклад найденного сотрудника оп. ИспользоватьО бъект(" Оклад", сотр .Т екущийЭлемент());
// Позиционируемся перед первой записью истории окладов сотрудника оп.ВыбратьЗначения();
// Метод ПолучитьЗначение позиционирует ОП на следующей записи // периодического реквизита Оклад пока оп.ПолучитьЗначение() = 1 цикл
дбф.Добавить(); // Новая запись в файле salary.dbf
дбф.И = сотр.Код; // Код сотрудника
дбф^Ыгу = оп.Значение; // Значение и ДатаЗнач- атрибуты ОП
дбф.Date = оп.ДатаЗнач;
// Документ, вызвавший изменение оклада док = оп.ТекущийДокумент(); если док.Выбран() = 1 тогда дбф.DocName = док.Вид(); дбф.БоеИ = док.НомерДок; иначе
дбф.DocName = ""; дбф.DocId = 0; конецЕсли;
дбф.3аписать( ); // Сохраняем данные
конецЦикла; // пока конецПроцедуры // ПеренестиОклад
 |
|
Рис. 9.4. Таблица тЗнач, преобразованная в процедуре ДляДБФ |
 |
|
Рис. 9.5. Таблица тЗнач, преобразованная в процедуре ДляДБФ2 |
 |
|
Рис. 9.6. Фрагмент файла employee.dbf |
 |
|
Рис. 9. 7. Фрагмент файла salary.dbf |
Замечания:
1. Поскольку путь к файлам не указан, то они будут созданы в каталоге пользователя, из которого запускается обработка Проба. Имя каталога возвращается встроенной функцией КаталогПользователя.
2. С файлом, на который ссылается объект XBase, может одновременно работать только один пользователь. Поэтому если есть не равная нулю вероятность одновременного доступа к одному и тому же DBF-файлу более одного пользователя, то с объектом XBase нужно соответствующим образом использовать конструкцию Попытка.
9.3.2. АТРИБУТЫ И МЕТОДЫ ОБЪЕКТА XBASE
9.З.2.1. АТРИБУТЫ ОБЪЕКТА XBASE
Объект XBase имеет два вида атрибутов: поля DBF-файла и его ключи.
Атрибут Поле позволяет по имени поля читать и изменять значение поля текущей записи DBF-файла. Число таких атрибутов равно числу полей файла, на который ссылается объект XBase.
Пример. В окне сообщений выводится значение поля Name 3-й записи файла ет-ployee.dbf. В соответствии с рис. 9.6 в этом поле хранится строка Агальцов Юрий Алексеевич. Затем меняется значение 6-й записи файла employee.dbf.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф, ин;
ОчиститьОкноСообщенийО; дбф = СоздатьОбъект(''ХВазе''); дбф.ОткрытьФайл(''emplоуее.dbf'); если дбф.Открыта( ) = 0 тогда
Предупреждение("Файла employee.dbf в каталоге пользователя нет."); возврат; конецЕсли;
// Перемещаемся на третью запись файла employee.dbf
// После того как файл открыт, он позиционируется на своей первой записи
дбф.Перейти(З);
, Сообщить(дбф.Name); // Напечатает Агальцов Юрий Алексеевич
// Перемещаемся на шестую запись файла employee.dbf дбф.Перейти(б);
дбф-Name = "Бараненков Иван Несторович";
дбф.3аписать( ); // Не забываем записать изменения в файл
Предупреждение('Тотово."); конецПроцедуры // Выполнить
Замечание. Файл employee.dbf изменялся при закрытом индексном файле ет-ployee.cdx, поэтому индексы этого файла, в которые входит в качестве выражения имя поля Name, не отвечают в полной мере файлу employee.dbf. Следовательно, для поиска по индексу файл employee.cdx необходимо предварительно переиндексировать.
Атрибут Ключ является объектом агрегатного типа. Число компонентов объекта равно числу полей DBF-файла, на который ссылается объект XBase. Имя компонента атрибута Ключ составляется по следующей схеме:
дбф.Ключ.<имя поля DBF-файла>
Атрибут применяется для задания значений, употребляемых при вычислении индексного выражения. Полученное значение индексного выражения используется методом НайтиПоКлючу в качестве ключа поиска. Этот метод осуществляет поиск по текущему индексу, применяя в качестве ключа выражение, составленное из значений компонентов атрибута Ключ. Например, с файлом employee.dbf используется индекс
Depart, вычисляемый по выражению TRIM(STR(ParentId)) + Name. Чтобы задать это выражение в программе 1С, необходимо определить два компонента ключа: Ключ. ParentI d и RnKiq.Name.
Пример 1. Задаются ключи, обеспечивающие получение значения индексного выражения индекса Depart, равное 12Бараненков.
дбф.Ключ.ParentId = 12; // Значение для TRIM(STR(ParentId))
дбф.Ключ.Name = "Бараненков"; // Значение для Name
// Индексное выражение TRIM(STR(12)) + "Бараненков" вернет 12Бараненков
Пример 2. В файле employee.dbf ищется по индексу Name, индексное выражение которого равно Name (см. процедуру СоздатьСотр в разд. 9.3.1.2), ключ, равный Агальцов Юрий Алексеевич.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перемдбф;
ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВаве"); дбф.ОткрытьФайл(''етр1оуее.dbf', "employee.cdx"); если дбф.Открыта() = 0 тогда
Предупреждение("Файла employee. dbf и/или файла employee.cdx | в каталоге пользователя нет."); возврат; конецЕсли;
дбф.ТекущийИндекс ("Name"); дбф.Ключ.Name = "Агальцов Юрий Алексеевич"; дбф. НайтиПоКлючу( 1);
Сообщить(дбф.Name); // Напечатает Агальцов Юрий Алексеевич
конецПроцедуры // Выполнить
Замечание. При таком использовании метода НайтиПоКлючу можно задать неполное значение ключа, например
дбф.Ключ.Name = "Ага”; дбф.НайтиПоКлючу(І);
Сообщшъ(дбф.Name); // Напечатает Агальцов Юрий Алексеевич
Пример 3. В файле employee.dbf ищется по индексу Depart, индексное выражение которого равно TRIM(STR(ParentId)) + Name (см. процедуру СоздатьСотр в разд. 9.3.1.2), Ключ, равный TRIM((STR(12)) + "Бараненков".
Процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф;
ОчиститьОкноСообщений(); дбф = СоздаIъОбъекг("ХВasе"); дбф.ОткрытьФайл("етр1оуее^Ь^ "employee.cdx"); если дбф.Открыта() = 0 тогда
Предупреждение("Файла employee.dbf и/или файла employee.cdx | в каталоге пользователя нет."); возврат;
дбф.ТекущийИндекс('^ераг1:");
дбф.Ключ.Раі-entId = 12; //Значение для TRIM(STR(ParentId))
дбф.Ключ^аше = "Бараненков"; // Значение для Name
дбф.НайтиПоКлючу(1); // Ключ равен 12Бараненков
Сообщить(дбф.Naшe); // Напечатает Бараненков Иван Несторович
конецПроцедуры // Выполнить
9.3.2.2. МЕТОДЫ ОБЪЕКТА XBASE
Приводятся в табл. 9.6.
|
|
Таблица 9.6
Методы объекта XBase |
|
Метод |
Описание |
дбф.СоздатьФайл
(ОВ?файл,
[СБХфайл]); |
Создает файл базы данных (DBF-файл) и, если задан второй параметр, индексный файл (CDX-файл). Имена файлов задаются символьными параметрами DBFфайл и СБХфайл. Если имя не содержит пути, то файлы будут созданы в каталоге пользователя. Если файлы с указанными именами на диске имеются, то они будут заменены на новые |
дбф.ОткрытьФайл
(ОВ?файл,
[СБХфайл],
[флагЧтения]); |
Открывает DBF-файл и, если задан второй параметр, индексный файл. Тип параметров DBFфайл и СБХфайл -символьный. Файлы открываются только для чтения, если флаг Чтения = 1, и доступны для редактирования, если флагЧтения = 0. По умолчанию флагЧтения = 0 |
|
флаг = дбф.Открыта(); |
Вернет 1, если DBF-файл открыт, или 0-в противном случае |
|
дбф.ЗакрытьФайл(); |
Закрывает ранее открытый или созданный DBF-файл. Игнорируется, если DBF-файл не был открыт или создан до употребления метода. DBF-файл при нормальном завершении программы будет закрыт и без вызова метода |
|
дбф. ОчиститьФайл (); |
Выполняет физическое удаление всех записей DBF-файла. После выполнения метода удаленные записи восстановить нельзя |
|
дбф.Сжать( ); |
Удаляет физически записи DBF-файла, имеющие пометку удаления |
|
дбф.Переиндексировать(); |
Выполняет переиндексацию индексного файла. Применяется для восстановления порядка следования записей в индексном файле, который может быть нарушен при аварийном завершении программы или при модификации DBF-файла при закрытом индексном файле |
|
режимТек = дбф.Показывать Удаленные ([режим]); |
Устанавливает режим доступа к записям, имеющим пометку удаления. Если режим = 1, то такие записи доступны, и недоступны, если режим = 0. По умолчанию режим = 0. Возвращает текущее значение режима |
|
Метод |
Описание |
|
флаг = дбф.Первая(); |
Перемещает DBF-файл на первую запись. Если задан текущий индекс, то первой является запись, отвечающая при возрастающем индексе его наименьшему значению или наибольшему - при убывающем индексе. Вернет 1 в случае успеха или 0 при неудаче |
|
флаг = дбф.Последняя(); |
Перемещает DBF-файл на последнюю запись. Если задан текущий индекс, то последней является запись, отвечающая при возрастающем индексе его наибольшему значению или наименьшему - при убывающем индексе. Вернет 1 в случае успеха или 0 при неудаче |
|
флаг = дбф.Следующая(); |
Перемещает DBF-файл на следующую запись. Если задан текущий индекс, то порядок записей определяется этим индексом. Вернет 1 в случае успеха или 0 при неудаче |
|
флаг = дбф.Предыдущая(); |
Перемещает DBF-файл на предшествующую запись. Если задан текущий индекс, то порядок записей определяется этим индексом. Вернет 1 в случае успеха или 0 при неудаче |
|
нЗап = дбф.НомерЗаписи(); |
Возвращает номер записи DBF-файла. Вернет 0, если файл позиционирован перед первой или вслед за последней записью |
|
дбф.Перейти(нЗап); |
Перемещает DBF-файл на запись, имеющую номер нЗап. Методу всегда доступны записи, имеющие пометку удаления. Если нЗап < 0 или нЗап > дбф.КоличествоЗаписей(), то возникнет информационная ошибка |
|
флаг = дбф.ВКонце(); |
Вернет 1, если DBF-файл находится вслед за своей последней записью, или О-в противном случае |
|
флаг = дбф.ВНачале(); |
Вернет 1, если DBF-файл находится перед своей первой записью, или О-в противном случае |
|
имяИндТек =дбф.Текущий Ивдекс([ИмяИнд]); |
Устанавливает, если задан параметр имяИнд, текущий индекс. Возвращает значение текущего индекса до вызова метода. Параметр имяИнд и результат имеют символьный тип |
флаг = дбф.Найти
(ключ, [режим]); |
Ищет ключ, используя текущий индекс. Вернет 1 в случае успеха или 0 при неудаче. При успешном поиске позиционирует файл на найденной записи. Если числовой параметр режим есть:
• 0, то ищется запись, индексное выражение которой точно равно ключу;
• 1, то ищется запись, индексное выражение которой больше или равно ключу;
• 2, то ищется запись, индексное выражение которой больше ключа;
• -1, то ищется запись, индексное выражение которой меньше или равно ключу;
• -2, то ищется запись, индексное выражение которой
меньше ключа.
По умолчанию режим = 0. Используется для простых индексов |
|
Метод |
Описание |
|
флаг = дбф.НайтиПоКлючу ([режим]); |
Ищет, используя текущий индекс, ключ, заданный компонентами атрибута Ключ. Описание метода такое же, как и метода Найти. Используется для любых индексов |
|
значение = дбф.Получить ЗначениеПоля (имяПоля\ номерПоля); |
Возвращает значение текущей записи в поле, заданным параметром имяПоля^омерПоля. Параметр имяПоля - это строка с именем поля. Параметр номерПоля - это номер поля. Возникнет информационная ошибка, если имяПоля (номерПоля) содержит несуществующее имя (несуществующий номер) или если файл находится перед первой или за последней записью |
|
дбф.УстановитьЗначение Поля(имяПоля \ номерПоля, значение); |
Устанавливает значение текущей записи в поле, заданным параметром имяПоля^омерПоля. Дальнейшую информацию о методе см. в описании метода ПолучитьЗначениеПоля. Для сохранения изменений, если не задан режим автосохранения, применяется метод Записать |
|
дбф.Добавить(); |
Добавляет пустую запись. Для ее сохранения в DBF-файле применяется, если не задан режим автосохранения, метод
Записать |
|
дбф.Скопировать(); |
Добавляет запись, которая является копией текущей записи. Для сохранения добавленной записи в DBF-файле применяется, если не задан режим автосохранения, метод
Записать |
режимТек =
дбф.АвтоСохранение
([режим]); |
Задает, если режим = 1, автоматическое сохранение (АС) измененных записей базы данных. В этом случае применение метода Записать избыточно. Для отмены изменений применяется метод Отменить. Если режим = 0, АС измененных записей не выполняется; изменения сохраняются методом Записать. Возвращает существовавший до вызова метода режим АС |
|
дбф.3аписать( ); |
Заносит изменения текущей записи в базу данных. Если метод не применен и не задано АС, смена позиции файла или его закрытие приведет к потере введенных данных |
|
дбф.Отменить(); |
Отменяет запись в базу данных изменений, выполненных в режиме автосохранения. Не отменяет действие метода Записать |
|
дбф.Удалить(); |
Проставляет пометку удаления текущей записи |
|
флаг = дбф.ЗаписьУдалена(); |
Возвращает 1, если запись имеет пометку удаления, или 0 -в противном случае |
|
дбф.Восстановить(); |
Снимает пометку удаления текущей записи |
|
дбф. Очистить(); |
Очищает текущую запись, то есть в символьное поле заносится строка нулевой длины, в числовое - 0, в логическое - .F., а в поле типа Дата - пустая дата. Изменения сохраняются, если задан режим автосохранения или если вслед за методом Очистить применен метод Записать |
числоЗап =
дбф.КоличествоЗаписей(); |
Возвращает число записей в DBF-файле |
|
Метод |
Описание |
|
числоПолей = дбф.Количество Полей(); |
Возвращает число полей DBF-файла |
|
числоИнд = дбф. Количество Индексов(); |
Возвращает число индексов открытого индексного файла |
|
дбф.ОписаниеПоля (номерПоля, имяПоля, тип, длина, точндсть); |
Возвращает для поля, имеющего номер, равный параметру номерПоля, имя, тип, длину иточность поля в соответствующие параметры метода |
дбф.ОписаниеИндекса
(номерИнд, имяИнд, выражение, уник, убыв, фильтр); |
Возвращает для индекса, имеющего номер, равный параметру номерИнд, имя, индексное выражение, флаги уникальности и убывания, а также фильтр в соответствующие параметры метода. Параметр уник равен единице, если индекс уникальный, или нулю - в противном случае. Параметр убыв равен единице, если индекс сортируется по убыванию значений индексного выражения, и равен нулю, если по возрастанию |
|
номПоля = дбф.НомерПоля (имяПоля); |
Возвращает номер поля по его имени |
|
дбф.ДобавитьПоле(ИмяПоля, тип, длина, точность); |
Добавляет в структуру DBF-файла поле, имя которого определено символьным параметром имяПоля, а тип, длина и точность задаются соответствующими параметрами метода. Параметр точность имеет смысл только для числового поля. Параметр тип равен:
• 1 или "N", если добавляется числовое поле;
• 2 или "S", если добавляется символьное поле;
• 3 или "D", если добавляется поле типа Дата;
• 4 или "L", если добавляется логическое поле;
• 5 или "F", если добавляется числовое поле.
После добавления всех полей употребляется метод СоздатьФайл |
дбф.ДобавитьИндекс
(имяИнд, выражение, уник, убыв, фильтр); |
Добавляет в структуру индексного файла индекс, имя которого определено символьным параметром имяИнд, а индексное выражение, флаги уникальности, убывания и фильтр индекса задаются соответствующими параметрами метода. Параметры выражение и фильтр имеют символьный тип. Смысл параметров уник и убыв см. в методе ОписаниеИндекса. После добавления всех индексов употребляется метод СоздатьФайл или
СоздатьИндексныйФайл |
дбф.СоздатьИндексныйФайл
(имяФайла); |
Создает индексный файл имяФайла, содержащий все индексы, сконструированные до вызова метода СоздатьИндексныйФайл методом ДобавитьИндекс. Тип параметра имяФайла - символьный. Также индексный файл может быть создан и методом СоздатьФайл |
|
Метод |
Описание |
кодСтрТек - дбф.Кодовая
Страница( [кодСтр]); |
Устанавливает, если кодСтр = 0, Windows-кодовую страницу или DOS-кодовую страницу, если кодСтр = 1. Возвращает существовавшую до вызова метода кодовую страницу.
По умолчанию кодСтр = 1 |
|
код = дбф.КодОшибки(); |
Возвращает код последней ошибки, возникшей при исполнении метода объекта XBase |
|
|
Замечания: |
1. Префикс дбф, употребленный с методами объекта XBase, может быть произвольным.
2. Фильтр индекса является логическим выражением, составленным по правилам, изложенным в разд. 9.3.1.3. В индексном файле, если фильтр задан, есть ссылка только на те записи DBF-файла, для которых выражение фильтра истинно. Тогда, если индекс с фильтром является текущим, записи, на которых нет ссылок в и н-дексном файле, пользователю недоступны. Отсутствие фильтра равнозначно фильтру, возвращающему для всех записей .Т. (истина).
Пример 1. Выводятся коды (табельные номера) всех сотрудников, имеющих оклад, равный 2900 руб.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф;
ОчистшъОкноСообщенийО; дбф = СоздатьОбъект("ХВаsе"); дбф.ОткрытьФайп("8а1аіу.йЬГ); если дбф.Открыта() = 0 тогда
Предупреждение("Файла salary.dbf в каталоге пользователя нет."); возврат; конецЕсли;
// Переход в начало файла salary.dbf; в данном примере метод может быть опущен,
// поскольку после открытия файл и так находится на своей первой записи
дбф.Первая();
пока дбф.ВКонце() = 0 цикл
если дбф.Sa1aIy = 2900 тогда Сообщить(цбф.И); конецЕсли; дбф.СледующаяО; конецЦикла; // пока конецПроцедуры // Выполнить
Результат:
111
209
Пример 2. Выводятся ФИО всех сотрудников, фамилия которых начинается с буквы Б.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф;
ОчиститьОкноСообщенийО; дбф = СоздатьОбъект("ХВаse"); дбф.ОткрытьФайл("етр1оуееЛЬГ, "employee.cdx");
если дбф.Открыта( ) = 0 тогда
Предупреждение("Файла employee.dbf и/или файла employee.cdx | в каталоге пользователя нет."); возврат; конецЕсли;
дбф.ТекущийИндекс("Name");
// Ищем запись, равную или большую символа "Б" если дбф.Найти("Б", 1) = 1 тогда
пока Лев(дбф.Name, 1) = "Б" цикл Сообщить(дбф.Name); дбф.Следующая(); конецЦикла; // пока иначе
Предупреждение
("Сотрудников, фамилия которых начинается на букву Б, в файле нет."); конецЕсли;
конецПроцедуры // Выполнить Результат:
Бараненков Иван Несторович Безверхний Игорь Петрович
Пример 3. Оклад сотрудника, табельный номер (код) которого равен 209, увеличивается на 500 руб. Для нового оклада в файл salary.dbfдобавляется запись.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф, окл;
ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВаse"); дбф.ОткрытьФайл("salary.dbf'," salary.cdx"); если дбф.Открыта() = 0 тогда
Предупреждение("Файла salary.dbf и/или файла salary.cdx | в каталоге пользователя нет."); возврат; конецЕсли;
дбф.ТекущийИндекс("IdDate"); дбф.Ключ.Ы = 209;
// Ищем запись, большую str(209)
// Помним, что индексное выражение - это STR(Id) + DTOS(Date) если дбф.НайтиПоКлючу(2) = 1 тогда
// Перемещаемся на последнее значение оклада сотрудника с кодом 209 пока дбф.И = 209 цикл дбф.Следующая(); конецЦикла; // пока
дбф.Предыдущая(); // Шаг назад
окл = дбф.ПолучитьЗначениеПоля("Salary");
// или, используя атрибут: окл = дбф.Salary; дбф.Добавить();
дбф.УстановитьЗначениеПоля("И", 209);
дбф .УстановитьЗначениеПоля("Date", ТекущаяДата());
дбф.УстановитьЗначениеПоля("Salaly", окл + 500);
// или, используя атрибуты:
// дбф.И= 209; дбф.БаІе = ТекущаяДата(); дбф.8аіагу = окл + 500; дбф.3аписать();
ПредупреждениеС'Тотово.");
иначе
ПредупреждениеС'Сотрудника с кодом 209 в файле нет."); конецЕсли;
конецПроцедуры // Выполнить
Пример 4. Копируется и записывается в файл salary.dbf его последняя запись.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф;
ОчиститьОкноСообщений(); дбф = СоздатьОбъектС'ХВаБе"); дбф. ОткрытьФайл('^1агу. dbf"); если дбф.Открыта() = 0 тогда
Предупреждение("Файла salary.dbf в каталоге пользователя нет."); возврат; конецЕсли;
дбф.АвтоСохранение(1); // Будем обходиться без метода Записать
дбф.Последняя(); . // Переход на последнюю запись
дбф.Скопировать( ); // Добавляем копию последней записи
Предупреждение('Тотово."); конецПроцедуры // Выполнить
Пример 5. Выводятся описания всех полей и индексов файла salary.dbf.
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф, ин, имяПоля, тип, длина, точность; перем имяИнд, выражение, уник, убыв, фильтр;
ОчиститьОкноСообщений(); дбф = СоздатъОбъектС'ХВазе"); дбф.ОткрытьФайп("sa1ary.dbf," salary.cdx"); если дбф.Открыта( ) = 0 тогда
Предупреждение("Файла salary.dbf и/или файла salary.cdx | в каталоге пользователя нет."); возврат; конецЕсли;
Сообщить("Описание полей файла salary.dbf:"); для ин = 1 по дбф.КоличествоПолей() цикл
дбф.ОписаниеПоля(ин, имяПоля, тип, длина, точность);
Сообщить(имяПоля + "" + тип + "" + длина + "" + точность); конецЦикла; // для
Сообщить("Описание индексов файла salary.dbf:"); для ин = 1 по дбф.КоличествоИндексов( ) цикл
дбф.ОписаниеИндекса(ин, имяИнд, выражение, уник, убыв, фильтр); Сообщить(имяИнд + " " + выражение + " " + уник + " " + убыв + " " + фильтр); конецЦикла; // для конецПроцедуры // Выполнить
Результат:
Описание полей файла salary. dbf:
ID 1 50 DATE 3 8 0 DOCNAME 2 15 0 DOCID 1 5 0 SALARY 1 10 2
Описание индексов файла salary. dbf:
IDDATE STR(id)+DTOS(date) 0 0
|
Пример 6. Содержимое произвольного DBF-файла выводится в таблицу значений. Диалог формы, содержащей таблицу значений, оформим в соответствии с рис. 9.8. |
 |
|
Рис. 9.8. Таблица значений для записей DBF-файла В заголовке таблицы значений будем выводить значение выражения "Состав файла " + имяФайла |
которое зададим в диалоге как формулу элемента диалога Текст.
// Вводим переменную модуля для ее использования в диалоге перем имяФайла;
процедура ПоказатьДБФ(дбф, имяФайла) далее
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф, флаг, папка;
ОчиститьОкноСообщений();
// Открываем диалог для выбора DBF-файла // В качестве примера выберем файл employee.dbf
флаг = ФСВыбратъФайл(0, имяФайла, папка, "Выберите файл"," | *.DBF"); если флаг = 0 тогда возврат; конецЕсли;
дбф = СоздатьОбъект("ХВаsе"); дбф.ОткрытьФайл(папка + имяФайла); если дбф.Открыта() = 0 тогда
Предупреждение("Не удалось открыть файл " + имяФайла); возврат; конецЕсли;
// Отобразим DBF-файл имяФайла в таблице значений // Результат приведен на рис. 9.9 ПоказатьДБФ(дбф, имяФайла); конецПроцедуры // Выполнить
// Выводит записи DBF-файла имяФайла в таблицу значений процедура ПоказатьДБФ(дбф, имяФайла)
перем ин, имяПоля, тип, длина, точность, номСтроки;
// Формируем столбцы таблицы значений и устанавливаем их параметры для ин = 1 по дбф.КоличествоПолей() цикл
дбф.ОписаниеПоля(ин, имяПоля, тип, длина, точность); тЗнач.НоваяКолонка(имяПоля, тип);
тЗнач.УстановитьПараметрыКолонки(ин, тип, длина, точность,, мин(10, длина)); конецЦикла; // для
// Заголовок таблицы значений диалога загТЗнач = "Состав файла " + имяФайла;
// Заполняем таблицу значений тЗнач данными из DBF-файла
дбф.Первая(); // Переходим на первую запись файла
номСтроки = 0;
пока дбф.ВКонце() = 0 цикл // Пока не достигнут конец файла
номСтроки = номСтроки + 1; тЗнач.НоваяСтрока(номСтроки); для ин = 1 по дбф.КоличествоПолей() цикл
тЗнач.УстановитьЗначение(номСтроки, ин, дбф.ПолучитьЗначениеПоля(ин)); конецЦикла; // для дбф. Следующая(); конецЦикла; // пока конецПроцедуры // ПоказатьДБФ
 |
|
Рис. 9.9. Файл employee.dbf в таблице значений |
Замечание. Подобного рода процедуру всегда удобно иметь под рукой для оперативного просмотра используемых DBF-файлов. Напомним, что таблицу значений также можно отобразить, применив метод ВыбратьСтроку.
Пример 7. Выводятся коды сотрудников, оклад которых больше 3000 руб. Для получения результата в дополнение к существующему создается индекс с выражением Salary и фильтром Salary > 3000.
перем имяФайла;
процедура Выполнить() // Связана с кнопкой Пуск обработки Проба
перем дбф, флаг, папка;
ОчиститьОкноСообщенийО; дбф = СоздатъОбьект(''ХВаsе''); дбф.ОткрытьФайл("salary.dbf'); если дбф.Открыта( ) = 0 тогда
Предупреждение("Файла salary.dbf в каталоге пользователя нет."); возврат; конецЕсли;
// Индекс IdDate обеспечит сортировку по дате в пределах заданного кода сотрудника дбф.ДобавитьИндекс("ІёБа1е", "str(Id) + dtos(Date)", 0, 0, "");
// Индекс Salary обеспечит сортировку по окладу дбф.ДобавитьИндекс("Salary", "Salary", 0, 0, "Salary > 3000"); дбф.СоздатьИндексныйФайл("Salaryxdx"); дбф.ТекущийИндекс("Salary");
дбф.Первая(); // Переход в начало файла
// Вывод результата. Доступны только те записи, у которых Salary > 3000 Сообщить("Коды сотрудников, оклад которых более 3000 руб."); пока дбф.ВКонце() = 0 цикл // Пока не достигнут конец файла
Сообщить(Строка(дбф.И) + Символ Табуляции +
"(оклад сотрудника равен " + Строка(дбф.Salary) + " руб.)"); дбф.Следующая(); конецЦикла; // пока имяФайла = "salary.dbf";
ПоказатьДБФ(дбф, имяФайла); // Код процедуры ПоказатьДБФ см. выше
конецПроцедуры
Результат работы процедуры ПоказатьДБФ см. на рис. 9.10.
Результат:
Коды сотрудников, оклад которых более 3000 руб.
301 (оклад сотрудника равен 3100 руб.)
122 (оклад сотрудника равен 3200 руб.)
2010 (оклад сотрудника равен 3200 руб.)
302 (оклад сотрудника равен 3200 руб.)
303 (оклад сотрудника равен 3200 руб.)
 |
|
Рис. 9.10. Файл salary.dbf под действием снабженного фильтром индекса Salary |
9.3.2.3. ВЫРАЖЕНИЯ ИНДЕКСА И ФИЛЬТРА
Выражения, употребляемые в методе -ДобавитьИндекс, для индекса и фильтра, могут содержать в качестве операндов имена полей, константы и вызовы функций. Аргументами функций, применяемых в выражениях, могут также быть имена полей, константы и вызовы, функций. Например, в методе
дбф.ДобавитьИндекс("Depart", "trim(str(ParentId)) + Name", 0, 0,"");
индексное выражение содержит функции TRIM, STR и имена полей DBF-файла ParentId и Name, а в методе
дбф.ДобавитьИндекс("Salary", "Salary", 0, 0, "Salary > 3000");
выражение фильтра включает имя поля Salary и числовую константу 3000.
В качестве логических констант используются .Т. и .F. для обозначения соответственно констант истина и ложь.
Константы типа Дата задаются в фигурных скобках.
Регистр написания операндов выражения не имеет значения.
Выражение индекса может иметь числовой, символьный, логический тип или тип Дата.
Выражение фильтра, если задано, должно иметь логический тип.
В выражениях индекса и фильтра могут применяться приведенные в табл. 9.7 операции (они расположены в таблице в порядке убывания их приоритета; операции с одним приоритетом размещаются в одной строке таблицы).
Таблица 9.7
Операции выражений индекса и фильтра |
|
Операции |
Значения |
|
Арифметические операции |
|
- |
Унарный минус |
|
** или Л |
Возведение в степень |
|
*,/ |
Умножение, деление |
|
_ |
Сложение, вычитание |
|
Символьные операции |
|
+ |
Объединение (конкатенация) |
|
- |
Объединение 2 (конкатенация 2) |
|
Операции отношения |
|
=, <> или #,<,>,<=,>= $ |
Равно, не равно, меньше, больше, меньше или равно, больше или равно, содержит |
|
Логические операции |
|
.NOT. |
Логическое НЕ (отрицание) |
|
.AND. |
Логическое И |
|
.OR. |
Логическое ИЛИ |
|
Замечания:
1. Все операции, кроме унарного минуса, являются двуместными (бинарными), то есть употребляются между двумя операндами.
2. Выражения вычисляются слева направо в порядке, определяемом приоритетом операций. Часть подвыражения, заключенная в круглые скобки, вычисляется в первую очередь. Более подробно о вычислении выражений см. в разд. 2.6.
3. Унарный минус имеет больший приоритет, чем иные арифметические (и другие) операции. Например, выражение
вернет, так же как и выражение (-2)**2 число 4.
4. Символьная операция в отличие от операции +, перемещает завершающие пробелы первого операнда в конец результата, например, выражение
"3 п "+"робела"
вернет строку "3 п робела", а выражение "3 п " - "робела"
- строку "3 пробела ".
5. Операция $ применяется только с символьными операндами. Выражение отношения с операцией $ вернет .Т., если первый операнд выражения является подстрокой второго, или .F. - в противном случае. Например выражение
"БВ” $"АБВГ"
вернет .Т., а выражение
"БГ" $ "АБВГ" вернет .F..
6. В отличие от 1С в выражениях индекса и фильтра нельзя смешивать символьные и арифметические операнды. Так, вместо
"АБС” + 2
чтобы получить строку "АБС2", нужно употребить выражение "АБС" + trim(str(2)) или выражение "АБС" + str(2', 1)
В выражениях индекса и фильтра используются приведенные в табл. 9.8 функции.
Таблица 9.8
Функции для выражений индекса и фильтра |
|
Функция |
Что возвращает |
Тип
результата |
|
DATE() |
Текущую дату, например 01/14/02 |
Дата |
|
DAY(dama) |
День месяца, заданного параметром дата |
Число |
|
DTOC(dama) |
Символьное представление даты, заданной параметром дата |
Строка |
|
DTOS(dama) |
Символьное представление даты, заданной параметром дата, в виде ГГГГММДД |
|
|
IIF(nBbip, выр1, выр2) |
Результат выражения выр1, если истинно логическое выражение лВыр, или результат выражения выр2 -в противном случае. Выражения выр1 и выр2 могут быть произвольного типа |
Совпадает
с типом выр1 или выр2 |
|
БТЯІМ(строка) |
Строку, в которой удалены ведущие пробелы параметра строка |
Строка |
|
|
Функция |
Что возвращает |
Тип
результата |
|
MONTH^a) |
Номер месяца в году, заданного параметром дата |
Число |
|
STOD(cmpo^) |
Дату в формате ГПТММДД |
Дата |
|
STR(число, [длина], [десСим]) |
Символьное представление параметра число в виде строки длиной длина, содержащей десСим десятичных символов. Если параметры длина и десСим опущены, то результирующая строка имеет 10 символов и не содержит десятичной части. Если опущен параметр десСим, то результат также не содержит десятичной части |
Строка |
SUBSTR^^^ra,
начПоз,
[числоСим]) |
Подстроку параметра строка, начинающуюся с позиции начПоз и содержащую числоСим последующих символов. Если последний параметр опущен, то результатом будут все символы от позиции начПоз до конца строки строка |
|
|
TIME() |
Текущее время в формате ЧЧ:ММ:СС |
" |
|
TRIM(строка) |
Строку, в которой удалены завершающие пробелы параметра строка |
|
|
UPPER(строка) |
Строку, преобразованную в верхний регистр |
" |
|
VAL(строка) |
Числовое представление параметра строка |
Число |
|
YEARC^'ra) |
Номер года, заданного параметром дата |
" |
Замечание. Параметры функций являются выражениями. Причем параметр дата является выражением типа Дата; параметр строка - символьное выражение; параметры число, длина, десСим, начПоз и числоСим - числовые выражения.
Примеры употребления функций приведены в табл. 9.9.
Примеры вызова функций для выражений индекса и фильтра
|
Таблица 9.9 |
|
Пример вызова |
Результат |
Тип |
|
day(date()) |
14 |
Числовой |
|
month(date()) |
1 |
" |
|
year(date()) |
2002 |
" |
|
time() |
16:08:46 |
Символьный |
|
dtoc(date()) |
01/14/02 |
" |
|
dtos(date()) |
20020114 |
" |
k = 5
IIF(k > 8, 2 * 3, "A" + "B") |
6 |
Числовой |
k = 9
IIF(k > 8, 2 * 3, "A" + "B") |
AB |
Символьный |
|
ltrim(" ABC") |
ABC |
" |
|
trim(" ABC ") + "D" |
ABCD |
" |
|
Бухгалтерия: Автоматизация - Система 1С