Адрес этой странички : http://doc-prg.narod.ru/art_00104/art_00104.htm 
Дата обновления : 08.08.2009
 

(c) Sergey Popov, Usinsk, Komi, 2007

© 08.08.2009 Сергей Попов

1Cv7.
Некоторые полезные алгоритмы.
Справочники.

Статью в виде файла (12.4 кб) можно скачать здесь: art_00104.zip

 1. Получить уникальный код в справочнике по реквизиту
//Получить СЛЕДУЮЩИЙ уникальный код (по заданному реквизиту) в заданном справочнике
//Реквизит может иметь типы : Строка или ЦЕЛОЕ Число.
//Если тип = СТРОКА, то все равно, содержание реквизита должно быть ЦИФРОВЫМ !!!
//Ест-нно, что Реквизит должен иметь атрибут "Сортировка"
//Производится проверка на переполнение
//Функция возвращает уникальный код (строка ненулевой длины или ненулевое число в зависимости от типа реквзита)
//Если неудачно, то пустую строку или число 0 (в зависимости от типа реквизита)
//Функция может располагаться в глобальном модуле.

Функция сп_ПолучитьУникКодВСправочникеПоРеквизиту(ИмяСправ="Сотрудники",ИмяРеквДляПоиска="УникальныйКод")  Экспорт
//Res - возвращаемое значение.
// Уникальный код в справочнике ИмяСправ по Реквизиту ИмяРеквДляПоиска.
// "" или 0 - НЕ удачно
Перем Res; 
Перем ТипРекв;
Res=0; 
ТипРекв=0;
YesOfCouse=0;
Длина=0;
Если Метаданные.Справочник(""+ИмяСправ).Выбран()>0 Тогда
    //Справочник есть
    Если Метаданные.Справочник(""+ИмяСправ).Реквизит(""+ИмяРеквДляПоиска).Выбран()>0 Тогда
        //Реквизит есть
        Sx=Метаданные.Справочник(""+ИмяСправ).Реквизит(""+ИмяРеквДляПоиска).Тип;
        Если ВРег(Sx)=ВРег("Число") Тогда
            ТипРекв=1;
            Res=0; 
        КонецЕсли;
        Если ВРег(Sx)=ВРег("Number") Тогда
            ТипРекв=1;
            Res=0; 
        КонецЕсли;
        Если ВРег(Sx)=ВРег("Строка") Тогда
            ТипРекв=2;
            Res=""; 
        КонецЕсли; 
        Если ВРег(Sx)=ВРег("String") Тогда
            ТипРекв=2;
            Res=""; 
        КонецЕсли; 
        Если ТипРекв>0 Тогда
            //Приемлемый тип реквизита
            Длина = Метаданные.Справочник(""+ИмяСправ).Реквизит(""+ИмяРеквДляПоиска).Длина;
            Если Длина>0 Тогда //Перестрахуемся на всякий случай
                Сорт = Метаданные.Справочник(""+ИмяСправ).Реквизит(""+ИмяРеквДляПоиска).Сортировка;
                Если Сорт>0 Тогда //Возможна сортировка
                    Если ТипРекв=1 Тогда
                        //Число
                        Точность = Метаданные.Справочник(""+ИмяСправ).Реквизит(""+ИмяРеквДляПоиска).Точность;
                        Если Точность <=0 Тогда //Перестрахуемся на всякий случай, что это ЦЕЛОЕ число
                            YesOfCouse=1;
                        КонецЕсли;
                    КонецЕсли;
                    Если ТипРекв=2 Тогда
                        //Строка
                        YesOfCouse=1;
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецЕсли;
Если YesOfCouse>0 Тогда 
    //Все OK - продолжим
    ПоследнийГерой2=1; //По умолчанию, в справочнике ничего нет
    Спр=СоздатьОбъект("Справочник."+ИмяСправ);
    Спр.ПорядокРеквизита(""+ИмяРеквДляПоиска);
    Спр.ОбратныйПорядок(1); 
    Если Спр.ВыбратьЭлементы(0)>0 Тогда
        Если Спр.ПолучитьЭлемент(1)>0 Тогда
            //Вычислим след.код
            ПоследнийГерой = Спр.ПолучитьАтрибут(""+ИмяРеквДляПоиска); 
            Если ТипРекв=1 Тогда
                ПоследнийГерой2=ПоследнийГерой+1;
            КонецЕсли;
            Если ТипРекв=2 Тогда
                //Строка
                ПоследнийГерой2=ЧИСЛО(ПоследнийГерой)+1;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
    //Вернем найденное значение в формате заданного реквизита
    Если ТипРекв=1 Тогда
        //Тип реквизита - число
        Res=ПоследнийГерой2; 
        Если СтрДлина(СТРОКА(Res))>Длина Тогда //Переполнение
            Res=0;
        КонецЕсли;
    КонецЕсли;
    Если ТипРекв=2 Тогда
        //Тип реквизита - строка
        Res=СТРОКА(ПоследнийГерой2); 
        Если СтрДлина(Res)<=Длина Тогда //Переполнения НЕТ
            Если СтрДлина(Res)<Длина Тогда
                //Добавим ведущие нули до Длины Реквизита
                Count=Длина-СтрДлина(Res);
                i=0;
                Пока i<Count Цикл
                    i=i+1;
                    Res="0"+Res; 
                КонецЦикла;
            КонецЕсли; 
        Иначе
             //Переполнение
            Res="";
        КонецЕсли
    КонецЕсли;
КонецЕсли;
Возврат Res;
КонецФункции //сп_ПолучитьУникКодВСправочникеПоРеквизиту

2. Прозрачное копирование элементов справочника(ов).
Функция сп_КопироватьЭлементСправочника(ТекЭлОС_откуда,ТекЭлОС_куда,СписОшибок="")
Скачать (3 Кб)

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


3. Универсальная функция чтения Значения из элемента справочника.
//СпрМХ - ТекущийЭлемент справочника (должен быть выбран)
//ИмяРеквизита - Идентификатор реквизита справочника
//ТипЗн - возвращаемое значение : ТипЗначения (строка). 
//Функция возвращает "обычные" и периодические реквизиты.
//Для периодического реквизита возвращает значение на Дату (Дата99)
//Если Дата99 = "", то возвращается ПустоеЗначение (для периодич.реквизита)
//"Понимает" ИмяРекв = [Код, Наименование, Владелец, Родитель]

Функция сп_Реквизит_ВернутьЗначениеИзСправочника(СпрМХ,ИмяРеквизита, ТипЗн, Дата99="") Экспорт
//23.01.2003 сп_
Перем Res; //Возвращаемое значение - Значение Реквизита справочника
//ТипЗн - возращаемое значение Типа Значения Реквизита
Res=ПолучитьПустоеЗначение();
ТипЗн=""; 
Если ТипЗначения(СпрМХ)=11 Тогда
    Если СпрМХ.Выбран()>0 Тогда
        Если Метаданные.Справочник(""+СпрМХ.Вид()).Выбран()>0 Тогда;
            Yes=1;
            Если ВРег(СокрЛП(ИмяРеквизита))="КОД" Тогда
                Yes=0;
                Res=СпрМХ.Код;
                ТипЗн=ВРег(ТипЗначенияСтр(СпрМХ.Код));
            КонецЕсли; 
            Если ВРег(СокрЛП(ИмяРеквизита))="НАИМЕНОВАНИЕ" Тогда
                Yes=0;
                Res=СпрМХ.Наименование;
                ТипЗн=ВРег(ТипЗначенияСтр(СпрМХ.Наименование));
            КонецЕсли; 
            Если ВРег(СокрЛП(ИмяРеквизита))="ВЛАДЕЛЕЦ" Тогда
                Yes=0;
                Res=СпрМХ.Владелец;
                ТипЗн=ВРег(ТипЗначенияСтр(СпрМХ.Владелец));
            КонецЕсли; 
            Если ВРег(СокрЛП(ИмяРеквизита))="РОДИТЕЛЬ" Тогда
                Yes=0;
                Res=СпрМХ.Родитель;
                ТипЗн=ВРег(ТипЗначенияСтр(СпрМХ.Родитель));
            КонецЕсли; 
            Если Yes>0 Тогда
                Если Метаданные.Справочник(""+СпрМХ.Вид()).Реквизит(""+ИмяРеквизита).Выбран()>0 Тогда
                    ЭтоПериодический=Метаданные.Справочник(""+СпрМХ.Вид()).Реквизит(""+ИмяРеквизита).Периодический;
                    Если ЭтоПериодический<=0 Тогда
                        Res=СпрМХ.ПолучитьАтрибут(""+ИмяРеквизита);
                        ТипЗн=ВРег(ТипЗначенияСтр((Res)));
                    Иначе
                        Если ДАТА(СокрЛП(Дата99))<>ДАТА(0) Тогда
                            Res=СпрМХ.ПолучитьАтрибут(""+ИмяРеквизита).Получить(ДАТА(СокрЛП(Дата99)));
                            ТипЗн=ВРег(ТипЗначенияСтр((Res)));
                        КонецЕсли;
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли; 
КонецЕсли;
Возврат Res;
КонецФункции //сп_Реквизит_ВернутьЗначениеИзСправочника

4.Проверка, существует ли Справочник с идентификатором ИдСпр
//Функция возвращает 1, если существует и 0 в противном случае
//ИдСпр - Идентификатор Справочника
Функция сп_СправочникСуществует(ИдСпр) Экспорт
//_new_ 05.04.2003 сп_
Перем Res;
Res=0;
Если Метаданные.Справочник(""+СокрЛП(ИдСпр)).Выбран()>0 Тогда
    Res=1;
КонецЕсли;
Возврат Res;
КонецФункции //сп_СправочникСуществует()
//----------------------------------------------------------------------

5. Проверка, существует ли реквизит с идентификатором ИмяРекв в справочнике с идентификатором ИмяСпр
//Функция возвращает 1, если существует и 0 в противном случае
Функция сп_Реквизит_СправочникаСуществует(ИмяСпр,ИмяРекв) Экспорт
//_new_ 02.02.2003 сп_
Перем Res;
Res=0;
ИмяСпр=СокрЛП(ИмяСпр);
ИмяРекв=СокрЛП(ИмяРекв);
Если Метаданные.Справочник(""+ИмяСпр).Выбран()>0 Тогда
    Если Метаданные.Справочник(""+ИмяСпр).Реквизит(""+ИмяРекв).Выбран()>0 Тогда
        Res=1;
    КонецЕсли; 
КонецЕсли; 
Возврат Res; 
КонецФункции //сп_Реквизит_СправочникаСуществует

 

6.Функция "вычисляет" тип и вид реквизита справочника (из метаданных)
//ИмяСпр - идентификатор справочника
//ИдРекв - идентификатор реквизита
//В параметрах ТипРекв и ВидРекв возвращается строковое значение Типа и Вида реквизита
//В параметре ЭтоПериодический возвращается 1, если реквизит периодический и 0, если нет
/Функция возвращает такое же значение, как функция ТипЗначения()
Функция сп_ПолучитьТипРеквизитаИзМетаданных(ИмяСпр,ИдРекв,ТипРекв,ВидРекв,ЭтоПериодический) Экспорт
//_new_ 01.04.2003 сп_
Перем Res; //Возвращаемое значение : код типа значения
Res = 0;
ТипРекв = "";
ВидРекв = "";
ЭтоПериодический = 0;
Yes=0; 
Если Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Выбран()>0 Тогда
    Если Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит(""+СокрЛП(ИдРекв)).Выбран()>0 Тогда
    Yes=1; 
    ТипРекв = СокрЛП(Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит(""+СокрЛП(ИдРекв)).Тип);
    ВидРекв = СокрЛП(Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит(""+СокрЛП(ИдРекв)).Вид);
    ЭтоПериодический = Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит(""+СокрЛП(ИдРекв)).Периодический;
    КонецЕсли; 
КонецЕсли; 
Если Yes>0 Тогда
    Если ВРег(ТипРекв) = ВРег("Число") Тогда
        Res=1;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Строка") Тогда
        Res=2;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Дата") Тогда
        Res=3;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Перечисление") Тогда
        Res=10;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Справочник") Тогда
        Res=11;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Документ") Тогда
        Res=12;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Календарь") Тогда
        Res=13;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("ВидРасчета") Тогда
        Res=14;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("Счет") Тогда
        Res=15;
    КонецЕсли; 
    Если ВРег(ТипРекв) = ВРег("ВидСубконто") Тогда
        Res=16;
    КонецЕсли; 
КонецЕсли;
Возврат Res;
КонецФункции //сп_ПолучитьТипРеквизитаИзМетаданных()

 

7. Прочитать список реквизитов справочника в СписокЗначений 
(на основании инфы из метаданных)

//Дополнительно в СписокЗначений включаются : Код, Наименование, Владелец, Родитель
//Возвращаемое значение: СписокЗначений
// СТРОКА : ИдРеквизита
// ЗНАЧЕНИЕ : ТипЗначения
Функция сп_ПолучитьСписокРеквизитовСправочника(ИмяСпр) Экспорт
//_new_ 01.04.2003 сп_
Перем Res;
Res = СоздатьОбъект("СписокЗначений");
Если Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Выбран()>0 Тогда
    Тип99 = "?";
    Res.ДобавитьЗначение(Тип99,"Код");
    Тип99 = "СТРОКА";
    Res.ДобавитьЗначение(Тип99,"Наименование");
    Тип99 = "?";
    Res.ДобавитьЗначение(Тип99,"Владелец");
    Тип99 = "?";
    Res.ДобавитьЗначение(Тип99,"Родитель");
    Колво = Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит();
    Если Колво>0 Тогда
        i=0;
        Пока i<Колво цикл
            i=i+1;
            ЭтоПериодический = Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит(i).Периодический;
            ИдРекв=СокрЛП(Метаданные.Справочник(""+СокрЛП(ИмяСпр)).Реквизит(i).Идентификатор);
            ТипРекв="";
            ВидРекв="";
            ЭтоП=0;
            Тип99 = сп_ПолучитьТипРеквизитаИзМетаданных(""+СокрЛП(ИмяСпр),ИдРекв,ТипРекв,ВидРекв,ЭтоП);
            Res.ДобавитьЗначение(Тип99,ИдРекв);
        КонецЦикла;
    КонецЕсли;
КонецЕсли; 
Возврат Res;
КонецФункции //сп_ПолучитьСписокРеквизитовСправочника()


8. Считывание значений реквизитов Элемента Справочника <ТекЭлСпр99> 
(элемент должен быть выбран) в ТаблицуЗначений <ТЗ99>
//Периодические реквизиты читаются на дату Дата99 (если не задана, то ТекущаяДата())
//Кроме реквизитов считываются : Код, Наименование, Владелец, Родитель
//Функция возвращает : 0 - если ошибка, или >0 (кол-во строк в ТЗ99), если все OK
//Колонки ТЗ99 : 
// ИдРеквизита - Идентификатор Реквизита
// ЗначРеквизита - Считанное значение Реквизита
// ТипИзМетаданных - Тип и Вид Реквизита (как задано в конфигураторе). 
// [Определение Типа для Код, Наименование,Владелец и Родитель - не реализовно]
// ТипПоЗначению - Тип и Вид Реквизита (по факту значения)
// Периодический - Если = 1, то периодический, в противном случае = 0
Функция сп_ПрочитатьРеквизитыЭлементаСправочника_в_ТЗ(ТЗ99,ТекЭлСпр99,Дата99="") Экспорт
//_new_ 01.04.2003 сп_
Перем Res;
Res=0;
ТЗ99="";
ТЗ99 = СоздатьОбъект("ТаблицаЗначений");
ТЗ99.НоваяКолонка("ИдРеквизита");
ТЗ99.НоваяКолонка("ЗначРеквизита");
ТЗ99.НоваяКолонка("ТипИзМетаданных");
ТЗ99.НоваяКолонка("ТипПоЗначению");
ТЗ99.НоваяКолонка("Периодический");
Если ДАТА(СокрЛП(Дата99))=ДАТА(0) Тогда
    Дата99=ТекущаяДата();
КонецЕсли; 
Если сп_ЗначениеАгрегатногоТипаВыбрано(ТекЭлСпр99)>0 Тогда
    СписРекв = сп_ПолучитьСписокРеквизитовСправочника(СокрЛП(ТекЭлСпр99.Вид()));
    Спр = СоздатьОбъект("Справочник."+СокрЛП(ТекЭлСпр99.Вид()));
    Если Спр.НайтиЭлемент(ТекЭлСпр99)>0 Тогда
        ТекЭл = Спр.ТекущийЭлемент();
        КолвоРеквизитов=СписРекв.РазмерСписка();
        Если КолвоРеквизитов>0 Тогда
            НомРекв=0;
            Пока НомРекв<КолвоРеквизитов Цикл
                НомРекв=НомРекв+1;
                ИдРекв = "";
                ТипРекв99 = СписРекв.ПолучитьЗначение(НомРекв,ИдРекв);
                ИдРекв = СокрЛП(ИдРекв);
                ТипЗн="";
                V = сп_Реквизит_ВернутьЗначениеИзСправочника(ТекЭл,ИдРекв, ТипЗн, Дата99);
                ТЗ99.НоваяСтрока();
                НомСтр = ТЗ99.КоличествоСтрок();
                ТЗ99.УстановитьЗначение(НомСтр,"ИдРеквизита",ИдРекв);
                ТЗ99.УстановитьЗначение(НомСтр,"ЗначРеквизита",V);
                ТипРекв="";
                ВидРекв="";
                ЭтоПериодический=0;
                Тип99 = сп_ПолучитьТипРеквизитаИзМетаданных(""+ТекЭл.Вид(),""+ИдРекв,ТипРекв,ВидРекв,ЭтоПериодический);
                ТипЗн=ТипРекв;
                Если СтрДлина(СокрЛП(ВидРекв))>0 Тогда
                    ТипЗн=ТипЗн+"."+ВидРекв;
                КонецЕсли; 
                ТЗ99.УстановитьЗначение(НомСтр,"ТипИзМетаданных",ТипЗн);
                ТипЗн = сп_Значение_ПолучитьТипВидСтр(V);
                ТЗ99.УстановитьЗначение(НомСтр,"ТипПоЗначению",ТипЗн);
                Если ЭтоПериодический>0 Тогда
                    ТЗ99.УстановитьЗначение(НомСтр,"Периодический",1);
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЕсли;
КонецЕсли;
Res=ТЗ99.КоличествоСтрок();
Возврат Res;
КонецФункции //сп_ПрочитатьРеквизитыЭлементаСправочника_в_ТЗ()

 

© 08.08.2009 Сергей Попов

 


Hosted by uCoz
-->