Добро пожаловать,
Поиск
Примечание - большая часть написанного здесь текста с примерами взята по памяти (пару лет назад изучал достаточно подробно, поэтому может что-то в алгоритмах не работать - я ведь их не копировал откуда-то, а прямо тут же и писал, так что за синтаксические ошибки не пинайте) - на данный момент я активно OLE не пользуюсь (не из-за каких-то проблем с самим OLE, а из-за отсутствия надобности в его использовании в текущий момент).
Основные преимущества, благодаря которым 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]);
Разместил: Егоров Андрей
В этой статье описываются полезные функции и процедуры, помогающие эффективно работать с различными типами данных в системе "1С:Предприятие 7.7".
* Обработка значений
* Форматирование
* Список значений
* Таблица значений
* Таблица
* Период и дата
* Календари и праздники
* Справочники
* Документы
* Предопределённые функции
* Налоговый учёт
Обработка значений в 1С
Код //функция проверяет, является ли переданный в функцию Символ числом
Функция ЭтоЧисло(Символ) Экспорт
Если (КодСимв(Символ)>=48) И (КодСимв(Символ)<=57) Тогда
Возврат(1);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
//функция возвращает копейки
Функция гКопейки(Значение) Экспорт
Грн=Цел(Значение);
Коп=Значение-Грн;
Возврат(Коп
0);
КонецФункции
//функция возвращает сумму без скидки
Функция гСкидка(Сумма,Скидка) Экспорт
Возврат Сумма*(1-Скидка/100);
КонецФункции
//функция устанавливает новое значение реквизита документа или справочника и задаёт вопрос, если новое значение не соответствует предыдущему
Функция гЗначение(Ко,Атрибут,Значение) Экспорт
Знач1=Ко.ПолучитьАтрибут(Атрибут);
Знач2=Значение;
//проверка
Если Не(ТипЗначенияСтр(Знач1)=ТипЗначенияСтр(Знач2)) Тогда
//несоответствие типов
Возврат(0);
ИначеЕсли Не(ТипЗначенияСтр(Знач2)="Число") И (ПустоеЗначение(Знач2)=1) Тогда
//пустое новое значение
Возврат(0);
КонецЕсли;
//реквизит
Если Метаданные.Документ(Ко.Вид()).Выбран()=1 Тогда
//документ
Если Метаданные.Документ(Ко.Вид()).РеквизитШапки(Атрибут).Выбран()=1 Тогда
Ж=Метаданные.Документ(Ко.Вид()).РеквизитШапки(Атрибут);
Имя=Ж.Представление();
ИначеЕсли Метаданные.Документ(Ко.Вид()).РеквизитТабличнойЧасти(Атрибут).
Выбран()=1 Тогда
Ж=Метаданные.Документ(Ко.Вид()).РеквизитТабличнойЧасти(Атрибут);
Имя=Ж.Представление()+" (строка "+Ко.НомерСтроки+")";
Иначе
Ж=Метаданные.ОбщийРеквизитДокумента(Атрибут);
Имя=Ж.Представление();
КонецЕсли;
ИначеЕсли Метаданные.Справочник(Ко.Вид()).Выбран()=1 Тогда
//справочник
Ж=Метаданные.Справочник(Ко.Вид()).Реквизит(Атрибут);
Имя=Ж.Представление();
Если ПустаяСтрока(Имя)=1 Тогда
Имя=Атрибут;
КонецЕсли;
КонецЕсли;
//форматирование
Если ТипЗначенияСтр(Знач2)="Строка" Тогда
Знач1=СокрЛП(Знач1);
Знач2=СокрЛП(Знач2);
ИначеЕсли ТипЗначенияСтр(Знач2)="Число" Тогда
Знач2=Окр(Знач2,Ж.Точность);
КонецЕсли;
//проверка
Если Знач1=Знач2 Тогда
Возврат(0);
КонецЕсли;
//установка значения
Если ПустоеЗначение(Знач1)=0 Тогда
Текст=
"Атрибут: "+Имя+"
|
|Старое значение: "+СимволТабуляции+Знач1+"
|Новое значение: "+СимволТабуляции+Знач2+"
|
|Установить новое значение?";
Если Вопрос(Текст,"Да+Нет")="Нет" Тогда
Возврат(0)
КонецЕсли;
КонецЕсли;
//значение
Ко.УстановитьАтрибут(Атрибут,Знач2);
Возврат(1);
КонецФункции
Форматирование данных в 1С
Код //форматирование числа
Функция гЧисло(Значение,Знаки=2) Экспорт
Ответ=Формат(Значение,"Ч18."+Знаки);
Возврат СокрЛП(Ответ);
КонецФункции
//функция убирает лишние пробелы
Функция гСжатьПробелы(аТекст) Экспорт
Текст=СокрЛП(аТекст);
//пробелы
Замена=Формат(" ","С5");
Для й=1 По 4 Цикл
Знак=Сред(Замена,й);
Текст=СтрЗаменить(Текст,Знак," ");
КонецЦикла;
//
Возврат СокрЛП(Текст);
КонецФункции
//функция возвращает переданную строку, в которой первая буква устанавливается в верхнем или в нижнем регистре
Функция гБуква(Текст,ФлагНрег=0) Экспорт
Буква=Лев(Текст,1);
Если ФлагНрег=0 Тогда
Буква=ВРег(Буква);
Иначе
Буква=НРег(Буква);
КонецЕсли;
Возврат(Буква+Сред(Текст,2));
КонецФункции
/функция возвращает представление переданного документа
Функция гПредставлениеДокумента(Д) Экспорт
Возврат Д.ПредставлениеВида()+" "+СокрЛП(Д.НомерДок)+" ("+Д.ДатаДок+")";
КонецФункции
//процедура выдаёт сообщение при проведении документа
Процедура гСообщить(Ко,Текст,НомерСтроки=0,Символ="!") Экспорт
//сигнал
Если Ко.Ошибка=0 Тогда
Сигнал();
КонецЕсли;
//документ
Документ=""+Ко.ДатаДок+" "+Ко.ПредставлениеВида()+" "+СокрЛП(Ко.НомерДок);
//номер строки
Если НомерСтроки>0 Тогда
Документ=Документ+" (строка "+НомерСтроки+")";
КонецЕсли;
//сообщение
Сообщить(Документ+": "+Текст,Символ);
КонецПроцедуры
Список значений в 1С
Код //процедура выполняется при добавлении нового значения в интерактивный список значений
Процедура сзДобавить(Список,Тип,Вид,Длина,Точность,Подсказка) Экспорт
//тип
Если (Тип="Справочник") Или (Тип="Документ") Тогда
Тип=Тип+"."+Вид;
КонецЕсли;
//значение
Если Список.ТекущаяСтрока()=0 Тогда
Значение="";
Иначе
Значение=Список.ПолучитьЗначение(Список.ТекущаяСтрока());
КонецЕсли;
//выбор
Если ВвестиЗначение(Значение,Подсказка,Тип,Длина,Точность)=1 Тогда
Список.ДобавитьЗначение(Значение);
КонецЕсли;
КонецПроцедуры
//процедура выполняется для изменения значения интерактивного списка значений
Процедура сзИзменить(Список) Экспорт
Позиция=Список.ТекущаяСтрока();
Если Позиция=0 Тогда
Возврат;
КонецЕсли;
//
Значение=Список.ПолучитьЗначение(Список.ТекущаяСтрока());
Тип=ТипЗначенияСтр(Значение);
Если (Тип="Справочник") Или (Тип="Документ") Тогда
Тип=Тип+"."+Значение.Вид();
Подсказка=Значение.Вид();
Иначе
Подсказка=Тип;
КонецЕсли;
Если ВвестиЗначение(Значение,Подсказка,Тип)=1 Тогда
Список.УстановитьЗначение(Позиция,Значение);
КонецЕсли;
КонецПроцедуры
//процедура выполняется при удалении значения из интерактивного списка значений
Процедура сзУдалить(Список) Экспорт
Если Список.ТекущаяСтрока()>0 Тогда
Список.УдалитьЗначение(Список.ТекущаяСтрока());
КонецЕсли;
КонецПроцедуры
//процедура изменяет позицию значения интерактивного списка значений
Процедура сзСдвинуть(Список,Количество) Экспорт
Если (Количество>0) И (Список.ТекущаяСтрока()=Список.РазмерСписка()) Тогда
Количество=1-Список.РазмерСписка();
ИначеЕсли (Количество<0) И (Список.ТекущаяСтрока()=1) Тогда
Количество=Список.РазмерСписка()-1;
КонецЕсли;
Список.СдвинутьЗначение(Количество,Список.ТекущаяСтрока());
КонецПроцедуры
//функция проверяет наличие в списке значений с пометками хотя бы одного помеченного значения
Функция сзПометка(Список) Экспорт
Для i=1 По Список.РазмерСписка() Цикл
Если Список.Пометка(i)=1 Тогда
Возврат(1);
КонецЕсли;
КонецЦикла;
//нет пометок
Возврат(0);
КонецФункции
//функция помечает или снимает пометку для всех значений списка
Процедура сзПометить(Список,Флаг) Экспорт
Для й=1 По Список.РазмерСписка() Цикл
Список.Пометка(й,Флаг);
КонецЦикла;
КонецПроцедуры
//процедура оставляет в списке значений заданное количество значений
Процедура сзОбрезать(Список,Размер) Экспорт
Если Список.РазмерСписка()>Размер Тогда
Количество=Список.РазмерСписка()-Размер;
Список.УдалитьЗначение(Размер+1,Количество);
КонецЕсли;
КонецПроцедуры
//функция выгружает значения колонки таблицы значений в список значений
Функция сзКолонка(М,Колонка) Экспорт
Список=СоздатьОбъект("СписокЗначений");
//
В=СоздатьОбъект("ТаблицаЗначений");
М.Выгрузить(В,,,Колонка);
В.Свернуть(Колонка,);
В.Выгрузить(Список,,,Колонка);
Возврат(Список);
КонецФункции
//процедура преобразует строку со значениями в список значений
Процедура сзПарсить(Список,Текст) Экспорт
Если ПустаяСтрока(Текст)=0 Тогда
Если Найти(Текст,"=")=0 Тогда
//делитель - Запятая
Значение=СтрЗаменить(СокрЛП(Текст),",",Симв(34)+","+Симв(34));
Значение=Симв(34)+Значение+Симв(34);
Список.ИзСтрокиСРазделителями(Значение);
Иначе
//делитель - Точка с запятой
Текст=СтрЗаменить(Текст,";",РазделительСтрок);
Для й=1 По Текст.КоличествоСтрок() Цикл
Стр=Текст.ПолучитьСтроку(й);
Если ПустаяСтрока(Стр)=0 Тогда
Позиция=Найти(Стр,"=");
Если Позиция>0 Тогда
Идентификатор=Лев(Стр,Позиция-1);
Значение=Сред(Стр,Позиция+1);
Список.Установить(СокрЛП(Идентификатор),СокрЛП(Значение));
Иначе
Список.ДобавитьЗначение(СокрЛП(Стр));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
//процедура позиционирует строку списка значений на заданном значении
Процедура сзУстановить(Список,Значение) Экспорт
Позиция=Список.НайтиЗначение(Значение);
Если Позиция>0 Тогда
Список.ТекущаяСтрока(Позиция);
КонецЕсли;
КонецПроцедуры
Таблица значений в 1С
Код //процедура сдвигает строку в таблице значений;
//если сдвигается последняя строка вниз, то строка становится первой;
//если сдвигается первая строка вверх, то строка перемещается в конец таблицы значений
Процедура Количество=1-М.КоличествоСтрок();
ИначеЕсли (Количество<0) И (М.ТекущаяСтрока()=1) Тогда
Количество=М.КоличествоСтрок()-1;
КонецЕсли;
М.СдвинутьСтроку(Количество,М.ТекущаяСтрока())());
КонецПроцедуры
//процедура обнуляет значения таблицы значений вниз от заданной строки и вправо от заданной колонки
Процедура тзОбнулить(М,НомерСтр,НомерКол) Экспорт
Для i=НомерСтр По М.КоличествоСтрок() Цикл
Для j=НомерКол По М.КоличествоКолонок() Цикл
М.УстановитьЗначение(i,j,0);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
//процедура удаляет строку в интерактивной таблице значений> Процедура тзУдалитьСтроку(М) Экспорт
//запоминание текущей строки
ТекСтрока=М.ТекущаяСтрока()-1;
//удаление
М.УдалитьСтроку();
//позиционирование
Если М.КоличествоСтрок()>0 Тогда
ТекСтрока=Мин(ТекСтрока,М.КоличествоСтрок());
М.ТекущаяСтрока(ТекСтрока);
КонецЕсли;
КонецПроцедуры
//процедура находит документ с заданным номером в таблице значений с документами
Процедура гЖурнал_Найти(М) Экспорт
НомерДок=0;
Если ВвестиЧисло(НомерДок,"Номер документа",5,0)=1 Тогда
//поиск по номеру в выборке
Если М.НайтиЗначение(НомерДок,,"Номер")=0 Тогда
Предупреждение("Документ № "+НомерДок+" не найден");
Возврат;
КонецЕсли;
//поиск документа
Список=СоздатьОбъект("СписокЗначений");
М.ВыбратьСтроки();
Пока М.ПолучитьСтроку()=1 Цикл
Если М.Номер=НомерДок Тогда
Список.ДобавитьЗначение(М.ТекущийДокумент);
КонецЕсли;
КонецЦикла;
//выбор
Значение="";
Если Список.РазмерСписка()=1 Тогда
Значение=Список.ПолучитьЗначение(1);
ИначеЕсли Список.ВыбратьЗначение(Значение,"Выбор документа")=0 Тогда
Возврат;
КонецЕсли;
//позиционирование
НомерСтр=0;
М.НайтиЗначение(Значение,НомерСтр,"ТекущийДокумент");
М.ТекущаяСтрока(НомерСтр);
КонецЕсли;
КонецПроцедуры
Таблица или печатная форма в 1С
Код //установление автоширины колонок таблицы
Процедура гАвтоШиринаКолонок(Таб,НачКол,НачСтр) Экспорт
Для НомерКол=НачКол По Таб.ШиринаТаблицы() Цикл
МаксШирина=0;
Для НомерСтр=НачСтр По Таб.ВысотаТаблицы() Цикл
ТекШирина=СтрДлина(Таб.Область(НомерСтр,НомерКол).Текст);
МаксШирина=Макс(МаксШирина,ТекШирина);
КонецЦикла;
Таб.Область(,НомерКол).ШиринаСтолбца(МаксШирина+2);
КонецЦикла;
КонецПроцедуры
Периоды и даты в 1С
Код //функция проверяет, равен ли месяцу интервал между заданными датами
Функция ЭтоМесяц(ДатаН,ДатаК) Экспорт
Если Не(ДатаН=НачМесяца(ДатаН)) Тогда
Возврат(0);
ИначеЕсли Не(ДатаК=КонМесяца(ДатаК)) Тогда
Возврат(0);
ИначеЕсли ДатаН=НачМесяца(ДатаК) Тогда
Возврат(1);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
//функция возвращает количество полных месяцев между датами
Функция гМесяцев(ДатаН,ДатаК) Экспорт
Если ДатаН<ДатаК Тогда
ТекДата=НачМесяца(ДатаН);
Значение=1;
Пока ТекДата<НачМесяца(ДатаК) Цикл
ТекДата=ДобавитьМесяц(ТекДата,1);
Значение=Значение+1;
КонецЦикла;
Возврат(Значение);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
//функция определяет порядковый номер месяца в квартале
Функция гМесяцКвартала(ДатаДок) Экспорт
НачМесяц=ДатаМесяц(НачКвартала(ДатаДок));
КонМесяц=ДатаМесяц(ДатаДок);
Возврат(КонМесяц-НачМесяц+1);
КонецФункции
//функция определяет порядковый номер квартала по дате
Функция гДатаКвартал(аДата) Экспорт
Возврат ДатаМесяц(КонКвартала(аДата))/3;
КонецФункции
Календари и праздники в 1С
Код //ф//функция возвращает дату, находящуюся на определённом интервале дней от заданной даты, без учёта выходных;
//например, используется для определения конечной даты действия счёта-фактуры
Функция an class="color-blue">гСрокДействия(ДатаДок,Период,Вид="Основной") Экспорт
К=СоздатьОбъект("Календарь."+Вид);
К.УчитыватьПраздники(1);
Если К.Автозаполнение(ДатаДок,ДобавитьМесяц(ДатаДок+Период,1))=1 Тогда
Возврат К.ПолучитьДату(ДатаДок,Период);
КонецЕсли;
КонецФункции
//функция определяет количество рабочих дней в интервале дат
Функция гРабочиеДни(ДатаН,ДатаК,Вид="Основной") Экспорт
К=СоздатьОбъект("Календарь."+Вид);
К.УчитыватьПраздники(1);
Если К.Автозаполнение(ДатаН,ДатаК)=1 Тогда
Возврат К.Дней(ДатаН,ДатаК);
КонецЕсли;
КонецФункции
//функция определяет количество праздничных дней в интервале дат
Функция гПраздники(ДатаН,ДатаК) Экспорт
Кол=0;
//
П=СоздатьОбъект("Праздники");
П.ВыбратьДаты(ДатаН,ДатаК);
Пока П.СледующаяДата()=1 Цикл
Если НомерДняНедели(П.Дата)<6 Тогда
Кол=Кол+1;
КонецЕсли;
КонецЦикла;
//
Возврат(Кол);
КонецФункции
Справочники в 1С
Код //функция возвращает элемент заданного справочника по значению реквизита "Счет"
Функция сНайтиПоСчету(Счет,Справочник,Реквизит="Счет") Экспорт
С=СоздатьОбъект("Справочник."+Справочник);
Если С.НайтиПоРеквизиту(Реквизит,Счет,1)=1 Тогда
Возврат С.ТекущийЭлемент();
Иначе
Возврат ПолучитьПустоеЗначение("Справочник."+Справочник);
КонецЕсли;
КонецФункции
//функция возвращает элемент заданного справочника по полному коду элемента
Функция сНайтиПоКоду(Справочник,Код) Экспорт
С=СоздатьОбъект("Справочник."+Справочник);
Если С.НайтиПоКоду(Код,2)=1 Тогда
Возврат С.ТекущийЭлемент();
Иначе
Возврат ПолучитьПустоеЗначение("Справочник."+Справочник);
КонецЕсли;
КонецФункции
//функция возвращает элемент заданного справочника по
//наименованию
//если элемент отсутствует в справочнике, то создаётся новый
Функция сНайтиПоНаименованию(Справочник,Наименование) Экспорт
С=СоздатьОбъект("Справочник."+Справочник);
Если С.НайтиПоНаименованию(Наименование,0,1)=0 Тогда
С.Новый();
С.Наименование=Наименование;
С.Записать();
Сообщить("Справочник "+Справочник+": Новый элемент "+Наименование);
КонецЕсли;
Возврат(С.ТекущийЭлемент());
КонецФункции
//процедура удаляет заданный элемент справочника
Процедура гЭлемент_Удалить(Элемент,Флаг) Экспорт
С=СоздатьОбъект("Справочник."+Элемент.Вид());
С.НайтиЭлемент(Элемент);
С.Удалить(Флаг);
КонецПроцедуры
//функция возвращает строку вида "Иванов И.И." из переданной в функцию строки вида "Иванов Иван Иванович"
Функция гФио_Получить(Значение)
Стр=гФорматС(Значение);
Стр=СтрЗаменить(Стр," ",РазделительСтрок);
Если СтрКоличествоСтрок(Стр)=1 Тогда
Фио=СокрЛП(Стр);
ИначеЕсли СтрКоличествоСтрок(Стр)=2 Тогда
СтрФ=СтрПолучитьСтроку(Стр,1);
СтрИ=СтрПолучитьСтроку(Стр,2);
Фио=СокрЛП(СтрФ)+" "+Лев(СокрЛП(СтрИ),1)+".";
Иначе
СтрО=СтрПолучитьСтроку(Стр,СтрКоличествоСтрок(Стр));
СтрИ=СтрПолучитьСтроку(Стр,СтрКоличествоСтрок(Стр-1));
СтрФ="";
Для й=1 По СтрКоличествоСтрок(Стр)-2 Цикл
СтрФ=СтрФ+" "+СтрПолучитьСтроку(Стр,й);
КонецЦикла;
Фио=СокрЛП(СтрФ)+" "+Лев(СокрЛП(СтрИ),1)+"."+Лев(СокрЛП(СтрО),1)+".";
КонецЕсли;
Возврат(Фио);
КонецФункции
//функция открывает подбор из справочника и предоставляет пользователю выбор из элементов фиксированной группы
Функция сПодборРодитель(Ко,Родитель,Элемент,Заголовок="")
Экспорт
Ко.ОткрытьПодбор("Справочник."+Родитель.Вид(),"ДляВыбора",,0);
Ко.КонтекстПодбора.ИспользоватьРодителя(Родитель,0);
Ко.КонтекстПодбора.ИерархическийСписок(1,0);
//текущий элемент
Если Элемент.Выбран()=1 Тогда
Ко.КонтекстПодбора.АктивизироватьОбъект(Элемент);
КонецЕсли;
//заголовок
Если ПустаяСтрока(Заголовок)=0 Тогда
Ко.КонтекстПодбора.Форма.Заголовок(Заголовок,0);
КонецЕсли;
//отмена стандартной обработки
Возврат(0);
КонецФункции
Документы в 1С
Код //удаление ведущих нолей в номере документа
Функция гНомерДок(Значение) Экспорт
Текст=СокрЛП(Значение);
Текст=СтрЗаменить(Текст," ","");
Текст=СтрЗаменить(Текст,"_","-");
Если Константа.ФлагНомерОсн=0 Тогда
Возврат(Текст);
ИначеЕсли Текст="0" Тогда
Возврат(Текст);
КонецЕсли;
//префикс
Префикс="";
Для i=1 По СтрЧислоВхождений(Текст,"-") Цикл
Позиция=Найти(Текст,"-");
Префикс=Префикс+Лев(Текст,Позиция);
Текст=Сред(Текст,Позиция+1);
КонецЦикла;
//удаление нолей
ФлагЧисло=0;
Номер="";
Для i=1 По СтрДлина(Текст) Цикл
Символ=Сред(Текст,i,1);
Если ЭтоЧисло(Символ)=0 Тогда
Номер=Номер+Символ;
ИначеЕсли Не(Число(Символ)=0) Тогда
Номер=Номер+Символ;
ФлагЧисло=1;
ИначеЕсли ФлагЧисло=1 Тогда
Номер=Номер+Символ;
КонецЕсли;
КонецЦикла;
//
Возврат(Префикс+Номер);
КонецФункции
//функция возвращает числовой номер документа без префикса
Функция гНомерБезПрефикса(Значение) Экспорт
Номер=гНомерДок(Значение);
Позиция=Найти(Значение,"-");
Номер=Сред(Номер,Позиция+1);
Возврат(Номер);
КонецФункции
//функция создаёт таблицу значений документов заданного вида по одному клиенту и даёт выбрать один документ
Функция гДокументКлиента(Значение,Клиент,ВидДокумента) Экспорт
Если Клиент.Выбран()=0 Тогда
Предупреждение("Не выбран Контрагент!");
Возврат(0);
КонецЕсли;
//таблица
М=СоздатьОбъект("ТаблицаЗначений");
М.НоваяКолонка("Дата","Дата",,,,10);
М.НоваяКолонка("Док","Строка",,,"Документ",50);
М.НоваяКолонка("Сумма","Число",,,,18,"Ч015.2");
М.НоваяКолонка("Документ","Документ");
М.ВидимостьКолонки("Документ",0);
//документы
Д=СоздатьОбъект("Документ");
Д.ВыбратьПоЗначению(,,"Клиент",Клиент);
Пока Д.ПолучитьДокумент()=1 Цикл
Состояние(""+Д.ДатаДок);
Если Не(Д.Вид()=ВидДокумента) Тогда
Продолжить;
КонецЕсли;
//
М.НоваяСтрока();
М.Документ=Д.ТекущийДокумент();
М.Дата=Д.ДатаДок;
М.Док=Д.ПредставлениеВида()+" "+СокрЛП(Д.НомерДок);
//сумма
Ж=Метаданные.Документ(Д.Вид());
Если Ж.РеквизитТабличнойЧасти("ВалСумма").Выбран()=1 Тогда
М.Сумма=Д.Итог("ВалСумма");
ИначеЕсли Ж.РеквизитТабличнойЧасти("СуммаС").Выбран()=1 Тогда
М.Сумма=Д.Итог("СуммаС");
ИначеЕсли Ж.РеквизитТабличнойЧасти("Сумма").Выбран()=1 Тогда
М.Сумма=Д.Итог("Сумма");
КонецЕсли;
КонецЦикла;
//проверка
Если М.КоличествоСтрок()=0 Тогда
Предупреждение("Документы не найдены!");
Возврат(0);
КонецЕсли;
//строка по умолчанию
НомерСтр=0;
Если М.НайтиЗначение(Значение,НомерСтр,"Документ")=0 Тогда
НомерСтр=М.КоличествоСтрок();
КонецЕсли;
//выбор
Заголовок=Метаданные.Документ(ВидДокумента).Представление()+": "+Клиент.Наименование;
Если М.ВыбратьСтроку(НомерСтр,Заголовок)=1 Тогда
Значение=М.ПолучитьЗначение(НомерСтр,"Документ");
Возврат(1);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
Предопределённые функции и процедуры в 1С
Код Процедура ОбработкаЯчейкиТаблицы(Значение,Флаг,Таблица,Адрес)
Перем Ответ;
Перем Ко;
Если ПустоеЗначение(Значение)=1 Тогда
Предупреждение("Невозможно обработать значение ячейки!");
ИначеЕсли ТипЗначенияСтр(Значение)="Документ" Тогда
Если гПользователь.ФлагСписок=0 Тогда
Флаг=1;
Иначе
А=СоздатьОбъект("СписокЗначений");
А.ДобавитьЗначение(0,"Открыть документ");
А.ДобавитьЗначение(1,"Открыть в журнале документов");
Если А.ВыбратьЗначение(Ответ,,,,1)=1 Тогда
Если Ответ=0 Тогда
Флаг=1;
Иначе
Журнал=Метаданные.Документ(Значение.Вид()).Журнал.
Идентификатор;
ОткрытьФорму("Журнал."+Журнал+".Основная",Ко);
Ко.АктивизироватьОбъект(Значение);
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли ТипЗначенияСтр(Значение)="Справочник" Тогда
Если гПользователь.ФлагСписок=0 Тогда
Флаг=1;
Иначе
А=СоздатьОбъект("СписокЗначений");
А.ДобавитьЗначение(0,"Открыть элемент");
А.ДобавитьЗначение(1,"Открыть в списке справочника");
Если А.ВыбратьЗначение(Ответ,,,,1)=1 Тогда
Если Ответ=0 Тогда
Флаг=1;
Иначе
Журнал=Метаданные.Справочник(Значение.Вид()).ОсновнаяФорма;
ОткрытьФорму("Справочник."+Значение.Вид()+"."+Журнал,Ко);
Ко.АктивизироватьОбъект(Значение);
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли ТипЗначенияСтр(Значение)="СписокЗначений" Тогда
//расшифровка - СписокЗначений
Кнопка=Значение.Получить("Кнопка");
Если Число(Кнопка)=0 Тогда
Значение.СортироватьПоПредставлению();
//обработка - Ячейка
Представление="";
А=СоздатьОбъект("СписокЗначений");
Для i=1 По Значение.РазмерСписка() Цикл
Отчет=Значение.ПолучитьЗначение(i,Представление);
Если ПустаяСтрока(Отчет)=1 Тогда
Продолжить;
ИначеЕсли Лев(Представление,4)="Меню" Тогда
//элемент контекстного меню в ячейке
Позиция=Найти(Отчет,"|");
Если Позиция=0 Тогда
Представление=Метаданные.Отчет(Отчет).Представление();
Иначе
Добавка=Сред(Отчет,Позиция+1);
Отчет=Лев(Отчет,Позиция-1);
Представление=Метаданные.Отчет(Отчет).Представление()+": "+Добавка;
КонецЕсли;
А.ДобавитьЗначение(Отчет,Представление);
КонецЕсли;
КонецЦикла;
//контекстное меню в ячейке
Если А.РазмерСписка()>0 Тогда
Если А.ВыбратьЗначение(Ответ,,,,1)=1 Тогда
Значение.Выгрузить(гПакет);
гПакет.Установить("Таблица","");
ОткрытьФормуМодально("Отчет."+Ответ,1+гПользователь.ФлагОтчет);
КонецЕсли;
КонецЕсли;
Иначе
//обработка - Кнопка
Значение.Выгрузить(гПакет);
гПакет.Установить("Таблица",Таблица);
Отчет=Значение.Получить("Отчет");
ОткрытьФормуМодально("Отчет."+Отчет,Кнопка);
гПакет.Установить("Таблица","");
КонецЕсли;
ИначеЕсли ТипЗначенияСтр(Значение)="Строка" Тогда
Если ВРег(Лев(СокрЛП(Значение),6))="ССЫЛКА" Тогда
СтрокаЗапуска=СокрЛП(Сред(Значение,7));
ЗапуститьПриложение(СтрокаЗапуска);
Иначе
Флаг=1;
КонецЕсли;
Иначе
//расшифровка - Стандартная обработка ячейки
Флаг=1;
КонецЕсли;
КонецПроцедуры
Налоговый учёт и первое событие в 1С
Код
//функция определяет сумму первого события за период по заданным остаткам на начало и конец периода
Функция гПервоеСобытие(НачД,НачК,КонД,КонК) Экспорт
//первое событие
СуммаД=Макс(КонД-НачД,0);
СуммаК=Макс(КонК-НачК,0);
//сумма
Возврат(СуммаД+СуммаК);
КонецФункции
Резюме
В статье описаны функции и процедуры, используемые в программе "1С:Предприятие 7.7" для работы со справочниками, документами, списками значений, таблицами значений и с прочими агрегатными типами данных. Образцы практического применения описанных средств Вы сможете найти в статьях "Отчёты для 1С" и "Обработки для 1С".
Источник публикации
Разместил: Андрей Громов
В практической работе приходится проводить импорт данных в "1С:Предприятие" из различных внешних приложений, обслуживающих базы данных. Встроенный язык программы "1С:Предприятие" и стандартизированные методы построения баз данных позволяют создавать универсальные обработки по импорту данных из внешних источников. Написание универсальной обработки, зачастую, - это сложный, но и достаточно увлекательный процесс. Сложным я могу назвать его потому, что на этапе разработки нужно заранее предусмотреть все возможные варианты импортирования и обработки данных. А увлекательным процесс написания универсальных обработок по импорту данных в 1С мне видится потому, что постоянно ощущаешь огромные выгоды от использования обработки в последующей работе.
Файловая система
Для начала давайте посмотрим, как проводится работа с файловой системой из программы 1С:Предприятие.
Код //открытие файла заданного типа
Функция гФайл_Открыть(Файл,Каталог,ФлагВсе,ФлагТекст=0,ФлагКнига=0,
ФлагДокумент=0,ФлагПрезентация=0,ФлагАкробат=0) Экспорт
//меню
Если ПустоеЗначение(Файл)=0 Тогда
А=СоздатьОбъект("СписокЗначений");
А.ДобавитьЗначение(0,"Открыть");
А.ДобавитьЗначение(1,"Выбрать");
Ответ=0;
Если А.ВыбратьЗначение(Ответ,,,,1)=0 Тогда
Возврат(0);
ИначеЕсли Ответ=0 Тогда
ЗапуститьПриложение(Каталог+Файл);
Возврат(0);
ИначеЕсли Ответ=1 Тогда
ФС.УстТекКаталог(Каталог);
КонецЕсли;
КонецЕсли;
//формат
Список="";
Если ФлагВсе=1 Тогда
Список=Список+"|Все файлы|*.*";
КонецЕсли;
Если ФлагТекст=1 Тогда
Список=Список+"|Текстовые файлы|*.txt";
КонецЕсли;
Если ФлагКнига=1 Тогда
Список=Список+"|Книги MS Excel|*.xls";
КонецЕсли;
Если ФлагДокумент=1 Тогда
Список=Список+"|Документы MS Word|*.doc";
КонецЕсли;
Если ФлагПрезентация=1 Тогда
Список=Список+"|Презентации MS PowerPoint|*.pps";
КонецЕсли;
Если ФлагАкробат=1 Тогда
Список=Список+"|Документы Adobe Acrobat|*.pdf";
КонецЕсли;
Список=Сред(Список,2);
//
Возврат ФС.ВыбратьФайл(0,Файл,Каталог,"Открыть файл",Список);
КонецФункции
//процедура определяет название файла и каталога на основании заданной адресной строки
Процедура гПуть_Получить(Путь,Файл,Каталог) Экспорт
Текст=СтрЗаменить(Путь,"\",РазделительСтрок);
//каталог
Для i=1 По СтрКоличествоСтрок(Текст-1) Цикл
Каталог=Каталог+СтрПолучитьСтроку(Текст,i)+"\";
КонецЦикла;
//файл
Файл=СтрПолучитьСтроку(Текст,СтрКоличествоСтрок(Текст));
КонецПроцедуры
Импорт данных в 1С из MS Excel
Программу Microsoft Excel сегодня можно называть стандартом работы с электронными таблицами. Именно поэтому довольно часто приходится встречаться с ситуациями, когда массивы данных хранятся именно в файлах формата MS Excel. Для того, чтобы умело импортировать данные из файлов формата MS Excel в базу данных 1С:Предприятия, вы можете воспользоваться следующими примерами.
Код //подключение к MS Excel через OLE
Функция гКнига_Открыть(Файл,Каталог,Область,Высота,Ширина) Экспорт
Оле=СоздатьОбъект("Excel.Application");
//поиск в открытом приложении
Для i=1 По Оле.Workbooks.Count Цикл
ТекКнига=Оле.Workbooks(i);
Если ТекКнига.Name=Файл Тогда
Книга=ТекКнига;
Прервать;
КонецЕсли;
КонецЦикла;
//открытие файла
Если ПустоеЗначение(Книга)=1 Тогда
Книга=Оле.Workbooks.Open(Каталог+Файл);
КонецЕсли;
Оле.Visible=1;
//выбор листа
Если Книга.Worksheets.Count=1 Тогда
НомерЛиста=1;
Иначе
Список=СоздатьОбъект("СписокЗначений");
Для i=1 По Книга.Worksheets.Count Цикл
Список.ДобавитьЗначение(i,Книга.Worksheets(i).Name);
КонецЦикла;
Если Список.ВыбратьЗначение(НомерЛиста,"Выбор листа - "+Книга.Name)=0 Тогда
Возврат(0);
КонецЕсли;
КонецЕсли;
//лист
Лист=Книга.Worksheets(НомерЛиста);
Лист.Activate();
//данные
Область=Книга.Worksheets(НомерЛиста).Cells.CurrentRegion;
Высота=Область.Rows.Count;
Ширина=Область.Columns.Count;
//
Возврат(1);
КонецФункции
//импорт цен из файла MS Excel
//поиск элемента справочника проводится по полному коду
Процедура ИмпортироватьЦеныТовара()
Перем Файл,Каталог,Область,Высота,Ширина;
//открытие
Каталог=КаталогПользователя();
Файл="";
Если ФС.ВыбратьФайл(0,Файл,Каталог,"Открыть файл","Файлы MS Excel|*.xls")=0 Тогда
Возврат;
ИначеЕсли гКнига_Открыть(Файл,Каталог,Область,Высота,Ширина)=0 Тогда
Возврат;
КонецЕсли;
//справочник
С=СоздатьОбъект("Справочник.Товары");
С.ИспользоватьРодителя("");
С.ИспользоватьДату(РабочаяДата(),1);
//данные
Для Стр=2 По Высота Цикл
Состояние("Прогресс: "+Цел(Стр/Высота
0)+"%");
//код
ТекКод=СокрЛП(Область.Cells(Стр,1).Text);
Если С.НайтиПоКоду(ТекКод,2)=0 Тогда
Сообщить("Не найден товар по коду: "+ТекКод,"!");
Продолжить;
КонецЕсли;
//цена
ТекЦена=Число(Область.Cells(Стр,2).Text);
Если ТекЦена=0 Тогда
Продолжить;
КонецЕсли;
//значение
С.УстановитьАтрибут("Цена",ТекЦена);
//запись
Попытка
С.Записать();
Исключение
Сообщить("Ошибка записи: "+ОписаниеОшибки(),"!");
КонецПопытки;
КонецЦикла;
Предупреждение("Импортированы цены для "+Высота+" наименований товаров");
КонецПроцедуры
Импорт данных в 1С из текстового файла.
Основными преимуществами текстовых файлов являются их маленький размер и простота хранения данных внутри файла. Пожалуй, именно поэтому многие данные до сего дня передаются посредством текстовых файлов. Учитывая существующую потребность, вам могут потребоваться умения в импортировании данных в 1С из текстового файла. И нижеприведённые примеры помогут вам в приобретении необходимых знаний.
Самым распространённым случаем передачи данных текстовым файлом является способ выгрузки данных из системы Клиент-Банк. В примере, приведённом ниже, вы можете увидеть, каким образом производится загрузка данных о банковских операциях в 1С из текстового файла, в который предварительно выгружены данные из системы Банк-Клиент.
Код //импорт данных выписки из текстового файла программы "Банк-Клиент"
Процедура ИмпортироватьВыписку()
//настройка
Н=СоздатьОбъект("Справочник.НастройкиИмпортаВыписки");
Если РСчет.НастройкаИмпортаВыписки.Выбран()=1 Тогда
Н.НайтиЭлемент(РСчет.НастройкаИмпортаВыписки);
ИначеЕсли Н.Выбрать("Выбор настройки импорта","ДляВыбора")=0 Тогда
Возврат;
КонецЕсли;
//очистка строк
Если КоличествоСтрок()>0 Тогда
Если Вопрос("Удалить строки?","ОК+Отмена")="Отмена" Тогда
Возврат;
КонецЕсли;
УдалитьСтроки();
КонецЕсли;
//файл
Файл=Формат(ДатаДок,"Д ДДММГГ");
Файл=СтрЗаменить(Файл,".","");
Файл=СокрЛП(Н.Каталог)+"\"+Файл+".txt");
Если ФС.СуществуетФайл(Файл)=0 Тогда
Сообщить("Файл не найден: "+Файл,"!");
Предупреждение("Файл электронной выписки за "+ДатаДок+" не найден!");
Возврат;
КонецЕсли;
//источник
Т=СоздатьОбъект("Текст");
Т.Открыть(Файл);
Если Т.КоличествоСтрок()=0 Тогда
Сообщить("Файл пустой: "+Файл, "!");
Предупреждение("Файл электронной выписки за "+ДатаДок+" пустой!");
Возврат;
КонецЕсли;
//установки
ОснСчет=СокрЛП(РСчет.НомерСчета);
ОснМфо=Формат(РСчет.Банк.Код,"Ч(0)9");
ОснВалюта=СокрЛП(РСчет.Валюта.Код);
СтавкаНдс=Константа.БазНдс.Ставка.Получить(ДатаДок);
К=СоздатьОбъект("Справочник.Контрагенты");
//выбор
Для й=1 По Т.КоличествоСтрок() Цикл
Стр=Т.ПолучитьСтроку(й);
Если ПустаяСтрока(Стр)=1 Тогда
Прервать;
КонецЕсли;
//перекодировка
Если Н.ФлагДос=1 Тогда
Стр=OemToAnsi(Стр);
Стр=СтрЗаменить(Стр,"\"+Симв(34),Симв(34));
КонецЕсли;
//деление
Стр=СтрЗаменить(Стр,Симв(34)+" "+Симв(34),РазделительСтрок);
//данные
Имя1=СтрПолучитьСтроку(Стр,3);
Окпо1=СтрПолучитьСтроку(Стр,4);
Банк1=СтрПолучитьСтроку(Стр,5);
ТекМфо1=СтрПолучитьСтроку(Стр,6);
ТекСчет1=СтрПолучитьСтроку(Стр,7);
Имя2=СтрПолучитьСтроку(Стр,8);
Окпо2=СтрПолучитьСтроку(Стр,9);
Банк2=СтрПолучитьСтроку(Стр,10);
ТекМфо2=СтрПолучитьСтроку(Стр,11);
ТекСчет2=СтрПолучитьСтроку(Стр,12);
ТекВалюта=СтрПолучитьСтроку(Стр,13);
ТекСумма=СтрПолучитьСтроку(Стр,14);
ТекИнфо=СтрПолучитьСтроку(Стр,16);
//проверка
Если Не(Оснвалюта=ТекВалюта) Тогда
Сообщить("Строка "+й+": Не найдена Валюта "+РСчет.Валюта.Наименование+" по коду: "+ОснВалюта,"!");
Продолжить;
ИначеЕсли Не(ОснМфо=ТекМфо1) И Не(ОснМфо=ТекМфо2) Тогда
Сообщить("Строка "+й+": Не найден Банк "+РСчет.Банк.Наименование+" по коду МФО: "+ОснМфо,"!");
Продолжить;
ИначеЕсли Не(ОснСчет=ТекСчет1) И Не(ОснСчет=ТекСчет2) Тогда
Сообщить("Строка "+й+": Не найден РСчет по коду: "+ОснСчет,"!");
Продолжить;
КонецЕсли;
//строка
НоваяСтрока();
Если (ОснМфо=ТекМфо1) И (ОснСчет=ТекСчет1) Тогда
//приход
УстановитьАтрибут("ПриходРасход",Перечисление.ПлюсМинус.Плюс);
УстановитьАтрибут("Счет",Н.СчетД);
КодКлиента=Окпо2;
ИмяКлиента=Имя2;
Иначе
//расход
УстановитьАтрибут("ПриходРасход",Перечисление.ПлюсМинус.Минус);
УстановитьАтрибут("Счет",Н.СчетК);
КодКлиента=Окпо1;
ИмяКлиента=Имя1;
КонецЕсли;
//содержание
УстановитьАтрибут("Содержание",ТекИнфо);
//сумма
УстановитьАтрибут("ВидНдс",Константа.БазНдс);
УстановитьАтрибут("СуммаСНдс",ТекСумма);
УстановитьАтрибут("Ндс",СуммаСНдс*СтавкаНдс/(1+СтавкаНдс));
//субконто
НазначитьТип("Субконто",ВидыСубконто.Контрагенты);
Если К.НайтиПоРеквизиту("ЕДРПОУ",КодКлиента,1)=1 Тогда
УстановитьАтрибут("Субконто",К.ТекущийЭлемент());
ИначеЕсли Н.ФлагСоздать=1 Тогда
К.Новый();
К.Наименование=ИмяКлиента;
К.ПолнНаименование=ИмяКлиента;
К.Едрпоу=КодКлиента;
К.Записать();
Сообщить("Строка "+й+": Новый контрагент: "+ИмяКлиента);
//контрагент
УстановитьАтрибут("Субконто",К.ТекущийЭлемент());
Иначе
Сообщить("Строка "+й+": Не найден Контрагент по коду ЕГРПОУ: "+КодКлиента,"!");
КонецЕсли;
КонецЦикла;
Предупреждение("Обработка выполнена");
КонецПроцедуры
Импорт данных из файла формата DBF
Старый добрый формат dBase по-прежнему используется для хранения массивов данных. Чего уж говорить, если обычная версия 1С:Предприятия (не SQL) сама хранит базы данных в файлах с расширением DBF? Формат файлов DBF, на мой взгляд, очень удобен для передачи данных в базу 1С, поскольку преимуществами файла формата dBase являются маленький размер и матричная система хранения данных.
Программист 1С может встретиться с необходимостью импортировать данные в 1С из файла DBF, в который экспортированы данные о банковских операциях из системы Банк-Клиент. В нижеприведённом примере вы можете увидеть пример обработки файла DBF, из которого в 1С импортируется банковская выписка.
Код //импорт банковских операций в базу 1С из внешнего файла DBF, созданного в системе Банк-Клиент
Процедура КнопкаИмпорт()
Перем Файл,Каталог;
Если Вопрос("Импортировать данные?","ОК+Отмена")="Отмена" Тогда
Возврат;
ИначеЕсли ФС.ВыбратьФайл(0,Файл,Каталог,"Открыть файл","Файлы Клиент-Банк (dbf)|*.dbf|Все файлы|*.*")=0 Тогда
Возврат;
КонецЕсли;
//удаление строк
Если КоличествоСтрок()>0 Тогда
Если Вопрос("Удалить все строки табличной части документа?","Да+Нет")="Да" Тогда
УдалитьСтроки();
КонецЕсли;
КонецЕсли;
//создание нового файла
Б=СоздатьОбъект("XBase");
Б.ОткрытьФайл(Каталог+Файл,,1);
Если Б.Открыта()=0 Тогда
Сообщить("Не удалось открыть файл DBF","!");
Возврат;
КонецЕсли;
//справочник
С=СоздатьОбъект("Справочник.Контрагенты");
//строки
Счетчик=0;
Для й=1 По Б.КоличествоЗаписей() Цикл
Б.Перейти(й);
//проверка
Если Не(Б.OperData=ДатаДок) Тогда
Продолжить;
ИначеЕсли Не(Б.KodVal=980) Тогда
Продолжить;
ИначеЕсли Не(Число(Б.Kod_Cred)=Число(Фирма.РегКод)) Тогда
Продолжить;
ИначеЕсли Не(Число(Б.Mfo_Cred)=Число(Фирма.Банк.Код)) Тогда
Продолжить;
ИначеЕсли Не(Число(Б.Acc_Credit)=Число(Фирма.Счет)) Тогда
Продолжить;
КонецЕсли;
//строка
НоваяСтрока();
УстановитьАтрибут("Сумма",Б.OperSum);
УстановитьАтрибут("Примечание",СокрЛП(Б.Naznach));
//контрагент
Если С.НайтиПоРеквизиту("РегКод",Б.Kod_Deb,1)=0 Тогда
С.Новый();
С.Наименование=СокрЛП(Б.Naim_Deb);
С.РегКод=Б.Kod_Deb;
С.Записать();
КонецЕсли;
УстановитьАтрибут("Контрагент",С.ТекущийЭлемент());
//счётчик
Счетчик=Счетчик+1;
КонецЦикла;
//закрытие файла
Б.ЗакрытьФайл();
//извещение
Предупреждение("Импортировано строк: "+Счетчик);
КонецПроцедуры
Импорт данных из файла формата XML
С недавних пор набирает популярность новый формат передачи многомерных массивов данных, который носит название eXtensible Markup Language или XML. Возможности нового языка разметки, используемого для хранения данных, огромны настолько, что его стали использовать даже для. передачи данных в программу 1С:Предприятие. Поэтому современный специалист по платформе 1С обязан уметь импортировать данные в 1С из файла, имеющего формат XML.
//процедура формирует печатную таблицу с данными, содержащимися в файле формата XML
Процедура Сформировать()
Перем Файл,Каталог;
Если ФС.ВыбратьФайл(0,Файл,Каталог,"Открытие документа XML","Документы XML|*.xml")=0 Тогда
Возврат;
КонецЕсли;
//таблица
Т=СоздатьОбъект("Таблица");
Т.ИсходнаяТаблица("");
Т.ВывестиСекцию("Шапка");
//документ
Анализатор=СоздатьОбъект("AddIn.XMLParser");
Д=Анализатор.СоздатьДокумент();
Д.Загрузить(Каталог+Файл);
//узлы
Узел=Д.ВыбратьУзел("Данные");
Для i=1 По Узел.КоличествоПодчиненных() Цикл
ТекУзел=Узел.ПолучитьПодчиненныйПоНомеру(i);
Состояние(ТекУзел.Текст);
//строка
тЭлемент=ТекУзел.Наименование;
тЗначение=ТекУзел.Значение;
Т.ВывестиСекцию("Строка");
КонецЦикла;
//таблица
Т.Опции(1,1,1,0);
Т.ПовторятьПриПечатиСтроки(1,1);
Т.ТолькоПросмотр(1);
Т.Показать("XML");
КонецПроцедуры
Ну вот собственно и все. Надеюсь данная статья оказалась вам полезна.
В статье продемонстрированы программные методы экспортирования данных из программы "1С:Предприятие 7.7".
Экспорт данных из 1С в Текстовой файл TXT, CSV
Код //сохранение данных таблицы значений в текстовой файл
//аргументы: М - таблица значений
Процедура ВыполнитьЭкспорт(М)
Т=СоздатьОбъект("Текст");
//выборка
М.ВыбратьСтроки();
Пока М.ПолучитьСтроку()=1 Цикл
Состояние("Экспорт: "+
Цел(М.НомерСтроки/М.КоличествоСтрок()
0)+"%");
тФирма=М.Фирма.ПолныйКод();
тТовар=М.Товар.ПолныйКод();
тСклад=М.Склад.ПолныйКод();
тКоличество=М.Количество;
Т.ДобавитьСтроку("Фирма="+тФирма+";Товар="+тТовар+";Склад="+тСклад+
";Количество="+тКоличество+";");
КонецЦикла;
//файл
Файл="export"+Формат(ДатаК,"Д ГГГГММДД")+".csv";
Т.Записать(Файл);
Сообщить("Файл с данными сохранен в каталоге
экспортной БД: "+КаталогИБ()+Файл);
КонецПроцедуры
Экспорт данных из 1С в файл dBase формата DBF
Код //процедура записывает данные об использовании
отчёта в файл dBase формата DBF
Процедура гЗаписатьСтатистикуИспользованияОтчета(ИдентификаторОтчета) Экспорт
//путь к файлу; имя файла не должно превышать 8 знаков
Путь=КаталогИБ()+"Stat.dbf";
//создание нового файла
Б=СоздатьОбъект("XBase");
Если ФС.СуществуетФайл(Путь)=0 Тогда
//добавление полей
Б.ДобавитьПоле("REPORT","S",100,0);
Б.ДобавитьПоле("USER","S",50,0);
Б.ДобавитьПоле("DATE","D",10,0);
Б.ДобавитьПоле("TIME","S",5,0);
//создание файла
Б.СоздатьФайл(Путь);
Б.ЗакрытьФайл();
КонецЕсли;
//открытие файла
Б.ОткрытьФайл(Путь);
Если Б.Открыта()=0 Тогда
Сообщить("Не удалось открыть файл DBF","!");
Возврат;
КонецЕсли;
//добавление записи
Б.Добавить();
Б.Date=ТекущаяДата();
Б.Time=ТекущееВремя();
Б.Report=СокрЛП(ИдентификаторОтчета);
Б.User=гПользователь.Наименование;
Б.Записать();
//закрытие файла
Б.ЗакрытьФайл();
КонецПроцедуры
Экспорт данных из 1С на лист MS Excel
Код //функция создаёт новую книгу в MS Excel и выгружает табличную часть заданного документа
Процедура гМногострочка_Экспортировать(Док) Экспорт
//документ
Д=СоздатьОбъект("Документ");
Д.НайтиДокумент(Док);
//приложение
Оле=СоздатьОбъект("Excel.Application");
Если ФлагВидимость=1 Тогда
Оле.Visible=1;
КонецЕсли;
Книга=Оле.Workbooks().Add();
Книга.Windows(1).Caption=Д.ПредставлениеВида()+" "+СокрЛП(Д.НомерДок);
Лист=Книга.Activesheet;
//шапка
Колонка=0;
Для i=1 По Метаданные.Документ(Д.Вид()).РеквизитТабличнойЧасти() Цикл
Ж=Метаданные.Документ(Д.Вид()).РеквизитТабличнойЧасти(i);
//колонка
Колонка=Колонка+1;
Ячейка=Лист.Cells(1,Колонка);
//текст
Ячейка.Value=Ж.Идентификатор;
//форматирование
Ячейка.Font.Bold=1;
Если Ж.Тип="Число" Тогда
Попытка
Лист.Columns(Колонка).NumberFormat="# ##0.00";
Исключение
Лист.Columns(Колонка).NumberFormat="# ##0,00";
КонецПопытки;
КонецЕсли;
КонецЦикла;
//строки
Д.ВыбратьСтроки();
Пока Д.ПолучитьСтроку()=1 Цикл
Лист.Range("A"+Число(Д.НомерСтроки+1)).Select();
Колонка=0;
//многострочка
Для i=1 По Метаданные.Документ(Д.Вид()).РеквизитТабличнойЧасти() Цикл
Ж=Метаданные.Документ(Д.Вид()).РеквизитТабличнойЧасти(i);
Колонка=Колонка+1;
//значение
Значение=Д.ПолучитьАтрибут(Ж.Идентификатор);
Лист.Cells(Д.НомерСтроки+1,Колонка).Value=СокрЛП(Значение);
КонецЦикла;
КонецЦикла;
//авто подбор ширины
Лист.Cells.EntireColumn.AutoFit();
//закрепление области
Лист.Range("A2").Select();
Оле.ActiveWindow.FreezePanes=1;
Оле.Visible=1;
КонецПроцедуры
Управление MS Word из 1С
Методы работы с MS Word через OLE активно использованы в конфигурации "Договоры". Для определения числового кода текстовых констант MS Word использована обработка "Константы VBA".
* Конфигурация "Договоры"
* Универсальная обработка "Константы VBA"
Код //поиск текста в открытом документе MS Word
Функция Текст_Найти(Оле,аТекст)
Текст=СокрЛП(аТекст);
//поиск
Оле.Selection.Find.ClearFormatting();
Оле.Selection.Find.Text=Текст;
Оле.Selection.Find.MatchCase=0;
Оле.Selection.Find.MatchWholeWord=0;
Оле.Selection.Find.MatchWildcards=0;
Оле.Selection.Find.MatchSoundsLike=0;
Оле.Selection.Find.MatchAllWordForms=0;
Оле.Selection.Find.Forward=1;
Оле.Selection.Find.Wrap=wdFindContinue;
Оле.Selection.Find.Format=0;
Ответ=Оле.Selection.Find.Execute();
//найден
Если Оле.Selection.Find.Found()=0 Тогда
Сообщить("Текст не найден: "+Текст);
Возврат(0);
Иначе
Возврат(1);
КонецЕсли;
КонецФункции
//поиск и замена текста в документе MS Word
Процедура Договор_Заменить()
//путь
Если ФС.ВыбратьФайл(0,Файл,Каталог,"Открыть старый файл","Файлы MS Word|*.doc")=0 Тогда
Возврат;
КонецЕсли;
//приложение
Оле=СоздатьОбъект("Word.Application");
Оле.Documents.Open(Каталог+Файл,,1);
//переход курсора в начало текста
Оле.Selection.HomeKey(wdStory);
//замена Номер договора
Если Текст_Найти(Оле,"ДОГОВОР")=1 Тогда
Оле.Selection.EndKey(wdLine,wdCharacter);
Оле.Selection.TypeText("ДОГОВОР № "+гНомерДок(НомерДок));
КонецЕсли;
//замена Дата договора
Если Текст_Найти(Оле,Константа.ГодСтарый)=1 Тогда
Оле.Selection.MoveLeft(wdWord,3);
Оле.Selection.EndKey(wdLine,wdCharacter);
Оле.Selection.TypeText(ДатаДоговора());
КонецЕсли;
//переход курсора в начало текста
Оле.Selection.HomeKey(wdStory);
Оле.Visible=1;
//предупреждение
Предупреждение("Создание нового договора копированием старого выполнено.");
КонецПроцедуры
Экспорт данных в файл формата XML
Код //процедура выгружает элементы справочника "Физические лица" в файл формата XML
Процедура Лица_Выгрузить()
//справочник
С=СоздатьОбъект("Справочник.Лица");
//анализатор
Анализатор=СоздатьОбъект("AddIn.XMLParser");
Корень=Анализатор.СоздатьДокумент();
//данные
Данные=Корень.СоздатьПодчиненныйЭлемент("Данные");
Данные.УстановитьАтрибут("Дата",ТекущаяДата());
Данные.УстановитьАтрибут("Время",ТекущееВремя());
Данные.УстановитьАтрибут("Автор",гПользователь.Наименование);
//наполнение
Группа=Данные;
С.ВыбратьЭлементы();
Пока С.ПолучитьЭлемент()=1 Цикл
Если С.ЭтоГруппа()=1 Тогда
Группа=Данные.СоздатьПодчиненныйЭлемент(С.Наименование);
Иначе
Э=Группа.СоздатьПодчиненныйЭлемент("Лицо");
Э.Значение=С.Код;
Э.УстановитьАтрибут("Наименование",С.Наименование);
КонецЕсли;
КонецЦикла;
//запись
Корень.Записать("C:\People.xml");
Предупреждение("ОК");
КонецПроцедуры
Управление MS Outlook из 1С
Код //создать новое сообщение из 1С в MS Outlook
Процедура Письмо_Создать()
//приложение
Попытка
Оле=CreateObject("Outlook.Application");
ЕстьОшибка=0;
Исключение
Предупреждение("Не удалось создать письмо в MS Outlook!");
ЕстьОшибка=1;
КонецПопытки;
//адрес
Адрес=СокрЛП(Лицо.АдресЭ);
//письмо
Если ЕстьОшибка=0 Тогда
//Outlook
Письмо=Оле.CreateItem(0);
Письмо.Subject=Клиент.Наименование+?(Лицо.Выбран()=0,"",", "+Лицо.Наименование);
Письмо.Body=гЛицо(Лицо);
Если ПустаяСтрока(Адрес)=0 Тогда
Письмо.Recipients.Add(Адрес);
КонецЕсли;
Если ПустаяСтрока(Путь)=0 Тогда
Письмо.Attachments.Add(Путь);
КонецЕсли;
Письмо.Display();
Иначе
//тема
Тема=Клиент.Наименование;
Если Лицо.Выбран()=1 Тогда
Тема=Тема+", "+Лицо.Наименование+"&body="+СокрЛП(Лицо.Имя);
КонецЕсли;
ЗапуститьПриложение("mailto:"+Адрес+"?subject="+Тема);
КонецЕсли;
КонецПроцедуры
//создать запись в календаре событий
Процедура Календарь_Создать()
//приложение
Попытка
Оле=CreateObject("Outlook.Application");
Исключение
Предупреждение("Не удалось создать запись в календаре событий в MS Outlook!");
Возврат;
КонецПопытки;
//задача
Задача=Оле.CreateItem(1);
Задача.Subject="Название встречи";
Задача.Start="01.11.2007 15:00:00";
Задача.End="01.11.2007 16:00:00";
Задача.Body="Описание встречи";
Задача.Location="Место встречи";
Задача.ReminderMinutesBeforeStart=30;
Задача.BusyStatus=0;
Задача.MeetingStatus=0;
Задача.Sensitivity=2;
Задача.Save();
КонецПроцедуры
//создать новую задачу из 1С в MS Outlook
Процедура Задача_Создать()
//приложение
Попытка
Оле=CreateObject("Outlook.Application");
Исключение
Предупреждение("Не удалось создать задачу в MS Outlook!");
Возврат;
КонецПопытки;
//задача
Задача=Оле.CreateItem(3);
Задача.Subject=Клиент.Наименование;
Задача.StartDate=ДатаДок+Константа.Фирма.ПериодСобытие;
Задача.Display();
Если Лицо.Выбран()=1 Тогда
Задача.Body=
""+Лицо.Наименование+"
|"+гЛицо(Лицо)+"
|"+СокрЛП(Лицо.Должность)+"
|моб. "+СокрЛП(Лицо.ТелефонМ)+"
|гор. "+СокрЛП(Лицо.ТелефонГ);
КонецЕсли;
КонецПроцедуры
Запустить из 1С страницу Интернет, отправить электронное почтовое сообщение
//создание почтового сообщения в ассоциированном почтовом клиенте с заданным электронным адресом
Процедура гКнопкаПочта(Значение) Экспорт
Если ПустаяСтрока(Значение)=0 Тогда
ЗапуститьПриложение("mailto:"+СокрЛП(Значение));
КонецЕсли;
КонецПроцедуры
//открытие страницы Интернет по заданному адресу в ассоциированном Интернет-браузере
Процедура гКнопкаИнтернет(Значение) Экспорт
Если ПустаяСтрока(Значение)=0 Тогда
ЗапуститьПриложение(СокрЛП(Значение));
КонецЕсли;
КонецПроцедуры
функция проверяет, является ли переданный в функцию Символ числом
Код
Функция ЭтоЧисло(Символ) Экспорт
Если (КодСимв(Символ)>=48) И (КодСимв(Символ)<=57) Тогда
Возврат(1);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
//функция возвращает копейки
Функция гКопейки(Значение) Экспорт
Грн=Цел(Значение);
Коп=Значение-Грн;
Возврат(Коп
0);
КонецФункции
//функция возвращает сумму без скидки
Функция гСкидка(Сумма,Скидка) Экспорт
Возврат Сумма*(1-Скидка/100);
КонецФункции
//функция устанавливает новое значение реквизита документа или справочника и задаёт вопрос, если новое значение не соответствует предыдущему
Функция гЗначение(Ко,Атрибут,Значение) Экспорт
Знач1=Ко.ПолучитьАтрибут(Атрибут);
Знач2=Значение;
//проверка
Если Не(ТипЗначенияСтр(Знач1)=ТипЗначенияСтр(Знач2)) Тогда
//несоответствие типов
Возврат(0);
ИначеЕсли Не(ТипЗначенияСтр(Знач2)="Число") И (ПустоеЗначение(Знач2)=1) Тогда
//пустое новое значение
Возврат(0);
КонецЕсли;
//реквизит
Если Метаданные.Документ(Ко.Вид()).Выбран()=1 Тогда
//документ
Если Метаданные.Документ(Ко.Вид()).РеквизитШапки(Атрибут).Выбран()=1 Тогда
Ж=Метаданные.Документ(Ко.Вид()).РеквизитШапки(Атрибут);
Имя=Ж.Представление();
ИначеЕсли Метаданные.Документ(Ко.Вид()).РеквизитТабличнойЧасти(Атрибут).Выбран()=1 Тогда
Ж=Метаданные.Документ(Ко.Вид()).РеквизитТабличнойЧасти(Атрибут);
Имя=Ж.Представление()+" (строка "+Ко.НомерСтроки+")";
Иначе
Ж=Метаданные.ОбщийРеквизитДокумента(Атрибут);
Имя=Ж.Представление();
КонецЕсли;
ИначеЕсли Метаданные.Справочник(Ко.Вид()).Выбран()=1 Тогда
//справочник
Ж=Метаданные.Справочник(Ко.Вид()).Реквизит(Атрибут);
Имя=Ж.Представление();
Если ПустаяСтрока(Имя)=1 Тогда
Имя=Атрибут;
КонецЕсли;
КонецЕсли;
//форматирование
Если ТипЗначенияСтр(Знач2)="Строка" Тогда
Знач1=СокрЛП(Знач1);
Знач2=СокрЛП(Знач2);
ИначеЕсли ТипЗначенияСтр(Знач2)="Число" Тогда
Знач2=Окр(Знач2,Ж.Точность);
КонецЕсли;
//проверка
Если Знач1=Знач2 Тогда
Возврат(0);
КонецЕсли;
//установка значения
Если ПустоеЗначение(Знач1)=0 Тогда
Текст=
"Атрибут: "+Имя+"
|
|Старое значение: "+СимволТабуляции+Знач1+"
|Новое значение: "+СимволТабуляции+Знач2+"
|
|Установить новое значение?";
Если Вопрос(Текст,"Да+Нет")="Нет" Тогда
Возврат(0)
КонецЕсли;
КонецЕсли;
//значение
Ко.УстановитьАтрибут(Атрибут,Знач2);
Возврат(1);
КонецФункции
В этой статье описываются полезные функции и процедуры, помогающие эффективно работать с различными типами данных в системе "1С:Предприятие 7.7".
Форматирование данных в 1С
Код //форматирование числа
Функция гЧисло(Значение,Знаки=2) Экспорт
Ответ=Формат(Значение,"Ч18."+Знаки);
Возврат СокрЛП(Ответ);
КонецФункции
//функция убирает лишние пробелы
Функция гСжатьПробелы(аТекст) Экспорт
Текст=СокрЛП(аТекст);
//пробелы
Замена=Формат(" ","С5");
Для й=1 По 4 Цикл
Знак=Сред(Замена,й);
Текст=СтрЗаменить(Текст,Знак," ");
КонецЦикла;
//
Возврат СокрЛП(Текст);
КонецФункции
//функция возвращает переданную строку, в которой первая буква устанавливается в верхнем или в нижнем регистре
Функция гБуква(Текст,ФлагНрег=0) Экспорт
Буква=Лев(Текст,1);
Если ФлагНрег=0 Тогда
Буква=ВРег(Буква);
Иначе
Буква=НРег(Буква);
КонецЕсли;
Возврат(Буква+Сред(Текст,2));
КонецФункции
/функция возвращает представление переданного документа
Функция гПредставлениеДокумента(Д) Экспорт
Возврат Д.ПредставлениеВида()+" "+СокрЛП(Д.НомерДок)+" ("+Д.ДатаДок+")";
КонецФункции
//процедура выдаёт сообщение при проведении документа
Процедура гСообщить(Ко,Текст,НомерСтроки=0,Символ="!") Экспорт
//сигнал
Если Ко.Ошибка=0 Тогда
Сигнал();
КонецЕсли;
//документ
Документ=""+Ко.ДатаДок+" "+Ко.ПредставлениеВида()+" "+СокрЛП(Ко.НомерДок);
//номер строки
Если НомерСтроки>0 Тогда
Документ=Документ+" (строка "+НомерСтроки+")";
КонецЕсли;
//сообщение
Сообщить(Документ+": "+Текст,Символ);
КонецПроцедуры
Список значений в 1С
Код //процедура выполняется при добавлении нового значения в интерактивный список значений
Процедура сзДобавить(Список,Тип,Вид,Длина,Точность,Подсказка) Экспорт
//тип
Если (Тип="Справочник") Или (Тип="Документ") Тогда
Тип=Тип+"."+Вид;
КонецЕсли;
//значение
Если Список.ТекущаяСтрока()=0 Тогда
Значение="";
Иначе
Значение=Список.ПолучитьЗначение(Список.ТекущаяСтрока());
КонецЕсли;
//выбор
Если ВвестиЗначение(Значение,Подсказка,Тип,Длина,Точность)=1 Тогда
Список.ДобавитьЗначение(Значение);
КонецЕсли;
КонецПроцедуры
//процедура выполняется для изменения значения интерактивного списка значений
Процедура сзИзменить(Список) Экспорт
Позиция=Список.ТекущаяСтрока();
Если Позиция=0 Тогда
Возврат;
КонецЕсли;
//
Значение=Список.ПолучитьЗначение(Список.ТекущаяСтрока());
Тип=ТипЗначенияСтр(Значение);
Если (Тип="Справочник") Или (Тип="Документ") Тогда
Тип=Тип+"."+Значение.Вид();
Подсказка=Значение.Вид();
Иначе
Подсказка=Тип;
КонецЕсли;
Если ВвестиЗначение(Значение,Подсказка,Тип)=1 Тогда
Список.УстановитьЗначение(Позиция,Значение);
КонецЕсли;
КонецПроцедуры
//процедура выполняется при удалении значения из интерактивного списка значений
Процедура сзУдалить(Список) Экспорт
Если Список.ТекущаяСтрока()>0 Тогда
Список.УдалитьЗначение(Список.ТекущаяСтрока());
КонецЕсли;
КонецПроцедуры
//процедура изменяет позицию значения интерактивного списка значений
Процедура сзСдвинуть(Список,Количество) Экспорт
Если (Количество>0) И (Список.ТекущаяСтрока()=Список.РазмерСписка()) Тогда
Количество=1-Список.РазмерСписка();
ИначеЕсли (Количество<0) И (Список.ТекущаяСтрока()=1) Тогда
Количество=Список.РазмерСписка()-1;
КонецЕсли;
Список.СдвинутьЗначение(Количество,Список.ТекущаяСтрока());
КонецПроцедуры
//функция проверяет наличие в списке значений с пометками хотя бы одного помеченного значения
Функция сзПометка(Список) Экспорт
Для i=1 По Список.РазмерСписка() Цикл
Если Список.Пометка(i)=1 Тогда
Возврат(1);
КонецЕсли;
КонецЦикла;
//нет пометок
Возврат(0);
КонецФункции
//функция помечает или снимает пометку для всех значений списка
Процедура сзПометить(Список,Флаг) Экспорт
Для й=1 По Список.РазмерСписка() Цикл
Список.Пометка(й,Флаг);
КонецЦикла;
КонецПроцедуры
//процедура оставляет в списке значений заданное количество значений
Процедура сзОбрезать(Список,Размер) Экспорт
Если Список.РазмерСписка()>Размер Тогда
Количество=Список.РазмерСписка()-Размер;
Список.УдалитьЗначение(Размер+1,Количество);
КонецЕсли;
КонецПроцедуры
//функция выгружает значения колонки таблицы значений в список значений
Функция сзКолонка(М,Колонка) Экспорт
Список=СоздатьОбъект("СписокЗначений");
//
В=СоздатьОбъект("ТаблицаЗначений");
М.Выгрузить(В,,,Колонка);
В.Свернуть(Колонка,);
В.Выгрузить(Список,,,Колонка);
Возврат(Список);
КонецФункции
//процедура преобразует строку со значениями в список значений
Процедура сзПарсить(Список,Текст) Экспорт
Если ПустаяСтрока(Текст)=0 Тогда
Если Найти(Текст,"=")=0 Тогда
//делитель - Запятая
Значение=СтрЗаменить(СокрЛП(Текст),",",Симв(34)+","+Симв(34));
Значение=Симв(34)+Значение+Симв(34);
Список.ИзСтрокиСРазделителями(Значение);
Иначе
//делитель - Точка с запятой
Текст=СтрЗаменить(Текст,";",РазделительСтрок);
Для й=1 По Текст.КоличествоСтрок() Цикл
Стр=Текст.ПолучитьСтроку(й);
Если ПустаяСтрока(Стр)=0 Тогда
Позиция=Найти(Стр,"=");
Если Позиция>0 Тогда
Идентификатор=Лев(Стр,Позиция-1);
Значение=Сред(Стр,Позиция+1);
Список.Установить(СокрЛП(Идентификатор),СокрЛП(Значение));
Иначе
Список.ДобавитьЗначение(СокрЛП(Стр));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
//процедура позиционирует строку списка значений на заданном значении
Процедура сзУстановить(Список,Значение) Экспорт
Позиция=Список.НайтиЗначение(Значение);
Если Позиция>0 Тогда
Список.ТекущаяСтрока(Позиция);
КонецЕсли;
КонецПроцедуры
Таблица значений в 1С
Код //процедура сдвигает строку в таблице значений;
//если сдвигается последняя строка вниз, то строка становится первой;
//если сдвигается первая строка вверх, то строка перемещается в конец таблицы значений
Процедура Количество=1-М.КоличествоСтрок();
ИначеЕсли (Количество<0) И (М.ТекущаяСтрока()=1) Тогда
Количество=М.КоличествоСтрок()-1;
КонецЕсли;
М.СдвинутьСтроку(Количество,М.ТекущаяСтрока())());
КонецПроцедуры
//процедура обнуляет значения таблицы значений вниз от заданной строки и вправо от заданной колонки
Процедура тзОбнулить(М,НомерСтр,НомерКол) Экспорт
Для i=НомерСтр По М.КоличествоСтрок() Цикл
Для j=НомерКол По М.КоличествоКолонок() Цикл
М.УстановитьЗначение(i,j,0);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
//процедура удаляет строку в интерактивной таблице значений> Процедура тзУдалитьСтроку(М) Экспорт
//запоминание текущей строки
ТекСтрока=М.ТекущаяСтрока()-1;
//удаление
М.УдалитьСтроку();
//позиционирование
Если М.КоличествоСтрок()>0 Тогда
ТекСтрока=Мин(ТекСтрока,М.КоличествоСтрок());
М.ТекущаяСтрока(ТекСтрока);
КонецЕсли;
КонецПроцедуры
//процедура находит документ с заданным номером в таблице значений с документами
Процедура гЖурнал_Найти(М) Экспорт
НомерДок=0;
Если ВвестиЧисло(НомерДок,"Номер документа",5,0)=1 Тогда
//поиск по номеру в выборке
Если М.НайтиЗначение(НомерДок,,"Номер")=0 Тогда
Предупреждение("Документ № "+НомерДок+" не найден");
Возврат;
КонецЕсли;
//поиск документа
Список=СоздатьОбъект("СписокЗначений");
М.ВыбратьСтроки();
Пока М.ПолучитьСтроку()=1 Цикл
Если М.Номер=НомерДок Тогда
Список.ДобавитьЗначение(М.ТекущийДокумент);
КонецЕсли;
КонецЦикла;
//выбор
Значение="";
Если Список.РазмерСписка()=1 Тогда
Значение=Список.ПолучитьЗначение(1);
ИначеЕсли Список.ВыбратьЗначение(Значение,"Выбор документа")=0 Тогда
Возврат;
КонецЕсли;
//позиционирование
НомерСтр=0;
М.НайтиЗначение(Значение,НомерСтр,"ТекущийДокумент");
М.ТекущаяСтрока(НомерСтр);
КонецЕсли;
КонецПроцедуры
Таблица или печатная форма в 1С
Код //установление автоширины колонок таблицы
Процедура гАвтоШиринаКолонок(Таб,НачКол,НачСтр) Экспорт
Для НомерКол=НачКол По Таб.ШиринаТаблицы() Цикл
МаксШирина=0;
Для НомерСтр=НачСтр По Таб.ВысотаТаблицы() Цикл
ТекШирина=СтрДлина(Таб.Область(НомерСтр,НомерКол).Текст);
МаксШирина=Макс(МаксШирина,ТекШирина);
КонецЦикла;
Таб.Область(,НомерКол).ШиринаСтолбца(МаксШирина+2);
КонецЦикла;
КонецПроцедуры
Периоды и даты в 1С
Код //функция проверяет, равен ли месяцу интервал между заданными датами
Функция ЭтоМесяц(ДатаН,ДатаК) Экспорт
Если Не(ДатаН=НачМесяца(ДатаН)) Тогда
Возврат(0);
ИначеЕсли Не(ДатаК=КонМесяца(ДатаК)) Тогда
Возврат(0);
ИначеЕсли ДатаН=НачМесяца(ДатаК) Тогда
Возврат(1);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
//функция возвращает количество полных месяцев между датами
Функция гМесяцев(ДатаН,ДатаК) Экспорт
Если ДатаН<ДатаК Тогда
ТекДата=НачМесяца(ДатаН);
Значение=1;
Пока ТекДата<НачМесяца(ДатаК) Цикл
ТекДата=ДобавитьМесяц(ТекДата,1);
Значение=Значение+1;
КонецЦикла;
Возврат(Значение);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
//функция определяет порядковый номер месяца в квартале
Функция гМесяцКвартала(ДатаДок) Экспорт
НачМесяц=ДатаМесяц(НачКвартала(ДатаДок));
КонМесяц=ДатаМесяц(ДатаДок);
Возврат(КонМесяц-НачМесяц+1);
КонецФункции
//функция определяет порядковый номер квартала по дате
Функция гДатаКвартал(аДата) Экспорт
Возврат ДатаМесяц(КонКвартала(аДата))/3;
КонецФункции
Календари и праздники в 1С
Код //ф//функция возвращает дату, находящуюся на определённом интервале дней от заданной даты, без учёта выходных;
//например, используется для определения конечной даты действия счёта-фактуры
Функция an class="color-blue">гСрокДействия(ДатаДок,Период,Вид="Основной") Экспорт
К=СоздатьОбъект("Календарь."+Вид);
К.УчитыватьПраздники(1);
Если К.Автозаполнение(ДатаДок,ДобавитьМесяц(ДатаДок+Период,1))=1 Тогда
Возврат К.ПолучитьДату(ДатаДок,Период);
КонецЕсли;
КонецФункции
//функция определяет количество рабочих дней в интервале дат
Функция гРабочиеДни(ДатаН,ДатаК,Вид="Основной") Экспорт
К=СоздатьОбъект("Календарь."+Вид);
К.УчитыватьПраздники(1);
Если К.Автозаполнение(ДатаН,ДатаК)=1 Тогда
Возврат К.Дней(ДатаН,ДатаК);
КонецЕсли;
КонецФункции
//функция определяет количество праздничных дней в интервале дат
Функция гПраздники(ДатаН,ДатаК) Экспорт
Кол=0;
//
П=СоздатьОбъект("Праздники");
П.ВыбратьДаты(ДатаН,ДатаК);
Пока П.СледующаяДата()=1 Цикл
Если НомерДняНедели(П.Дата)<6 Тогда
Кол=Кол+1;
КонецЕсли;
КонецЦикла;
//
Возврат(Кол);
КонецФункции
[pagebreak]
Справочники в 1С
Код //функция возвращает элемент заданного справочника по значению реквизита "Счет"
Функция сНайтиПоСчету(Счет,Справочник,Реквизит="Счет") Экспорт
С=СоздатьОбъект("Справочник."+Справочник);
Если С.НайтиПоРеквизиту(Реквизит,Счет,1)=1 Тогда
Возврат С.ТекущийЭлемент();
Иначе
Возврат ПолучитьПустоеЗначение("Справочник."+Справочник);
КонецЕсли;
КонецФункции
//функция возвращает элемент заданного справочника по полному коду элемента
Функция сНайтиПоКоду(Справочник,Код) Экспорт
С=СоздатьОбъект("Справочник."+Справочник);
Если С.НайтиПоКоду(Код,2)=1 Тогда
Возврат С.ТекущийЭлемент();
Иначе
Возврат ПолучитьПустоеЗначение("Справочник."+Справочник);
КонецЕсли;
КонецФункции
//функция возвращает элемент заданного справочника по наименованию
//если элемент отсутствует в справочнике, то создаётся новый
Функция сНайтиПоНаименованию(Справочник,Наименование) Экспорт
С=СоздатьОбъект("Справочник."+Справочник);
Если С.НайтиПоНаименованию(Наименование,0,1)=0 Тогда
С.Новый();
С.Наименование=Наименование;
С.Записать();
Сообщить("Справочник "+Справочник+": Новый элемент "+Наименование);
КонецЕсли;
Возврат(С.ТекущийЭлемент());
КонецФункции
//процедура удаляет заданный элемент справочника
Процедура гЭлемент_Удалить(Элемент,Флаг) Экспорт
С=СоздатьОбъект("Справочник."+Элемент.Вид());
С.НайтиЭлемент(Элемент);
С.Удалить(Флаг);
КонецПроцедуры
//функция возвращает строку вида "Иванов И.И." из переданной в функцию строки вида "Иванов Иван Иванович"
Функция гФио_Получить(Значение)
Стр=гФорматС(Значение);
Стр=СтрЗаменить(Стр," ",РазделительСтрок);
Если СтрКоличествоСтрок(Стр)=1 Тогда
Фио=СокрЛП(Стр);
ИначеЕсли СтрКоличествоСтрок(Стр)=2 Тогда
СтрФ=СтрПолучитьСтроку(Стр,1);
СтрИ=СтрПолучитьСтроку(Стр,2);
Фио=СокрЛП(СтрФ)+" "+Лев(СокрЛП(СтрИ),1)+".";
Иначе
СтрО=СтрПолучитьСтроку(Стр,СтрКоличествоСтрок(Стр));
СтрИ=СтрПолучитьСтроку(Стр,СтрКоличествоСтрок(Стр-1));
СтрФ="";
Для й=1 По СтрКоличествоСтрок(Стр)-2 Цикл
СтрФ=СтрФ+" "+СтрПолучитьСтроку(Стр,й);
КонецЦикла;
Фио=СокрЛП(СтрФ)+" "+Лев(СокрЛП(СтрИ),1)+"."+Лев(СокрЛП(СтрО),1)+".";
КонецЕсли;
Возврат(Фио);
КонецФункции
//функция открывает подбор из справочника и предоставляет пользователю выбор из элементов фиксированной группы
Функция сПодборРодитель(Ко,Родитель,Элемент,Заголовок="") Экспорт
Ко.ОткрытьПодбор("Справочник."+Родитель.Вид(),"ДляВыбора",,0);
Ко.КонтекстПодбора.ИспользоватьРодителя(Родитель,0);
Ко.КонтекстПодбора.ИерархическийСписок(1,0);
//текущий элемент
Если Элемент.Выбран()=1 Тогда
Ко.КонтекстПодбора.АктивизироватьОбъект(Элемент);
КонецЕсли;
//заголовок
Если ПустаяСтрока(Заголовок)=0 Тогда
Ко.КонтекстПодбора.Форма.Заголовок(Заголовок,0);
КонецЕсли;
//отмена стандартной обработки
Возврат(0);
КонецФункции
Документы в 1С
Код //удаление ведущих нолей в номере документа
Функция гНомерДок(Значение) Экспорт
Текст=СокрЛП(Значение);
Текст=СтрЗаменить(Текст," ","");
Текст=СтрЗаменить(Текст,"_","-");
Если Константа.ФлагНомерОсн=0 Тогда
Возврат(Текст);
ИначеЕсли Текст="0" Тогда
Возврат(Текст);
КонецЕсли;
//префикс
Префикс="";
Для i=1 По СтрЧислоВхождений(Текст,"-") Цикл
Позиция=Найти(Текст,"-");
Префикс=Префикс+Лев(Текст,Позиция);
Текст=Сред(Текст,Позиция+1);
КонецЦикла;
//удаление нолей
ФлагЧисло=0;
Номер="";
Для i=1 По СтрДлина(Текст) Цикл
Символ=Сред(Текст,i,1);
Если ЭтоЧисло(Символ)=0 Тогда
Номер=Номер+Символ;
ИначеЕсли Не(Число(Символ)=0) Тогда
Номер=Номер+Символ;
ФлагЧисло=1;
ИначеЕсли ФлагЧисло=1 Тогда
Номер=Номер+Символ;
КонецЕсли;
КонецЦикла;
//
Возврат(Префикс+Номер);
КонецФункции
//функция возвращает числовой номер документа без префикса
Функция гНомерБезПрефикса(Значение) Экспорт
Номер=гНомерДок(Значение);
Позиция=Найти(Значение,"-");
Номер=Сред(Номер,Позиция+1);
Возврат(Номер);
КонецФункции
//функция создаёт таблицу значений документов заданного вида по одному клиенту и даёт выбрать один документ
Функция гДокументКлиента(Значение,Клиент,ВидДокумента) Экспорт
Если Клиент.Выбран()=0 Тогда
Предупреждение("Не выбран Контрагент!");
Возврат(0);
КонецЕсли;
//таблица
М=СоздатьОбъект("ТаблицаЗначений");
М.НоваяКолонка("Дата","Дата",,,,10);
М.НоваяКолонка("Док","Строка",,,"Документ",50);
М.НоваяКолонка("Сумма","Число",,,,18,"Ч015.2");
М.НоваяКолонка("Документ","Документ");
М.ВидимостьКолонки("Документ",0);
//документы
Д=СоздатьОбъект("Документ");
Д.ВыбратьПоЗначению(,,"Клиент",Клиент);
Пока Д.ПолучитьДокумент()=1 Цикл
Состояние(""+Д.ДатаДок);
Если Не(Д.Вид()=ВидДокумента) Тогда
Продолжить;
КонецЕсли;
//
М.НоваяСтрока();
М.Документ=Д.ТекущийДокумент();
М.Дата=Д.ДатаДок;
М.Док=Д.ПредставлениеВида()+" "+СокрЛП(Д.НомерДок);
//сумма
Ж=Метаданные.Документ(Д.Вид());
Если Ж.РеквизитТабличнойЧасти("ВалСумма").Выбран()=1 Тогда
М.Сумма=Д.Итог("ВалСумма");
ИначеЕсли Ж.РеквизитТабличнойЧасти("СуммаС").Выбран()=1 Тогда
М.Сумма=Д.Итог("СуммаС");
ИначеЕсли Ж.РеквизитТабличнойЧасти("Сумма").Выбран()=1 Тогда
М.Сумма=Д.Итог("Сумма");
КонецЕсли;
КонецЦикла;
//проверка
Если М.КоличествоСтрок()=0 Тогда
Предупреждение("Документы не найдены!");
Возврат(0);
КонецЕсли;
//строка по умолчанию
НомерСтр=0;
Если М.НайтиЗначение(Значение,НомерСтр,"Документ")=0 Тогда
НомерСтр=М.КоличествоСтрок();
КонецЕсли;
//выбор
Заголовок=Метаданные.Документ(ВидДокумента).Представление()+": "+Клиент.Наименование;
Если М.ВыбратьСтроку(НомерСтр,Заголовок)=1 Тогда
Значение=М.ПолучитьЗначение(НомерСтр,"Документ");
Возврат(1);
Иначе
Возврат(0);
КонецЕсли;
КонецФункции
Предопределённые функции и процедуры в 1С
Код Процедура ОбработкаЯчейкиТаблицы(Значение,Флаг,Таблица,Адрес)
Перем Ответ;
Перем Ко;
Если ПустоеЗначение(Значение)=1 Тогда
Предупреждение("Невозможно обработать значение ячейки!");
ИначеЕсли ТипЗначенияСтр(Значение)="Документ" Тогда
Если гПользователь.ФлагСписок=0 Тогда
Флаг=1;
Иначе
А=СоздатьОбъект("СписокЗначений");
А.ДобавитьЗначение(0,"Открыть документ");
А.ДобавитьЗначение(1,"Открыть в журнале документов");
Если А.ВыбратьЗначение(Ответ,,,,1)=1 Тогда
Если Ответ=0 Тогда
Флаг=1;
Иначе
Журнал=Метаданные.Документ(Значение.Вид()).Журнал.Идентификатор;
ОткрытьФорму("Журнал."+Журнал+".Основная",Ко);
Ко.АктивизироватьОбъект(Значение);
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли ТипЗначенияСтр(Значение)="Справочник" Тогда
Если гПользователь.ФлагСписок=0 Тогда
Флаг=1;
Иначе
А=СоздатьОбъект("СписокЗначений");
А.ДобавитьЗначение(0,"Открыть элемент");
А.ДобавитьЗначение(1,"Открыть в списке справочника");
Если А.ВыбратьЗначение(Ответ,,,,1)=1 Тогда
Если Ответ=0 Тогда
Флаг=1;
Иначе
Журнал=Метаданные.Справочник(Значение.Вид()).ОсновнаяФорма;
ОткрытьФорму("Справочник."+Значение.Вид()+"."+Журнал,Ко);
Ко.АктивизироватьОбъект(Значение);
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли ТипЗначенияСтр(Значение)="СписокЗначений" Тогда
//расшифровка - СписокЗначений
Кнопка=Значение.Получить("Кнопка");
Если Число(Кнопка)=0 Тогда
Значение.СортироватьПоПредставлению();
//обработка - Ячейка
Представление="";
А=СоздатьОбъект("СписокЗначений");
Для i=1 По Значение.РазмерСписка() Цикл
Отчет=Значение.ПолучитьЗначение(i,Представление);
Если ПустаяСтрока(Отчет)=1 Тогда
Продолжить;
ИначеЕсли Лев(Представление,4)="Меню" Тогда
//элемент контекстного меню в ячейке
Позиция=Найти(Отчет,"|");
Если Позиция=0 Тогда
Представление=Метаданные.Отчет(Отчет).Представление();
Иначе
Добавка=Сред(Отчет,Позиция+1);
Отчет=Лев(Отчет,Позиция-1);
Представление=Метаданные.Отчет(Отчет).Представление()+": "+Добавка;
КонецЕсли;
А.ДобавитьЗначение(Отчет,Представление);
КонецЕсли;
КонецЦикла;
//контекстное меню в ячейке
Если А.РазмерСписка()>0 Тогда
Если А.ВыбратьЗначение(Ответ,,,,1)=1 Тогда
Значение.Выгрузить(гПакет);
гПакет.Установить("Таблица","");
ОткрытьФормуМодально("Отчет."+Ответ,1+гПользователь.ФлагОтчет);
КонецЕсли;
КонецЕсли;
Иначе
//обработка - Кнопка
Значение.Выгрузить(гПакет);
гПакет.Установить("Таблица",Таблица);
Отчет=Значение.Получить("Отчет");
ОткрытьФормуМодально("Отчет."+Отчет,Кнопка);
гПакет.Установить("Таблица","");
КонецЕсли;
ИначеЕсли ТипЗначенияСтр(Значение)="Строка" Тогда
Если ВРег(Лев(СокрЛП(Значение),6))="ССЫЛКА" Тогда
СтрокаЗапуска=СокрЛП(Сред(Значение,7));
ЗапуститьПриложение(СтрокаЗапуска);
Иначе
Флаг=1;
КонецЕсли;
Иначе
//расшифровка - Стандартная обработка ячейки
Флаг=1;
КонецЕсли;
КонецПроцедуры
Налоговый учёт и первое событие в 1С
Код //функция определяет сумму первого события за период по заданным остаткам на начало и конец периода
Функция гПервоеСобытие(НачД,НачК,КонД,КонК) Экспорт
//первое событие
СуммаД=Макс(КонД-НачД,0);
СуммаК=Макс(КонК-НачК,0);
//сумма
Возврат(СуммаД+СуммаК);
КонецФункции
Резюме
В статье описаны функции и процедуры, используемые в программе "1С:Предприятие 7.7" для работы со справочниками, документами, списками значений, таблицами значений и с прочими агрегатными типами данных. Образцы практического применения описанных средств Вы сможете найти в статьях "Отчёты для 1С" и "Обработки для 1С".
Внимание! Если у вас не получилось найти нужную информацию, используйте
рубрикатор или воспользуйтесь
поиском .
книги по программированию исходники компоненты шаблоны сайтов C++ PHP Delphi скачать