Авг
13

Monitor1C

1с

Альтернативный монитор пользователей 1С Предприятия. Данная программа задумана как альтернатива стандартному монитору 1С Предприятия. Ставилась цель максимально облегчить отслеживание пользователей “находящихся” в информационной базе и переключение между различными ИБД. При запуске программа сворачивается в трей. Сканирование начинается с последней использовавшейся на данном компьютере базе (возможен выбор “фиксированной” ИБД – запуск всегда будет производится по выбранной ИБД). В иконке в трее показывается общее количество пользователей которые работают с отслеживаемой базой в данный момент. При наведении курсора мыши на иконку во всплывающем окне показываются имена пользователей. Если пользователей много, то они показываются в виде таблицы, по 15 пользователей в колонке (ограничение 60 пользователей для одной базы). Переключиться на другую базу можно щелкнув правой кнопкой мышки на иконке и выбрав в появившемся меню другую ИБД. Двойной щелчек по иконке открывает основную форму программы. Кроме имен пользователей в ней показываются также и сетевые имена компьютеров на которых эти пользователи работают. Завершить работу программы можно либо через пункт “Выход” в меню, либо закрыв основную форму. Большинство параметров программы можно изменить в настройках.

Авг
13

Кодирование в 1С

1с

Что такое для вас красота? Когда я учился в колледже на бухгалтера-аудитора, на лекции по психологии я услышал высказывание (кажется, Гумилёва) о том, что такое есть красота, и звучало оно следующим образом.

Красота – это наивысшая степень целесообразности

Ещё с того времени эта идея запала ко мне в память. Я согласился с ней, потому что я также считаю, что красивым можно называть только то, что предельно соответствует изначально поставленной цели. И не важно, что мы можем называть красивым.

Кодирование

* Красивым может быть дом. И красота дома будет выражаться в целесообразности его архитектуры, внутреннего убранства, цветового сочетания мебели, обоев и ковра, цветов в вазе и свежих фруктов на журнальном столике.

* Красивой может быть женщина. И красота женщины проявляется в её гармоничном и целесообразном вплетении в канву жизни. Жизни с окружающими друзьями и сотрудниками, кухонной утварью и косметикой, зимними сапожками и парфюмерией, любимым мужем и не менее красивыми детьми.

Красивым может быть и программный код, из которого потом слагаются алгоритмы, диалоговые формы, бизнесс-процессы и конфигурации, с которыми затем работают люди, желающие жить в красивом и целесообразном мире.

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

Красота спасёт мир

Для человека важно не только видеть прекрасное вокруг себя. Не менее важным является способность творить красоту. И даже, пожалуй, творить красоту – это самое главное призвание человека.

Почему же тогда некоторым людям так сложно увидеть в окружающем мире красивое? Почему некоторые творения совершенно не вписываются в окружающий мир, из-за чего не могут быть названы красивыми? Наверно, потому, что творец, желающий создать красивое, не осознаёт цели, поставленной перед ним Творцом, который создал его самого. И чтобы понять, для чего, например, программисту создавать конфигурацию, ему стоит разобраться, для чего был создан он сам. Не так ли, друзья?

Почему бухгалтеры не понимают программистов?

В конце сентября 2008 года я беседовал со своей очень хорошей знакомой. Мы вместе проработали в организации, для которой я создал конфигурацию. Я неизбежно благодарен той организации, потому что именно на ней я нашёл себя, как программиста. И теперь я питаю к этой организации самые тёплые чувства потому, что в ней осталось моё самое первое детище, созданное на платформе 1С.

О чём обычно говорят люди? Как правило, о проблемах. Ведь ещё великий русский классик Лев Николаевич Толстой заметил, что все счастливые люди одинаковы, а из несчастных людей каждый несчастен по-своему. И если разобраться, то в счастливых людях нет разнообразия, новизны и остроты чувств. А потому говорить о них скучно. Поэтому люди если говорят друг с другом, то о проблемах. И именно наши проблемы делают нас индивидуальностями.

Моя знакомая рассказала мне о том, как ей тяжело работается с новым программистом. Со мной ей было работать удобнее, потому что мне можно было всего лишь сказать “Андрей, расходная накладная неправильно считает”, и я сам находил ошибку и исправлял её. Нынешний же программист требует, чтобы бухгалтер составила ему техническое задание и объяснила, по каким синтетическим счетам и какие суммы должны проводиться. Я понимаю, что не у всех программистов 1С есть высшее экономическое образование и степень магистра по бухгалтерскому учёту. Но я также понимаю бухгалтера, который ничего не понимает в программировании и зачастую не способен найти с программистом 1С общий язык. Из-за чего, кстати, большинство проектов автоматизации оказываются незавершёнными. А если и завершаются, то бухгалтер работать с ним не может. Иначе говоря, сие творение оказывается нецелесообразным и некрасивым.

Кодеры

И тогда я сам понял то, о чём часто слышал от знакомых программистов. Ведь из числа программистов можно и даже нужно вычленить многочисленную армию людей, которые не способны мыслить системно. Эти люди не могут воссоздать в своей голове всю многообразную структуру той системы, для которой они пишут свой программный код. Ведь из теории систем известно, что надёжность всей системы определяется надёжностью самого слабого её элемента. И если один из программных модулей 1С будет работать неправильно, значит и на всей системе 1С можно ставить крест!

Раньше, когда моя знакомая работала со мной, она была счастлива работать с 1С и рассказывала всем своим знакомым о том, насколько 1С – хорошая программа. Теперь же программа 1С для неё – это источник проблем и головной боли. Более того, некоторые операции нужно вести в MS Excel. А ведь это ужасно!

Раздел о кодировании

Чем закончилась история с моей знакомой? Я посоветовал ей найти нового программиста. Но и для меня беседа не прошла бесследно. Я понял, что на моём сайте “Я люблю 1С” нужно создать выделенный раздел о кодировании. Не скрою, что я несколько недолюбливаю людей, которые способны только писать программный код по составленному кем-то другим техническому заданию. Но я также смиренно признаю право таких людей на самоидентифиувцию и на занятие тем, что им удаётся лучше всего.

О красоте

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

Или другой пример. На главной странице сайта “Я люблю 1С” располагается блок с картинками, нажав на которые можно перейти к соответствующему разделу сайта. Картинок уже много, и их нужно располагать в два ряда. Семь, как известно, пополам без остатка не делится, а потому ряды были несимметричными, и общая картина была некрасивой. Я понимал и чувствовал, что картинки расположены некрасиво. И я также предвидел, что однажды наступит тот день, когда на сайте появится новый интересный раздел, а в рядах картинок – новая пиктограммка.

И вот теперь этот день настал! Информация на сайте теперь в ещё большей степени соответствует главной цели “Творить красоту”, а сам сайт “Я люблю 1С” стал ещё более красивым!

Авг
13

Программирование в 1С

1с

На тему программирования и общения с программистами хочу рассказать такой случай. Ходил я однажды на собеседования с целью устройства на постоянную работу программистом. И довелось мне общаться с двумя типами специалистов, которые проводили со мной собеседование. К первому типу собеседователей я отнесу менеджеров по персоналу, а ко второму – специалистов по программированию.

Какая между ними разница? Разница огромная! Менеджеры по персоналу начинали разговор с общих вопросов: о смысле жизни, о жизненных приоритетах, о причинах увольнения с предыдущих мест работы, о карьерных планах. Поговорить на эти темы очень увлекательно, тем более если знаешь, что менеджеры по персоналу хотят услышать. А если менеджер по персоналу оказывается, как правило, женщиной, то собеседование становится бессмысленно потраченным временем.

Программирование

Но совсем другое дело, когда собеседование проводит программист. Собственно, это даже не собеседование получается. Мне сразу выдали задание и определили время на его решение. Сделал – молодец, не сделал – свободен. К чему лишние слова?

Вы когда-нибудь видели программиста, который бы на общение с людьми тратил больше времени, чем на общение с компьютером? Я тоже нет. Так о чём можно говорить с программистом? Ведь программист – это не профессия, а стиль мышления и жизни. Насколько я понимаю, если Вы дочитали до этого места, то Вы работаете программистом. Поэтому разговор у нас с Вами будет короткий и по существу.

Волшебное программирование

Вам, уважаемый программист 1С, приходилось когда-нибудь объяснять своим непосвящённым в программирование товарищам о том, чем Вы занимаетесь за компьютером? Если подпустить такого товарища к экрану монитора, то сценка будет примерно такой. Сначала подошедший будет долго и сосредоточенно всматриваться в чередующиеся в непонятной закономерности красненькие, синенькие, зелёненькие и чёрненькие буквочки, а потом произнесёт что-то банальное, типа “И как ты во всём этом разбираешься”.

Чистое кодирование

На самом деле, работа программиста заключается не только в написании программного кода. Толковый программист должен ещё уметь и думать. И в частности, хороший программист должен уметь видеть и анализировать всю систему, для которой он пишет кусочек кода или создаёт новый документ.

О том, как писать программный код наилучшим образом, можно прочитать в разделе “Кодирование”, а в разделе “Программирование” я решил помещать материал о том, как создавать программные системы в 1С.

Авг
13

Бухгалтерский учёт в 1С

1с

Говорят, что о жизни любого человека можно написать книгу. И пускай все люди – разные, но одни предпочитают читать чужие книги, а другие пишут книги сами, и кое-кто даже берётся запечатлеть свою жизнь в неком автобиографическом повествовании.

Мне ещё рано писать мемуары. Но поверьте мне, насколько приятно знать о том, что уже несколько лет я веду рассылки, которые читают более тысячи человек, о том, что у меня есть свой сайт “Я люблю 1С”, в котором я выразил мой профессиональный опыт, и о том, что у меня есть моё любимое дело, которым я занимаюсь с удовольствием.

Бухгалтерский учёт в 1С

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

С другой стороны, бухгалтерия – это, во-первых, достаточно монотонный труд, забирающий у бухгалтера много времени, сил и нервов (не без помощи любимой налоговой администрации, естественно). А во-вторых, это труд, ценность которого для владельца бизнеса ещё приходится доказывать.

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

Первое, что мне захотелось автоматизировать, была калькуляция себестоимости импортированных товаров. Ну, разве не надоедает снова и снова вводить одно и то же наименование поставщиков и товаров, если товар растамаживается по несколько машин на неделе? А эти расчёты? Сложные и, одновременно, из раза в раз одинаковые?

Потом была калькуляция себестоимости готовой продукции и расчёт налогов по заработной плате. И по сей день эти самые сложные, на мой взгляд, участки учёта (я говорю о производстве и зарплате) остаются моими самыми любимыми. Шутка ли, если мне удалось наладить расчёт заработной платы на производственном предприятии без использования компоненты “Расчёт”?

Но самое главное в бухгалтерии – это бухгалтеры! И дело не в том, что я – мужчина, а бухгалтеры, с которыми мне преимущественно посчастливилось работать, – женщины. Нет. В бухгалтерии работают очень хорошие люди. Потому что плохому человеку хороший учёт наладить не удастся. Как говорят умные люди, “что во мне, то и вовне”. Если у человека в голове гармония и порядок, то и бухгалтерский учёт у него на должном уровне.

Что мне хочется сказать в заключение вступительной статьи к разделу “Бухгалтерия”?

Всё, что написано мной в качестве программиста, естественно написано с любовью к программе “1С:Бухгалтерия”. Но всегда, когда я пишу ту или иную программку для автоматизации учёта, я делаю это с любовью к бухгалтерскому учёту и к бухгалтерам.

Июль
30

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

1сВ случае применения объекта “Запрос” для выборки информации из справочников 1С:Предприятия необходимо учитывать следующую особенность. При обработке справочника объект “Запрос” не обрабатывает группы справочника. То есть он не использует их в качестве исходных данных для получения первичной выборки. При обработке уже полученных записей запрос добавляет группы для выбранных записей – элементов, если существует группировка по переменной запроса типа “Справочник”. Такой способ обработки является стандартным, и Запрос выполняет ее так же, как он это делает, например, для реквизитов документа имеющих тип “Справочник”. То есть, если в запросе по документам использовать группировку по реквизиту “Товар” документа “Счет”, то в полученном отчете можно получить записи и по группам товаров, вошедших в запрос. Аналогично, если в запросе по справочнику получать в качестве группировки текущий элемент, то в полученный отчет будут включены записи, соответствующие группам отобранных запросом элементов. Однако так как сами группы не обрабатываются запросом при заполнении таблицы выборки, то в отчет не попадут те группы, которые не имеют элементов, или группы, элементы которых не попали в выборку. Соответственно объект “Запрос” не может применяться в тех случаях, когда нужно обрабатывать собственно группы, или получать все элементы, включая группы. С другой стороны, так как в большинстве случаев должны выбираться непосредственно элементы, запрос может быть успешно применен для обработки справочника. В том числе, Запрос позволяет существенно ускорить выборку элементов по условию, при работе с базой данных в формате SQL.

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

Июль
30

Взаимодействие через OLE

1сОсновные преимущества, благодаря которым OLE активно используется:

  • Для вызывающей базы “по барабану” – какой тип вызываемой базы (DBF или SQL)
  • Объектами вызываемой базы можно управлять всеми известными методами работы с объектами в 1С (т.е. со справочниками работают методы ВыбратьЭлементы(), ИспользоватьДату() и т.п., с документами – ВыбратьДокументы() и т.п.), соответственно, можно напрямую решить – стоит отрабатывать конкретные объекты базы OLE или пропустить их.

Пример 1. Присоединение к базе 1С через OLE.

БазаОле=СоздатьОбъект(“V77.Application”); // Получаем доступ к OLE объекту 1С
Локальная версия (на одного пользователя): V77L.Application
Сетевая версия: V77.Application
Версия SQL: V77S.Application

Далее вместо термина “вызываемая база” будет написано просто “база OLE”, а вместо термина “вызывающая база”“местная база”

Теперь, мы должны знать несколько параметров для запуска базы OLE: Каталог базы, имя пользователя и пароль. Ну, наверное, еще и желание запустить 1С в монопольном режиме :)

КаталогБазыОЛе = “C:\program files\1cv77\МояБаза\”;
ПользовательОле = “Администратор”;
ПарольОле = “qwerty”;
МонопольныйРежимOLE = “ /m”; // для немонопольного запуска указать пустую строку!
ЗапускБезЗаставки = 1; // для появления заставки (например, чтобы наблюдать
// процесс запуска базы OLE визуально) поставьте здесь ”0″
РезультатПодключения = БазаОле.Initialize ( БазаОле.RMTrade , “/d” +
СокрЛП(КаталогБазыОле) + “ /n” + СокрЛП(ПользовательОле)+
“ /p” + СокрЛП(ПарольОле) + МонопольныйРежимOLE,
?(ЗапускБезЗаставки = 1,“NO_SPLASH_SHOW”,“”));
Если
РезультатПодключения = 0 Тогда
Предупреждение(“Не удалось подключится к указанной базе - проверьте вводные!”);
КонецЕсли;

Комментарий: функции СокрЛП() стоят в примере на случай, если пользователь захочет указанные выше переменные сделать в форме диалога, а проблема при этом состоит в том, что в алгоритм программа передаст полное значение реквизита (т.е. допишет в конце значения то количество пробелов, которое необходимо для получения полной длины строки (указана в свойствах реквизита диалога)).

Пример 2. Доступ к объектам базы OLE.

Запомните на будущее как непреложный факт:

  1. Из местной базы в базу OLE (и, соответственно, наоборот) напрямую методом присвоения можно перенести только числовые значения, даты и строки ограниченной длины!!! Т.е. местная база поймет прекрасно без дополнительных алгоритмов преобразования полученного значения только указанные типы значений. Кроме того, под ограничением строк подразумевается проблемы с пониманием в местной базе реквизитов объектов базы OLE типа “Строка неограниченной длины”. К этому же еще надо добавить и периодические реквизиты. Естественно, под методом присвоения подразумеваются и попытки сравнить объекты разных баз в одном условии (например, в алгоритмах “Если” или “Пока” и т.п.).
  2. Есть проблемы при попытке перенести “пустую” дату – OLE может ее конвертировать, например, в 31.12.1899 года и т.п. Поэтому вам лучше заранее выяснить те значения, которые могут появится в местной базе при переносе “пустых” дат, чтобы предусмотреть условия преобразования их в местной базе.

A) Доступ к константам базы OLE:

ЗначениеКонстантыOLE = БазаОле.Константа.ДатаЗапретаРедактирования;

Б) Доступ к справочникам и документам базы OLE (через функцию “CreateObject”):

СпрOLE = БазаОле.CreateObject(“Справочник.Фирмы”); // ”СоздатьОбъект” в OLE не работает!
ДокOLE = БазаОле.CreateObject(“Документ.РасходнаяНакладная”);

После создания объекта справочника или документа к ним применимы все методы, касающиеся таких объектов в 1С:

СпрОле.ВыбратьЭлементы();
Пока
СпрОле.ПолучитьЭлемент()=1 Цикл
Сообщить(Спр.Наименование);
КонецЦикла;

Заметьте, что если вместо “Сообщить(Спр.Наименование)” вы укажете “Сообщить(Спр.ТекущийЭлемент())”, то вместо строкового/числового представления этого элемента программа выдаст вам в окошке сообщение “OLE”. Именно это я и имел в виду, когда говорил, что напрямую мало что можно перенести. Т.е. не будут работать следующие методы (ошибки 1С не будет, но и результат работы будет нулевой). Рассмотрим следующий пример:

СпрOLE = БазаОле.CreateObject(“Справочник.Фирмы”); // это справочник в базе OLE
Док = СоздатьОбъект(“Документ.РасходнаяНакладная”); // а это документ в местной базе
Док.Новый(); // создаем новый документ в местной базе
СпрOLE.НайтиПоКоду(1,0); // спозиционируем в базе OLE
// на фирме с кодом ”1″.
Док.Фирма = СпрOLE.ТекущийЭлемент(); // такой метод не сработает, т.к. справа от ”=” стоит
// объект не местной базы, и местная база 1С его не понимает!

Однако,  сработает следующий метод:

Спр = СоздатьОбъект(“Справочник.Фирмы”); // создаем объект справочника местной базы
Спр.НайтиПоНаименованию(СпрОле.Наименование,0,0); // Или Спр.найтиПоКоду(СпрОле.Код,0);
// т.е. СпрОле.Код и Спр.наименование
// являются обычными числовыми/строковыми
// значениями, которые понимает местная база!
Док.Фирма = Спр.ТекущийЭлемент(); // Вот теперь все в порядке, т.к. с обоих сторон метода
// стоят объекты только местной базы!

Отсюда вывод: возможность доступа к объектам базы 1С через OLE требуется, в основном, только для определенной задачи – получить доступ к реквизитам определенного элемента справочника или документа. Однако, не забываем, что объекты базы OLE поддерживают все методы работы с ними, в т.ч. и “Новый()”, т.е. приведем пример противоположный предыдущему:

ДокОле = CreateObject(“Документ.РасходнаяНакладная”); // Создаем документ в базе OLE
ДокОле.Новый();
Спр = СоздатьОбъект(“Справочник.Фирмы”); // В местной базе получаем доступ к справочнику
Спр.НайтиПоКоду(1,0); // Находим в местной базе фирму с кодом 1 (если есть)
ДокОле.Фирма = Спр.ТекущийЭлемент(); // такой метод не сработает

Однако,  сработает следующий метод:

СпрОле = БазаОле.CreateObject(“Справочник.Фирмы”); // создаем объект справочника базы OLE
СпрОле.НайтиПоНаименованию(Спр.Наименование,0,0); // Или СпрОле.найтиПоКоду(Спр.Код,0);
// т.е. Спр.Код и Спр.Наименование являются обычными числовыми/строковыми значениями,
// которые понимает база OLE!
ДокОле.Фирма = СпрОле.ТекущийЭлемент(); // Вот теперь все в порядке, т.к. с обоих сторон
// метода стоят объекты базы OLE!
ДокОле.Записать(); // запишем документ в базе OLE
Если ДокОле.Провести()=0 тогда
Сообщить(“Не смогли провести документ!”);
КонецЕсли;

В) Доступ к регистрам базы OLE (Не сложнее справочников и документов):

РегОле=БазаOLE.CreateObject(“Регистр.ОстаткиТоваров”);
РегОле.ВыбратьИтоги();
Пока
РегОле.ПолучитьИтог()=1 Цикл // Не забываем, что надо указывать наименование!
Сообщить(“Остаток для ” + РегОле.Товар.Наименование+ “ на складе ” +
РегОле.Склад.Наименование + “ равен ” + РегОле.ОстатокТовара);
КонецЦикла;

Г) Доступ к перечислениям базы OLE (аналогичен константе):

ЗначениеПеречисленияOLE = БазаОле.Перечисление.Булево.НеЗнаю; // :)

Заметьте, что пользы для местной базы от переменной “ЗначениеПеречисленияOLE” особо-то и нет, ведь подобно справочнику и документу перечисление также напрямую недоступно для местной базы. Пожалуй, пример работы с ними может быть следующим (в качестве параметра условия):

СмотретьТолькоВозвратыПоставщикам = 1; // предположим, что это - флажок в форме диалога,
// который мы либо устанавливаем, либо снимаем
ДокОле = БазаОле.CreateObject(“Документ.РасходнаяНакладная”);
ДокОле.ВыбратьДокументы(НачДата,КонДата); // НачДата и КонДата - также реквизиты формы
// диалога, но база OLE прекрасно их понимает -
// ведь это же даты!
Пока ДокОле.ПолучитьДокумент()=1 Цикл
Если СмотретьТолькоВозвратыПоставщикам = 1 Тогда
Если ДокОле.ПризнакНакладной <> БазаОле.Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Продолжить;
КонецЕсли;
Иначе
Если ДокОле.ПризнакНакладной = БазаОле.Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
Сообщить(ДокОле.Вид() + “ № ”+ДокОле.НомерДок + “ от ” + ДокОле.датаДок);
КонецЦикла;

Д) Доступ к счетам базы OLE:

СчтОле=БазаОле.CreateObject(“Счет”);
СчтОле.НайтиПоКоду(“10.5″); // нашли в базе OLE счет 10.5

Е) Доступ к ВидамСубконто базы OLE (аналогичен перечислению):

ВидСубконтоКонтрагентыОле = БазаОле.ВидыСубконто.Контрагенты;

По аналогии со справочниками и документами работает объект “Периодический”, план счетов работает по аналогии с ВидомСубконто, ну и далее в том же духе… Отдельную главу посвятим запросу, а сейчас… стоп. Еще пункт забыл!

Ж) Доступ к функциям и процедурам глобального модуля базы OLE!

Как же я про это забыл-то, а? Поскольку при запуске базы автоматически компилируется глобальный модуль, то нам становятся доступны функции и процедуры глобального модуля (поправлюсь – только те, у которых стоит признак “Экспорт”). Плюс к ним еще и различные системные функции 1С. А доступны они нам через функцию 1С OLE – EvalExpr(). Приведем примеры работы с базой OLE:

ДатаАктуальностиОле = БазаОле.EvalExpr(“ПолучитьДатуТА()”);
// Возвращает дату актуальности
ИмяПользователяОле = БазаОле.EvalExpr(“ИмяПользователя()”);
// возвращает строку
//
// попробуем теперь получить числовое значение НДС у элемента номенклатуры
// через функцию глобального модуля ПроцентНДС(СтавкаНДС) Экспорт!
ТовОле = БазаОле.CreateObject(“Справочник.Номенклатура”);
ТовОле.ВыбратьЭлементы();
// Найдем элемент справочника (не группа!)
Пока ТовОле.ПолучитьЭлемент()=1 Цикл
Если ТовОле.ЭтоГруппа()=0 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ЧисловоеЗначениеПроцентаНДСТовараОле = БазаОле.EvalExpr(“ПроцентНДС(Перечисление.ЗначенияНДС.” +
ТовОле.СтавкаНДС.Идентификатор()+“)”);

На самом деле, в последней строке примера я исхитрился и забежал немного вперед. Дело в том, что как и запрос (см. отдельную главу), так и EvalExpr() выполняются внутри базы OLE, причем команды передавается им обычной строкой, и поэтому надо долго думать, как передать необходимые ссылки на объекты базы OLE в строке текста местной базы. Так что, всегда есть возможность поломать голову над этим…

Алгоритмы преобразования объектов в “удобоваримый вид” между базами.

Ясно, что алгоритмы преобразования нужны не только для переноса объектов между и базами, но и для такой простой задачи, как попытки сравнить их между собой.

И еще раз обращу внимание: ОБЪЕКТЫ ОДНОЙ БАЗЫ ПРЕКРАСНО ПОНИМАЮТ ДРУГ ДРУГА, ПРОБЛЕМЫ ВОЗНИКАЮТ ТОЛЬКО ТОГДА, КОГДА ВЫ НАЧИНАЕТЕ СВЯЗЫВАТЬ МЕЖДУ СОБОЙ ОБЪЕКТЫ РАЗНЫХ БАЗ, т.е. команда

ДокОле.Фирма=СпрОле.ТекущийЭлемент();
// где ДокОле - документ базы OLE, а СпрОле - справочник ”Фирмы” базы OLE

будет прекрасно работать без ошибок. Не забывайте это, чтобы не перемудрить с алгоритмами!

Итак, повторяюсь, что напрямую перенести, да и просто сравнить можно только даты (причем не “пустые”), числа и строки ограниченной длины. Итак, как же нам сравнить объекты разных баз (не числа, не даты, не строки), т.е. как их преобразовать в эту самую строку/число/дату.

А) Преобразование справочников/документов базы OLE (если есть аналогичные справочники/документы в местной базе). В принципе, преобразование их было уже рассмотрено в примерах выше и сводится к поиску их аналогов в местной базе. Могу еще раз привести пример, заодно с использованием регистров:

// ВыбФирма, НачДата, КонДата, ВыбДокумент - реквизиты диалога в местной базе
// причем они все указаны, т.е. не пустые (чтобы не делать лишних команд в примере)
ДокОле = БазаОле.CreateObject(“Документ.РасходнаяНакладная”); // объект базы OLE
Док = СоздатьОбъект(“Документ.РасходнаяНакладная”); // а это - его аналог в местной базе
Спр = СоздатьОбъект(“Справочник.Фирмы”); // а это - местный справочник фирм
ДокОле.ВыбратьДокументы(НачДата,КонДата);
Пока
ДокОле.ПолучитьДокумент()=1 Цикл
// Ищем в местном справочнике фирм аналог фирмы из базы OLE (по коду)…
Если Спр.НайтиПоКоду(ДокОле.Фирма.Код,1)=0 Тогда
Сообщить(“Найден документ с неизвестной фирмой! Ее код: ” + ДокОле.Фирма.Код);
// На самом деле, она может быть просто не указана :))
Если ДокОле.Фирма.Выбран()=0 Тогда
Сообщить(“Извините - она просто не указана! :))”);
КонецЕсли;
ИначеЕсли Спр.ТекущийЭлемент()=ВыбФирма Тогда
Сообщить(“Найден документ указанной вами фирмы! № ”+ДокОле.НомерДок+“ от ”+ДокОле.ДатаДок);
КонецЕсли;
// Ищем аналог документа в местной базе
Док.НайтиПоНомеру(ДокОле.НомерДок,ДокОле.ДатаДок);
Если Док.Выбран()=1 Тогда
Сообщить(“Документ № ”+Док.НомерДок + “ от ” + Док.ДатаДок + “ уже есть!”);
Если Док.ТекущийДокумент() = ВыбДокумент Тогда
Предупреждение(“Приз в студию! Найден указанный вами документ!!!”);
КонецЕсли;
Иначе
Сообщить(“Документ № ”+ДокОле.НомерДок+“ от ”+ДокОле.ДатаДок+“ не найден в базе!”);
КонецЕсли;
КонецЦикла;
// А заодно и получим остаток товара в базе OLE:
РегОле = БазаОле.CreateObject(“Регистр.ОстаткиТоваров”);
ТовОле = БазаОле.CreateObject(“Справочник.Номенклатура”);
ТовОле.НайтиПоКоду(ВыбТовар.Код,0);
ФрмОле = БазаОле.CreateObject(“Справочник.Фирмы”);
ФрмОле.НайтиПоКоду(ВыбФирма.Код,0);
ОстатокТовараНаСкладеОле = РегОле.СводныйОстаток(ТовОле.ТекущийЭлемент(),,
ФрмОле.ТекущийЭлемент(),“ОстатокТовара”);

Б) Преобразование перечислений и видов субконто (подразумевается, что в обоих базах есть аналогичные перечисления и виды субконто). Вся задача сводится к получению строкового или числового представления перечисления или вида субконто.
Не поймите это как прямую команду воспользоваться функцией Строка() или Число() :) ) Нет. Для этого у нас есть обращение к уникальному представлению перечисления и вида субконто – метод Идентификатор() или ЗначениеПоНомеру(). Второй вариант не очень подходит, так как зачастую в разных базах даже перечисления бывают расположены в другом порядке, а вот идентификаторы стараются держать одинаковыми в разных базах. Отсюда вывод, пользуйтесь методом Идентификатор(). Кстати, не путайте вид субконто с самим субконто! Привожу пример преобразования:

// ДокОле - документ базы OLE, и уже спозиционирован на нужном нам документе,
// Док - документ местной базы (например, новый), который мы пытаемся заполнить
// реквизитами из документа базы OLE…
// Будем считать, что реквизиты типа ”справочник” мы уже перенесли :)
// Преобразуем перечисление - и не говорите потом - с ума сойти, как оказалось все просто!
Если ПустоеЗначение(ДокОле.ПризнакНакладной.Идентификатор())=0 Тогда
// если не проверим реквизит на пустое значение - нарвемся на ошибку 1С
Док.ПризнакНакладной = Перечисление.ПризнРасхНакл.ЗначениеПоИдентификатору(
ДокОле.ПризнакНакладной.Идентификатор()); // Что и требовалось сделать
КонецЕсли;
// Преобразуем вид субконто
Если ПустоеЗначение(ДокОле.ВидСубконтоСчетаЗатрат.Идентификатор())=0 Тогда
// если не проверим реквизит на пустое значение - нарвемся на ошибку 1С
Док.ВидСубконтоСчетаЗатрат = ВидСубконто.ЗначениеПоИдентификатору(
ДокОле.ВидСубконтоСчетаЗатрат.Идентификатор()); // Что и требовалось сделать
КонецЕсли;

То же самое относится и к плану счетов – принцип у него тот же, что и у вида субконто…

В) Преобразование счетов:

Во многом объект “Счет” аналогичен объекту “Справочник”. Отсюда и пляшем:

Док.СчетУчета=СчетПоКоду(ДокОле.СчетУчета.Код); // присвоили документу реквизит счета
Если СчетПоКоду(ДокОле.СчетУчета.Код)=СчетПоКоду(“10.5″) Тогда
// Это именно счет 10.5 :)
КонецЕсли;
// Я специально оставил в ”Если” функцию СчетПоКоду(), т.к. в планах счетов разных баз
// могут быть разные форматы счетов, и просто сравнение кода может привести к
// противоположному результату. (Кстати, и сам СчетПоКоду() тоже может иногда подвести,
// так что, вам решать - каким методом пользоваться…)

Работа с запросами и EvalExpr().

Наконец-то добрались и до запросов. Надо пояснить несколько вещей, касаемых запросов (да и EvalExpr() тоже). Самое главное – компиляция текста OLE-запроса (т.е. разбор всех переменных внутри запроса), как и сами OLE-запросы выполняются внутри базы OLE и поэтому ни одна переменная, ни один реквизит местной базы там недоступны, да и запрос даже не подозревает, что его запускают по OLE из другой базы!!! Поэтому, чтобы правильно составить текст, иногда требуется не только обдумать, как передать параметры запроса в базу OLE, но и обдумать, что нужно добавить в глобальный модуль той самой OLE-базы, чтобы как-то собрать для запросы переменные!

  1. Поскольку сам текст запроса и функции EvalExpr() является по сути текстом, а не набором параметров, то напрямую передать ему ссылку на элемент справочника, документ, счет и т.п. нельзя. Исключение может быть составлено для конкретных значений перечислений, видов субконто, констант, планов счетов и т.п.
  2. Хоть и многим и так понятно, что я скажу дальше, но я все-таки уточню: при описании переменных в тексте запроса не забывайте, что объекты базы надо указывать напрямую, без всяких префиксов типа “БазаОле”.
  3. Отрабатывать запрос сложно тем, что ошибки, например, при компиляции напрямую не увидеть. Поэтому начинаем пошагово готовится к отработке запроса в базе OLE.

Вначале допишем в глобальном модуле базы OLE немного строк, которые нам помогут в работе:

//**************************************************************
Перем СписокЗначенийЗапроса[10] Экспорт; // Мы в них ”запихнем” значения для запроса
//**************************************************************
Функция СкорректироватьСписок(ИндексМассива,
Действие,
ТипОбъекта = “”,
ВидОбъекта = “”,
Параметр1 = “”,
Параметр2 = “”,
Параметр3 = “”, // Ну и далее по параметрам, сколько надо
// …………………
Параметр99 = “”) Экспорт
ИндексМассива=Число(ИндексМассива);
Если ИндексМассива = 0 Тогда
Возврат -99; // Обышка: Не указали индекс массива ?
КонецЕсли;
Если Действие = 1 Тогда // Очистить список значений
СписокЗначенийЗапроса[ИндексМассива].УдалитьВсе();
Возврат 1;
ИначеЕсли Действие = 2 Тогда // Добавить объект в список
Если ТипОбъекта = “Документ” Тогда
Если ВидОбъекта = “” Тогда
Возврат -99; // Обышка: Передавайте нормальный вид объекта!
КонецЕсли;
Попытка
Док = СоздатьОбъект(“Документ.”+ВидОбъекта);
Исключение
Возврат -99; // Обышка: Попытка обращения к неверному объекту
КонецПопытки;
Если Док.НайтиПоНомеру(Параметр1,Параметр2)=1 Тогда
СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(Док.ТекущийДокумент());
Возврат 1; // Нашли документ
Иначе
Возврат 0; // Не нашли документ :(
КонецЕсли;
ИначеЕсли ТипОбъекта = “Справочник” Тогда
Если ВидОбъекта = “” Тогда
Возврат -99; // Обышка: Передавайте нормальный вид объекта!
КонецЕсли;
Попытка
Спр = СоздатьОбъект(“Справочник.”+ВидОбъекта);
Исключение
Возврат -99; // Обышка: Попытка обращения к неверному объекту
КонецПопытки;
// Параметр1 - Код
// Параметр2 - наименование
// Параметр3 - флаг глобального поиска
Если Спр.НайтиПоКоду(Параметр1,Число(Параметр3))=1 Тогда
СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(Спр.ТекущийЭлемент());
Возврат 1; // Нашли элемент
ИначеЕсли Спр.НайтиПоНаименованию(Параметр2,Число(Параметр3))=1 Тогда
СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(Спр.ТекущийЭлемент());
Возврат 1; // Нашли элемент
Иначе
Возврат 0; // Не нашли элемент :(
КонецЕсли;
ИначеЕсли ТипОбъекта = “Счет” Тогда
// Вид объекта - Идентификатор плана счетов
// Параметр1 - Код счета
Попытка
Если ВидОбъекта<>“” Тогда
ИскомыйСчет = СчетПоКоду(Параметр1, ПланСчетов.ЗначениеПоИдентификатору(ВидОбъекта));
Иначе
ИскомыйСчет = СчетПоКоду( Параметр1);
КонецЕсли;
Если ПустоеЗначение(ИскомыйСчет) = 1 Тогда
Возврат 0; // не нашли счет :(
Иначе
СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(ИскомыйСчет);
Возврат 1; // нашли счет
КонецЕсли;
Исключение
Возврат -99; // Ошибка: Неверный тип объекта
КонецПопытки;
ИначеЕсли Действие = 3 Тогда // Вернуть размер списка
Возврат СписокЗначенийЗапроса[ИндексМассива].РазмерСписка();
Иначе
Возврат -99; // Ошибка: Неверное действие
КонецЕсли;
Возврат -999; // ???
КонецЕсли;
КонецФункции
//**************************************************************
Процедура ПриНачалеРаботыСистемы()
// Данная процедура уже есть в глобальном модуле, просто надо
// дописать в ней несколько строк:
Для Сч=1 По 10 Цикл
СписокЗначенийЗапроса[Сч]=СоздатьОбъект(“СписокЗначений”);
КонецЦикла;
КонецПроцедуры
//**************************************************************

Теперь начинаем потихоньку писать сам запрос. Что мы имеем:
В форме диалога местной базы несколько реквизитов диалога (либо местные переменные):

  • Даты периода (НачДата и КонДата)
  • Элементы справочников для фильтрации (ВыбТовар, ВыбФирма, ВыбКлиент, и т.д.)
  • Какие-либо флажки (ТолькоЗамерзающийЗимойТовар , ..)

Мы начинаем писать запрос и сразу попадаем в такую ловушку:

ТекстЗапроса = “ Период с НачДата по КонДата; ”;

Вроде все в порядке, но такой запрос не выполнится в базе OLE, так как там понятия не имеют, что такое НачДата и КонДата :) ) Ведь эти переменные действительны только для местной базы! Переписываем запрос заново:

ТекстЗапроса = “ Период с ’” + НачДата + “‘ по ’” + КонДата + “‘;
// Будет типа ’01.01.02′
// т.е. прямое представление даты, которое всегда поймет любой запрос
| Товар = Регистр.ОстаткиТоваров.Товар;
| Фирма = Регистр.ОстаткиТоваров.Фирма;
| Склад = Регистр.ОстаткиТоваров.Склад;
| Остаток = Регистр.ОстаткиТоваров.Остаток;
| Группировка Товар без групп;
| Группировка Документ;
| Функция НачОст =  НачОст(Остаток);
| Функция КонОст =  КонОст(Остаток);
| Функция ПрихОст = Приход(Остаток);
| Функция РасхОст = Расход(Остаток);”;

Так… Дошли до условий отбора в запросе. Рассмотрим два варианта, когда выбран ВыбТовар:

// 1-й вариант - когда выбран элемент справочника (не группа).
// Самый простой случай - коды товаров совпадают абсолютно
// Вариант 1а.
Если ВыбТовар.Выбран()=1 Тогда
ТекстЗапроса = ТекстЗапроса +
| Условие (Товар.Код = ” +ВыбТовар.Код+“);”;
КонецЕсли;
// Вариант 1б. Чтоб запрос быстрее был:
// Вначале добавим к запросу переменную в общем списке:
| КодТовара = Регистр.ОстаткиТоваров.Товар.Код;
// А уж потом добавим к запросу условие (такое условие будет выполнятся проще, так как
// запрос при формировании таблицы запроса сразу сформирует отдельную колонку кодов и по
// ней уже будет отбирать, а не будет каждый раз при обработке товаров извлекать из них
// код):
Если ВыбТовар.Выбран()=1 Тогда
ТекстЗапроса = ТекстЗапроса +
| Условие (КодТовара = ” +ВыбТовар.Код+“);”;
КонецЕсли;

Казалось бы все очень просто. По аналогии – если уникальность для товаров ведется по наименованию, то простой заменой слова “код” на “наименование” мы решаем вопрос и здесь. Теперь рассмотрим, когда мы выбрали группу, т.е. текст условия должен будет выглядеть так:

| Условие (Товар.ПринадлежитГруппе(КакаяТоГруппа)=1);

И здесь, правда можно проблему решить “двумями путями” :) ) Первый пусть – когда мы имеем дело с двухуровне вымсправочником. Тогда проблема группы решается также просто, как и в 1-м варианте:

// Добавляем в списке переменных строку:
| КодРодителя = Регистр.ОстаткиТоваров.Товар.Родитель.Код;
// Далее пишем условие:
Если ВыбТовар.Выбран()=1 Тогда
ТекстЗапроса = ТекстЗапроса +
| Условие (КодРодителя = ” +ВыбТовар.Код+“);”;
КонецЕсли;
// В качестве домашнего задания - переписать условие по наименоваиню :)))

А если справочник очень даже многоуровневый? Вот для этого мы и используем написанную ранее функцию. Предположим, что список значений запроса с индексом массива ” 1 ” мы будем использовать для хранения подобных значений (например, хранить в нем группы товаров, клиентов) для хитрых условий. Итак, например, в ВыбТовар у нас указана группа товаров, а в ВыбКлиент – группа клиентов, которым мы товары группы ВыбТовар продавали. Кроме того, мы должны пропустить накладные возвратов поставщикам, и не забыть, что товары надо еще отбирать по флажку ТолькоЗамерзающийЗимойТовар:

// Очистим список значений запроса
Результат = БазаОле.EvalExpr(“СкорректироватьСписок(1,1)”);
// Закинем в список значений запроса группу товаров (он сам найдет ее в базе OLE)
// И запоминаем (в уме), что этой группе соответствует 1-е значение списка
Результат = БазаОле.EvalExpr(“СкорректироватьСписок(1, 2 , ”"Справочник”", ”"” +
Выбтовар.Вид())+ “”",” + ВыбТовар.Код + “, ”"” +
ВыбТовар.Наименование + “”")”);
// Теперь закинем в список значений запроса группу клиентов
// И запоминаем, что этой группе соответствует 2-е значение списка
Результат = БазаОле.EvalExpr(“СкорректироватьСписок(1, 2 , ”"Справочник”", ”"” +
ВыбКлиент.Вид())+ “”",” + ВыбКлиент.Код + “, ”"” +
ВыбКлиент.Наименование + “”")”);
// А еще до кучи и фирму из ВыбФирма
// И запоминаем, что этой фирме соответствует 3-е значение списка
Результат = БазаОле.EvalExpr(“СкорректироватьСписок(1, 2 , ”"Справочник”", ”"” +
ВыбФирма.Вид())+ “”",” + ВыбФирма.Код + “, ”"” +
ВыбФирма.Наименование + “”")”);
// Теперь формируем текст запроса
ТекстЗапроса = “ Период с ’”+НачДата+ “‘ по ’”+КонДата+“‘;
| Товар = Документ.РасходнаяНакладная.Товар;
| Замерзает = Документ.РасходнаяНакладная.Товар.ЗамерзаетЗимой;
| Признак = Документ.РасходнаяНакладная.ПризнакНакладной;
| Фирма = Документ.РасходнаяНакладная.Фирма;
| Клиент = Документ.РасходнаяНакладная.Клиент;
| Количество = Документ.РасходнаяНакладная.Количество;
| СуммаДок = Документ.РасходнаяНакладная.Сумма;
| Группировка Товар без групп;
| Группировка Документ;
| Функция СуммаОтгрузки=Сумма(СуммаДок);
| Условие (Признак<>Перечисление.ПризнРасхНакл.ВозвратПоставщику);
| Условие (Замерзает = ” + ТолькоЗамерзающийЗимойТовар + “);
// Внимание! Начинается:
| Условие (Товар.ПринадлежитГруппе(СписокЗначенийЗапроса[1].ПолучитьЗначение(1))=1);
| Условие (Клиент.ПринадлежитГруппе(СписокЗначенийЗапроса[1].ПолучитьЗначение(2))=1);
| Условие (Фирма= СписокЗначенийЗапроса[1].ПолучитьЗначение(3));”;

Уфф. Вроде все… Остается только запустить запрос:

Запрос = БазаОле.CreateObject(“Запрос”);
Если
Запрос.Выполнить(ТекстЗапроса)=0 Тогда
Предупреждение(“Запрос безутешен!”);
Возврат;
КонецЕсли;

Ну, а с реквизитами запроса разбираемся так же, как указано было выше в предыдущих разделах… И не забываем, что кроме хранения конкретных значений, можно использовать другие списки значений запроса. Например, можно заполнить какой-либо список значений запроса списком клиентов и использовать его в запросе:

// Всякими правдами/неправдами заполнили список значений (хотя бы через другой запрос :))
// конкретными клиентами…
// Предположим, индекс массива равен ”2″. Тогда в тексте запроса появится следующее:
| Условие (Клиенты в СписокЗначенийЗапроса[2]);

Июль
30

Принципы организации бухгалтерских операций и проводок

1сПри освоении средств конфигурирования 1С:Предприятия одним из частых вопросов, которые требуют дополнительного разъяснения является вопрос об общих принципах организации в системе бухгалтерских операций и проводок. Часто этот вопрос возникает у тех специалистов, которые знакомы с принципами организации регистров оперативного учета. Действительно, проводки бухгалтерского учета имеют много общего с движениями регистров. Однако, движения регистров подчиняются непосредственно документу, а для проводок существует понятие “Операция”, объединяющая проводки сформированные одним документом. Наличие понятия операции объясняется несколькими причинами, связанными с назначением и практикой использования компоненты “Бухгалтерский учет”.

Очень важным отличием механизма бухгалтерского учета от механизма оперативного учета является то, что механизм операций и проводок наряду с автоматическим формированием проводок документами рассчитан на ведение учета вручную. Это возможно благодаря тому, что сама модель бухгалтерского учета (проводки, двойная запись, счета синтетического учета, аналитика) доступна пользователю (бухгалтеру) и программа может общаться с ним именно в тех категориях, в которых и ведется учет. Для оперативного учета это не так. Пользователь не работает напрямую с регистрами, так как механизм оперативного учета не является “общечеловеческим” понятием, а разработан как специализированное средство 1С:Предприятия. Наличие в метаданных понятия “Операция” позволяет обеспечить, для ведения ручного учета возможность удобного ввода проводок в специализированной форме, которая также как и большинство форм в 1С:Предприятии может быть изменена разработчиком конфигурации.

Заметим, что назначение регистров оперативного учета, может быть самое различное. Каждый регистр представляет собой фактически независимую учетную систему. Иногда один или два регистра могут быть логически связаны, но в то же время могут использоваться регистры, которые предназначены для отражения некоторого факта хозяйственной жизни в совершенно разных учетных задачах поддерживаемых конфигурацией. Проводки бухгалтерского учета, как правило, относятся к одному плану счетов и являются отражением хозяйственной операции в одной учетной системе описываемой планом счетов. Таким образом, проводки сформированные документом или введенные вручную в одной операции представляют собой обычно нечто большее, чем просто набор отдельных движений. Понятие “Операция” позволяет объединить все проводки формируемые документом или вводимые вручную. В отличии от движений регистров, которые с помощью соответствующего объекта встроенного языка могут только записываться и считываться по одному движению, все проводки операции считываются при обращении к операции. Затем с ними могут выполняться различные действия, например, можно изменять, добавлять и удалять проводки. Измененная операция записывается целиком.

Пожалуй, одной из самых важных задач операции является возможность вводить для операции реквизиты. Для оперативного учета практически не имели бы смысла, какие либо данные, которые относились бы ко всем документам, записывающим движения регистров. Однако для бухгалтерского учета эта задача вполне актуальна. С точки зрения бухгалтера, все операции (и введенные вручную и сформированные документами) являются равноценными записями, отражающими хозяйственную операцию в бухгалтерском учете. И у этой записи должны быть некоторые данные, характеризующие ее в целом. Наиболее яркими примерами таких данных являются “штатные” реквизиты операции (”Содержание” и “Сумма операции”). Когда бухгалтер работает с отчетами или журналами ему необходима информация, которая не связана с тем, как записана операция (сформирована одним из документов или введена вручную). Введение таких общих данных свойственных бухгалтерским операциям во все документы было бы весьма расточительным, так как во многих конфигурациях далеко не все документы  записывают проводки.

Другой задачей решаемой операциями является отражение всех документов, относящихся к бухгалтерскому учету в журнале операций. Эта задача тесно связана с предыдущей. Она так же помогает представить бухгалтеру все документы с точки зрения их отношения к бухгалтерскому учету. В журнал операций могут не включаться документы, не имеющие отношения к бухгалтерскому учету. При этом в журнале операций обычно не отражается специфическая информация документов, а отражается только та информация, которая единообразно представляет все документы в механизме бухгалтерского учета. Наличие в метаданных объекта “Операция” позволяет определить в конфигурации не только состав данных свойственных всем операциями, но и способ представления операций в журнале.

Июль
29

Технологические вопросы

Обработка ошибочных ситуаций во встроенном языке системы 1С:Предприятие 7.7

Во встроенный язык системы 1С:Предприятие 7.7 внесена возможность обработки ошибочных ситуаций. В предыдущих версиях системы 1С:Предприятие любая ошибка, происшедшая при выполнении модулей встроенного языка приводила к завершению выполнения модуля и выдаче в окно сообщений информации о характере ошибки и модуле, в котором она произошла. При этом разработчик конфигурации не имел возможности вмешаться в процесс обработки ошибочной ситуации и предусмотреть некоторые действия, которые могут нейтрализовать последствия ошибки и позволить продолжить выполнение модуля. Особенно неприятны ситуации, когда из-за несущественных поводов прекращается выполнение длительных процедур, после чего их приходилось начинать сначала. Примером такой ситуации может послужить обработка, выполняющая обход и обновление некоторого реквизита большого числа элементов справочника в случае, если в процессе работы будет произведена попытка обновить реквизит заблокированный другим пользователем. Неприятны также ситуации, когда конфигурации, использующие внешние по отношению к системе 1С:Предприятие программные средства через механизмы OLE Automation не могли произвести проверку наличия установленных на компьютере пользователя необходимых программных средств. Примером для такого случая может послужить поведение отчета, выводящего результаты через OLE Automation в таблицу MS Excel, в условиях, когда MS Excel на компьютере пользователя отсутствует.

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

Попытка

// Некоторые действия

Исключение

// Обработка исключительной (ошибочной) ситуации)

КонецПопытки

Суть в следующем: если при выполнении последовательности операторов <// Некоторые действия> происходит ошибка, то выполнение оператора прекращается и управление передается на первый оператор последовательности <// Обработка исключительной (ошибочной) ситуации)>. После завершения выполнения данной последовательности управление получает первый оператор, следующий за КонецПопытки. В случае, если при выполнении <// Некоторые действия> ошибок не произошло, то управление, минуя <// Обработка исключительной (ошибочной) ситуации)> также попадает на первый оператор, следующий за КонецПопытки. Конструкции Попытка…Иключение…КонецПопытки могут быть вложенными, при этом для передачи управления из более внутреннего обработчика исключительной ситуации в более внешний служит оператор ВызватьИсключение. В случае, если оператор ВызватьИсключение будет выполнен в самом внешнем обработчике ошибки, то выполнение модуля будет прекращено и сообщение об ошибке будет выдано в окно сообщений, как и в случае полного отсутствия обработчиков ошибок. Для получения текста описания ошибки внутри последовательности операторов <// Обработка исключительной (ошибочной) ситуации)> служит встроенная функция ОписаниеОшибки(). Более подробно о механизме обработки исключительных ситуаций можно прочитать в книге “1С:Предприятие 7.7. Описание встроенного языка. Часть 1.”.

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

Если в процессе записи какого-либо элемента справочника Товары произойдет ошибка, то управление будет передано в блок обработки исключительных ситуаций. Пользователю будет выдано сообщение об ошибке и запрос на повторение попытки записи элемента справочника. Если пользователь, выберет вариант “Да”, то попытка записи будет повторена, а если нет, то все сделанные изменения в справочнике будут отменены и выполнение процедуры будет прекращено.

Блокировка объектов базы данных

В данном разделе рассматриваются различные стратегии и логика механизмов блокировок базы данных системы 1С:Предприятие 7.7, используемых для обеспечения многопользовательского режима работы. Как известно, все варианты системы 1С:Предприятие 7.7 способны работать с базами данных в формате .DBF/.CDX. Кроме того, имеются варианты поставки – 1С:Предприятие 7.7 для SQL, способные работать с базами данных, размещаемыми в среде серверов баз данных Microsoft SQL Server 6.5/7.0. Естественно, что для этих двух форматов баз данных используются совершенно разные механизмы доступа к данным. Но при этом логика работы с базой данных в общем остается неизменной. Соответственно, все, о чем будет рассказано в данном разделе является справедливым для обоих возможных форматов построения баз данных системы 1С:Предприятие 7.7.

Блокировки, осуществляемые в базе данных системы 1С:Предприятие 7.7 можно разделить на две группы:

* Табличные (транзакционные) блокировки

* Блокировки отдельных объектов базы данных

Табличные (транзакционные) блокировки , как следует из названия выполняются на уровне таблиц и служат для обеспечения взаимодействия транзакций, выполняемых несколькими экземплярами системы 1С:Предприятие в одной информационной базе. Блокировки данного вида автоматически устанавливаются и снимаются программами системы 1С:Предприятие в процессе отработки транзакций и предназначены для обеспечения неизменности считанных данных в процессе выполнения транзакции. Имеются два уровня табличных блокировок “на чтение” и “на запись”. Различаются эти два уровня тем, что “на чтение” одна и та же таблица может быть заблокирована более чем одним экземпляром системы 1С:Предприятие, в то время как блокировка “на запись” является исключительной, то есть “на запись” таблица может быть заблокирована только одним экземпляром системы.

Работают табличные блокировки следующим образом. Если в процессе выполнения транзакции производится чтение из какой-либо таблицы базы данных, то предпринимается попытка заблокировать данную таблицу “на чтение” (если она не была заблокирована ранее “на чтение” или “на запись”). Если попытка завершается успешно, то чтение завершается успешно и выполнение транзакции продолжается. При этом блокировка с таблицы не снимается до завершения выполнения транзакции. Другие же экземплярами системы 1С:Предприятие лишаются возможности выполнять операции записи в эту таблицу, так как это нарушит принцип неизменности данных, считанных в процессе выполнения транзакции.

Аналогично, если в процессе выполнения транзакции выполняется операция записи, то предпринимается попытка заблокировать таблицу, в которую выполняется запись (если, конечно, блокировка не была установлена ранее) . Если установка блокировки завершается успешно, то операция записи также успешно завершается и таблица остается заблокированной до завершения выполнения транзакции. При этом транзакции, выполняемые другими экземплярами системы 1С:Предприятие лишаются возможности производить чтение из заблокированной “на запись” таблицы, так как для них не может быть гарантирована неизменность считанных ими данных.

Установка табличных блокировок выполняются с таймаутом. Это означает, что в случае неудачной попытки установить блокировку таблицы сразу, попытки будут повторяться в течение некоторого интервала времени. Этот интервал может устанавливаться пользователем с помощью параметра “Время ожидания захвата таблиц Базы Данных”, который доступен через диалог установки параметров системы 1С:Предприятие (пункт меню <Сервис/Параметры>, страница диалога <Общие>).

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

* “Пессимистические”

* “Оптимистические”

“Пессимистические” блокировки предназначены для обеспечения исключительного доступа для изменения к объектам базы данных системы 1С:Предприятие. Данный вид блокировок хорошо знаком пользователям системы 1С:Предприятие. В частности “пессимистическая” блокировка автоматически устанавливается системой 1С:Предприятие при начале редактирования в форме или списке констант, элементов справочников, документов и т. п. Установка “пессимистической” блокировки не позволяет никому (кроме того, кто заблокировал объект) модифицировать заблокированный объект. Только одна “пессимистическая” блокировка может быть установлена для одного объекта базы данных. Это означает, что если тот или иной объект открыт для редактирования одним экземпляром системы 1С:Предприятие, то не только другой экземпляр системы 1С:Предприятия не сможет открыть для редактирования или изменить этот объект, но и никакой модуль встроенного языка в рамках того же экземпляра не сможет его модифицировать.

В более ранних чем 7.7 версиях системы 1С:Предприятие механизм “пессимистических” блокировок использовался только при редактировании тех или иных объектов базы данных и никак не мог быть задействован из встроенного языка. В версии 7.7 введена возможность явной блокировки объектов из встроенного языка. Данная возможность доступна только для объектов, создаваемых посредством обращения к функции СоздатьОбъект . Соответственно, таким способом могут быть заблокированы такие объекты базы данных как элементы справочника, счета бухгалтерского учета и документы. Блокировка отдельных объектов осуществляется с помощью обращения к методу Блокировка(<ВклВыкл>). Необязательный параметр <ВклВыкл> обозначает действие, которое надо выполнить: 1 – заблокировать объект базы данных, 0 – разблокировать. Метод возвращает значение, показывающее результат выполнения операции: 1 – операция выполнена

успешно, 0 – операция не выполнена. Если параметр при обращении к методу не задан, то возвращается текущий статус блокировки объекта базы данных: 1 – заблокирован, 0 – “свободен”. Следует понимать, что имеется в виду статус блокировки, установленной этим же объектом типа справочник, документ или счет, а не каким-либо другим объектом или другим экземпляром системы 1С:Предприятие. Примером использования метода Блокировка может послужить следующий фрагмент модуля:

Спр = СоздатьОбъект(”Справочник.Товары”);

Спр.ВыбратьЭлементы();

Пока Спр.ПолучитьЭлемент() = 1 Цикл

Пока Спр. Спр.Блокировка(1) = 0 Цикл

Если Вопрос(”Элемент справочника заблокирован! Повторить попытку?”,

“Да+Нет”) = “Нет” Тогда

Возврат;

КонецЕсли;

КонецЦикла;

// Модифицируем реквизиты элемента справочника

Спр.Записать(); // Записываем измененный элемент справочника

КонецЦикла;

Следует обратить внимание, что после записи модифицированного элемента справочника не производится снятия блокировки в явном виде. В этом нет необходимости, так как блокировка автоматически снимается при переходе к следующему элементу с помощью метода ПолучитьЭлемент().

Механизм “оптимистических” блокировок предназначен для обеспечения непротиворечивости модификации объектов базы данных. Работают “оптимистические” блокировки полностью автоматически. Отличие “оптимистических” блокировок от “пессимистических” можно пояснить на примере. Предположим имеется задача модификации справочника Товары (например, пересчет цен). Для выполнения этой задачи может использоваться одна из двух имеющихся специальных обработок. Каждая из них последовательно обходит элементы справочника и модифицирует их. Однако первая, подобно тому, как это было показано в приведенном выше примере перед модификацией блокирует элемент справочника, а вторая такой блокировки не производит.

Теперь представим себе, что модификация справочника Товары производится одновременно двумя экземплярами системы 1С:Предприятие. При этом Экземпляр 1 пользуется первым вариантом обработки, а Экземпляр 2 – вторым. При их взаимодействии может наблюдаться следующий результат, если оба экземпляра “встретятся” на модификации одного и того же элемента справочника:

Действия Экземпляра 1 Действия Экземпляра 2 Результат

ПолучитьЭлемент() ОК

ПолучитьЭлемент() ОК

Блокировка(1)

Записать() Ошибка!

Записать() ОК

Из приведенной таблицы видно, что Экземпляр 2 не смог произвести запись элемента справочника, заблокированного Экземпляром 1. Сработал механизм “пессимистической” блокировки. Аналогично, если бы оба экземпляра системы 1С:Предприятие пользовались первым вариантом обработки, то Экземпляр 2 не смог бы заблокировать элемент справочника.

А теперь представим, что оба экземпляра системы 1С:Предприятие пользуются вторым вариантом обработки. Тогда “встреча” на одном и том же элементе справочника может пройти следующим образом:

Действия Экземпляра 1 Действия Экземпляра 2 Результат

ПолучитьЭлемент() ОК

ПолучитьЭлемент() ОК

Записать() Ошибка!

Записать() ОК

Ошибка, которая происходит при записи элемента справочника Экземпляром 2 и является следствием работы механизма “оптимистических” блокировок. Как было упомянуто выше, задачей механизма “оптимистических” блокировок является обеспечение непротиворечивости модификации объектов базы данных. В данном же случае имеет место следующее. Экземпляр 2 считал элемент справочника и приступил к его модификации. В это время Экземпляр 1 успел считать, модифицировать и записать этот же элемент справочника. Когда Экземпляр 2 приступил к выполнению операции записи, значения реквизитов элемента справочника уже отличались от тех, которые были считаны перед модификацией. И в данной ситуации запись элемента справочника может привести к некорректным результатам, так как в общем случае, модификация реквизитов может производиться исходя из их предшествующего состояния, которое оказалось изменившимся.

Таким образом, можно сформулировать различия в логике функционирования двух рассматриваемых механизмов блокировок. Логика механизма “оптимистических” блокировок исходит из предположения (оптимистического), что в промежутке между считыванием и записью измененного состояния объекта вероятность того, что этот же объект будет изменен кем-то другим невелика. Логика же механизма “пессимистических” блокировок в соответствии с их названием исходит из того, что случиться может всякое и лучше, если объект будет гарантированно защищен от посторонних изменений.

Вычисление логических выражений в операторах встроенного языка

В условных операторах и операторах цикла встроенного языка системы 1С:Предприятие для определения последовательности выполняемых действий используются логические выражения. Логическим выражением может быть элементарное логическое выражение (сравнение двух значений) или более сложные конструкции полученные из элементарных логических выражений при помощи логических операций И/ИЛИ/НЕ.

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

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

Процедура Обработать(Об)

Если (ТипЗначенияСтр(Об) = “Справочник”) И (Об.Вид() = “Товары”) Тогда

// Некоторые действия

КонецЕсли;

КонецПроцедуры

Если в качестве значения параметра, передаваемого в данную процедуру, будет фигурировать элемент справочника любого вида, то процедура будет работать нормально, но если в качестве параметра будет передано значение типа “Число” или “Дата”, то выполнение процедуры будет аварийно завершено. В логическом выражении, используемом в операторе ‘Если’ только составляющая ТипЗначенияСтр(Об) = “Справочник” будет корректно функционировать независимо от типа передаваемого параметра, а составляющая Об.Вид() = “Товары” сможет нормально работать только в том случае, если в качестве параметра в процедуру передано значение агрегатного типа и для данного агрегатного типа определен метод Вид(). Дело в том, что при вычислении логических выражений встроенный язык системы 1С:Предприятие 7.х сначала вычисляет элементарные логические выражения (операции сравнения), а затем производит вычисление логического выражения в целом (операции И/ИЛИ/НЕ).

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

Процедура Обработать(Об)

Если ТипЗначенияСтр(Об) = “Справочник” Тогда

Если Об.Вид() = “Товары” Тогда

// Некоторые действия

КонецЕсли

КонецЕсли

КонецПроцедуры

В данном случае порядок вычисления логических выражений в операторах Если выражен в явном виде и выражение Об.Вид() = “Товары” будет вычисляться только в том случае если условие ТипЗначенияСтр(Об) = “Справочник” окажется истинным и ошибки при выполнении процедуры не произойдет при любом значении параметра.

Заметим, что приведенный выше порядок вычислений не распространяется на вычисление выражений определяющих результат оператора “?”. Само условие оператора “?” вычисляется по общим правилам логических выражений описанным выше, но из двух выражений определяющих результат оператора “?” выполняется только одно (в зависимости от результата логического выражения). То есть, в одном из выражений определяющих результат оператора “?” (не вычисляемом) ошибок времени выполнения не будет возникать вне зависимости от используемых в нем конструкций.

Особенности применения предопределенных процедур встроенного языка

Во встроенном языке системы 1С:Предприятие 7.x предусмотрен ряд системных предопределенных процедур При…, таких как “ПриЗаписи”, “ПриУдаленииДокумента”, “ПриУдаленииЭлемента”, “ПриЗаписиКонстанты”, “ПриОтменеПроведенияДокумента” и т. п., определяемых в различных модулях конфигурации и вызываемых системой при выполнении соответствующих действий. Назначение указанных процедур состоит в том, чтобы специалист по конфигурированию мог предусмотреть необходимые проверки при интерактивном выполнении соответствующих операций, и, в случае необходимости, имел возможность запретить их выполнение.

При этом следует учитывать следующие особенности данных процедур:

1. Указанные предопределенные процедуры не связаны непосредственно с действиями, при выполнении которых они вызываются, а сам вызов производится только при интерактивном выполнении указанных действий. Например, процедура “ПриУдаленииДокумента” будет вызвана в том случае, когда удаление документа будет инициировано “нажатием кнопки” в форме журнала. В то же время вызов этой предопределенной процедуры не будет производиться, если удаление документа производится из какого-либо модуля встроенного языка (например, из некоторой обработки).

2. Вызовы указанных предопределенных процедур не объединены с выполняемым действием единой транзакцией. Это означает, что в случае интерактивного удаления документа, само удаление документа выполняется в транзакции, отдельной от действий, которые могут выполняться в процедуре “ПриУдаленииДокумента”. И если в процедуре “ПриУдаленииДокумента” действия будут выполняться в раках одной, явно определенной в процедуре транзакции, то все равно приходится говорить о двух транзакциях:

- удаление документа;

- действия, выполняемые в процедуре “ПриУдаленииДокумента”

Примером неправильного применения таких предопределенных процедур является использование предопределенных процедур группы “При…” для выполнения действий критичных с точки зрения поддержки целостности данных. Например, при записи документа создается, записывается и проводится ряд связанных с ним документов (процедура “ПриЗаписи” модуля формы документа). И эти же связанные документы удаляются при удалении “ведущего” документа (процедура “ПриУдаленииДокумента” глобального модуля).

Такую технику вряд ли следует признать правильной, в силу приведенных выше особенностей предопределенных процедур. Так как предопределенные процедуры не связаны жестко с выполняемыми действиями, то вполне вероятно, что при очередном изменении конфигурации удаление документа станет выполняться не из формы журнала, а из специально созданной обработки, что приведет к тому, что процедура “ПриУдаленииДокумента” в данном случае вызываться не будет и, соответственно, не будут произведены необходимые для этого случая действия. Но если возникновение ситуаций такого рода еще можно как-топредотвратить путем более тщательной проработки конфигурации, то объединить действия, выполняемые в рамках процедуры “ПриУдаленииДокумента” и собственно удаление документа в одну транзакцию не возможно. При этом разнесение единого по логике действия в разные транзакции может быть весьма опасно с точки зрения поддержания логической целостности данных, так как ситуация, когда одно действие выполняется, а другое по каким-либо причинам – нет, вполне вероятна, особенно в многопользовательских системах.

Заметим, что описанные выше особенности предопределенных процедур не распространяются на предопределенные процедуры “ОбработкаПроведения” и “ОбработкаУдаленияПроведения”. Эти предопределенные процедуры вызываются непосредственно в транзакции проведения (отмены проведения) и выполняемые в них алгоритмы логически связанны с самим выполняемым действием. Кроме того, в отличие от других предопределенных процедур эти предопределенные процедуры выполняются и в случае проведения (отмены проведения) средствами встроенного языка.

Сохранение (восстановление) значений в строку

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

Заметим, что в данном случае речь идет не о преобразовании к строке значения вызовом функции “Строка” или аналогичном автоматическом преобразовании в выражении строкового типа. Такое преобразование используется лишь для получения визуального представления значения и кроме типов “число”, “строка”, “дата”, не имеет возможности обратного преобразования.

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

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

Какие значения преобразуются в строку.

К строковому виду могут быть преобразованы значения любых типов, которые могут храниться в информационной базе, то есть тех типов, которые доступны, например, при создании реквизита документа. Это, прежде всего, базовые типы (”число”, “строка”, “дата”), а также типы определяемые метаданными (”перечисление”, “счет”, “справочник”, “документ” и т.д.).

Кроме того, к строке могут быть преобразованы значения типа “СписокЗначений” и “ТаблицаЗначений”, которые фактически представляют собой набор отдельных значений.

Значения других типов используемых во встроенном языке 1С:Предприятия, но не хранящиеся в информационной базе (например, “Таблица” или “Запрос”) не могут быть преобразованы к строке.

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

Также следует иметь в виду, что преобразуются к строке отдельные значения, а не объекты данных. То есть, можно преобразовать к строке значение реквизита элемента справочника, но нельзя преобразовать к строке весь элемент справочника целиком. Для сохранения в строке элемента справочника, необходимо сохранять отдельно все его реквизиты.

Способы преобразования к строке.

Значения могут преобразовываться к строке в двух разных форматах – внутреннем и внешнем. Использование этих форматов существенно отличается по своему назначению и возможностям. При преобразовании к строке формат (внутренний или внешний) всегда задается явно. Он определяется именем функции или ее параметром. При обратном преобразовании (из строки) необходимо вызывать соответствующую функцию преобразования именно из того формата, в котором выполнялось сохранение значения в сроковом виде.

Внутренний формат.

Для преобразования к строковому виду (и обратно) во внутреннем формате используются следующие функции:

- ЗначениеВСтрокуВнутр / ЗначениеИзСтрокиВнутр;

- ЗначениеВФайл / ЗначениеИзФайла – параметр “Формат” =1;

- СохранитьЗначение / ВосстановитьЗначение.

Кроме того, во внутреннем строковом формате хранятся значения расшифровок табличного документа.

Значение, полученное в сроковом виде во внутреннем формате, может быть преобразовано из строки к исходному типу только в той же информационной базе. Это объясняется тем, что для сохранения значения во внутреннем формате используются системные идентификаторы (не отображаемые на экране), как объектов метаданных, так и объектов данных. При попытке преобразовать значение, сохраненное во внутреннем формате, в другой конфигурации может произойти неправильное преобразование значения.

Если объект данных в информационной базе, на который ссылалось значение, удален (например, элемент справочника), то при преобразовании значения из строки обращение к этому значению не вызовет системной ошибки, но, разумеется и не позволит получить данные удаленного объекта.

Строки, полученные преобразованием значений к строке во внутреннем формате нельзя хранить в информационной базе. Прежде всего, это приведет к нарушению работы механизма контроля ссылочной целостности. Также, это может повлиять на работу компоненты “Управление распределенными данными ИБ”. Разумеется, такое хранение значений, также не позволит системе оптимизировать обращение к данным при использовании версий 1С:Предприятия для SQL. Заметим, что хранение в информационной базе значений преобразованных в строку нарушает идеологию 1С:Предприятия и затрудняет отладку и модификацию конфигураций.

Отдельно следует отметить возможность использования преобразования значений к строке во внутреннем формате для однозначной идентификации объектов, при переносе информации из одной информационной базы в другую. То есть, при загрузке некоторых данных из другой информационной базы строковые представления значений другой ИБ в данной ИБ не могут использоваться собственно для обратного преобразования, но могут использоваться для сопоставления двух значений той ИБ, из которой идет загрузка. Например, если загружается справочник, то ссылку на родителя загружаемого элемента можно сопоставить со ссылкой ранее загруженной группы справочника, для точной идентификации родителя. Разумеется, сопоставлять можно только строки, полученные в одной информационной базе. То есть в описанном примере строковое представление во внутреннем формате должно выгружаться и для самих групп и для родителей элементов, чтобы при загрузке их можно было сопоставить. Для сопоставления можно рекомендовать запоминать при загрузке групп строковые представления этих групп в исходной ИБ, а при загрузке элементов искать группу соответствующую загружаемому элементу по строковому представлению родителя элемента в исходной ИБ.

Внешний формат

Для преобразования к строковому виду во внешнем формате используются

следующие функции:

- ЗначениеВСтроку / ЗначениеИзСтроки;

- ЗначениеВФайл / ЗначениеИзФайла – параметр “Формат” =0.

В отличие от внутреннего формата, при преобразовании значения в строку во внешнем формате система использует не системные идентификаторы объектов метаданных и данных, а обычные строковые идентификаторы объектов метаданных и те значения данных, на основании которых можно однозначно идентифицировать объект. Например, для преобразования к строке во внешнем формате значения типа “Справочник.Товары” будет использован идентификатор справочника “Товары”, а также код элемента справочника. Если для кода справочника уникальность установлена в пределах группы, то будет использован полный код с учетом всех вышестоящих групп. Если справочник является подчиненным, то для идентификации значения будут использован код элемента справочника – владельца. Разумеется, если для справочника отключен контроль уникальности кодов, то преобразование значения этого типа практически не имеет смысла. Для сохранения значения типа “документ”, если уникальность номеров поддерживается в пределах некоторого интервала (года, месяца), то для сохранения и восстановления значения используется также дата документа.

Внешний формат преобразования к строке может использоваться для переноса значений между различными информационными базами. Разумеется, успех обратного преобразования зависит от того, имеются ли в той информационной базе, в которой значение преобразуется из строки объекты метаданных с соответствующими идентификаторами и объекты данных соответствующими кодами/номерами. Например, полученное нами в строковом виде значение типа “Справочник.Товары”, будет правильно обратно преобразовано, если имеется справочник, товары и элемент справочника с тем кодом, который был у элемента, на который ссылалось значение преобразованное к строке.

При восстановлении значения из строки во внешнем формате преобразование может быть не выполнено по нескольким причинам. Например, в той конфигурации, в которой происходит преобразование из сроки, не существует объекта метаданных с идентификатором, соответствующим типу значения, сохраненного в строке. Другой причиной может быть отсутствие в информационной базе объекта данных с тем кодом (номером), который был у элемента справочника, документа или счета, на который ссылалось сохраненное в строке значение. Кроме того, преобразование может быть не выполнено из-за отличий в свойствах объектов метаданных. Например, если при сохранении в строку значения типа “Справочник.Товры” у справочника “Товары” была установлена уникальность кода в пределах подчинения, а при восстановления значения из строки уникальность кода была установлена в пределах всего справочника, то значение из строки не будет восстановлено. Однако, неудачное преобразование из строки не вызывает системной ошибки, а приводит лишь к получению пустого значения.

Заметим, что возможность преобразования к строке во внешнем формате может использоваться при передаче данных из одной информационной базы 1С:Предприятия в другую с помощью Ole Automation, так как непосредственно передать значение типа “справочник”, “документ” и т.п. через Ole

Automation нельзя.

Следует учитывать, что восстановление значений типа “справочник”, “документ” или “счет” из строки во внешнем формате в отличие от использования внутреннего формата занимает определенное время, так как при этом выполняется обращение к информационной базе для поиска значений по сохраненному номеру (коду).

Заметим, что преобразование к строке и обратно значений типа “число”, “строка” и “дата” происходит однозначно (гарантированно) в обоих форматах, так как эти значения не зависят от конфигурации. В качестве примера такого сохранения в методической конфигурации в обработке “НастройкаПрописи” выполняется сохранение в файле строк, используемых для вывода чисел, дат и периодов прописью.

Работа со значениями агрегатных типов во встроенном языке

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

Каждое значение агрегатного типа в системе 1С:Предприятие включает две составляющие:

* внутренний идентификатор объекта данных;

* ссылка на объект доступа.

Внутренний идентификатор объекта предназначен для максимально полной идентификации объекта, соответствующего значению агрегатного типа. А объект доступа служит для обращения к объекту данных посредством реквизитов и методов. При выполнении присваивания переменной встроенного языка значения агрегатного типа, в переменную копируется внутренний идентификатор объекта и ссылка на объект доступа, если таковой имеется. Сам объект доступа при этом не копируется! Таким образом, в результате

выполнения оператора

A = B;

при условии, что переменная B имела значение агрегатного типа и уже имела ссылку на объект доступа, переменные A и B будут ссылаться на один и тот же объект доступа. В отличие от базовых типов (число, строка, дата), для которых при присваивании копируется само значение, при присваивании агрегатных типов копируется не объект доступа, а только ссылка на него.

Здесь, однако, следует учитывать, что не всегда значение агрегатного типа содержит ссылку на тот или иной объект доступа. В некоторых случаях объекта доступа, соответствующего значению агрегатного типа может еще не существовать.

Значение агрегатного типа всегда содержит ссылку на объект доступа в тех случаях, когда значение было создано с помощью функции СоздатьОбъект(). А вот у атрибутов запросов, реквизитов справочников, документов и т. п., имеющих агрегатный тип, значения изначально не содержат ссылок на объекты доступа, пока они не будут созданы при обращении к атрибутам и методам. Соответственно и при присваивании таких значений переменным встроенного языка, переменные также не приобретают ссылок на объекты доступа, если они еще не были созданы.

Как же тогда в таких случаях происходит обращение к атрибутам и методам? Дело в том, что значение агрегатного типа, у которого нет ссылки на объект доступа может существовать только для конкретных типов системы 1С:Предприятие – элементов справочников, документов, счетов бухгалтерского учета и т. п.. И здесь выручает внутренний идентификатор объекта, который всегда содержится в значении агрегатного типа и для указанных типов может предоставить исчерпывающую информацию, необходимую для создания объекта. А само создание объекта доступа производится при первом обращении его методу или атрибуту. Поясним вышесказанное на примере:

Тов = Док.Товар; // Объект доступа еще не создан, при условии, что ранее не было обращений к атрибутам и методам;

Тов2 = Док.Товар; // Аналогично

Цена = Тов.Цена; // Для переменной Тов создается объект доступа

Цена2 = Тов2.Цена; // Для переменной Тов2 создается объект доступа. Тов и Тов2 ссылаются на разные объекты доступа

Тов3 = Тов; // Тов и Тов3 ссылаются на один объект доступа

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

Надо отметить, что объекты доступа продолжают существовать до тех пор, пока на них есть ссылки. Для приведенного выше примера уничтожение объектов, созданных для доступа к реквизитам элемента справочника может быть вызвано выполнением последовательности операторов:

Тов = 0; // Удалена ссылка на объект доступа

Тов2 = 0; // Уничтожен первый объект доступа

Тов3 = 0; // Уничтожен второй объект доступа

В результате выполнения этих операторов ссылки на объекты доступа удаляются путем присваивания переменным других значений. Ссылки на объекты доступа были бы также уничтожены при выходе из процедуры или функции, для которой переменные Тов, Тов2 и Тов3 были локальными. Если же переменная, содержащая ссылку на объект доступа, является глобальной переменной глобального модуля, то единственный способ уничтожить ссылку на объект доступа – это присвоить переменной другое значение.

Теперь рассмотрим случай, когда обращение к реквизиту происходит не через одну, как в рассмотренных выше примерах, а через две и более точек? Например, в случае выполнения оператора:

Цена = Док.Товар.Цена;

В этом случае, исполняющая система встроенного языка получает значение реквизита Товар документа, представленного значением переменной Док. При этом полученное значение не будет содержать ссылки на объект доступа. Затем, исполняющая система создает объект доступа, соответствующий реквизиту Товар, и, затем, с помощью созданного объекта, получает значение реквизита Цена. Затем объект доступа удаляется, так как ни одна из переменных после выполнения указанного оператора на объект не ссылается. Таким образом, при выполнении последовательности операторов

Наимен = Док.Товар.Наименование;

Цена = Док.Товар.Цена;

объект доступа, соответствующий Док.Товар будет дважды создан и дважды уничтожен. С точки зрения производительности для достижения той же цели было бы эффективнее воспользоваться последовательностью операторов:

Тов = Док.Товар; // Присваивается реквизит документа. Объект доступа еще не создан

Наимен = Тов.Наименование; // Для переменной Тов создается объект доступа

Цена = Тов.Цена; // Используется созданный ранее объект доступа

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

Значения типов, соответствующих объектам информационной базы во встроенном языке

Для таких объектов информационной базы системы 1С:Предприятие как справочники, документы и счета бухгалтерского учета значения, представляющие эти объекты во встроенном языке могут выступать в двух разных видах:

- значения, полученные путем вызова системной функции СоздатьОбъект

- значения полученные из реквизитов форм и атрибутов объектов информационной базы

Значения, полученные при помощи вызова СоздатьОбъект() не представляют какой-то конкретный объект (элемент справочника, документ, счет бухгалтерского учета), а предназначены главным образом для обработки групп объектов. С помощью таких значений можно получать выборки множества объектов, последовательно обходить объекты, попавшие в выборку, производить их обновление, создавать новые и удалять существующие объекты и т. п.. Такие значения могут использоваться “многократно”, то есть с помощью одного значения можно получить доступ сначала к одной выборке, потом к другой и так много раз.

Значения, содержащихся в реквизитах форм и атрибутах объектов информационной базы, являются точными значениями и представляют ровно один конкретный объект информационной базы (элемент справочника, документ, счет бухгалтерского учета). Такие значения также могут быть пустыми – не представляющими никакого объекта. С помощью таких значений можно получать доступ к атрибутам соответствующего объекта, но нельзя производить действий по созданию, удалению и изменению объекта.

Но несмотря на такие существенные различия оба описанных варианта значений одинаковы во многих проявлениях. Рассмотрим пример:

Спр1 = СоздатьОбъект(”Справочник.Товары”);

Спр2 = Док.Товар;

Переменные Спр1 и Спр2 содержат значения двух описанных выше видов. Для этих переменных способ доступа к атрибутам справочника производится одним и тем же способом. Многие методы объекта типа Справочник могут применяться как к Спр1, так и Спр2. Функции ТипЗначения() и ТипЗначенияСтр(), будучи примененными к Спр1 и Спр2 дадут одинаковые результаты. Многие методы встроенного языка также не различают какого вида значение передано им в качестве параметра: точное значение объекта или спозиционированная выборка.

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

1.

Спр1 = СоздатьОбъект(”Справочник.Товары”);

Спр1.ВыбратьЭлементы();

Пока Спр1.ПолучитьЭлемент() = 1 Цикл

Обработать(Спр1);

КонецЦикла;

2.

Спр2 = Док.Товар;

Обработать(Спр2);

В первом случае в качестве параметра процедуре Обработать() передается выборка, спозиционированная на конкретный элемент справочника, а во втором – точное значение элемента справочника. И, если, например, в процедуре Обработать() производится только считывание реквизитов справочника, то результаты, полученные в обоих случаях будут неразличимы. Но если в процедуре Обработать() производится присвоение переданного в качестве параметра значения реквизиту формы или атрибуту объекта (например, документа), то первый вариант просто не будет работать, так как вместо точного значения элемента справочника процедура получит выборку. Для того, чтобы все работало нормально первый вариант должен выглядеть так:

Спр1 = СоздатьОбъект(”Справочник.Товары”);

Спр1.ВыбратьЭлементы();

Пока Спр1.ПолучитьЭлемент() = 1 Цикл

Обработать(Спр1.ТекущийЭлемент());

КонецЦикла;

Функция ТекущийЭлемент() в качестве значения возвращает точное значение элемента справочника, на который спозиционирована выборка. А если функция ТекущийЭлемент() применяется к переменной, значением которой является уже точное значение элемента справочника, эта функция вернет само это значение. Так что равноценным вариантом решения показанной в примере проблемы было бы, если для выполнения действий процедура Обработать() использовала бы не сам переданный параметр, а значение некоторой переменной (например, Спр), значение которое получила бы из переданного параметра (Парам) следующим способом:

Спр = Парам.ТекущийЭлемент();

Однако следует иметь в виду, что при вызове метода ТекущийЭлемент() у переменной, значение которой получено из реквизитов форм и атрибутов объектов информационной базы, а не путем вызова функции СоздатьОбъект() будет выполняться поиск элемента справочника в информационной базе, что повлечет к дополнительным затратам времени. Соответственно, если полученное конкретное значение предполагается просто присвоить (например, измерению регистра), а не обращаться к его атрибутам и методам, и известно, что это именно конкретное значение, а не выборка, использовать метод ТекущийЭлемент() не следует. Поэтому можно рекомендовать создавать процедуры ориентированные на получение в качестве параметра только конкретного значения, а при вызове процедуры с передачей в качестве фактического параметра выборки вызывать метод ТекущийЭлемент().

Обработать(Спр1.ТекущийЭлемент());

Аналогичные соображения справедливы для объектов типа документ и счет бухгалтерского учета. Для документов аналогом функции ТекущийЭлемент() является функция ТекущийДокумент(), а для счетов бухгалтерского учета – ТекущийСчет().

Выбор разрядности для данных числовых типов

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

При установке формата числового типа данных, разрядность должна обеспечивать возможность хранения чисел необходимой величины. Например, если у нас реквизит “Цена” имеет формат (8.2), то при записи в него значения 10000 * 26.85 мы получим переполнение числа (99999.99).

Аналогичные соображения следует учитывать при выборе формата таких данных как ресурсы регистров оперативного учета, реквизиты многострочных частей документов, для которых установлен флаг “Итог по колонке”, суммы проводок и операций, и т. п.. Для указанных величин необходимо помнить, что поля, в которых хранятся значения перечисленных величин и поля, в которых размещаются итоговые значения (суммы) имеют одинаковый формат. Поэтому, для такого рода числовых величин в формате должно быть учтено не только максимальное значение отдельной величины, но и максимально возможные значения сумм. Так, например, при выборе разрядности ресурсов регистров оперативного учета следует устанавливать разрядность, которая сможет вместить максимально возможный оборот и остаток по данному ресурсу.

Перебор объектов и групповое изменение данных

Весьма часто при разработке и внедрении конфигураций возникает необходимость в разработке алгоритма, который выполняет обход объектов информационной базы и вносит в них некоторые изменения. При реализации такого алгоритма в определенных случаях возникают ситуации, когда после изменения объекта не выполняется продолжение выборки следующих объектов. Это объясняется тем, что последовательная выборка и изменение объектов выполняются непосредственно в информационной базе. В основном проблемы возникают в тех случаях, когда при записи изменяются именно те данные, по которым собственно и происходит отбор объектов. В результате текущий объект не должен больше относиться к выборке и само продолжение выборки не выполняется системой. Например, в процессе перебора подчиненных документов, у найденного документа изменяется реквизит, в котором собственно записано значение того документа, для которого выбираются подчиненные. Ситуация осложняется тем, что при использовании методов языка разработчик конфигурации не всегда может точно определить каким способом система будет выполнять перебор объектов.

Прежде всего, можно рекомендовать не выполнять изменение данных тем же объектом (переменной) которой выполняется выбора, а создать для этой цели отдельную переменную и позиционировать ее на выбранный объект информационной базы.

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

Следует заметить, что при выполнении выборки объектов информационной базы с помощью объекта “Запрос” подобных проблем не возникает, так как при обходе результатов запроса используется временный массив построенный в ходе выполнения запроса.

Ошибки базы данных и их обработка

Ошибки базы данных и их обработка. При работе системы 1С:Предприятие могут возникать ошибки базы данных. Эти ошибки могут иметь место как при работе с базой данных, представленной в формате DBF/CDX , так и с базой данных, хранимой в среде MS SQL Server . И, хотя характер ошибок в обоих приведенных случаях может различаться, процедура их обработки стандартизована в системе 1С:Предприятие. По последствиям ошибки базы данных разделяются на две группы

* невосстановимые ошибки

* восстановимые ошибки

Невосстановимые ошибки базы данных

Невосстановимые ошибки базы данных являются следствием значительных нарушений в работе системы 1С:Предприятие: физического разрушения базы данных, нарушения ее структуры, серьезных рассогласований во взаимодействии программы с базой данных и т. п.. В таких случаях восстановить нормальное функционирование системы 1С:Предприятие невозможно и единственно правильной реакцией является завершение работы системы. Видимым проявлением таких ошибок в случае работы с базой данных в формате DBF/CDX является появление диалогового окна, содержащего текст, начинающийся со слов “Н евосстановимая ошибка Базы Данных”, в след за которыми приводится описание ошибки. В случае работы с базой данных, размещенной в среде MS SQL Server сначала появляется окно, в котором содержится описание ошибки SQL , а затем окно, содержащее текст “Н евосстановимая ошибка базы данных!”. П осле этого в обоих случаях происходит завершение работы системы. Невосстановимые ошибки базы данных не могут быть перехвачены и обработаны из встроенного языка с помощью конструкций Попытка … Исключение … КонецПопытки .

Восстановимые ошибки базы данных

Восстановимые ошибки базы данных в известном смысле ошибками не являются, а представляют собой штатные ситуации, которые так или иначе могут возникать в процессе нормальной работы системы 1С:Предприятие. К восстановимым ошибкам относятся ошибки блокировки отдельных объектов (записей) базы данных, ошибки захвата таблиц при выполнении транзакций и т. п.. Ошибками они являются в том смысле, что при этом не могут быть успешно завершены выполняемые над базой данных операции (транзакции). Но при этом не происходит каких-то фатальных нарушений в работе системы 1С:Предприятие и имеется возможность восстановления нормального функционирования. Реакция системы на восстановимые ошибки базы данных зависит от того, в какой ситуации происходит ошибка: при выполнении интерактивного действия или при выполнении модуля встроенного языка.

При выполнении интерактивной процедуры (например, при записи документа из формы при нажатии кнопки), в случае возникновения восстановимой ошибки базы данных происходит откат транзакции базы данных, а сама система 1С:Предприятие возвращается к состоянию, в котором она находилась до начала выполнения интерактивной процедуры. После этого на экран выводится диалоговое окно, содержащее вопрос: “П ри выполнении транзакции произошла ошибка! <О писание ошибки> П овторить попытку выполнить транзакцию?”. В случае положительного ответа на вопрос производится повторная попытка выполнить операцию. Если повторная попытка выполнить операцию снова завершится восстановимой ошибкой, то снова будет выдан запрос на повторение операции и так далее. В случае отрицательного ответа повторная попытка выполняться не будет. В модулях встроенного языка восстановимые ошибки базы данных могут быть перехвачены и обработаны с помощью конструкции встроенного языкаПопытка … Исключение … КонецПопытки так же, как и другие ошибки встроенного языка. В случае, если обработки ошибки в модуле не предусмотрено, то будет произведен откат выполняемой в данный момент транзакции, в окно сообщений 1С:Предприятия будет выведено сообщение о произошедшей ошибке, а выполнение модуля будет прервано, как и в случае возникновения в процессе выполнения модуля любой другой ошибки. В случае работы с базой данных, размещенной в среде MS SQL Server , в окно сообщений будет выдана ошибка SQL. После возникновения восстановимой ошибки алгоритм, вызвавший ошибку, может быть вызван пользователем повторно. Если используется конструкция встроенного языка Попытка … Исключение … КонецПопытки, то повторная операции записи может быть вызвана модулем автоматически.

Использование строковых реквизитов неограниченной длины

При определении структуры справочников и документов для строковых реквизитов необходимо выбрать определенную длину или указать режим “Неограниченная длина” (кроме реквизитов табличной части). Вариант “Неограниченная длина” существенно отличается по внутреннему способу хранения.

При работе с базами данных в формате DBF/CDX реквизиты неограниченные длины хранятся в отдельной таблице блоками по 80 символов. Для пустой строки в этой таблице записи не хранятся. Разумеется, хотя само значение блока имеет длину 80 символов, дополнительные ресурсы расходуются на поддержание связи с этой таблицей. В базах данных в формате SQL для хранения реквизитов неограниченной длины используется соответствующий тип поля таблицы, который также хранит только заполненные строки. Соответственно, если в создаваемом реквизите значения будут задаваться далеко не для всех объектов, то использование реквизита неограниченной длины может существенно уменьшить количество используемого дискового пространства.

Обращение к реквизитам неограниченной длины несколько замедляет считывание объекта, если происходит обращение к этим реквизитам. Запись объекта замедляется несколько более существенно, но только если конкретное значение изменялось. Скорость записи, разумеется, зависит от количества записываемых блоков (в базах данных DBF/CDX), то есть от длины строки.

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

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

При создании колонки таблицы значений можно указать или не указать тип значений, которые будут храниться в данной колонке. Информация в типизированных и не типизированных колонках таблицы значений хранится по-разному. В колонке с неуказанным типом значения хранится значение и его контекст, тогда как в колонке с указанным типом хранится только его значение. У каждого способа есть свои плюсы и минусы. Хранение значения и контекста позволяет увеличить производительность при частых обращениях к значениям реквизитов объектов, которые хранятся в таблице значений. Но при этом расходуется много памяти на хранение каждого объекта. Хранение только значения позволяет более компактно хранить информацию. Минусом является то, что при каждом обращении к атрибуту или методу объекта, который хранится в такой колонке, объект будет создаваться, позиционироваться на соответствующую запись и уничтожаться после использования. Чтобы избежать таких накладных расходов, перед обращением к нескольким атрибутам или методам объекта, рекомендуется поместить его значение во временную переменную и использовать ее для доступа к атрибутам и методам объекта. Данный способ позволяет компактно хранить информацию и получить хорошую производительность при работе с большим объемом информации.

Применение процедуры ПриНачалеРаботыСистемы() глобального модуля

В глобальном модуле может быть определена процедура ПриНачалеРаботыСистемы(), которая вызывается на выполнение при запуске системы 1С:Предприятие. Данная процедура предназначена для того, чтобы в конфигурации можно было определить действия, которые должны быть выполнены при начале работы системы 1С:Предприятие. Однако операторы тела глобального модуля (операторы, размещаемые в конце модуля и не входящие в какую-нибудь процедуру) также выполняются при запуске системы 1С:Предприятие. При выполнении тела глобального модуля сам глобальный модуль еще не полностью инициализирован, а если точнее, то его экспортируемые переменные, процедуры и функции на данный момент еще не доступны извне самого глобального модуля. И если в теле глобального модуля, например, с помощью функции ОткрытьФорму() запустить какую-либо обработку, то данная обработка не сможет быть выполнена, если в ней содержатся обращения к переменным, процедурам или функциям глобального модуля.

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

Доступ во встроенном языке к метаданным

В 1С:Предприятии 7.7 существует возможность обращаться к объектам метаданных средствами встроенного языка. Эта возможность используется, прежде всего, для создания универсальных алгоритмов, не зависящих от конфигурации и конкретных объектов метаданных.

Весь доступ к метаданным осуществляется через объект “Метаданные” и иерархию подчиненных ему объектов. Фактически объект “Метаданные” является корнем иерархической системы объектов, которые во многом похожи на дерево метаданных в конфигураторе.

В отличие от других средств встроенного языка доступ к метаданным не имеет подробного описания в документации. Это объясняется тем, что названия атрибутов и методов совпадают с терминами, выводимыми в текстовом представлении структуры метаданных (меню “Конфигурация – Описание структуры метаданных”). Соответственно для ознакомления с составом атрибутов и методов следует получить текстовое представление и определить в нем необходимые термины. Специфические атрибуты и методы (не

отображаемые в текстовом представлении) отражены в документации и Синтакс-Помощнике.

Обращение к объектам метаданных выполняется с помощью методов вышестоящего объекта. Название метода совпадает с названием типа объекта метаданных. В качестве параметра может быть передан идентификатор искомого объекта или его номер. Если объект найден, то возвращается собственно объект метаданных. Если объект не найден то возвращается пустой объект метаданных. Для проверки того, возвращен пустой объект или нет, следует использовать метод “Выбран”.

Например:

Если Метаданные.Документ(”Счет”).Выбран()=0 Тогда

Сообщить(”В конфигурации нет документа Счет”);

КонецЕсли

Если параметр не задан, то возвращается количество объектов метаданных данного типа.

Например:

Сообщить(”В конфигурации “+Метаданные.Документ()+” документов”);

Эта возможность используется для обхода всех объектов метаданных

определенного типа.

Например:

Для Инд=1 По Метаданные.Документ() Цикл

Сообщить(”Документ “+Метаданные.Документ(Инд));

КонецЦикла;

Для доступа к объектам метаданных, которые подчинены полученным объектам, также соответственно используются методы, совпадающие с именами метаданных. Заметим, что реквизит документа также является объектом метаданных (имеет идентификатор, синоним и т.д.).

Например:

Если

Метаданные.Документ(”Счет”).РеквизитШапки(”Заказчик”).Выбран()=0 Тогда

Сообщить(”В конфигурации нет реквизита Заказчик документа

Счет”);

КонецЕсли;

Для доступа к свойствам объектов метаданных используются атрибуты с соответствующими именами.

Например:

Сообщить(”Тип номера расходного ордера:

“+Метаданные.Документ(”РасходныйОрдер”).ТипНомера);

Таким образом, если ознакомиться с содержимым текстового представления метаданных, то можно определить названия методов и атрибутов для доступа ко всем объектам метаданных и их свойствам.

Некоторые свойства объектов метаданных являются ссылками на другие объекты. В этом случае возвращается объект метаданных, к которому можно обращаться также как и объектам, полученным с помощью методов объекта “Метаданные”.

Например:

Сообщить(”Длина кода справочника владельца справочника Договора:

“+Метаданные.Справочник(”Договора”).Владелец.ДлинаКода);

Для некоторых объектов их свойства могут содержать несколько ссылок на различные объекты метаданных. В этом случае к ним применяются методы “Количество” и “Получить”.

Например:

Сообщить(”Количество ссылок в графе Сумма журнала Общий :”

+Метаданные.Журнал(”Общий”).Графа(”Сумма”).Ссылки.Количество());

Заметим, что возвращаемые значения свойств объектов метаданных, соответствующие одному из нескольких возможных вариантов, возвращаются в строковом виде в соответствии с установленном для конфигурации языком (русским или английским). Возможные значения в английском варианте можно посмотреть, сформировав текстовое описание метаданных при установленном в конфигурации английском языке.

Следует учитывать, что механизм обращения к метаданным не связан непосредственно с данными и не позволяет получать значения, хранящиеся в информационной базе или значения агрегатных типов которые могут храниться в информационной базе. Он предназначен только для получения информации о структуре метаданных. То есть все объекты, получаемые через объект “Метаданные”, имеют специальный тип “Метаданные”. Например, используя доступ к метаданным нельзя получить значение типа “Перечисление”. То есть объект метаданных может сообщить свойства перечисления, но не может выдать собственно значение типа “Перечисления” чтобы присвоить его, например, реквизиту документа или сравнить с существующим значением. Для получения собственно значения типа “Перечисление” необходимо воспользоваться самим объектом “Перечисление”. Однако существует возможность искать значение перечисления по идентификатору, полученному из метаданных.

Например:

Для Инд=1 По Метаданные.Перечисление(”ВидыПлатежа”).Значение() Цикл

Сообщить(Перечисление.ВидыПлатежа.ЗначениеПоИдентификатору(

Метаданные.Перечисление(”ВидыПлатежа”).Значение(Инд).Идентификатор));

КонецЦикла;

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

Например:

МДСчет= Метаданные.Документ(”Счет”);

Сообщить(”Тип реквизита Заказчик документа Счет:

“+МДСчет.РеквизитШапки(”Заказчик”).Тип);

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

Особенности работы с реквизитами неопределенного типа

В 1С:Предприятии 7.7 существует возможность создавать в объектах метаданных реквизиты неопределенного типа. Например, эта возможность активно используется для хранения в документе значений субконто связанных с некоторым счетом, по которому должны формироваться проводки документом.

Особенность использования реквизитов неопределенного типа заключается в том, что их значения нельзя присваивать, не назначив предварительно тип. Тип назначается с помощью метода “НазначитьТип” того объекта, которому принадлежит реквизит. Таким образом, реквизиты неопределенного типа отличаются от обычных переменных модулей, тип которых может свободно изменяться при присвоении значения.

Замечание!

В модуле формы документа (аналогично и справочника) для назначения типа реквизиту документа следует вызывать метод “НазначитьТип” у самого документа (то есть не через точку, а непосредственно). Вызов метода “НазначитьТип” для элемента управления (через объект Форма) следует применять только к реквизитам диалога формы (не являющимися реквизитами документа).

Следует учитывать, что реквизиты, имеющие неопределенный тип, не могут использоваться для хранения строк длиннее 22 символов.

Особенности написания тела модуля

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

Фактически тело модуля служит только для инициализации переменных модуля объявленных в его верхней части.

Для модуля формы в теле модуля не могут выполняться некоторые методы, которые управляют элементами управления и свойствами формы. Все эти действия рекомендуется выполнять в процедуре “ПриОткрытии”.

Для глобального модуля в теле модуля также могут не выполняться некоторые функции встроенного языка. Например, в теле модуля не допускается открытие форм.

Для модуля документа если документ проводится из формы документа, то тело модуля будет выполнено только один раз, хотя проведение может быть выполнено несколько раз без закрытия формы. При групповом проведении тело модуля не будет выполняться перед началом проведения каждого документа (групповое проведение документов выполняется системой при переносе точки актуальности вперед и в режиме “Проведение документов”). Таким образом, переменные, которые должны инициализироваться при каждом проведении следует инициализировать в процедуре “ОбработкаПроведения”, а не в теле модуля.

Июль
29

Производительность

Июль
29

Обучение пользователей работе с 1С:Предприятием и конкретной конфигурацией

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

Очевидно, что большинство приемов необходимых пользователям хорошо известно специалистам. В данном разделе мы хотим подчеркнуть важность такой “просветительской” работы.

Разумеется, основным источником информации при освоении 1С:Предприятия должна служить документация.

При начале работы  с системой, можно обратить внимание пользователей на рекомендации, выдаваемые системой в “Советах дня”. Заметим, что файл, содержащий советы дня для режима запуска “1С:Предприятие” (1cv7Main.tip) может быть помещен в каталог с информационной базой и отредактирован. То есть вы можете внести в него собственные рекомендации, касающиеся не только общих возможностей системы, но и конкретной конфигурации.

Далее следует обратить внимание пользователей на все основные имеющиеся в системе приемы для получения необходимой информации:

  • меню действие и контекстное меню;
  • режим “помощь”;
  • встроенное описание;
  • подсказки к элементам диалога и кнопкам панели инструментов;

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

Рекомендуется привлечь внимание пользователей к режиму “Параметры”. Зачастую пользователи работают достаточно продолжительное время с системой и не используют сервисные возможности, предоставляемые системой в режиме “Параметры”.

Многие рекомендации, которые отвечают наиболее типовым потребностям пользователей, приведены на диске ИТС в разделе “Практические рекомендации по работе с 1С:Предприятием”. Специалистам, работающим с пользователями, можно рекомендовать ознакомиться с содержанием этого раздела.


Выпуски 1С:Предприятия (Релизы)

В течение жизненного цикла программных продуктов системы 1С:Предприятие фирмой 1С в них вносятся различные изменения, исправляются обнаруженные недостатки и ошибки. Периодически производится очередной выпуск продуктов 1С:Предпряития. Такой выпуск называется релизом (англ. release – выпуск).

Выход очередного релиза относится ко всем компонентам системы 1С:Предприятие, а также к отдельным продуктам типа (1С:Платежные документы, 1С:Налогоплательщик). Релизы имеют единую нумерацию. Исключение составляют внешние компоненты, разрабатываемые фирмой 1С и компонента “Управление распределенными информационными базами”, которые имеют независимую нумерацию релизов и которые могут использоваться с различными релизами 1С:Предпряития. Однако при выходе новых релизов этих компонент их также рекомендуется обновлять. Компонента “Управление распределенными информационными базами” будет автоматически обновляться при установке нового релиза любого из программных продуктов системы 1С:Предприятие, однако отдельная установка этой компоненты не обновит другие компоненты системы.

Заметим, что типовые конфигурации программных продуктов системы 1С:Предприятие имеют отдельный жизненный цикл. Каждая типовая конфигурация имеет свою нумерацию релизов. Однако замена релиза типовой конфигурации не может быть выполнена повторной установкой. Она может производиться только в режиме объединения конфигурация (в режиме загрузки измененной конфигурации в базовых версиях).

Наиболее простым способом определения релиза установленного комплекта 1С:Предприятия является вызов режима “О программе” в меню “Помощь”. Номер релиза выводится в верхнем правом углу.

Программные файлы (.EXE, .DLL), входящие в состав каждого очередного релиза отличаются от аналогичных файлов предыдущих релизов. Номер релиза для системы 1С:Предприятие 7.7 обозначается как 7.NNN, где NNN – трехзначное число. Для того, чтобы можно было отличить программные файлы, входящие в состав различных релизов, в каждый из файлов заносится метка версии, соответствующая номеру релиза.

Для того, чтобы установить номер релиза системы 1C:Предприятие 7.7 следует взглянуть на метку версии одного из перечисленных ниже файлов:

  • ACCOUNT.DLL
  • BASIC.DLL
  • BKEND.DLL
  • BLANG.DLL
  • CONFIG.DLL
  • EDITR.DLL
  • MONITOR.DLL
  • MOXEL.DLL
  • MXL2XL.DLL
  • RGPROC.DLL
  • SALARY.DLL
  • SEVEN.DLL
  • TRACER.DLL
  • TRADE.DLL
  • TXTEDT.DLL
  • USERDEF.DLL
  • V7CHART.DLL
  • 1CV7.EXE
  • 1CV7L.EXE
  • 1CV7S.EXE

Для просмотра версии программного файла следует запустить Проводник (Windows Explorer), выделить интересующий файл, нажать на нем правую кнопку мышки и в появившемся меню выбрать пункт Свойства (Properties) и переключиться на закладку Версия (Version).

Программные файлы, входящие в состав одного релиза системы 1С:Предприятие полностью соответствуют друг другу. В одной установке системы (в одном каталоге) не допускается смешивание программных файлов из разных релизов системы. Если установка какого-либо из программных продуктов системы 1С:Предприятие производится в каталог, в который уже был установлен один из предыдущих релизов системы, все программные файлы будут обновлены до состояния соответствующего релизу устанавливаемого продукта. Обновлены будут все программные файлы, независимо от состава ранее установленных компонент и самого устанавливаемого продукта. Например, если в каком либо каталоге уже были установлены компоненты “Оперативный учет” и “Расчет”, и поверх производится установка более нового релиза компоненты “Оперативный учет”, то в результате каталог будет содержать обновленные версии программных файлов относящихся как к компоненте “Оперативный учет” так и к компоненте “Расчет”.

При работе с сетевой версией системы 1С:Предприятие или версией для SQL администратору системы следует обеспечить работу всех пользователей с одним и тем же релизом 1С:Предприятия. Наиболее простой путь для достижения этого – установить систему таким образом, чтобы программные файлы находились только на сервере. Это гарантирует работу всех пользователей с одним релизом системы.

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

1C – Фирма

1C – Фирма

Prime RSS - Крупнейший каталог блогов, новостных лент и RSS

Русские темы для WordPress. Бесплатные шаблоны для блогов WordPress на любой вкус