Бартеньев О. В. 1С:Предприятие: программирование для всех. Базовые объекты и расчеты на одной дискете. - М.: Диалог-МИФИ...
438 downloads
474 Views
6MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Бартеньев О. В. 1С:Предприятие: программирование для всех. Базовые объекты и расчеты на одной дискете. - М.: Диалог-МИФИ, 2005. - 464 с.
Рассматриваются элементы встроенного языка.программирования 1С:Предприятие и методы написания программ на этом языке. Также на примере компонента Расчеты демонстрируется технология построения заказных, использующих модели 1С оптимальных систем. В качестве критериев оптимизации выступают быстродействие, надежность программ, уровень защищенно сти данных и др. Дополнительно приводятся справочные сведения об использованных в пособии объектах 1С и их методах. Включенные в пособие примеры программ и компоненты предложен ной облегченной версии системы размещены на дискете, которую можно приобрести в издательстве. Предназначено для всех лиц, желающих освоить или усовершенствовать технику разработки программ на основе моделей 1С:Предприятие, а также для руководящих работников, имеющих потребность расширить свои знания относительно характера и способов построения систем ав томатизации деятельности административно-хозяйственных подразделений организаций различ ного профиля.
Учебно-справочное издание Бартеньев Олег Васильевич 1С:Предприятие: программирование для всех Базовые объекты и расчеты на одной дискете
ПРЕДИСЛОВИЕ Широкое распространение системы 1С:Предприятие (далее вместо длинного на звания "Система 1С:Предприятие" будем, где это возможно, употреблять более корот кие названия 1С и система) вызывает к жизни разнообразную литературу, освещаю щую различные стороны программы. Имеющаяся на прилавках магазинов литература содержит преимущественно сведения для пользователей системы - работников бухгал терии, отделов снабжения, сбыта и иных административно-хозяйственных подразде лений предприятия. Однако для функционирования системы одних пользователей недостаточно: с сис темой должен постоянно работать ее сопровождающий специалист, имеющий обшир ный круг обязанностей как по администрированию программы, так и по ее усовершен ствованию. Возможно, вы хотите приобрести такие навыки - тогда эта книга для вас. Возмож но, вы озабочены поиском такого специалиста, тогда в этой книге есть ответ на воп рос, какими профессиональными навыками должен обладать подбираемый вами ра ботник. Если же вы реализуете средствами 1С некоторый проект, вам тоже полезна эта книга, поскольку всегда не будет лишним сопоставить различные подходы и поста раться выбрать в результате наилучший. В книге решаются, по сути, три задачи. Первая - оснастить лиц, желающих нау читься писать программы в 1С, необходимыми приемами и сведениями. Вторая - рас смотреть оптимизационный подход к построению или модификации системы и, реали зуя его, решать первую задачу. И третья - снабдить ответственных лиц информацией об объеме и характере проблем, которые приходится улаживать при настройке систе мы и ее сопровождении. Характер изложения таков, что после описания базовых понятий раскрываются этапы реализации облегченной системы расчета зарплаты на основе моделей 1С (дру гие задачи, например бухгалтерии, строятся на аналогичных моделях). Далее обсуж даются вопросы эффективности системы и комплекс мер по ее повышению. Попутно излагаются справочные сведения о встроенном языке программирования системы 1С:Предприятие 7.7. На вопрос, зачем взамен поставляемых фирмой средств разрабатывать альтернати вы, ответ известен. Практически на любом предприятии при внедрении системы стоят задачи ее адаптации и оптимизации, собственно для решения которых и приспособлен встроенный язык программирования 1С. Как правило, предприятие, внедряющее систему, по причине недостаточной под готовки персонала возлагает решение этих задач на сторонних лиц и организации так называемые франчайзи* (партнеры) 1С. Иногда это экономически обременительно (час работы представителя партнера оценивается в 20-30 у. е.). Поэтому зачастую шаги
Франчайз, или франшиза, - это право на создание коммерческого предприятия и на торговлю продукцией старшего партнера. Франчайзи, или франшизы, - это лицо или организация, поку пающие франчайз (франшизу).
по настройке программы являются половинчатыми и система не выходит на соответ ствующий ее возможностям уровень функционирования. Согласитесь, что во многих случаях выгоднее иметь в штате специалиста (или двух), сопровождающего систему, знающего ее особенности и понимающего за дачи ее развития, чем полагаться на структуры массового обслуживания. С выходом этой книги подготовка таких специалистов упростится, а их число увеличится. По существу, при надлежащем прилежании им может стать любой имеющий склон ность к программированию сотрудник предприятия, привлекаемый руководством к внедрению и сопровождению системы. Включенные в пособие примеры программ и компоненты предложенной об легченной версии системы размещены на дискете, которую можно приобрести в издательстве. Этот же материал находится в Интернете на сервере издательства (www.bitex.ru/~dialog). Эта дискета позволит вам посмотреть в работе представ ленные в пособии объекты, отдельные обработки, а также реализованную облег ченную версию конфигурации системы. Это станет возможным (если вам доступна программа 1С:Предприятие версии 7.7) сразу после выполнения изложенных в прил. 2 инструкций.
1. НАЧАЛЬНЫЕ СВЕДЕНИЯ 1.1. ВВЕДЕНИЕ Система 1С:Предприятие, версии 7.7 эксплуатируется на большом числе рос сийских предприятий. Комплексная поставка включает следующие компоненты: Бухгалтерия, Торговля, Склад, Заработная плата, Кадры, Услуги и Производство. Субъекты хозяйственной деятельности (предприятия, фирмы и др.) нередко ис пользуют часть возможностей системы, например подсистему Бухгалтерия, или Торговля и Склад, или Зарплата и Кадры. Такие подсистемы в 1С называются кон фигурациями. Приспособление системы к потребностям предприятия осуществляется средства ми встроенного языка программирования, первые шаги по освоению которого делают ся в этой главе. Встроенный язык программирования 1С оперирует большим числом сложных объектов (около 30), предлагая для них исчерпывающий набор методов и предопреде ленных процедур. По существу, освоение языка и состоит в изучении этих объектов и приобретении навыков их употребления в алгоритмах и реализующих их програм мах. Однако подойти к этой цели мы сможем, лишь пройдя необходимые этапы освое ния языка. На первом этапе мы научимся запускать тривиальные программы. На втором. вкладывать в эти программы некоторый смысл. На третьем - оснащать их базовы ми конструкциями языка, с пониманием строить числовые, символьные, логиче ские выражения и выражения с датами, употребляя в них имеющиеся в языке опе рации и встроенные функции. И так далее. И тогда любой имеющий тягу к программированию пользователь познает язык системы, что пойдет на благо как ему самому, так и организации, в которой он служит. Для освоения материала читателю не требуется иметь специальных навыков программирования, а достаточно обладать знаниями в пределах школьного курса информатики или первого курса высшего учебного заведения. Это обусловлено тем, что из ложение предмета носит, как правило, неформальный характер, строится по принципу от простого к сложному и иллюстрируется большим числом примеров.
1.2. ИНТЕРФЕЙС УЧЕНИК Создадим для учебных целей простой, не обремененный избыточными кнопками и пунктами меню пользовательский интерфейс, дав ему имя Ученик. Запустим для этого систему в режиме Конфигуратор и выберем некоторую информационную базу, например Расчет зарплаты и кадровый учет (рис. 1.1), или любую иную.
Рис. I. 1. Запуск системы Откроем после запуска системы ее конфигурацию, выбрав пункты меню Конфигу рация - Открыть конфигурацию (рис. 1.2).
Рис. 1.2. Открываем конфигурацию системы В отобразившемся окне выберем закладку Интерфейсы. Ударим по правой кнопке мыши и в появившемся меню выберем пункт Новый интерфейс (рис. 1.3).
Рис. 1.3. Ввод нового интерфейса В окне Свойства пользовательского интерфейса в поле Название введем слово Ученик и отключим меню Операции (рис. 1.4).
Рис. 1.4. Задание основных свойств интерфейса
Нажав на кнопку ОК, получим окно, содержащее интерфейс Ученик (рис. 1.5).
Рис. 1.5. Закладка с интерфейсом Ученик Добавим теперь в меню интерфейса Ученик колонку Проба. Разместим для этого на элементе Ученик курсор, нажмем правую кнопку мыши или дважды ударим по ее ле вой кнопке и выберем в появившемся списке возможностей пункт Редактировать меню. В появившемся окне разместим курсор на элементе Ученик, задействуем правую кнопку мыши и в раскрывшемся списке выберем пункт Свойства (рис. 1.6, а). В окне задания свойств в поле Название введем имя Проба (рис. 1.6, б) и нажмем на кнопку ОК.
Рис. 1.6. Изменение имени колонки меню: а - вызов окна ввода свойств колонки меню; б - общие свойства колонки Вставим далее в колонку Проба меню интерфейса Ученик пункт Пуск. Ударим для этого мышью по крестику, расположенному перед элементом Проба, разместим кур сор на пункте и вновь приведем в действие правую кнопку мыши. В поя вившемся списке выберем пункт Свойства (рис. 1.7, а) и в поля окна задания свойств введем указанные на рис. 1.7, б значения.
а
б Рис. 1.7. Добавление пункта Пуск: а - вызов окна ввода свойств элемента меню; б - общие свойства элемента
Замечание. Для задания объекта Отчет достаточно разместить курсор на поле Объ ект и нажать на клавиатуре на русскую букву О (строчную или прописную). На следующем шаге выберем закладку Акселератор, нажмем на кнопку Выбрать акселератор и задействуем сочетание клавиш, например Alt+1, которое затем будем использовать для вызова связанного с пунктом меню Пуск файла. После нажатия на кнопку ОК просмотрим созданное меню, нажав на правую кноп ки мыши и выбрав пункт Тест. Результат тестирования приведем на рис. 1.8.
Рис. 1.8. Просмотр меню интерфейса Ученик Замечание. На самом деле в соответствии с рис. 1.4 колонка Операции при исполь зовании интерфейса Ученик в 1С:Предприятии будет отсутствовать. Имя файла, который будет связан с пунктом меню Пуск, зададим несколько позже.
1.3. ПОЛЬЗОВАТЕЛЬ ПО ИМЕНИ УЧЕНИК Чтобы создать такого пользователя, выберем пункты меню Администрирование Пользователь и в появившемся окне (рис. 1.9), нажав на правую клавишу мыши, выбе рем пункт Новый и зададим в окне свойств атрибуты (рис. 1.10, а) И роль (рис. 1.10, б) пользователя.
Рис. 1.9. Список пользователей
а
б
Рис. 1.10. Характеристики пользователя Ученик: а - атрибуты; б - роль Замечания: 1. В поле Рабочий каталог рис. 1.10, а установлен путь к папке, содержащей инфор мационную базу данных системы. 2.
Вопросы задания прав доступа пользователей рассматриваются в разд. 8,5. Пока что установим пользователю Ученик полные права (рис. 1.10, б).
При необходимости для пользователя Ученик в окне, изображенном на рис. 1.9, можно установить пароль, который придется вводить при входе в систему. Для зада ния или смены пароля воспользуйтесь иконкой с изображением замка или нажмите на правую кнопку мыши и выверите пункт изменить пароль. Введенные данные, разумеется, надо сохранить. Теперь при входе в систему нам нужно будет выбирать пользователя с именем Ученик и вводить пароль, если он задан (рис. 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, а).
а
б
Рис. 1.15. Задание свойств элемента диалога: а - общих; б - дополнительных Откроем затем закладку Дополнительно и в поле Формула взамен текста Сформи ровать( ) разместим текст Выполнить( ) (рис. 1.15, б). Это изменение означает, что по сле нажатия на кнопку Пуск будет запускаться процедура обработки под именем Вы полнить (если таковая определена в модуле обработки). На закладке Описание введем текст Запуск учебной программы. Чтобы использовать этот текст в качестве подсказ ки, проставим флажок Использовать описание (рис. 1.16) и сохраним, нажав наОК, изменения.
Рис. 1.16. Описание и подсказ.л элемента диалога Приведем диалог к виду, представленному т. рис. 1.14. б, употребив для центри рования по горизонтали кнопок Пуск и Закрыть иконку инструментов Редактор диалога (рис. 1.17).
, расположенную на панели
Рис. 1.17. Панель инструментов Редактор диалога Для просмотра диалога можно нажать Ctrl+R или выбрать иконку веденной панели инструментов.
на вышепри
Замечания: 1. Перечень имеющихся в системе панелей инструментов выводится в окне рис. 1.18, а, отображаемом после выбора пункта меню Панели инструментов в колонке Сервис.
а
б
Рис. 1.18. Панели инструментов: а - выбор отображаемых панелей; б - настройка панелей 2. Рассматривая компоненты системы, мы не будем без необходимости подробно ос танавливаться на всех их возможностях. Так, в случае панели инструментов Редак тор диалога мы обратили внимание на две его иконки: Назначение осталь ных иконок этой панели легко понять, испытав их воздействие на выделенные эле менты диалога и их группы или обратившись к закладке Модификация окна управ ления панелями инструментов (рис. 1.18,6). Не забудем связать файл Проба.ert с пунктом меню Пуск колонки Проба из меню интерфейса Ученик. Для этого откроем конфигурацию, выберем закладку Интерфей сы, в ней перейдем на интерфейс Ученик, вызовем редактор меню, дойдем до элемента Пуск и дважды ударим по нему мышью. Выберем в появившемся окне закладку Пара метры и определим в ней полное имя файла, связанного с пунктом меню Пуск (рис. 1.19). Заметим, что имя файла можно задать, указав в нем путь относительно ка талога с базами данных.
Рис. 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. МОДУЛЬ ОБРАБОТКИ ПРОБА Процедура Выполнить принадлежит модулю обработки. Модуль обработки в об щем случае может содержать следующие компоненты: • • •
объявления переменных модуля, которые доступны в любом его программном компо ненте; процедуры, в том числе и предопределенные, и функции, созданные пользователем; операторы основной программы модуля, следующие за его процедурами и функциями; основная программа выполняется один раз при загрузке модуля.
Запишем в качестве примера в модуле обработки код, содержащий объявление переменной модуля а, пользовательскую процедуру Выполнить и основную програм му из одного оператора. // Объявляем переменную модуля обработки // Она может быть использована в любой процедуре (функции) модуля // и его основной программе перем а; процедура Выполнить( ) // Выполнить - имя процедуры перем б; // Локальная переменная процедуры Выполнить Сообщить("а = " + а); // Выводим значение переменной а в окно сообщений б = 4.2; // Определяем значение локальной переменной б Сообщить("Сумма а и б равна " + (а + б)); конецПроцедуры // Выполнить // Основная программа модуля состоит из одного оператора а = 5.1; // Определяем значение переменной модуля После загрузки и запуска обработки в 1С:Предприятие в окне сообщений выведут ся две следующие строки: а=5.1 Сумма а и б равна 9.3 Замечания: 1. Нельзя изменить использованный порядок следования компонентов модуля То есть ошибочен, например, код перем а;
//
Объявляем переменную модуля
// Основная программа модуля; такое ее расположение в модуле ошибочно а = 5.1; // Определяем значение переменной модуля процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем б; // Локальная переменная процедуры Выполнить Сообщить("а = " + а); // Выводим значение переменной а в окно сообщений б = 4.2; // Определяем значение локальной переменной б Сообщить("Сумма а и б равна " + (а + б)); конецПроцедуры // Выполнить
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.
6 а Рис. 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 01.01.01 25.08.01
EV EV EV
1000 1500 2500
В приведенном фрагменте отображается состояние константы Единовременная ВыплатаНаРебенка на 3 разные даты. (О том, что записи относятся к одной и той же константе, говорят совпадающие значения поля Id.) Значения, которые ранее имела периодическая константа, можно просмотреть, на с названием История, расположенную в окне со списком констант жав на иконку (см. рис. 1.26). С периодическими константами употребляются методы Получить и Установить, соответственно возвращающие и устанавливающие значение константы на заданную дату. Применив для взятой в качестве примера константы вызовы Сообщить(Константа.ЕдиновременнаяВыплатаНаРебенкаПолучить('21.05.00')); Сообщить(Константа.ЕдиновременнаяВыплатаНаРебенка.Получить('21.07.01')); Сообщить(Константа.ЕдиновременнаяВыплатаНаРебенка.Получить('21.09.01')); получим следующие сообщения:
:,
1000 1500 3500 Также с периодическими константами применяются методы объекта Периодиче ский, рассматриваемые в гл. 6. В частности, л разд. 6.1 приводится код вывода значе ний определенных в конфигурации непериодических констант. Замечания: 1. 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.31. Список констант в элементе диалога Таблица значений
1.9. ФОРМИРОВАНИЕ ОТЧЕТА СО СПИСКОМ КОНСТАНТ При необходимости список констант можно распечатать. Для этого, однако, его предварительно нужно представить либо в виде табличного отчета, либо в виде тек стового документа, расположив информацию в отчете (документе) в удобном для про чтения виде. Расширим обработку Проба, которую мы до сих пор использовали для отладки и запуска учебных программ, до внешнего отчета 1С, использовав в ней вывод данных в таблицу, созданную на закладке Таблица (рис. 1.32).
Рис. 1.32. Начальный вид закладки Таблица
Первоначально, если не пользоваться помощником создания отчета, в таблице нет заполненных ячеек. Если поставить курсор на имя закладки Таблица и нажать на правую кнопку мы ши, то раскроется список действий, которые можно предпринять (рис. 1.33).
Рис. 1.33. Меню операций для таблицы
Из списка видно, что форма может в общем случае содержать более одной таблицы. Воспользуемся пунктом Задать имя таблицы и присвоим ей имя Константы, кото рое затем и будем использовать в программе. Поставим задачу получить отчет со списком констант в виде табл. 1.5. Таблица 1.5 Список непериодических констант, 02.10.01 Идентификатор
Значение
Синоним
АдресГНИ АдресОрганизации Архиватор
Адрес ГНИ Адрес Организации
ОграничиватьПосмотрСписка
Ограничивать просмотр списка
Некоторый адрес Некоторый адрес Нет Нет Всего непериодических констант: 94
Для ее решения потребуется в отчете Проба на закладке Константы (новое имя за кладки Таблица) сформировать макет отчета по образцу, приведенному на рис. 1.34, а затем написать программу вывода данных в таблицу Константы.
Рис. 1.34. Образец для отчета Список непериодических констант Проделаем эту работу в следующем порядке. Перейдем на закладку Константы, выделим ячейки 2, 3 и 4 первой строки и выполним их объединение, нажав на иконку панели инструментов Редактор таблиц (рис. 1.35) или выбрав пункт Объединить Колонки Таблицы меню конфигуратора.
Рис. 1.35. Панель инструментов Редактор таблиц Занесем в объединенные ячейки шаблон следующего вида: Список непериодических констант, [ТекущаяДата()], введя его на закладке Текст в окне Свойства ячейки, которое появляется после позиционирования курсора на ячейке, удара по правой клавише мыши и выбора пункта Свойства (рис. 1.36). (В квадратных скобках содержится выражение, вы числяемое при использовании шаблона. В нашем случае выражение - это встроенная функция, возвращающая установленную в вашем компьютере текущую дату.)
Рис. 1.36. Задание свойства Текст ячейки таблицы Константы Используя закладки Положение и Шрифт, расположим текст по центру ячеек 2-4, сделаем его полужирным и увеличим его размер до 12. Проведя аналогичные действия, сформируем в ячейках 2, 3 и 4 строки 3 заголовки будущей таблицы со списком констант, а затем увеличим, оперируя мышью, ширину каждого столбца с заголовками. При этом на закладке Текст окна Свойства ячейки в поле Тип установим значение не Шаблон, а Текст. Высоту шрифта и его толщину можно изменить сразу для всех заголовков, выделив их и вызвав затем окно Свойства ячейки. Кроме изменения параметров шрифта, зададим, перейдя на закладку Рамка, разделяющие ячейки вертикальные и горизонтальные линии.
Просмотрим промежуточный вариант макета отчета, выбрав на стандартной пане или пункт Просмотр колонки системного ли инструментов конфигуратора иконку меню Файл. Замечание. Чтобы изменить размер столбца таблицы, нужно захватить мышью, нажав на ее левую кнопку, разделяющую номера столбцов линию и переместить ее в нужном направлении. В строке 5 формируемого макета отчета в ячейку второго столбца (эта ячейка име ет номер R5C2) занесем текст иден, задав для него в поле Тип значение Выражение (рис. 1.37).
Рис. 1.37. Свойства ячейки R5C2 В нашем случае выражение иден - это имя переменной в программе, которой в процессе чтения информации об очередной константе присваивается значение ее идентификатора. Далее аналогичным образом зададим в ячейках 3 и 4 строки 5 выражения син и значен, являющиеся в нашем случае именами переменных, получающими соответст венно синоним и значение константы. Затем, выделив три ячейки с выражениями, на закладке Рамка зададим разделяющие их вертикальные линии. Замечание. Можно организовать перенос длинных имен, не умещающихся в за данных для них ячейках таблицы. Для этого в поле Контроль (рис. 1.37) следует уста новить значение Переносить. В строке 7 после объединения столбцов 3 и 4 зададим шаблон Всего непериодических констант: [числоКонст], в котором выражение числоКонст - это переменная, получающая в процессе вычислений значение, равное количеству непериодических констант. Перейдем к формированию секций. Объединим в секцию первые 3 строки табли^ цы. Для этого выполним их выделение, проведя мышью, у которой нажата левая кноп ка, по номерам строк 1-3, выберем иконку (см. рис. 1.35) и присвоим идентифика тору секции значение Заголовок. Аналогичным образом создадим секции оКонстанте и Всего. Макет отчета готов. Направим в него данные и отобразим результат, использовав в отчете Проба следующий снабженный обширным комментарием код: // Процедура формирования отчета, содержащего список непериодических констант процедура Выполнить() // Связана с кнопкой Пуск обработки (отчета) Проба перем ин, числоКонст, син, иден, значен; перем табл; ОчиститьОкноСообщений(); табл = СоздатьОбъект("Таблица"); // Свяжем переменную табл с таблицей Константы, содержащей макет отчета табл.ИсходнаяТаблица("Константы"); // При выводе применяем заданные по умолчанию параметры таблицы; // для их изменения следует обратиться к методу Опции
// Выводим, используя шаблон Список непериодических констант, [ТекущаяДата()], // секцию Заголовок табл.ВывестиСекцию("Заголовок"); числоКонст = 0; // Число непериодических констант для ин = 1 по Метаданные.Константа() цикл если Метаданные.Константа(ин).Периодический = 1 тогда продолжить; // Значения периодических констант не выводятся конецЕсли; числоКонст = числоКонст + 1; // Еще одна константа // Определяем значения переменных идеи, син и значен // Эти значения будут использованы при выводе секции оКонстанте идеи = Метаданные.Константа(ин).Идентификатор; син = Метаданные.Константа(ин).Синоним; значен = сокрЛ(Константа.ПолучитьАтрибут(иден)); // Вывод очередной строки в отчет табл.ВывестиСекцию("оКонстанте"); конецЦикла; // для табл.ВывестиСекцию("Всего"); // Вывод данных о числе непериодических констант // Запрещаем редактирование результирующей таблицы табл.ТолькоПросмотр(1); // Задаем в методе Показать заголовок окна с результирующей таблицей табл.Показать("Отчет о константах"); конецПроцедуры // Выполнить. Результат приведен в табл. 1.5.
1.10. ВЫВОД СПИСКА КОНСТАНТ В ТЕКСТОВЫЙ ФАЙЛ Текстовые файлы часто используют для обмена данными между программами, на пример для передачи из 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 . 1 1 . ЗАГРУЗКА ТЕКСТА МОДУЛЯ ИЗ ФАЙЛА До сих пор мы редактировали диалог или таблицу формы или набирали код моду ля, находясь в конфигураторе, затем выполняли его синтаксический контроль, сохра няли, устранив ошибки, файл обработки (отчета), переходили в 1С:Предприятие, за гружали там обновленную обработку и выполняли ее запуск. Если же диалог и таблица в процессе работы над формой не изменяются, а моди фицируется только код программных компонентов модуля, то процесс запуска изме ненной программы можно несколько ускорить. Для этого следует воспользоваться ко мандой #ЗагрузитьИзФайла ИмяФайла Эта команда должна быть размещена в первой строке модуля и начинаться с ее первой позиции. ИмяФайла - это указанное без кавычек имя файла, в котором разме щается текст редактируемого модуля, например Проба.ert. При наличии в модуле такой команды весь расположенный вслед за ней код игно рируется. Редактирование данных должно выполняться в файле ИмяФайла. При этом файл загружается не в конфигураторе, а в 1С:Предприятии (Файл - Открыть). Чтобы появившийся текст представлялся как программа, то есть с использованием заданных для текста программ шрифта, цветов и размера табуляции, необходимо после откры тия файла выбрать в меню пункты Текст - Текст модуля. После внесения изменений необходимо сохранить файл (Ctrl+S), закрыть файл формы (обработки), если она открыта, и открыть его заново. В загруженной форме бу дет использован обновленный в файле ИмяФайла код модуля. Выполним только что приведенные рекомендации. Добавим, во-первых, в код мо дуля обработки Проба.ert, открытой в конфигурации, команду (в вашем случае путь, разумеется, может быть иным) // Команда размещена в первой строке модуля #ЗагрузитьИзФайла d:\1cv77\Test\TXT\Пpoбa.txt Затем создадим, например в папке ТХТ, текстовый файл Проба.txt, откроем его в 1С:Предприятии, скопируем в него код модуля обработки Проба.ert, выберем пункты меню Текст - Текст модуля, внесем в текст файла изменения, добавив, например, в процедуру выполнить оператор Сообщить("Код модуля загружен из файла Пpoбa.txt"); Сохраним файл Проба.Ш, откроем и запустим обновленную обработку (файл Пpoбa.txt закрывать не нужно).
Еще одна рекомендация. При работе с кодом модуля не забывайте о возможностях колонки меню Текст и панели инструментов Текстовый редактор (рис. 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", "Отчет и обработки | *.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, имяФайла, "Находим файл Проба.еrt, "Отчет и обработки | *.ert"); если флаг = 1 тогда // Если файл обработки выбран если ОткрытьФорму("Отчет", контОбрПроба, имяФайла) = 0 тогда Предупреждение("Не удается открыть обработку " + имяФайла); возврат; иначе НовыйКонтекст(контОбрПроба); // Изменяем значения переменных дЧ и пер конецЕсли; // и обновляем окно формы обработки Проба иначе Предупреждение("Файл обработки не выбран."); конецЕсли; конецПроцедуры // Открыть // Закрывает открытую обработку Проба, используя для доступа к методу Закрыть // переменную модуля контОбрПроба процедура ПриЗакрытии() если ПустоеЗначение(контОбрПроба) = 0 тогда контОбрПроба.Форма.Закрыть(); конецЕсли; конецПроцедуры // ПриЗакрытии
Рис. 1.44. Диалог обработки Проба: а - до обновления; б - после него
Структура контекста говорит о том, что он является объектом агрегированного ти па, включающего компоненты (в нашем случае реквизиты формы) и методы, употреб ляемые с обработкой. Приведем еще один пример управления формой обработки Про ба через ее контекст. Так, если в процедуру перед вызовом контОбрПроба.Форма.Обновить(); выполнить оператор контОбрПроба.Форма.дЧ.Видимость(0);
//
Скрываем элемент диалога дЧ
то рис. 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С Имя каталога временных файлов, образуемых при работе с 1С Единицу, если программа запущена в монопольном режиме, или нуль - в противном случае Единицу, если основной язык русский, или нуль, если английский
Пример: процедура Выполнить() // Связана с кнопкой Пуск обработки Проба ОчиститьОкноСообщений(); ЗаголовокСистемы("Система с учебными формами"); Сообщить(ИмяКомпьютера()); // DEFAULT Сообщить(ИмяПользователя()); // Ученик Сообщить(ПолноеИмяПользователя()); // Николаев Н. А. Сообщить(НазваниеНабораПрав()); // ПолныеПрава Сообщить(ПравоДоступа("ВводНового", "Справочник.КадровыеДанные")); //1 // Для справочников регулируются права доступа со следующими названиями: // чтение; // любыеИзменения; // вводНового; // удаление; // пометкаНаУдаление; // снятиеПометкиНаУдаление; // корректировка Сообщить(ПазваниеИнтерфейса()); // Ученик Сообщить(КаталогПользователя()); , //D:\lCv77\Test\ Сообщить(КаталогИБ()); // D:\lCv77\Test\ Сообщить(КаталогПрограммы()); // D:\l CV77\BIN\ Сообщить(КаталогВременныхФайлов()); // С:\ТЕМР\ Сообщить(МонопольныйРежим()); //1 Сообщить(ОсновнойЯзык()); //1 конецПроцедуры // Выполнить Замечания: 1.
Любая встроенная функция может быть вызвана как процедура, то есть в виде самостоятельного оператора, например ОсновнойЯзык(); В большинстве случаев такой вызов не окажет никакого воздействия на работу приложения. Так, из приведенных в табл. 1.6 функций только первая, будучи упот ребленная как самостоятельный оператор, позволяет вносить изменения.
2. Если при вызове встроенной функции и процедуры возникает ошибка исполнения, то выводится диагностическое сообщение и может произойти аварийное заверш ение программы. Выводимые в таких случаях сообщения, правда, не всегда адек ватны ситуации. Так, при запуске процедуры процедура Выполнить( ) // перем х; ОчиститьОкноСообщений(); х = 0; Лог(х); конецПроцедуры // Выполнить
Связана с кнопкой Пуск обработки Проба
получим сообщения х = 0; {D:\lCV77\TEST\EXTFORMS\ПРОБA.ERT(3)}: Деление на 0
1.15. ВЫВОДЫ Приведенные сведения позволяют сделать ряд выводов. 1. Для каждого пользователя можно (и нужно) создать свой интерфейс с определен ными правами доступа. 2.
Пользовательские программы (внешние обработки и отчеты) создаются в виде ' форм, содержащих диалог, модуль, одну или более таблиц.
3.
Формы разрабатываются в конфигураторе, а запускаются в 1С:Предприятии.
4.
Имена переменных, процедур и функций, заданных в форме (в ее диалоге, модуле или его программных компонентах), доступны только в этой форме. Причем имя переменной модуля или диалога может быть закрыто локальным именем процеду ры или функции модуля.
5.
Модуль формы в общем случае содержит объявления переменных модуля и про граммные компоненты - основную программу, пользовательские процедуры (в том числе и предопределенные) и функции. Предопределенные процедуры, то есть созда ваемые пользователем процедуры, имеющие определенные в документации имена и интерфейсы и исполняемые либо при наступлении стандартных событий, например при открытии формы, либо при рбращении к ним из других программных компонен тов модуля, включаются в модуль по мере необходимости. Порядок следования про граммных компонентов модуля подчиняется определенным правилам.
6.
Существуют по-настоящему глобальные имена (разд. 1.6), доступные в каждом программном модуле.
7.
Объекты, такие, как Таблица значений, Текст и др., становятся доступными после их создания в результате применения функции СоздатьОбъект; к иным объектам, например Константам, можно обратится по их полному имени. С каждым видом объектов связан набор методов, позволяющих выполнять необходимые для управ ления объектами действия.
8. 9.
Такие объекты, как Таблица и Список значений, становятся доступными в модуле формы после их размещения в диалоге формы (разд. 1.8). Вывод данных может быть выполнен в окно сообщений, в некоторые элементы диалога формы, например в таблицу значений, в таблицу (отчет), в текстовый до кумент и другие пока что нерассмотренные объекты системы. Кроме того, объек ты, это мы покажем ниже, позволяют выполнять и обратную операцию - ввод оп ределенных в них данных.
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' '03.11.42' '03.11.41'
//3 // //
ноября 1942 г. Так же 3 ноября 1942 г. Это 3 ноября 2041 г.
Убедимся в этом визуально, активизировав кнопку 4 (рис. 2.1), сохранив новую настройку и запустив обработку, содержащую два следующих сообщения: Сообщить('03.11.42'); Сообщить('03.11.41');
// //
Напечатает 03.11.1942 Напечатает 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 * а; Сообщить(ПустоеЗначение(б)); Сообщить(б); // Сообщить(б + 3); Сообщить(а + 3);
// //
// //
Объявляем скалярную переменную а Напечатает 1 Напечатает пустую строку Напечатает 1. То есть б имеет пустое значение Напечатает 0, а не пустую строку, // несмотря на то что б имеет пустое значение Напечатает 3 Напечатает пустую строку
Переменная обретает тип при ее определении, то есть когда она получает значение в результате выполнения оператора присваивания или если переменная является фор мальным параметром процедуры, при вызове этой процедуры, в котором определены соответствующие фактические параметры.
Пример 2. Переменные а и стр после выполнения присваивания будут иметь соот ветственно числовой и символьный тип. перем а, стр; а = 1.22; стр = "Это строка";
// // //
Объявляем скалярные переменные а и стр Теперь переменная а имеет числовой тип Теперь переменная стр имеет символьный тип
Пример 3. При вызове функции ВычислитьУ ее формальный параметр х будет оп ределен как числовая переменная (текст функции ВычислитьУ см. выше). процедура Выполнить() б = ВычислитьУ(3.0); // При вызове функции ВычислитьУ определяется Сообщить("б = " + б); // тип и значение ее формального параметра х конецПроцедуры // Выполнить Замечание. Переменные, имена которых неизвестны в программном компоненте, нельзя использовать в качестве фактических параметров других программных компо нентов. Например, ошибочен следующий код: процедура ОпределитьХ(х) х = 2.0; конецПроцедуры // ОпределитьХ процедура Выполнить() ОпределитьХ(х); // Сообщить(х); конецПроцедуры // Выполнить
Этот вызов в текущей версии недопустим
В то же время вполне корректен второй вариант процедуры Выполнить: процедура Выполнить() перем х; // ОпределитьХ(х); // Сообщить(х); // конецПроцедуры // Выполнить
Объявляем переменную х Теперь этот вызов возможен Напечатает 2
По ходу выполнения программы одна и та же переменная может менять свой тип, например: перем а; а = 1.22; Сообщить(а); а = "Это строка"; Сообщить(а); а = '24.12.01' Сообщить(а);
// //
// // // // //
Объявляем скалярные переменные а Теперь переменная а имеет числовой тип Напечатает 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С могут присутствовать операнды разных типов (при наличии в выражении с несколькими операндами операнда агрегатного типа данных этот опе ранд воспринимается как пустое значение). Тип выражения определяется типом его результата. Тип результата выражения (или его подвыражения) определяется типом его первого операнда или первого заключенного в круглые скобки подвыражения. На пример (выражения располагаются в правых частях операторов присваивания): а= 1.4; //1.4 - числовое выражение из одного операнда б = 2 + 5 * а; // Числовое выражение, возвращающее число 9 в = 2 + " 1 -я строка"; // Числовое выражение, возвращающее число 3 г = "Строка и символ " + 2; // Символьное выражение, возвращающее строку // "Строка и символ 2" д = 2 + '21.12.01'; // Числовое выражение, возвращающее число 2452267 е = '21.12.01' + 2; // Выражение типа Дата, возвращающее дату 23.12.01 ж = (2 * "2-я строка") + 1; // Числовое выражение, возвращающее число 5 Из примеров видно, что порядок вычисления выражения таков: первоначально по первому операнду определяется тип выражения; затем выполняется вычисление выражения с учетом круглых скобок и приоритета выполнения операций, при этом значения операндов, имеющих тип, отличный от типа выражения (или вычисляемого в данный момент подвыражения), преобразовываются в значения, тип которых совпа дает с типом выражения. Например, переменная з в операторе з = "Результат = " + 4 / "2-я строка"; получит символьный тип и значение, равное "Результат = 2". Действительно, опера ция / имеет более высокий приоритет, чем операция +, поэтому прежде будет вычисле но подвыражение 4/"2-я строка", которое, судя по его первому операнду, является чис ловым и поэтому вернет число 2. Далее это число будет преобразовано в строку "2", которая объединится со строкой "Результат = ". Результатом выражения будет пустое значение, если первый операнд выражения имеет пустое значение. Например: перем а; б = 2 + а; в = а + 2;
// // //
Объявляем скалярную переменную а Вернет 2 Вернет пустое значение
Переменная агрегатного типа данных воспринимается в выражениях, имеющих более одного операнда, как пустое значение. Например: табл = СоздатьОбъект("Таблица"); а = табл + 2; // б = табл; //
Вернет пустое значение Типы переменных б и табл совпадают
Выражение называется логическим, если в нем есть хотя бы одна операция отно шения или логическая операция. Например: 2.5 /1.33 > 0 (а = 5) и (б = 2)
//Вернет //
1 Вернет 0, если, например, а = 1
Логические выражения употребляются в управляющих конструкциях языка, на пример если 2.5 /1.33 > 0 тогда Сообщить("Да"); иначе Сообщить("Нет"); конецЕсли; Замечания: 1. Логические выражения отличаются от иных, например числовых, выражений 1С тем, что их нельзя использовать в правой части оператора присваивания или в ка честве фактических параметров процедур, функций и методов. Так, ошибочен оператор флаг = (а = 5) и (б = 2);
//
Ошибка! В правой части оператора присваивания // размещено логическое выражение
Этот недостаток создает определенные неудобства при записи программ. 2.
Тип данных выражения возвращают функции ТипЗначения и ТипЗначенияСтр. Первая возвращает число, по которому определяется тип данных ее параметра, вторая - имя типа данных параметра. Например: а =1.2; Сообщить(ТипЗначения(а)); // Напечатает 1 Сообщить(ТипЗначенияСтр(а)); // Напечатает Число сСотр = СоздатьОбъект("Справочник.Сотрудники"); Сообщить(ТипЗначенияСтр(сСотр)); // Напечатает Справочник
2.6.2. АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ ДЛЯ ЧИСЛОВОГО ТИПА ДАННЫХ С каждым типом данных связан набор операций. С числовыми данными употреб ляются известные арифметические операции *, /, +, - и операция %, возвращающая ос таток от деления операндов, например: 5%2 5.2 % 2 5.8 % 2 5.8 % "2-я строка"
// // // //
Вернет 1 Вернет 1 Вернет 0 Также вернет 0
Из примеров видно, что при вычислении результата выражения с операцией % числовые операнды округляются до целых значений (если второй операнд является нечисловым, то он прежде приводится к числовому типу), а затем вычисляется ос таток от деления двух целых чисел.
2.6.3. ОПЕРАЦИИ ДЛЯ СТРОК И ДАТ В символьных выражениях допустима только операция +, называемая операцией конкатенации. Например: "1-я строка и " + "строка 2"
//
Вернет строку "1-я строка и строка 2"
В выражениях типа Дата можно употреблять операции + и -, например // Выражение типа Дата, возвращающее дату 01.01.02 // Выражение типа Дата, возвращающее дату 10.12.01
'21.12.01'+11; '21.12.01' -11;
Следующее выражение ошибочно: '21.12.01' * 11
//
Операция * недопустима в выражениях типа Дата
2.6.4. " И С Т И Н А " И " Л О Ж Ь " В 1С Констант со значениями истина и ложь во встроенном языке 1С нет. В то же вре мя понятия истина и ложь используются в 1С при оценке логических выражений, появляющихся в управляющих конструкциях языка.
2.6.5. ОПЕРАЦИИ ОТНОШЕНИЯ В логических выражениях используются приведенные в табл. 2.4 операции отно шения. Таблица 2.4 Операции отношения Операция < >= =
Описание Меньше Меньше или равно Больше Больше или равно Равно Не равно
Операндами операций отношения могут быть выражения числового или символь ного типа, а также даты. Причем типы операндов должны совпадать. Например: 2=5 "Строка 2">"Строка 1" 2
// Это ложь // Это истина // Это неверное выражение отношения, так как его // операнды имеют разный тип
Также операндами операций = и могут быть переменные агрегатного типа. На пример: тЗнач1 = СоздатьОбъект("ТаблицаЗначений"); сСотр = СоздатьОбъект("Справочник.Сотрудники"); тЗнач2 =тЗнач1; // Круглые скобки в нижезаписанном логическом выражении обязательны
если (тЗнач1 = тЗнач2) и (тЗнач1 = сСотр) тогда Сообщить("Да"); иначе Сообщить("Нет"); конецЕсли; Если операция отношения выполняется над строками, то они сравниваются по символьно до тех пор, пока не будут обнаружены несовпадающие символы. Они то и решат судьбу сравнения. Следует помнить, что символ сим_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 8 % (2 * 3)
// //
Вернет 0 Вернет 2
Поскольку логические операции старше операций отношения, то ошибочно сле дующее логическое выражение: 3>2и4 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],..., [числоN);
Минимальное значение своих параметров. Может иметь только один параметр - число!
максЗначение = Макс(чнсло1, [число2],..., [числоN);
Максимальное значение своих параметров. Может иметь только один параметр - число1
результат = Лог10(число);
Десятичный логарифм аргумента число или нуль, если аргумент меньше нуля. Возникнет завершающая ошибка, если аргумент равен нулю
результат - Лог(число);
Натуральный логарифм аргумента число или нуль, если аргумент меньше нуля. Возникнет завершающая ошибка, если аргумент равен нулю
Примеры: Сообщить(Окр(2.45, Сообщить(Окр(2.45, 1, 0)); Сообщить(Окр(2.597)); Сообщить(Цел(2.9)); Сообщить(Мин(-2.9,-5,
1,
1)); // // // 12));
//2.5 2.4 3 2 //-5
2.8.2. ВСТРОЕННЫЕ ФУНКЦИИ ДЛЯ СИМВОЛЬНЫХ ДАННЫХ Приводятся в табл. 2.8. Параметры, имя которых содержит слово строка или текст, являются символьными выражениями, а имеющие слово число - числовыми. Исполь зуются целые части числовых параметров, если они являются нецелыми числами. Таблица 2.8 Функции для строк функция
Что возвращает
длина - СтрДлина(строка);
Длину параметра строка
флаг = ПустаяСтрока(строка);
Число 1, если строка имеет нулевую длину или состоит из одних пробелов, или 0 -в противном случае
новаяСтрока - СокрЛ(строка);
Строку, получаемую в результате удаления ведущих пробелов в аргументе строка
новаяСтрока = СокрП(строка);
Строку, получаемую в результате удаления завершающих пробелов в аргументе строка
новаяСтрока = СокрЛП(строка);
Строку, получаемую в результате удаления ведущих и завершающих пробелов в аргументе строка
подстрока = Лев(строка, число);
Строку, содержащую первые число символов параметра строка или всю строку строка, если число => СтрДлина(строка). Если число СтрДлина(строка). Если число < 0, то возвращается строка нулевой длины
подстрока = Сред(строка, число1, [число 2]);
Строку, содержащую подстроку параметра строка, начинающуюся с символа под номером число 1 длиной число2. Если параметр число2 опущен, возвращается подстрока, начинающаяся с символа под номером число1 длиной до конца строки. Если число1 > СтрДлина(строка) или число2 < 0, то возвращается строка нулевой длины. Если параметр число1 < 0, то он принимается равным единице
позиция = Найти(строка, подстрока);
Позицию, с которой подстрока начинается в параметре строка, или нуль, если подстрока не найдена в первом параметре
новаяСтрока = СтрЗаменить (строка, подстрока!, подстрока2);
Строку, в которой все вхождения параметра подстрока 1 в параметр строка заменены на параметр подстрока2
кол = СтрЧислоВхождений(строка, Число вхождений параметра подстрока в параметр строка подстрока);
Функция Что возвращает Число строк в тексте текст. Строки в тексте разделены кол = СтрКоличествоСтрок символом РазделительСтрок (см. разд. 2.3) {текст); стр = СтрПолучитьСтроку(текст, Строку параметра текст, имеющую номер номерСтроки. номерСтроки); Если номерСтроки < 0 или номерСтроки больше числа строк в тексте, то возвращается строка нулевой длины новаяСтрока = Врег(строка); Строку, в которой все символы параметра строка преобразованы в верхний регистр новаяСтрока - Нрег(строка); Строку, в которой все символы параметра строка преобразованы в нижний регистр новаяСтрока = OemToAnsi Строку, в которой OEM-коды символов параметра (строка); строка преобразованы в ANSI-коды новаяСтрока = AnsiToOem Строку, в которой ANSI-коды символов параметра (строка); строка преобразованы в ОЕМ-коды символ = Симв(кодСимвола); Символ, код которого равен значению параметра кодСимвола код = КодСимв(строка); Код первого символа параметра строка Примеры: длина = СтрДлина("ААББСС"); // Вернет 6 флаг = ПустаяСтрока(" ААББСС"); // Вернет О новаяСтрока = СокрЛП(" ААББСС "); // "ААББСС" подстрока = Лев(" ААББСС", 2); // Вернет "АА" подстрока = Прав("ААББСС", 2); // Вернет "СС" подстрока = Сред("ААББСС", 3); // Вернет "ББСС" подстрока = Сред("ААББСС", 3,2); // Вернет "ББ" позиция = Найти("ААББСС", "БС"); // Вернет 4 позиция = Найти("ААББСС", "БС1"); // Вернет О новаяСтрока = СтрЗаменить("ААББАА", "АА", "ДДЦ") // Вернет "ДДЦББДДЦ" кол = СтрЧислоВхождений("ААББАА", "АА"); // Вернет 2 текст = "Это длинная символьная константа, | поскольку она размещается не на одной, | а на трех строчках"; кол = СтрКоличествоСтрок(текст); // Вернет 3 стр = СтрПолучитьСтроку(текст, 3); // Вернет "а на трех строчках" новаяСтрока = Врег("ааббсс"); // Вернет "ААББСС" новаяСтрока = Нрег("ААББСС"); // Вернет "ааббсс" стр = "вГСбв DOS"; // Содержит значение "текст DOS" в DOS-кодировке новаяСтрока = OemToAnsi(cтp); // Вернет строку "текст DOS" в кодировке ANSI новаяСтрока = AnsiToOem(новаяСтрока); // Вернет вГСбв DOS уже в кодировке OEM символ = Симв(200); // Вернет И код = КодСимв("И"); // Вернет 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.3. Задание начала и конца стандартного интервала на закладке Журналы
Рис. 2.4. Диалог задания дат начала и конца периода Примеры: рДата = РабочаяДата(); тДата = ТекущаяДата(); новая Дата = ДобавитьМесяц(рДата, -2); нМесяца = НачМесяца(рДата); кМесяца = КонМесяца(рДата); нКвартала = НачКвартала(рДата); кКвартала = КонКвартала(рДата); нГода = НачГода(рДата); кГода = КонГода(рДата); нНедели = НачНедели(рДата); кНедели = КонНедели(рДата); год = ДатаГод(рДата); месяц = ДатаМесяц(рДата); дч = ДатаЧисло(рДата); неделя = НомерНеделиГода(рДата); деньГода = НомерДняГода(рДата); деньНедели = НомерДняНедели(рДата); период = ПериодСтр(нКвартала, кКвартала); // Новая установка начала стандартного интервала НачалоСтандартногоИнтервала("Месяц"); нИнтервала = НачалоСтандартногоИнтервала( );
// 10.10.01 // 10.10.01 // 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: дат = Дата(год, месяц, число);
В первом варианте функция преобразовывает значение выра жения параметр в значение типа Дата. Выражение может быть числовым, символьным или типа Дата. В первом случае значение выражения трактуется как число дней от Рождества Христова и преобразовывается в соответствующую дату, во втором случае строка преобразовывается в дату, в третьем преобразований не выполняется. Во втором варианте функция преобразовывает дату, заданную числовыми выражениями год, месяц, число, в значение типа Дата. Причем для задания значения параметра год использу ются все цифры, а не две последние
Функция стр = Строка(параметр);
чис = Чиспо(параметр);
Что делает Преобразовывает значение выражения параметр в строку. Выражение может быть датой или иметь числовой или символьный тип. В последнем случае преобразований не выполняется Преобразовывает значение выражения параметр в число. Выражение может быть датой или иметь символьный или числовой тип. В последнем случае преобразований не выполняется
Примеры (используем при выводе две цифры для представления года даты): дат = Дата(2452573); // Имеем: дат = '25.10.02' дат = Дата("25.10.2002"); // Имеем: дат = '25.10.02' дат = Дата("25.10.02"); // Имеем: дат = '25.10.02' дат = Дата('25.10.2002'); //Имеем: дат = '25.10.02' дат = Дата(2002, 10, 25); // Имеем: дат = '25.10.02' стр = Строка('25.10.02'); // Имеем: стр = "25.10.02" стр = Строка(+123.45); //Имеем: стр = "123.45" стр = Строка("25.10.02"); // Имеем: стр = "25.10.02" чис = Число('25.10.2002'); // Имеем: чис = 2452573 чис = Число('25.10.02'); // Имеем: чис = 2452573 чис = Число("123.45"); //Имеем: чис = 123.45 чис = Число("+123.45"); //Имеем: чис = 123.45 чис = Число("-123.45"); // Имеем: чис = -123.45 чис = Число(123.45); //Имеем: чис= 123.45
("число - дата") ("строка - дата") ("строка - дата") ("дата - дата") ("дата - строка") ("число - строка") ("строка - строка") ("дата - число") ("дата - число") ("строка - число") ("строка - число") ("строка - число") ("число - число")
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")); Сообщить(Формат( 1234567.89, "Ч14.4,_")); Сообщить(Формат( 123456000, "Ч(0)14>3"));
// Напечатает 000000001234567.8900 // Напечатает 1_234_567,8900 // Напечатает 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.
ФОРМАТИРОВАНИЕ
СИМВОЛЬНЫХ ДАННЫХ
Форматная строка при форматировании символьных данных имеет вид "С[Д]", где Д - длина результирующей строки. Если Д больше длины форматируемой строки, то последняя дополняется пробелами справа, если меньше, то в результате сохраняют ся первые Д символов. Например: Сообщить(СтрДлина(Формат("ААББВВ", Сообшить(Формат("ААББВВ", "С2"));
"С10"))); //
//
Напечатает 10 Напечатает АА
Форматируемая строка не изменяется, если компонент Д форматной строки отсут ствует или на его месте стоит не число. Например: Сообщить(Формат("ААББВВ", "С"))); Сообщить(Формат("ААББВВ", "СК")); 2.8.5.4.
// //
Напечатает ААББВВ Напечатает ААББВВ
ФОРМАТИРОВАНИЕ ДАТ
При форматировании дат форматная строка начинается с буквы Д. Варианты зада ния форматной строки приведены в табл. 2.11. В ее последнем столбце приводятся ре зультаты форматирования дат 21.12.01 и 05.12.01. Таблица 2.11 Форматные строки для дат Форматная строка "ДДЦММГГ" "ДДЦММГГГГ" "ДДДММММГГГГ" "Д(0)ДДММММГГГГ"
"ДММММГГГГ" "ДММММГГ" "ДММММ"
Примеры
Вид результата
дд.мм.гг дд.мм.гггг
21.12.01
ДД месяц прописью ГГГГ г.
5 Декабря 2001 г.
ДД месяц прописью ГГГГ г., если в дне две цифры ОД месяц прописью ГГГГ г., если в дне одна цифра
21 Декабря 2001 г.
Месяц прописью ГГГГ г. Месяц прописью ГГ г.
Декабрь 2001 г.
21.12.2001
Декабрь 01г. Декабрь
Месяц прописью
"ДККККГГГГ" "ДККККГГ" "ДКККК"
Номер квартала ГГГГ г. Номер квартала ГГ г.
4 Квартал 2001 г. 4 Квартал 01 г. 4 Квартал
Номер квартала. ГГГММДЦ
"ДГГГММДД" "ДНННН"
05 Декабря 2001 г.
20011205
Название дня недели даты; по умолча нию берется из секции WeekDay файла 1CV7.SPL
Среда
Представление даты не изменяется, если форматная строка не отвечает приведен ным в табл. 2.11 требованиям. 2.8.5.5.
ИЗМЕНЕНИЕ СПОСОБА
ВЫВОДА
ЧИСЕЛ ПРОПИСЬЮ
Осуществляется процедурой Пропись([образец]); в которой параметр образец - это • либо строка, задающая имя файла образцов прописей; • либо переменная типа СписокЗначений, содержащая образцы прописей (тип данных СписокЗначений рассмотрен в разд. 3.2); • либо пустая строка.
В последнем случае образцы прописей берутся из заданного по умолчанию файла 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 в ветвлении "если - то - иначе" являются выраже ниями, то для выбора вычисляемого выражения лучше употреблять функцию, вычис ляющую выражение по условию. Ее синтаксис: результат = ?(ЛВ, выражение1 , выражение2 ); Пример: у = ?(х > 0, Лог(х), х);
//
Вернет Лог(х), если х >0, или х - в противном случае
Приведенный оператор заменяет следующее ветвление: если х > 0 тогда у = Лог(х); иначе у = х; конецЕсли; Для ветвления "если - то - иначе - если" укажем только способ его записи в 1 С: если ЛВ1 тогда БОК1 иначеЕсли ЛВ2 тогда БОК2
//
Некоторые операторы
//
Некоторые операторы
иначеЕсли ЛВк тогда БОКк // [иначе // БОК к+1 ] // конецЕсли;
Некоторые операторы Последние два элемента конструкции являются необязательными
2.9.3. "ПОПЫТКА" Ветвление Попытка служит для обработки исключений и реализуется в 1С виде следующей конструкции: попытка БОК1, исключение БОК2 конецПопытки; В конструкции БОК, - это последовательность операторов, в которых может воз никнуть исключение, а в БОК 2 - это последовательность операторов, обрабатывающих исключение. Напомним, что исключение - это ошибка, возникающая при исполнении програм мы, например деление на нуль или выход за границы массива. В первом случае систе ма выдаст сообщение "Деление на 0", во втором - "Значение индексного выражения
Работа программы, если не используется обработка исключений, при возникнове нии ошибки прекращается. Некоторые ошибки, приводящие к останову программы, могут быть, однако, устранены. Например, ошибка блокировки данных, возникающая при обращении к файлу, захваченному в настоящий момент другим приложением, устраняется после завершения работы этого приложения. Другие ошибки, если их иг норировать, не исказят конечного результата. Например, выход за границы массива. В таких случаях целесообразно применить конструкцию Попытка с тем, чтобы при возникновении ошибки выполнить ее обработку, например просто сообщить об ошиб ке, и продолжить расчеты. Пример. Вычисляется сумма элементов вектора. В процедуре при обращении к вектору умышленно введена ошибка - выход за границы вектора. Для ее преодоле ния применяется конструкция Попытка. процедура Выполнить() // Запускаем процедуру из обработки Проба перем а[5], ин, сум; // Инициализация вектора а а[1] = 0; а[2] = 1.5; а[3] = 2.5; а[4] = -1; а[5] = 7; // Сумма элементов массива а. Ожидаемый результат: сум = 10 сум = 0; // Умышленно для иллюстрации работы конструкции Попытка // задаем верхний параметр цикла большим числа элементов вектора а для ин = 1 по 7 цикл попытка // При выходе за границы вектора сум = сум + а[ин]; // произойдет обработка исключения; исключение // исполнение программы не прекратится Сообщить(ОписаниеОшибки() + ". Вычисления будут продолжены."); конецПопытки; конецЦикла; // для Сообщить("сум = " + сум); // Напечатает 10 конецПроцедуры // Выполнить Замечание. Встроенная функция ОписаниеОшибки возвращает описание ошибки в том виде, в каком оно выдается системой в окно сообщений при отсутствии обработ ки исключений. Конструкции Попытка могут быть вложенными. В таких случаях при возникнове нии ошибки ее обработка передается оператору Исключение того уровня вложенно сти, на котором ошибка возникла. Чтобы передать обработку ошибки оператору более высокого уровня, применяется оператор ВызватьИсключение. Если оператор ВызватьИсключение применен, а внешнего обработчика не существует, то произойдет останов программы с выдачей сообщения об ошибке. Последний эффект будет, в ча стности, получен, если оператор ВызватьИсключение вставить в код вышеприведен ного примера перед оператором КонецПопытки. Пример. Вычисляется сумма элементов вектора. В процедуре при обращении к вектору умышленно введена ошибка - выход за его границы. Для ее преодоления применяется конструкция Попытка. Однако в этот раз в результате применения опера тора ВызватьИсключение осуществляется выход из цикла и передача управления внешнему обработчику.
процедура Выполнить() // Запускаем процедуру из обработки Проба перем а[5], ин, сум; // Инициализация вектора а а[1] = 0; а[2] = 1.5; а[3] = 2.5; а[4] = -1; а[5] = 7; // Сумма элементов массива а. Ожидаемый результат: сум = 10 сум = 0; // Умышленно для иллюстрации работы конструкций Попытка // задаем верхний параметр цикла большим числа элементов вектора а попытка для ин = 1 по 7 цикл попытка // При выходе за границы вектора передадим сум = сум + а[ин]; // управление внешнему обработчику исключений исключение вызватьИсключение; // Передача управления внешнему обработчику конецПопытки; // внутренней конецЦикла; // для исключение Сообщить(ОписаниеОшибки() + ". Осуществлен выход из цикла. Работа продолжается"); конецПопытки; // внешней Сообщить("сум = " + сум); // Напечатает 10 конецПроцедуры // Выполнить Замечание. Внешний обработчик в данной ситуации, конечно же, избыточен и введен лишь для иллюстрации оператора ВызватьИсключение. При отсутствии внешней конструкции Попытка вместо оператора ВызватьИсключение следует упот ребить оператор Прервать, предваренный, например, тем же, что и в приведенном при мере, вызовом процедуры Сообщить.
2.9.4. ЦИКЛЫ В цикле "с параметром n" задаются начальное значение параметра к, его конечное значение к и шаг ш - отличная от нуля величина, на которую изменяется значение па раметра и после выполнения очередной итерации. В 1С шаг ш всегда принимается равным единице. Параметр п также называют переменной цикла, которая должна быть целочисленной. Параметры ник являются в 1С числовыми выражениями и представ ляют соответственно нижнюю и верхнюю границы переменной цикла. Если параметр н(к) вычисляется с нецелым значением, то в качестве параметра используется целая часть результата. Замечание. Параметр цикла часто называют его индексом, для обозначения кото рого в программах нередко употребляют имя ин или инд. Графически цикл "с параметром" иллюстрирует рис. 2.6.
Рис. 2.6. Цикл с параметром
Цикл "с параметром" работает так (случай ш > 0): 1°. Присвоить: п = н. 2°. Если п к , то переход к п. 3°, иначе завершить цикл. Замечания: 1. В цикле "с параметром" приведенные в пп. 1° и 4° операторы в тексте программы не присутствуют, но будут автоматически встроены компилятором в объектный код при компиляции программы. 2.
Во многих языках программирования, например в Фортране, в цикле "с парамет ром" запрещается в теле цикла менять значения переменной цикла и. Изменение параметров н, к и шага ш в теле цикла не отразится на выполнении цикла: цикл будет выполняться с теми значениями параметров, какие они имели до начала первой итерации цикла. В 1С запрет на изменение значения переменной цикла п не действует. Однако следует помнить, что изменение п в теле цикла - это плохой стиль программирования. Запись цикла "с параметром" в линейной схеме алгоритма:
Х°. С параметром п = н,к,ш [выполнить:] БОК конец цикла [с параметром п] | [Х°]. и в 1С: для п = н по к цикл БОК конецЦикла; Цикл Пока выполняется до тех пор, пока истинно некоторое ЛВ. Причем проверка ис тинности ЛВ выполняется перед началом очередной итерации. Цикл До отличается от цикла Пока тем, что проверка истинности ЛВ осуществляется после выполнения оче редной итерации. Графическая интерпретация циклов Пока и До приведена на рис. 2.7.
6 Рис. 2.7. Циклы: а - цикл Пока; б - цикл До
Замечание. При работе с циклами Пока и До надо следить, чтобы ЛВ обязательно рано или поздно приняло значение ложь. Иначе произойдет зацикливание - "бесконеч ное" выполнение операторов цикла. Запись циклов Пока в линейной схеме алгоритма: Х°. Пока истинно ЛВ [, выполнить:] БОК конец цикла Х°. и в 1С: пока ЛВ цикл БОК конецЦикла;
//
Некоторые операторы
Замечания: 1. Далее при ссылке на циклы будем использовать принятые в 1С имена операторов циклов - Для и Пока. 2.
Циклы Для и Пока могут быть вложенными. То есть в теле цикла Для (Пока) могут быть другие циклы Для и/или Пока.
Проиллюстрируем второе замечание примером, записав код вывода групп подряд следующих непериодических констант, сообщающий перед выводом группы ее номер. (Уточним: в примере группа - это подмножество подряд следующих непериодических констант, не имеющее периодических констант. То есть группы разделяются одной и более периодическими константами.) // Процедура, выводящая группы непериодических констант // Запускается из обработки Проба процедура Выполнить() перем всегоКонстант, ин, номерГруппы, идеи; ОчиститьОкноСообщений(); номерГруппы = 0; всегоКонстант = Метаданные.Константа(); ин = 1; // Номер константы пока ин всегоКонстант тогда прервать; // Досрочный выход из вложенного цикла конецЕсли; конецЦикла; // пока Метаданные.Константа(ин).Периодический = 0 иначе ин = ин + 1;
//
//
Имеем периодическую константу Не забываем перейти к следующей константе
конецЦикла; // пока ин 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 УдалитьСтроки(); конецЕсли; если КоличествоСтрок() = 0 тогда форма.Удалить.Доступность(0); форма.Очистить.Доступность(0); конецЕсли; конецЕсли; конецПроцедуры // УдалитьЗап Результат автоматического заполнения табеля для сотрудников второго цеха при веден на рис. 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.
Рис. 7.47. Документ Табель проведен для сотрудников 2-го цеха
Замечания: 1. Расчеты одного объекта располагаются в ЖЗ в порядке очередности их исполнения. 2. Чтобы быстро найти в ЖЗ сотрудника, следует переместиться на поле Сотрудник и начать набирать на клавиатуре его фамилию (рис. 7.48).
Рис. 7.48. Локализация сотрудника в форме списка ЖЗ
При поиске должна быть выбрана иконка , обеспечивающая отображение всех сотрудников текущего подразделения. 3. Ввод нового документа Табель проще всего выполнить, воспользовавшись кноп кой Ввод расчета, предусмотренной в диалоге формы ЖЗ (см. рис. 7.21). 4. Чтобы открыть документ Табель, породивший текущий расчет, достаточно, нахо дясь в ЖЗ, нажать на правую кнопку мыши и выбрать соответствующий пункт появившегося меню (рис. 7.49).
Рис. 7.49. Открываем документ Табель Тот же пункт можно выбрать и из колонки Действия меню интерфейса Ученик. Команда проведения документа при выполнении перепроведения отслеживает все возможные произошедшие в документе изменения. Так, если в предопределенной про цедуре ОбработкаПроведения после проведения документа закомментировать код, вводящий, например, расчеты с ВР ВБанк_2, то соответствующие расчеты исчезнут из ЖЗ в результате перепроведения документа. Если из проведенного документа уда лить табель для какого-либо сотрудника, то в результате перепроведения все ранее по рожденные документом расчеты, относящиеся к удаленному сотруднику, будут удале ны и из ЖЗ и т. д. Если по какой-либо причине табель на сотрудника заполняется повторно, то его проведение не приведет к появлению в ЖЗ новых расчетов, поскольку расчеты с ВР Оклад_2, НДФЛ_2 и ВБанк_2 созданы как самовытесняющиеся. Однако при этом ста рые расчеты будут заменены на вновь вводимые, поскольку нами использован метод ВвестиРасчет. Метод ЗаписатьРасчет также вводит расчеты в ЖЗ, но при этом само вытесняющиеся расчеты остаются в ЖЗ неизмененными. Если же перепроводится существующий Табель, то методы ВвестиРасчет и Запи сатьРасчет работают совершенно одинаково. Результаты введенных документом Табель расчетов оцениваются в процедуре Об работкаПроведения после ввода расчетов следующим кодом: // Выполняем расчет всех введенных записей жз.ВыбратьЗаписиПоДокументу(ТекущийДокумент( ));
пока жз.ПолучитьЗапись() = 1 цикл // Метод Рассчитать вызывает процедуру ПровестиРасчет соответствующего ВР жз.Рассчитать( ); // или жз.ВыполнитьРасчет( ); конецЦикла; // пока Рассмотрим теперь, как задаются свойства используемых нами ВР, и запишем для них код, возвращающий результат расчета. Прежде, однако, зададим правила перера счета ВР.
7.6.6. ФОРМА СПИСКА ЖУРНАЛА ДОКУМЕНТОВ ТАБЕЛЬ Документы Табель отображаются в одноименном журнале документов (см. рис. 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).
Рис. 7.52. Расчет отдельной записи ЖЗ Правила перерасчета срабатывают не только при вводе, но и при ручной правке ведущего ВР. Замечание. Ситуация, когда не работают правила перерасчета, анализируется в разд. 7.10.1.
7.8. ВИДЫ РАСЧЕТОВ ДОКУМЕНТА ТАБЕЛЬ 7.8.1. ВИД РАСЧЕТА ОКЛАД_2 Выполним всю цепочку задания свойств ВР Оклад_2, включающую также и напи сание кода процедуры получения результата. Предварительно, однако, нам потребуется создать группу ВР ВсеНачисления_2, в которую мы будем включать расчеты-начисления, облагаемые НДФЛ. Войдем к конфигурацию, добавим группу ВР ВсеНачисления_2 (рис. 7.53), вклю чив в нее указанные на рис. 7.54 ВР.
Рис. 7.53. Добавляем группу ВР ВсеНачисления_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
ДатаНачСум, ДатаКонСум ДатаНач1234, ДатаКон1234
Соответственно дата начала и конца действия расчетов с ВР ПремияСум_2
кто
Способ заполнения табличной части документа. Используется как идентификатор радиокнопок диалога формы списка документа. Если кто = 1, то подбор выполняется по одному сотруднику; если кто = 2, то в табличную часть документа заносятся сотрудники выбранного подразделения. Используется при открытии проведенного документа Флаги начисления премий соответственно коэффициентом, суммой или 1234. Премия начисляется, если флаг равен единице, и не начисляется, если флаг равен нулю Номер выбранной строки в списке подразделений сПодр. Используется при открытии проведенного документа для верного позиционирования списка подразделений Реквизиты табличной части документа Сотрудник, получающий премию
коэф, сум, п1234
текСтрока
Сотрудник к3
Сумма Премия1234
Тип (разновидность типа) /Длина.Точность Дата "
Соответственно дата начала и конца действия расчетов с ВР Премия 1234_2
Коэффициент для расчета ПремииКоэф_2. По умолчанию к3 = 10. Соответствующий столбец табличной части имеет заголовок Коэф. Сумма премии по ВР ПремияСум_2 Флаг начисления премии по ВР Премия 1234_2
Числовой /1.0
Числовой /1.0
Числовой / 3.0
Справочник. Сотрудники_2 Числовой / 3.0
Числовой /10.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), оставив справа полосу для размещения трех нижних кнопок четвертого слоя.
Рис. 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 изображения.
Рис. 7.66. Закладка Ввод премий
Рис. 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) процедура КнопкиВидимость(флаг) // заполнить, удалить и очистить - идентификаторы одноименных кнопок Форма.Заполнить.Видимость(флаг); Форма.Удалить.Видимость(флаг); Форма.Очистить.Видимость(флаг); конецПроцедуры // КнопкиВидимость // Управляет доступностью элемента диалога сПодр процедура Проследить() если кто = 1 тогда // форма.СПодр.Доступность(0); иначе // форма.СПодр.Доступность(1); конецЕсли; КонецПроцедуры // Проследить
Премия отобранным сотрудникам кто = 2
//Управляет видимостью столбцов Коэф., Сумма и Премия 1234 табличной части документа // и доступностью элементов задания дат на слое ИнтервалыРасчетов
процедура Столбцы() форма.к3.Видимость(коэф); // Премия коэффициентом форма.ДатаНачКоэф.Доступность(коэф); форма.ДатаКонКоэф.Доступность(коэф); форма.Сумма.Видимость(сум); // Премия суммой форма. ДатаНачСум.Доступность(сум); форма.ДатаКонСум.Доступность(сум); форма.Премия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 тогда форма.Удалить.Доступность(0); форма.Очистить.Доступность(0); конецЕсли; конецЕсли; конецПроцедуры // УдалитьЗап // Выполняет проверку дат процедура ПриЗаписи() перем ош; ош = 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; // Процедура выполняется при проведении расчета с ВР Премия1234_2 // Вычисляется по следующей формуле: // Премия 12342 = (Оклад_2 + ПремияКоэф_2 + ПремияСум_2) * к5, где // к5 - постоянный для всех сотрудников коэффициент // Коэффициент к5 - берется из списка периодических констант жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); нтп = жз.НачалоТекущегоПериода(); ктп = жз.КонецТекущегоПериода(); прем 1234 = 0; жз.ВыбратьПериодПоОбъекту(Объект, нтп); пока жз.ПолучитьЗапись() = 1 цикл если (жз.ВидРасч = ВидРасчета.Оклад_2) или (жз.ВидРасч = ВидРасчета.ПремияКоэф_2) или (жз.ВидРасч = ВидРасчета.ПремияСум_2) тогда прем 1234 = прем 1234 + жз.результат; конецЕсли; конецЦикла; // пока результат = прем1234 * Константа.К5.Получить(ктп); конецПроцедуры // ПровестиРасчет
1234_2
Значение числовой константы к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, Премия1234_2
15
НДФЛ_2
ВБанк_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. Интервалы действия премий Агальцова Ю. А
Рис. 7.71. Расчеты-премии Агальцова Ю. А Знакомясь с новыми записями, во-первых, отметим, что в ЖЗ нет длинного задан ного в документе расчета. Он разбился на обычные так, что период действия каждого лежит в пределах некоторого расчетного периода. Во-вторых, обратим внимание, что разбиение затрагивает только временной пара метр расчетов. Сумма премии переносится в каждый интервал разбиения. То есть в нашем случае 1С удваивает премии Агальцова Ю. А. по сравнению с величинами, заданными в документе. В-третьих, как и ожидалось, расчет Премия суммой вытеснил расчет Премия коэф фициентом, укоротив (на временной оси) последний на 15 дней слева. При этом вновь изменились только временные параметры расчета. Его результат сохранился. Единственный случай, когда наблюдается изменение результата, - это полное вытеснение рас чета.
В-четвертых, скорректируем наши представления об упорядочении расчетов: в пределах выбранного объекта расчеты располагаются по приоритетам (очередности исполнения), в пределах одного приоритета - в порядке возрастания атрибута расчета ДатаНачала, а при равных датах - в алфавитном порядке. Итак, на временной оси ЖЗ введенные расчеты располагаются в соответствии с рис. 7.72, а количественные характеристики каждого расчета удвоились.
Рис. 7.72. ВР ПремияСум_2 (ПС) и ПремияКоэф_2 (ПК) из приведенного на рис. 7.69 и 7.70 документа на временной оси ЖЗ Если рис. 7.72 закономерен, то двукратное увеличение результатов входит в про тиворечие с документом и реальными событиями. В самом деле, если ваш отпуск длится, скажем, 40 дней, то в документе-приказе об отпуске, в котором отпускные вводятся единой суммой, нужно указать именно эту сумму, а также даты начала и конца отпуска. После проведения документа мы получим 2 или 3 расчета (в зависимости от отпускного периода), но общая сумма отпускных должна сохра ниться. То есть, разбивая длинный расчет на к частей, мы должны иметь некоторый алгоритм деления его суммы на те же к частей. Если расчет А вытесняется расчетом Б, интервал действия которого лежит в пре делах интервала действия расчета А (см. рис. 7.4, б), наблюдается та же, что и в слу чае длинных ВР, картина: интервал действия расчета А разбивается на 2 части, но при этом результат расчета сохраняется для каждой из частей разбиения. Это приводит к удвоению результата по сравнению со значением, определенным в документе, поро дившим расчет. Этот эффект иллюстрирует рис. 7.73, в котором в качестве расчета А выступает Премия коэффициентом, а Премия суммой является расчетом Б.
Рис. 7.73. После разбиения результат расчета Премия коэффициентом удвоился В документе для расчетов Агальцова Ю. А. Премия суммой и Премия коэффици ентом заданы приведенные на рис. 7.74 интервалы действия.
Рис. 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 цикл Сообщить("" + жз.Объект + СимволТабуляции + жз.ВидРасч + Символ Табуляции + жз.Результат); конецЦикла; // пока конецПроцедуры // Выполнить Результат: Добрецов Борис Юрьевич Добрецов Борис Юрьевич Добрецов Борис Юрьевич Добрецов Борис Юрьевич Добрецов Борис Юрьевич Добрецов Борис Юрьевич Добрецов Борис Юрьевич
Начальное сальдо Премия коэффициентом Премия суммой Перечисление в банк НДФЛ Оклад Премия 1234
0.75 1670 2000 8444 1261.65 2800 3235
Пример 5. В окно сообщений выводятся все расчеты ЖЗ, относящиеся к выбран ному документу. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем док, жз; док = СоздатьОбъект("Документ.Премия"); // Метод Выбрать вызывает диалог для выбора документа // Если документ не выбран если док.Выбрать("Выберите документ") = 0 тогда Предупреждение("Документ не выбран."); возврат; конецЕсли; жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьЗаписиПоДокументу(док.ТекущийДокумент()); пока жз.ПолучитьЗапись() = 1 цикл Сообщить("" + жз.Объект + СимволТабуляции + жз.ВидРасч + СимволТабуляции + жз.Результат); конецЦикла; // пока конецПроцедуры // Выполнить Результат: Волосков Михаил Андреевич Волосков Михаил Андреевич Волосков Михаил Андреевич
Премия суммой Премия коэффициентом Премия 1234
500 1600 2550
Пример 6. В окно сообщений выводятся все зарегистрированные в текущем пе риоде расчеты ЖЗ (объект, ВР и результат) сотрудников второго цеха. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем сСотр_2, жз, пер, подр; сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); если сСотр_2.НайтиПоНаименованию("02 Цех", 0) = 0 тогда Предупреждение("Второй цех не найден."); возврат; конецЕсли; жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); пер = жз.ТекущийПериод(); // Подразделение предприятия (найденная выше группа справочника Сотрудники_2) подр = сСотр_2.ТекущийЭлемент(); жз.ВыбратьПоЗначению("Родитель", подр, пер, пер); пока жз.ПолучитьЗапись() = 1 цикл Сообщить("" + жз.Объект + СимволТабуляции + жз.ВидРасч + СимволТабуляции + жз.Результат); конецЦикла; // пока конецПроцедуры // Выполнить Результат: Абрамова Лариса Сергеевна Абрамова Лариса Сергеевна Абрамова Лариса Сергеевна Абрамова Лариса Сергеевна
Начальное сальдо Оклад НДФЛ Перечисление в банк
2.6 2500 325 2177
Пример 7. Удаляются все расчеты ЖЗ, относящиеся к выбранному документу, и сам документ. Записи получают DBF-пометку удаления, а документу проставляется 1С-пометка удаления. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем док, жз; док = СоздатьОбъект("Документ.Премия"); // Метод Выбрать вызывает диалог для выбора документа // Если документ не выбран если док.Выбрать("Выберите документ") = 0 тогда Предупреждение("Документ не выбран."); возврат; конецЕсли; жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьЗаписиПоДокументу(док.ТекущийДокумент()); пока жз.ПолучитьЗапись() = 1 цикл жз.УдалитьЗапись(); // Удаляем расчет (ставим DBF-пометку удаления) конецЦикла; // пока док.Удалить(0); // Удаляем документ (ставим 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.
Рис. 7.76. Установлены отбор по графе Образование и режим представления по одному объекту Замечание. Чтобы полноценно использовать отбор по графе Образование, нужно внести соответствующие изменения и в диалог формы списка ЖЗ Зарплата 2, и в модуль формы. В частности, флажок на рис. 7.77 переключатель.
придется заменить на приведенный
Рис. 7.77. Переключатель видов отборов
Пример 10. В форме списка ЖЗ Зарплата_2 выводятся только сотрудники с задан ным образованием. процедура ПриОткрытии() // Предопределенная процедура перем обр, флаг, сОбр_2, графаОтбора, значениеОтбора; // Выбираем вид образования обр сОбр_2 = СоздатьОбъект("Справочник.Образование_2"); флаг = сОбр_2.Выбрать("Выберите вид образования",""); если флаг = 1 тогда обр = сОбр_2.ТекущийЭлемент(); // Задаем режим вывода записей о сотрудниках с образованием обр УстановитьОтбор("Образование", обр); конецЕсли; // Контрольный вывод если ПолучитьОтбор(графаОтбора, значениеОтбора) = 1 тогда Сообщить("Установлен отбор по графе " + графаОтбора + " со значением " + значениеОтбора); конецЕсли; УстановитьПредставление(1); // Вывод списка сотрудников // Для иных процедур модуля определим нтп нтп = НачалоТекущегоПериода(); конецПроцедуры // ПриОткрытии Результат: Установлен отбор по графе Образование со значением Среднее Пример 11.В форме списка ЖЗ Зарплата_2 выводятся только записи, относящиеся к документу, выбранному в предопределенной процедуре ПриОткрытии. процедура ПриОткрытии() // Предопределенная процедура перем док; док = СоздатьОбъект("Документ.Премия"); // Метод Выбрать вызывает диалог для выбора документа // Если документ не выбран если док.Выбрать("Выберите документ") = 0 тогда Предупреждение("Документ не выбран."); возврат; конецЕсли; // Вывод расчетов, порожденных выбранным ранее документом УстановитьПредставление(3, док.ТекущийДокумент()); // Для иных процедур модуля определим нтп нтп = НачалоТекущегоПериода(); конецПроцедуры // ПриОткрытии
7.14. П Р Е Д О П Р Е Д Е Л Е Н Н Ы Е П Р О Ц Е Д У Р Ы МОДУЛЯ ФОРМЫ ЖУРНАЛА РАСЧЕТОВ Приведены в табл. 7.17.
Таблица 7.17 Предопределенные процедуры модуля формы ЖР
Пример. Запрещается ручное исправление результатов во всем ЖР. // Процедура входит в состав модуля формы списка ЖР процедура ПриИсправленииРезультата(запись) Предупреждение("Ручная правка невозможна."); СтатусВозврата(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.Вытесняет ВидРасчета(ВР2);
Возвращает 1, если вид расчета ВР1 вытесняет вид расчета ВР2, или О-в противном случае
флаг = ВР1.Вытесняется ВидомРасчета (ВР2);
Возвращает 1, если вид расчета ВР1 вытесняется видом расчета ВР2, или О-в противном случае
Возвращает 1, если вид расчета ВР входит в группу ВР, задан ную параметром группа типа ГруппаРасчетов
Методы групп ВР флаг = ГВР.Содержит ВидРасчета(ВР); кол = ГВР.Количество(); ВР = ГВР.Получить Расчет(ном);
Вернет 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.17.2. ФОРМИРОВАНИЕ РАСЧЕТНОГО ЛИСТКА Так же как и при расчете зарплаты, мы создадим процедуру ЛистокСотрудника, формирующую расчетный листок (РЛ) для одного сотрудника, и будем использовать ее нужное число раз, когда задача решается для выбранного подразделения. Вывод РЛ будем осуществлять в специально созданную в форме списка ЖЗ табли цу, которой дадим имя РЛ (рис. 7.79).
Рис. 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 вБанк = Результат; конецЕсли; конецЦикла; // пока вып = сальдоНач + нач - уд; // Полагается к выплате В сальдоКон = вып - вБанк; // Сальдо на конец месяца ВыводНачУд(табл, тЗначНач, 1); //Вывод начислений ВыводНачУд(табл, тЗначУд, 2); //Вывод удержаний табл.ВывестиСекцию("Пусто"); // Пустая строка в РЛ сальдоНач = Формат(сальдоНач,' "4-10.2"); табл.ВывестиСекцию("сНач"); // Выводим сальдо на начало месяца вып = Формат(вып, "4-10.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 Оклад 12 Премия суммой 12 Премия коэффициентом 1 Премия коэффициентом 12 Премия 1234 Удержания Мес. Видудержания 12 НДФЛ Остаток прошлого месяца Начислено Удержано Полагается к выплате: Перечислено в банк Остаток на конец месяца
Сумма 3100.00 700.00 1650.00 1650.00 3550.00
Часы
Сумма 1384.50
Часы
165 165 165
-
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(зХозОп.хозОп, жз, нтп); всего = всего + сумРез; Сообщить("Сумма результатов по операции " + СокрП(зХозОп.хозОп) + " равна " + символТабуляции + сумРез); конецЦикла; // пока Сообщить("Всего по всем операциям: " + всего); конецПроцедуры // Выполнить Результат: Сумма результатов по операции 2013000 равна Сумма результатов по операции 2013001 равна Сумма результатов по операции 2017002 равна Сумма результатов по операции 2300100 равна Сумма результатов по операции 2300111 равна Сумма результатов по операции 2300112 равна Всего по всем операциям: 209892.1
5.5 61793 13642.6 91301 33550 9600
Если нужно просмотреть отдельные составляющие каждой группы с указанием объекта, текст запроса нужно сформировать следующим образом: текстЗапХозОп =" | период с нтп по ктп; // Период запроса // Переменные запроса; добавляем переменную сотр | сотр = журналРасчетов.Зарплата_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).
Рис. 8.1. Список, открываемый иконкой на панели инструментов ЖЗ Мы заменили эту иконку кнопкой Ввод расчета, показывающей для выбора список документов (см. рис. 7.25), вводящих расчеты в ЖЗ Зарплата_2. Их перечень, напом ним, мы внесли в перечисление ВР 2 (разд. 7.3.3). из панели инструментов можно, только убрав всю па Однако удалить иконку нель инструментов (Сервис - Панели инструментов - Дополнительные - Инструмен тальные панели окон - ). Но даже после этого аналогичный пункт оста нется в колонке Действия меню системы. В большей мере нежелательно присутствие на панели инструментов ЖЗ иконки , предлагающей удалить документ. Для этого есть по меньшей мере три причины. Во-первых, пользователь, наблюдая ЖЗ, не видит документа, который ему предла гают удалить, - перед ним лишь часть расчетов, порожденных документом (а эти рас четы могут быть рассыпаны по всему ЖЗ), а чтобы принять решение, нужно иметь пе ред глазами объект, а не его производные. Во-вторых, пользователь, находясь в ЖЗ, наблюдает удаление не документа, а за писей ЖЗ. Такая рассогласованность намерений и визуального результата несколько обескураживает. В-третьих, расчеты, порожденные удаляемым документом, могут иметь неотмененную ручную правку. И если ошибочное удаление документа, расчеты которого не имеют ручной правки, - дело поправимое (для преодоления ошибки нужно снять по метку удаления документа в соответствующем журнале документов и провести доку мент заново), то расчеты с ручной правкой после восстановления ошибочно удаленно го документа придется произвести заново.
Ситуацию можно поправить, если в предопределенную процедуру ПриУдаленииДокумента, которую нужно расположить в глобальном модуле, добавить вызов ниже приводимой функции ЕстьЛиРучнаяПравка, которая как раз-то и фиксирует наличие расчета с ручной правкой и запрещает при наличии такового удаление породившего его документа. Функцию придется разместить в глобальном модуле, поскольку оттуда осуществляется ее вызов. // Вернет 0, если хотя бы один расчет удаляемого документа имеет ручную правку функция ЕстьЛиРучнаяПравка(док) перем жз; жз = СоздатьОбъект("ЖурналРасчетов.Зарплата_2"); жз.ВыбратьЗаписиПоДокументу(док); // Просматриваем все расчеты, порожденные документом док пока жз.ПолучитьЗапись() = 1 цикл если жз.Исправлена = 1 тогда возврат 0; // Есть ручная правка конецЕсли; конецЦикла; // пока возврат 1; // Нет расчетов с ручной правкой конецФункции // ЕстьЛиРучнаяПравка Саму же предопределенную процедуру ПриУдаленииДокумента можно записать следующим образом: // Предопределенная процедура глобального модуля // Интерфейс процедуры задан в системе и содержит два входных параметра: док и режим // док - удаляемый документ // Параметр режим равен единице, если проставляется DBF-пометка удаления, // и равен нулю, если документ получает 1С-пометку удаления // В нашей проблеме этот параметр неинтересен процедура ПриУдаленииДокумента(док, режим) если док.ПометкаУдаления() = 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аписать(); {D:\ПPOБA.ERT(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).
Рис. 8.3. Редактор пользовательских прав В этом редакторе для выбранного набора прав (в нашем случае - Ученик) можно определить права Ученика в отношении каждого класса объектов в целом (рис. 8.4) и отдельных представителей классов (рис. 8.5).
Рис. 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 Реквизиты справочника ПраваРасчетчика Реквизит Описание имяПользователя Имя, с которым расчетчик входит в систему. Задается в конфигурации подразделение Подразделение, с которым может работать расчетчик. Вводится как группа справочника Сотрудники_2
Примечание Строка длиной в 15 символов Имеет разновидность типа Справочник.Сотрудники_2
Правами ввода и редактирования данных справочника обладает только админист ратор системы. Редактирование данных осуществляется в форме списка, и после заполнения спра вочник будет содержать отображенные на рис.'8.8 сведения.
Рис. 8.8. Имена пользователей предприятия и обслуживаемые ими подразделения Чтобы в справочнике Сотрудники_2 можно было выбирать группы (подразделе ния), в модуль формы ФормаДляВыбора мы добавили следующий код: // Предопределенная процедура ПриОткрытии процедура ПриОткрытии() ВыборГруппы(1); конецПроцедуры // ПриОткрытииСами же имена пользователей определим в конфигурации в соответствии с рис. 8.9, задав им одинаковые права, интерфейс и рабочий каталог.
Рис. 8.9. Задание имен пользователей и их прав в конфигурации системы
8.5.3. МЕНЮ И ПРАВА ПОЛЬЗОВАТЕЛЕЙ В меню пользователя Ученик добавим возможность вызова вновь созданного справочника ПраваРасчетчика, оставив иные пункты меню без изменений. Для работ ника, отвечающего за кадры, создадим интерфейс Кадры, меню которого построим в соответствии с рис. 8.10.
Рис. 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 // Интерактивно отбор управляется иконками // лежащими на панели управления ЖЗ процедура ПриУстановкеОтбора(графаОтбора, значениеОтбора) если флагРасч = 0 тогда // Если работает не расчетчик, то возврат; // контроль прав не осуществляется конецЕсли; // Простым перебором устанавливаем, можно ли расчетчику расч работать // с интерактивно выбираемым им подразделением сПраваРасч.ВыбратьЭлементы(); пока сПраваРасч.ПолучитьЭлемент() = 1 цикл если (расч = СокрЛП(сПраваРасч.ИмяПользователя)) и (сПраваРасч.Подразделение = значениеОтбора) тогда СтатусВозврата(1); // Работать можно возврат; // Выход из процедуры конецЕсли; конецЦикла; // пока СтатусВозврата(0); // Работать нельзя Предупреждение("Это не Ваше подразделение."); конецПроцедуры // ПриУстановкеОтбора процедура При6ткрытии() // Предопределенная процедура перем реж, значРеж; // Восстанавливаем с диска значения переменных диалога закл и кто // для текущего сеанса работы закл = ВосстановитьЗначение("ЗакладкиВЗарплате"); если ТипЗначения(закл) = 0 тогда // Если значение переменной закл не восстановлено закл = 1; кто = 1; иначе кто = ВосстановитьЗначение("КтоВЗарплате"); конецЕсли; ктоСтар = кто; ПоЦехам( ); если флагРасч = 0 тогда // Добавленная строка кода если закл = 1 тогда значОтбора = ВосстановитьЗначение("ЗначениеОтбора"); ЗакладкиОтбора("Родитель", значОтбора); конецЕсли;
иначе // Еще 5 добавленных строк кода Форма.Закл.Видимость(0); // Элемент диалога закл расчетчику не нужен // Установим разрешенный для расчетчика расч отбор УстановитьОтбор("Родитель", значениеОтбора); конецЕсли; реж = ВосстановитьЗначение("РежимПредставления"); значРеж = ВосстановитьЗначение("ЗначениеПредставления"); если реж = 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. СОПРОВОЖДЕНИЕ СИСТЕМЫ. ОБНОВЛЕНИЕ КОНФИГУРАЦИИ Задачами сопровождения системы являются поддержание ее работоспособности и повышение эффективности ее функционирования. В комплексе мероприятий по сопровождению можно выделить два вида работ: регламентные и инициативные.
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.
При попытке удалении документа (рис. 8.13)
1С может
возникнуть предупреждение
Рис. 8.13. Предупреждение при попытке удаления документа ВводОтработанногоВремени. и поясняющее его сообщение Данный объект использован в: ГрафаОтбора.Сотрудник Чтобы это препятствие преодолеть, следует в конфигурации открыть указан ные на рис. 8.14 пункты меню, а затем дважды ударить мышью по подпункту Сотрудник.
Рис. 8.14. Графы отбора журнала документов В появившемся диалоге (рис. 8.15) перенести вправо элемент левого списка Документ.ВводОтработанногоВремени.
Рис. 8.15. Устраняем препятствие для удаления документа ВводОтработанногоВремени Теперь документ ВводОтработанногоВремени может быть удален. 3.
При удалении документа система удаляет CDX- и DBF-файлы, созданные ей для документа.
4.
На самом деле с целью ускорения работы системы из конфигурации удалены все, кроме созданных нами и используемых в работе, ВР, правила перерасчето в, груп пы ВР, перечисления, документы, справочники, перечисления, отчеты и обработ ки. В результате таких манипуляций файл конфигурации 1CV7.MD уменьшился почти в 6 раз до 1,3 Мбайт.
5.
Получить список введенных в конфигурацию изменений можно, загрузив прежде копию неизмененной конфигурации, а затем, имитируя попытку объединения ее с модифицированной (разд. 8.6.4), выпустить отчет об изменениях. В нашем слу чае он будет содержать следующий текст: Задача Библиотека Картинок - Объект изменен Глобальный модуль - Объект изменен Справочник.Сотрудники_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. ПОНЯТИЕ КЛЮЧА Пусть файл данных содержит некоторую последовательность из п элементов: r1, r2,..., rn. Каждый элемент файла будем называть записью. Как правило, записи фай ла состоят из одинакового числа компонентов, называемых полями записи. В общем случае компоненты записи могут быть разного типа. Пример. В табл. 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
Другие поля
Свяжем с. каждой записью файлов ri ключ ki , понимая под ключом одно из полей записи. Правда, такое понятие ключа является узким: в общем случае ключом записи rt является некоторое выражение, среди операндов которого присутствует одно или не сколько полей записи. Так, в приведенной таблице данные упорядочены по выраже нию СсылкаНаГруппу + Наименование (знак сложения в выражении уместен, по скольку поле СсылкаНаГруппу имеет символьный тип). Выбор ключа диктуется практическими целями поиска и представления данных. Так, в приведенной таблице естественно для просмотра упорядочить данные по номе ру цеха (группы), а в пределах каждого цеха разместить фамилии сотрудников в алфа витном порядке. Файл отсортирован по ключу, если для любых ki < kj запись ri всегда предшествует rj, где i и j - номера записей в файле до выполнения сортировки. (Первая запись файла имеет номер 1.) Вполне возможно, что две записи имеют в некотором файле одинаковый ключ. Метод сортировки называется устойчивым, если для всех записей ri, и rj, таких, что кi = kj, выполняется условие: в отсортированном файле ri, предшествует rj , если ri,предшествует ri, в первоначальном файле.
9.1.3. СОРТИРОВКА ТАБЛИЦЫ УКАЗАТЕЛЕЙ Сортировать можно или сами записи файла, или указатели некоторой вспомога тельной таблицы. Пример первого случая приведен на рис. 9.1. Номер записи
Ключ
Другие поля
Ключ
1
8
4
2
20
8
3
15
10
4
4
15
5
10
20 а
Другие поля
б
Рис. 9.1. Сортировка записей: а - исходный файл; б - отсортированный файл
Если объем данных в каждой записи файла велик, то сортировка самих записей является нецелесообразной, в частности по причине больших временных затрат на пе ремещение записей в процессе сортировки. Кроме того, часто файл имеет не один, а несколько ключей. В этом случае можно ввести вспомогательную таблицу указате лей или несколько таких таблиц и перемещать при сортировке не записи, а указатели на записи (рис. 9.2). Такая сортировка называется сортировкой таблицы адресов (ука зателей). В базах данных таблица указателей может размещаться в отдельном индекс ном файле. Таблица указателей может содержать два поля: ключ и номер соответствующей записи исходного файла.
Рис. 9.2. Отсортированная таблица указателей При работе с таблицами указателей задача поиска записи решается в два этапа: 1) в таблице указателей ищется ключ; 2) в файле данных ищется запись (по ее номеру), с которой связан найденный в таблице указателей ключ. Рассмотрим теперь алгоритмы внутренней пузырьковой и быстрой сортировки ключей. Расширение этих методов для сортировки записей файла или таблицы указа телей представляется очевидным.
9.1.4. СОРТИРОВКА МАССИВА МЕТОДОМ ПУЗЫРЬКА Сортировка методом пузырька наиболее проста для реализации, но имеет незначи тельную вычислительную эффективность. Не теряя общности, будем для простоты изложения в дальнейшем рассматривать задачу сортировки массива х целых чисел, в котором первые п чисел должны быть от сортированы так, чтобы для Идея сортировки методом пузырька в том, чтобы просмотреть массив последова тельно несколько раз. Один просмотр состоит из сравнения каждого элемента массива со следующим за ним элементом (xi сравнивается с xi+1) и обмена этих двух элементов, если они располагаются не в нужном порядке (если xi> хi+1). Рассмотрим массив: 25 57 48 37 12 92 86 33. Результат сортировки: 12 25 33 37 48 57 86 92. Проанализируем процесс сортировки.
Н а п е р в о м п р о с м о т р е делаются сравнения: x1 c x2 (25 с 57) Нет обмена х2 с х3 (57 с 48) Обмен х3 с х4 (57 с 37) Обмен х4 с х5 (57 с 12) Обмен х5 с х6 (57 с 92) Нет обмена х6 с х7 (92 с 86) Обмен х7 с х8 (92 с 33) Обмен После первого просмотра в результате обменов элементы массива расположатся в таком порядке: 25 48 37 12 57 86 33 92 Отметим, что наибольший элемент (в данном случае 92) находится после первого просмотра в нужной позиции. В общем случае элемент xn-pass+1 результирующего массива будет находиться в нужной позиции после итерации pass. Отсюда и идет на звание метода: каждое число медленно "всплывает", как пузырек, вверх на свою ко нечную позицию. После второго просмотра в результате обменов элементы массива расположатся так: 25 37 12 48 57 33 86 92 Как и ожидалось, в нужной позиции оказалось второе по величине число, 86. По скольку каждая итерация помещает в нужную позицию очередной элемент, для сорти ровки массива из и чисел потребуется не более п - 1 итераций. Полный набор итераций при сортировке методом пузырька таков: Массив до начала сортировки 25 57 48 37 12 92 86 33 Итерация 1 25 48 37 12 57 86 33 92 Итерация 2 25 37 12 48 57 33 86 92 Итерация 3 25 12 37 48 33 57 86 92 Итерация 4 12 25 37 33 48 57 86 92 Итерация 5 12 25 33 37 48 57 86 92 Итерация 6 12 25 33 37 48 57 86 92 Итерация 7 12 25 33 37 48 57 86 92 В каждой строчке приведенного списка итераций подчеркнуты элементы массива, находящиеся в нужной позиции. Анализ полного набора итераций подсказывает два очевидных улучшения метода. Во-первых, поскольку все элементы в позициях к> п - 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) - (2k*п - k2 - k)/2. Можно показать, что среднее число ите раций k представляет собой 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] и x [ R 1 ] , то есть чисел 12 и 37. Приведем и результат: 12 25 33 37 48 92 86 57 Итак, массив разбит на две части (до и после разделителя), которые можно сорти ровать отдельно, применяя к каждой из частей только что приведенную схему. Завер шим же сортировку, когда длина каждой из полученных в результате разбиения частей будет равна единице. Замечание. Выбор в качестве будущего разделителя первого элемента массива (или последующего фрагмента) необязателен и в ряде случаев неудовлетворителен. Так, в случае почти отсортированного массива будущий разделитель лучше выбирать ближе к середине рассматриваемого фрагмента. Вычислительная сложность быстрой сортировки оценивается как 0(nlog2n). Так, если сортируется массив из 1024 элементов, то пузырьковая сортировка будет в сред нем выполняться в
раза медленнее.
9.2. ПОИСК ДАННЫХ Поиск данных в векторе и файле выполняется по ключу. Как и при сортировке, выделяют два метода поиска: внутренний и внешний. В первом случае весь файл нахо дится в отведенной под программу памяти ЭВМ. В случае внешнего поиска большая часть данных находится во внешней памяти, например на жестком диске.
Рассмотрим внутренний поиск применительно к одномерному массиву. Предположим, что х - это вектор, содержащий п ключей. Пусть key является аргументом поиска, то есть искомым значением ключа. Сформулируем задачу поиска: установить в переменную search наименьшее целое число i такое, что x[i] = key, если такое i существует, и нуль - в противном случае. (При такой постановке задачи нижняя граница массива х должна быть больше нуля.)
9.2.1. ПОСЛЕДОВАТЕЛЬНЫЙ ПОИСК Последовательный поиск является простейшей формой поиска. В представленной формулировке запись фрагмента поиска тривиальна: перем х[20], нашел, ключ, ин, п; n = 20; нашел = 0; ин= 1; пока (ин х[сред], выполнить аналогичным образом поиск в позициях массива х, следующих за позицией сред. Исключить из дальнейшего рассмотрения часть массива позволяет тот факт, что массив упорядочен. Проиллюстрируем процесс бинарного поиска. Число элементов массива п = 17, тогда [п/2] = 8. Поэтому первоначально выполняется сравнение сред с x 8 = 5 7 . Так как сред > x8, то зона поиска на следующем шаге ограничивается участком от 9-го элемента до 17-го. Этот участок состоит из девяти элементов и его середи ной является элемент х13 = 107 ([(9 + 17)/2] = 13). Поскольку сред > x 1 3 , то зона по иска ограничивается участком от 14-го до 17-го элемента. Его серединой является элемент x15. На этом процесс поиска завершен, так как х15 = сред. Отобразим на рис. 9.3 процесс поиска элемента ключ = 129, выделяя посредством подчеркива ния на каждом шаге зоны поиска. •
Итерация 0 Итерация 0 Итерация 1 Итерация 3
5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179 5 7 11 18 26 32 44 57 81 90 94 97 107 116 129 147 179 Рис. 9.3. Пример дихотомии
Каждое сравнение уменьшает число возможных кандидатов в 2 раза. Максималь ное число шагов поиска будет в том случае, когда аргумент поиска находится в начале или в конце массива. В этом случае потребуется log2n + 1 итераций. Действительно, т если число элементов в массиве равно п = 2 , ключ будет найден, когда нерассмотрен ным останется только один элемент, то есть через т шагов. В свою очередь, при за данном п имеем т = log2n. После анализа последнего элемента получаем общее число итераций log2n + 1. Поэтому вычислительная сложность бинарного поиска составляет O(log2n). Однако приведенный алгоритм не позволяет в общем случае точно решить задачу поиска, когда файл или массив содержат повторяющиеся значения ключей. Рассмот рим, например, массив 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 (210) элемента. В случае последовательного поиска наибольшее число итераций будет равно 1024, а бинарного - 11. То есть разница в два порядка. Сравним теперь временные затраты на поиск в случае неотсортированного файла. При последовательном поиске максимальное число итераций, разумеется, сохраняется. Бинарный поиск неприменим. Выполним, однако, быструю сортировку файла. В сред нем для этого потребуется 1024*log21024 = 10240 итераций. Далее выполним бинар ный поиск, на который будет затрачено не более 11 итераций. Приведенные цифры позволяют сделать вывод: если файл неотсортирован и в про цессе вычислений задача поиска в файле возникает сравнительно редко (в нашем при мере не более 10 раз), то можно применять последовательный поиск, в противном слу чае более целесообразно прежде отсортировать файл или таблицу указателей и при вычислениях применять бинарный поиск. Как правило, именно такой подход исполь зуется на практике.
9.3. ПЕРЕДАЧА ДАННЫХ ИЗ 1С В DBF-ФАЙЛЫ 9.3.1. ЭКСПОРТ ДАННЫХ ИЗ СПРАВОЧНИКА СОТРУДНИКИ_2 9.3.1.1. ПОСТАНОВКА ЗАДАЧИ В разд. 7.4.6 мы загрузили в 1С, используя объект типа XBase, DBF-файл с данными о начальном сальдо. Объекты того же типа применяются и для выгрузки данных из 1С. Рассмотрим задачу переноса данных из справочника Сотрудники_2 в файл еmployee.dbf. Задача осложняется тем, что реквизит Оклад справочника Сотрудники_2 является пе риодическим. Перенос значений этого реквизита мы выполним в отдельный файл salary.dbf, то есть поступим так же, как и 1С, которая хранит данные о периодических рек визитах в файле 1SCONST.DBF. Структуру файла salary.dbf воспроизводит табл. 9.2, в заголовках столбцов которой после символа / указано имя соответствующего поля DBFфайла. Таблица 9.2 Структура файла salary.dbf на примере истории окладов Горюновой У. В. Код\Id 2010 2010 2010
Дата/Date 20.11.2001 22.11.2001 30.11.2001
Имя документа /DocNarne ПриказОПриеме ИзменениеОклада -
Номер документа /Docld
2 2 -
Оклад/Salary 2500 2700 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реквизита
Id
Код
Parentld
-
IsGroup
Свойства DBF-поля
Описание
Числовое поле формата 5.0 Код сотрудника или группы " " 5.0 Ссылка на группу, в которую вхо дит текущий элемент Логическое поле
-
Имеет значение истина, если эле мент является группой, или ложь в противном случае
Name
Наименование Строка из 30 символов
ФИО сотрудника или имя группы
Ed
Образование
Строка из 13 символов
Имеет значение Образование_2
EdId
"
Числовое поле формата 3.0 Код соответствующей записи в справочнике Образование_2
Имя DBFполя OrderEng OrderEngld OrderSal OrderSalld Calendar
Свойства DBF-поля Имя 1Cреквизита ПриказПрием Строка из 15 символов " Числовое поле формата 5.0 ПриказОклад Строка из 13 символов " Числовое поле формата 5.0 Календарь Строка из 9 символов
Описание Имеет значение ПриказОПриеме Номер приказа о приеме на работу Имеет значение ИзменениеОклада Номер приказа об изменении оклада Идентификатор календаря
Очевидно, что, имея файлы employee.dbf и salary.dbf, можно полностью восстано вить справочник Сотрудники_2. Правда, восстановленный справочник не будет точ ной копией оригинала. 9.3.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. 3. 4. 5.
Начало. Выполнить выборку элементов справочника Сотрудники_2. Для каждого элемента найти переносимые в DBF-поля значения. Создать новую запись в файле employee.dbf и перенести в нее найденные в п. 3 значения. Конец.
Для выбранного сотрудника пп. 3 и 4 алгоритма реализует следующий код: дбф.Добавить(); дбф.Id = сСотр_2.Код; дбф.ParentId= сСотр_2.Родитель.Код; дбф.IsGroup = сСотр_2.ЭтоГруппа(); дбф.Name = сСотр_2.Наименование; дбф.Ed = сСотр_2.0бразование.Вид(); дбф.EdId = сСотр_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 тЗнач.НайтиЗначение("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", "Name", 0, 0,""); // Индекс Depart обеспечить сортировку по группам (поле Parentld), // а в пределах групп по полю Name дбф.ДобавитьИндекс("Depart", "trim(str(ParentId)) + Name", 0, 0, ""); дбф.СоздатьФайл("employee.dbf, "employee.cdx"); конецПроцедуры // СоздатьСотр
// Готовит таблицу значений тЗнач для создания файл salary.dbf процедура ДляДБФ2(тЗнач) перем сЗнач, ин, значен, предст, номСтроки, тЗнач2, колСтрок; // Модифицируем таблицу значений тЗнач в соответствии с табл. 9.2 //Для этого создадим список значений сЗнач, содержащий соответствия между // старыми и новыми значениями поля Идентификатор таблицы тЗнач // Строки таблицы значений тЗнач, не отраженные в списке сЗнач, удаляются сЗнач = СоздатьОбъект("СписокЗначений"); сЗнач.ДобавитьЗначение("Id", "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 и вызывает процедуру ПеренестиОклад, которая добавляет //данные в файл salary.dbf для выбранного сотрудника процедура ПеренестиСотр(дбф, дбф2) перем сСотр_2, оп;
// Создаем объект типа Периодический для работы с файлом оп = СоздатьОбъект("Периодический"); сСотр_2 = СоздатьОбъект("Справочник.Сотрудники_2"); сСотр_2.ВыбратьЭлементы(); пока сСотр_2.ПолучитьЭлемент() = 1 цикл дбф.Добавить(); // Новая запись в файле employee.dbf дбф.Id = сСотр_2.Код; дбф.ParentId = сСотр_2.Родитель.Код; дбф.IsGroup = сСотр_2.ЭтоГруппа(); дбф.Name = сСотр_2.Наименование; дбф.Ed = сСотр_2.0бразование.Вид(); дбф.EdId = сСотр_2.0бразование.Код; дбф.OrderEng = сСотр_2.ПриказПрием.Вид(); дбф.OrderEngId = сСотр_2.ПриказПрием.НомерДок; дбф.OrderSal = сСотр_2.ПриказОклад.Вид(); дбф.OrderSalId = сСотр_2.ПриказОклад.НомерДок; дбф.Calendar = сСотр_2.Календарь.Вид(); дбф.3аписать(); // Сохраняем данные // Если выбран сотрудник, а не группа если сСотр_2.ЭтоГруппа() = 0 тогда // Добавляем данные об окладе текущего сотрудника в файл salary.dbf ПеренестиОклад(сСотр_2, оп, дбф2); конецЕсли; конецЦикла // пока конецПроцедуры // ПеренестиСотр // Добавляет для сотрудника сотр записи в файл salary.dbf процедура ПеренестиОклад(сотр, оп, дбф) перем док; // Прикрепляем ОП к периодическому реквизиту Оклад найденного сотрудника оп.ИспользоватьОбъект("Оклад", сотр.ТекущийЭлемент()); // Позиционируемся перед первой записью истории окладов сотрудника оп.ВыбратьЗначения(); // Метод ПолучитьЗначение позиционирует ОП на следующей записи // периодического реквизита Оклад пока оп.ПолучитьЗначение() = 1 цикл дбф.Добавить(); // Новая запись в файле salary.dbf дбф.Id = сотр.Код; // Код сотрудника дбф.Salary = оп.Значение; // Значение и ДатаЗнач- атрибуты ОП дбф.Date = оп.ДатаЗнач; // Документ, вызвавший изменение оклада док = оп.ТекущийДокумент(); если док.Выбран() = 1 тогда дбф.DocName = док.Вид(); дбф.DocId = док.НомерДок; иначе дбф.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.3.2.1. АТРИБУТЫ ОБЪЕКТА XBASE Объект XBase имеет два вида атрибутов: поля DBF-файла и его ключи. Атрибут Поле позволяет по имени поля читать и изменять значение поля текущей записи DBF-файла. Число таких атрибутов равно числу полей файла, на который ссы лается объект XBase. Пример. В окне сообщений выводится значение поля Name 3-й записи файла е т ployee.dbf. В соответствии с рис. 9.6 в этом поле хранится строка Агальцов Юрий Алексеевич. Затем меняется значение 6-й записи файла employee.dbf. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем дбф, ин; ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВазе"); дбф.ОткрытьФайл("emplоуее.dbf"); если дбф.Открыта( ) = 0 тогда Предупреждение("Файла employee.dbf в каталоге пользователя нет."); возврат; конецЕсли; // Перемещаемся на третью запись файла employee.dbf // После того как файл открыт, он позиционируется на своей первой записи дбф.Перейти(3); , Сообщить(дбф.Name); // Напечатает Агальцов Юрий Алексеевич // Перемещаемся на шестую запись файла employee.dbf дбф.Перейти(6); дбф-Name = "Бараненков Иван Несторович"; дбф.3аписать( ); // Не забываем записать изменения в файл Предупреждение("Готово."); конецПроцедуры // Выполнить Замечание. Файл employee.dbf изменялся при закрытом индексном файле етployee.cdx, поэтому индексы этого файла, в которые входит в качестве выражения имя поля Name, не отвечают в полной мере файлу employee.dbf. Следовательно, для поиска по индексу файл employee.cdx необходимо предварительно переиндексировать. Атрибут Ключ является объектом агрегатного типа. Число компонентов объекта равно числу полей DBF-файла, на который ссылается объект XBase. Имя компонента атрибута Ключ составляется по следующей схеме: дбф.Ключ. Атрибут применяется для задания значений, употребляемых при вычислении ин дексного выражения. Полученное значение индексного выражения используется мето дом НайтиПоКлючу в качестве ключа поиска. Этот метод осуществляет поиск по те кущему индексу, применяя в качестве ключа выражение, составленное из значений компонентов атрибута Ключ. Например, с файлом employee.dbf используется индекс
Depart, вычисляемый по выражению TRIM(STR(ParentId)) + Name. Чтобы задать это выражение в программе 1С, необходимо определить два компонента ключа: К л ю ч . P a r e n t I d и Ключ.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 = "Ага"; дбф.НайтиПоКлючу(1); Сообщить(дбф.Name);
// Напечатает Агальцов Юрий Алексеевич
Пример 3. В файле employee.dbf ищется по индексу Depart, индексное выражение ко торого равно TRIM(STR(ParentId)) + Name (см. процедуру СоздатьСотр в разд. 9.3.1.2), Ключ, равный TRIM((STR(12)) + "Бараненков". Процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем дбф; ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВasе"); дбф.ОткрытьФайл("етр1оуее.dbf, "employee.cdx"); если дбф.Открыта() = 0 тогда Предупреждение("Файла employee.dbf и/или файла employee.cdx | в каталоге пользователя нет."); возврат;
дбф.ТекущийИндекс("Depart"); дбф.Ключ.ParentId = 12; //Значение для TRIM(STR(ParentId)) дбф.Ключ.Name = "Бараненков"; // Значение для Name дбф.НайтиПоКлючу(1); // Ключ равен 12Бараненков Сообщить(дбф.Name); // Напечатает Бараненков Иван Несторович конецПроцедуры // Выполнить
9.3.2.2. МЕТОДЫ ОБЪЕКТА XBASE Приводятся в табл. 9.6. Таблица 9.6 Методы объекта XBase Метод
Описание
дбф.СоздатьФайл (DBFфайл, [СDХфайл]);
Создает файл базы данных (DBF-файл) и, если задан второй параметр, индексный файл (CDX-файл). Имена файлов задаются символьными параметрами DBFфайл и СDХфайл. Если имя не содержит пути, то файлы будут созданы в каталоге пользователя. Если файлы с указанными именами на диске имеются, то они будут заменены на новые
дбф.ОткрытьФайл (DBFфайл, [СDХфайл], [флагЧтения]);
Открывает DBF-файл и, если задан второй параметр, индексный файл. Тип параметров DBFфайл и СDХфайл символьный. Файлы открываются только для чтения, если флагЧтения = 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е"); дбф.ОткрытьФайл("Salary.dbf"); если дбф.Открыта() = 0 тогда Предупреждение("Файла salary.dbf в каталоге пользователя нет."); возврат; конецЕсли; // Переход в начало файла salary.dbf; в данном примере метод может быть опущен, // поскольку после открытия файл и так находится на своей первой записи дбф.Первая(); пока дбф.ВКонце() = 0 цикл если дбф.Salary = 2900 тогда Сообщить(дбф.Id); конецЕсли; дбф.Следующая(); конецЦикла; // пока конецПроцедуры // Выполнить Результат: 111 209 Пример 2. Выводятся ФИО всех сотрудников, фамилия которых начинается с буквы Б. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем дбф; ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВаse"); дбф.ОткрытьФайл("emploуее.dbf", "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"); дбф.Ключ.Id = 209; // Ищем запись, большую str(209) // Помним, что индексное выражение - это STR(Id) + DTOS(Date) если дбф.НайтиПоКлючу(2) = 1 тогда // Перемещаемся на последнее значение оклада сотрудника с кодом 209 пока дбф.Id = 209 цикл дбф.Следующая(); конецЦикла; // пока дбф.Предыдущая(); // Шаг назад окл = дбф.ПолучитьЗначениеПоля("Salary"); // или, используя атрибут: окл = дбф.Salary; дбф.Добавить(); дбф.УстановитьЗначениеПоля("Id", 209); дбф.УстановитьЗначениеПоля("Date", ТекущаяДата()); дбф.УстановитьЗначениеПоля("Salary", окл + 500);
// или, используя атрибуты: // дбф.Id= 209; дбф.Date = ТекущаяДата(); дбф.Salary = окл + 500; дбф.3аписать(); Предупреждение("Готово."); иначе Предупреждение("Сотрудника с кодом 209 в файле нет."); конецЕсли; конецПроцедуры // Выполнить Пример 4. Копируется и записывается в файл salary.dbf его последняя запись. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем дбф; ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВаse"); дбф.ОткрытьФайл("salary.dbf"); если дбф.Открыта() = 0 тогда Предупреждение("Файла salary.dbf в каталоге пользователя нет."); возврат; конецЕсли; дбф.АвтоСохранение(1); // Будем обходиться без метода Записать дбф.Последняя(); . // Переход на последнюю запись дбф.Скопировать( ); // Добавляем копию последней записи Предупреждение("Готово."); конецПроцедуры // Выполнить Пример 5. Выводятся описания всех полей и индексов файла salary.dbf. процедура Выполнить() // Связана с кнопкой Пуск обработки Проба перем дбф, ин, имяПоля, тип, длина, точность; перем имяИнд, выражение, уник, убыв, фильтр; ОчиститьОкноСообщений(); дбф = СоздатьОбъект("ХВаse"); дбф.ОткрытьФайл("salary.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 обеспечит сортировку по дате в пределах заданного кода сотрудника дбф.ДобавитьИндекс("IdDate", "str(Id) + dtos(Date)", 0, 0, ""); // Индекс Salary обеспечит сортировку по окладу дбф.ДобавитьИндекс("Salary", "Salary", 0, 0, "Salary > 3000"); дбф.СоздатьИндексныйФайл("Salary.cdx"); дбф.ТекущийИндекс("Salary"); дбф.Первая(); // Переход в начало файла // Вывод результата. Доступны только те записи, у которых Salary > 3000 Сообщить("Коды сотрудников, оклад которых более 3000 руб."); пока дбф.ВКонце() = 0 цикл // Пока не достигнут конец файла Сообщить(Строка(дбф.Id) + Символ Табуляции + "(оклад сотрудника равен " + Строка(дбф.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 Операции выражений индекса и фильтра Операции ** или ^ *,/ +,+ =, или #,,= $ .NOT. .AND. .OR.
Значения Арифметические операции Унарный минус Возведение в степень Умножение, деление Сложение, вычитание Символьные операции Объединение (конкатенация) Объединение 2 (конкатенация 2) Операции отношения Равно, не равно, меньше, больше, меньше или равно, больше или равно, содержит Логические операции Логическое НЕ (отрицание) Логическое И Логическое ИЛИ
Замечания: 1. Все операции, кроме унарного минуса, являются двуместными (бинарными), то есть употребляются между двумя операндами. 2. Выражения вычисляются слева направо в порядке, определяемом приоритетом операций. Часть подвыражения, заключенная в круглые скобки, вычисляется в первую очередь. Более подробно о вычислении выражений см. в разд. 2.6. 3. Унарный минус имеет больший приоритет, чем иные арифметические (и другие) операции. Например, выражение -2**2 вернет, так же как и выражение (-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() DAY(дama) DTOC(дama)
Что возвращает
Текущую дату, например 01/14/02 День месяца, заданного параметром дата Символьное представление даты, заданной параметром дата DTOS(дama) Символьное представление даты, заданной параметром дата, в виде ГГГГММДД IIF(лВыр, выр1, выр2) Результат выражения выр1, если истинно логическое выражение лВыр, или результат выражения выр2 в противном случае. Выражения выр1 и выр2 могут быть произвольного типа LTRIM(cтрокa) Строку, в которой удалены ведущие пробелы параметра строка
Тип результата Дата Число Строка " Совпадает с типом выр1 или выр2 Строка
Тип результата
Что возвращает
Функция MONTH(дaтa)
Номер месяца в году, заданного параметром дата
Число
STOD(cmpoкa)
Дату в формате ГПТММДД
Дата
STR(число, [длина], [десСим])
Строка Символьное представление параметра число в виде строки длиной длина, содержащей десСим десятич ных символов. Если параметры длина и десСим опущены, то результирующая строка имеет 10 сим волов и не содержит десятичной части. Если опущен параметр десСим, то результат также не содержит десятичной части
SUBSTR(строка, начПоз, [числоСим])
Подстроку параметра строка, начинающуюся с позиции начПоз и содержащую числоСим последующих символов. Если последний параметр опущен, то результатом будут все символы от позиции начПоз до конца строки строка
"
TIME()
Текущее время в формате ЧЧ:ММ:СС
"
TRIM(строка)
Строку, в которой удалены завершающие пробелы параметра строка
"
UPPER(строка)
Строку, преобразованную в верхний регистр
"
VAL(строка)
Числовое представление параметра строка
Число
YEAR(дата)
Номер года, заданного параметром дата
"
Замечание. Параметры функций являются выражениями. Причем параметр дата является выражением типа Дата; параметр строка - символьное выражение; парамет ры число, длина, десСим, начПоз и числоСим - числовые выражения. Примеры употребления функций приведены в табл. 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") ltrim(" ABC")
AB
Символьный
ABC ABCD
" "
trim("
ABC
") + "D"
Тип
Результат
Пример вызова
substr("Небосклон", 3, 3)
бос
substr("Hебосклон", 5)
склон
upper("Небосклон")
НЕБОСКЛОН
" " " " " "
va1("Небосклон")
0
Числовой
val("-1.23")
-1.23
val("+432")
432
val("1.3e+2")
130
" " "
str(5.234) str(5.234, 5) str(5.234, 6, 4)
5 5 5.2340
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"
"ДатаНовОклада" "Дата нового оклада" "Дата, с которой вступает в силу новый оклад" "Дата" "0" "0" "0" "0" "Сотрудник" "Сотрудник" "Ссылка на справочник Сотрудники_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 cv77\Test\TXT\измОкл.txt При необходимости код из текстовых файлов можно перенести в модули соответ ствующих объектов. В папку 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. В файл Проба.txt не включен ряд программ, изменяющих состояние системы. На пример, в нем нет процедуры из разд. 7.2, выполняющей смену расчетного периода, процедур из разд. 7.4.5 удаления записей ЖЗ и мягкой смены расчетного периода, про цедур и функций из разд. 7.4.6, выполняющих загрузку начального сальдо из DBFфайла, и т. д. Замечание. Из-за большого числа строк в файле пpoбa.txt его компиляция может занять продолжительное время. Его можно уменьшить либо разбив файл на несколько частей, либо удалив не представляющий интереса код.
Отдельно в обработке Проба_1.ert размещена процедура Выполнить из разд. 5.12.2, Демонстрирующая общие методы справочников. Примеры, использующие помимо кнопок Пуск и Закрыть иные элементы диалога, демонстрируются обработками, список которых представлен в табл. П-2.1. Таблица П-2.1 Обработки для примеров пособия Имя обработки
Что демонстрирует
Проба.ert
Большинство программ, не использующих переменные диалога. Запускает из меню интерфейса Ученик в результате выбора Проба Пуск или Alt+1
Проба_1.ert
Общие методы справочников (процедура Выполнить из разд. 5.12.2)
Проба_2.ert
Пример из разд. 1.5. Диалог с числовым полем приведен на рис. 1.20
Проба_3.ert
Список непериодических констант в таблице значений (пример из разд. 1.8)
Проба_4.ert
Отчет со списком непериодических констант (пример из разд. 1.9)
Открыть.ert
Пример из разд. 1.12. Запускает из меню интерфейса Ученик в результате выбора Проба - Открыть или Alt+5
Открыть_2.ert, Проба_5.ert
Контекст обработки Проба_5, загружаемой из обработки Открыть_2. Модифицированный пример из разд. 1.13
Проба_6.ert
Список значений как элемент диалога (пример из разд. 3.3.4)
Проба_7.ert
Редактирование таблицы значений в диалоге (пример из разд. 3.4.2)
Проба_8.ert
Использование пиктограмм в таблице значений (пример 8 из разд. 3.4.4)
Проба_9.ert
Отчет о сотрудниках по справочнику Сотрудники_2 (пример из разд. 5.11.1)
Проба_10.ert
Тот же отчет, что и в npo6a_9.ert, но с запросом (пример из разд. 5.11.2)
Проба_11.ert
Данные запроса о суммарных результатах по хозяйственным операциям (программа из разд. 7.17.4.)
Проба_12.ert
То же, но с выводом данных о составе групп (программа из разд. 7.17.4)
Проба_13.ert
Данные о суммарных результатах по хозяйственным операциям возвращаются не запросом, а функцией сумХозОп2 (программа из разд. 7.17.4)
Проба_14.ert
Процедуры и функции из разд. 9.3.1.2 переноса данных 1С а DBF-файлы
Проба_15.ert
Вывод произвольного DBF-файла в таблицу значений (пример 6 из разд. 9.3.2.2)
Замечания: 1.
Обработку из табл. П-2.1 будет проще открыть, если в меню интерфейса Ученик выбрать Проба - Открыть или использовать Alt+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.
ОГЛАВЛЕНИЕ Предисловие
3
1. Начальные сведения
5
1.1. Введение
5
1.2. Интерфейс Ученик
5
1.3. Пользователь по имени Ученик 1.4. Обработка по имени Проба 1.4.1. Диалог обработки 1.4.2. Первая программа 1.4.3. Обсуждение первой программы 1.4.4. Модуль обработки Проба 1.5. Переменные диалога
.:
,
8 9 9 12 14 15 18
1.6. Глобальные имена
20
1.7. Константы 1.7.1. Доступ к константам 1.7.2. Непериодические и периодические константы 1.7.3. Примеры работы с непериодическими константами 1.7.4. Методы констант 1.8. Отображение списка констант в диалоговом окне
22 22 23 25 27 29
1.9. Формирование отчета со списком констант
31
1.10. Вывод списка констант в текстовый файл
34
1.11. Загрузка текста модуля из файла 1.12. Как открыть отчет или обработку в программе
36 37
1.13. Контекст обработки Проба
38
1.14. Функции для администратора 1.15. Выводы
42 44
2. Базовые понятия
46
2.1. Объекты и типы данных
46
2.2. Буквальные Константы
47
2.3. Системные Константы
48
2.4. Переменные числовые, символьные и даты
49
2.5. Ввод значений разных типов
50
2.6. Выражения и операции 2.6.1. Выражения 2.6.2. Арифметические операции для числового типа данных 2.6.3. Операции для строк и дат 2.6.4. "Истина" и "ложь" в 1С 2.6.5. Операции отношения 2.6.6. Логические операции 2.6.7. Приоритет выполнения операций 2.7. Массивы
53 53 54 55 55 55 56 56 57
2.8. Встроенные функции для разных типов данных 2.8.1. Встроенные математические функции 2.8.2. Встроенные функции для символьных данных 2.8.3. Встроенные функции для дат и времени 2.8.4. Встроенные функции преобразования типов данных 2.8.5. Форматирование данных 2.8.5.1. Форматирование числовых данных 2.8.5.2. Вывод денежных величин и целых чисел прописью 2.8.5.3. Форматирование символьных данных 2.8.5.4. Форматирование дат 2.8.5.5. Изменение способа вывода чисел прописью 2.9. Управляющие операторы и конструкции.... 2.9.1. Алгоритм как совокупность базовых структур 2.9.2. Ветвления "если" 2.9.3. "Попытка" 2.9.4. Циклы 2.9.5. О вычислении логических выражений 2.9.6. Пример записи алгоритма
59 59 60 61 65 67 68 68 69 70 70 72 72 73 74 76 79 79
2.9.7. Прерывания цикла. Объединение условий 2.9.8. Переход по метке
81 82
2.10. Пользовательские процедуры и функции 2.10.1. Программирование "сверху вниз" 2.10.2. Структура процедур и функций 2.10.3. Параметры процедур и функций 2.10.4. Вложенные вызовы процедур и функций 2.10.5. Оператор Возврат 2.11. Выводы
84 84 84 87 90 91 .....91
3. Агрегатные типы данных общего назначения 3.1. Общие свойства агрегатных типов данных 1С 3.2. Обобщение Пустого значения 3.3. Список значений 3.3.1. Структура списка значений 3.3.2. Пример списка значений 3.3.3. Методы списка значений 3.3.4. Список значений как элемент диалога 3.4. Таблица значений 3.4.1. Атрибуты таблицы значений 3.4.2. Редактирование таблицы значений в диалоге 3.4.3. Текущая строка таблицы значений 3.4.4. Методы таблицы значений 3.5. Выводы
4. Перечисления 4.1. Перечисления 1С 4.2. Перечисление Скидки 4.2.1. Создаем перечисление Скидки 4.2.2. Методы перечислений 4.3. Ввод значений перечисления 4.4. Выводы
93 93 98 99 99 100 103 107 109 109 112 114 115 131
132 132 133 133 135 137 138
6. Объекты типа Периодический 6.1. Порядок использования объекта Периодический
240 240
6.2. Атрибуты объекта Периодический
:242
6.3. Методы объекта Периодический
243
6.4. Просмотр истории периодического объекта
.246
6.5. Выводы
247
7. Журнал и виды расчетов. Календари и табель .... 248 7.1. Журнал расчетов в задаче начисления заработной платы 7.1.1. Понятие журнала расчетов 7.1.2. Пример простого расчета 7.1.3. Некоторые свойства журнала зарплаты и его расчетов. 7.1.4. Мероприятия по созданию журнала зарплаты 7.2. Задание расчетного периода журнала зарплаты
248 248 248 251 251 252
7.3. Виды расчетов 253 7.3.1. Свойства видов расчетов 253 7.3.1.1. Несовместимые виды расчетов. Вытеснение расчета 253 7.3.1.2. Длинные расчеты 254 7.3.2. Перечень видов расчетов предприятия 255 7.3.3. Доступ к документам, вводящим расчеты в журнал зарплаты 256 7.3.4. Порядок ввода и вычисления расчетов журнала зарплаты. Приоритет видов расчетов 257 7.3.5. Добавление видов расчетов в конфигурацию 257 7.3.6. Вид расчета Начальное сальдо 258 7.3.6.1. Свойства вида расчета Начальное сальдо 258 7.3.6.2. Модуль вида расчета Начальное сальдо 259 7.3.6.3. Документ НачПериода_2 261 7.3.7. Справочник хозяйственных операций видов расчетов 264 7.4. Построение журнала зарплата 265 7.4.1. Атрибуты журнала расчетов и его периода 265 7.4.2. Добавление журнала зарплаты в конфигурацию системы 267 7.4.3. Форма списка журнала зарплаты 269
7.4.4. Модуль формы списка журнала зарплаты 7.4.4.1. Процедуры, управляющие элементами диалога 7.4.4.2. Выбор вида расчета для ввода в журнал зарплаты 7.4.4.3. Ввод начального сальдо 7.4.5. Удаление записей журнала зарплаты и мягкая смена расчетного периода 7.4.6. Загрузка начального сальдо из DBF-файла 7.4.7. Отчет по начальному сальдо 7.5. Календари и Праздники
272 273 274 275 277 279 282 286
7.5.1. Создание календаря
...286
7.5.2. Применение календарей и празников 7.5.2.1. Доступ к календарям и праздникам 7.5.2.2. Атрибуты календарей и праздников 7.5.2.3. Методы календарей и праздников 7.5.2.4. Усовершенствование справочника Сотрудники_2 7.6. Табель 7.6.1. Порядок заполнения табеля 7.6.2. Реквизиты и диалог табеля 7.6.3. Модификация меню интерфейса Ученик 7.6.4. Модуль формы списка документа , 7.6.5. Модуль документа 7.6.6. Форма списка журнала документов Табель
287 287 289 290 292 294 294 295 300 300 304 307
7.7. Правила перерасчета видов расчетов
308
7.8. Виды расчетов документа Табель
309
7.8.1. Вид расчета Оклад_2 7.8.2. Вид расчета 7.8.3. Вид расчета ВБанк_2
НДФЛ_2 ;
7.9. Премии 7.9.1. Свойства документа 7.9.2. Диалог формы списка документа 7.9.2.1. Слои диалога 7.9.2.2. Закладки диалога 7.9.2.3. Элементы диалога и их формулы 7.9.3. Модуль формы списка документа 7.9.4. Модуль документа 7.9.5. Форма списка журнала документов Расчеты
309 311 312 312 312 315 315 317 ....319 320 325 328
7.10. Виды расчетов документа Премия 7.10.1. Премия коэффициентом 7.10.2. Премия суммой 7.10.3. Премия 1234 7.11. Взаимодействие вида расчета предприятия
329 329 329 330 330
7.12. Длинные расчеты. Эффект вытеснения расчета
331
7.13. Методы журнала расчетов и его периода
334
7.14. Предопределенные процедуры модуля формы журнала расчетов 7.15. Виды расчетов и их группы 7.15.1. Вывод списков видов расчетов и их групп 7.15.2. Атрибуты видов расчетов и их групп 7.15.3. Методы видов расчетов и их групп 7.16. Атрибуты и методы правил перерасчета 7.16.1. Атрибуты правил перерасчета 7.16.2. Методы правил перерасчета 7.17. Завершаем кодирование Процедур модуля формы списка журнала Зарплата_2 7.17.1. Расчет зарплаты 7.17.2. Формирование расчетного листка 7.17.3. Ведомость перечислений в банк 7.17.4. Сведения для бухгалтерского учета зарплаты 7.18. Первый расчетный период нового года 7.19. Выводы
344 346 346 347 348 349 349 350 352 353 355 359 361 364 365
8. Повышение эффективности функционирования системы... 366 8.1. 8.2. 8.3. 8.4.
Критерии эффективности Увеличение быстродействия Улучщение качества интерфейса Надежность программ
366 366 366 369
8.4.1. Проверка данных 8.4.2. Преодоление конфликтов 8.4.3. Транзакции 8.5. Защита данных 8.5.1. Постановка задачи 8.5.2. Справочник ПраваРасчетчика 8.5.3. Меню и права пользователей 8.5.4. Модификация модуля формы списка журнала Зарплата_2 8.5.5. Модификация модуля формы списка справочника Сотрудники_2 8.6. Сопровождение системы. Обновление конфигурации 8.6.1. Регламентные работы 8.6.2. Инициативные работы 8.6.3. Оптимизация конфигурации и информационной базы 8.6.4. Обновление конфигурации 8.7. Выводы
9. Обмен данными 9.1. Методы сортировки данных 9.1.1. Внешняя и внутренняя сортировка 9.1.2. Понятие ключа 9.1.3. Сортировка таблицы указателей 9.1.4. Сортировка массива методом пузырька 9.1.5. Быстрая сортировка 9.2. Поиск данных 9.2.1. Последовательный поиск 9.2.2. Бинарный поиск 9.2.3. Сравнение последовательного и бинарного поиска 9.3. Передача данных из 1С в DBF-файлы 9.3.1. Экспорт данных из справочника Сотрудники_2
369 370 374 376 376 379 380 381 384 386 386 390 392 395 396
397 397 397 397 398 399 401 402 403 403 ....405 405 405
9.3.1.1. Постановка задачи
405
9.3.1.2. Процедуры переноса данных
407
9.3.2. Атрибуты и методы объекта XBase 9.3.2.1. Атрибуты объекта XBase 9.3.2.2. Методы объекта XBase 9.3.2.3. Выражения индекса и фильтра
9.4. Выводы
Приложение 1. Примеры структур метаданных
416 416 418 427
431
432
Приложение 2. Инструкция по работе с дискетой ..439 Литература
443