Версия для печати темы (https://pro1c.org.ua/index.php?s=2d1a4a56a601b319d9061b303745bc26&showtopic=67835)

Нажмите сюда для просмотра этой темы в обычном формате

Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7 _ Программирование в 1С Предприятие 8.3 _ COM Соединение с другой базой

Автор: Profi_1C77 27.05.25, 9:48

Есть база BAS UT , и есть база BAS бух CORP
В базе УТ нужно построить отчет по остаткам товаров ( бех проблем ) + создать соединение к бух базе ( она кстати SQL ) - получить тоже остатки по 281 , выгрузить их в ТЗ и потом соединить в отчете остатков UT;
Номенклатура / Склады - синхронизированы ( Код - Артикул - ШтрихКод)

1. Не не писал такое ни разу , накидайте пож пример соединения и как через объект COM пишется запрос на 281.
2. В отчете как инициализировать ТЗ с бух базы и передать его как ИсточникДанных ?

Автор: UmbertoVasyl`ovich 27.05.25, 10:30

Profi_1C77 @ Сегодня, 9:48 * ,
щось типу цього

Функция ПодключениеВыполнено(ткошибка) Экспорт
    ПодклУстановлено = Истина;
    СомСоединение = Новый COMОбъект("V83.ComConnector");    
        
    СтрокаСоединения = ПутьКБазе+"Usr = """+СокрЛП(Логин)+"""; Pwd = """+СокрЛП(Пароль)+"""";
    Если НЕ Серверная Тогда                
        СтрокаСоединения = "File = """+СокрЛП(ПутьКБазе)+"""; Usr = """+СокрЛП(Логин)+"""; Pwd = """+СокрЛП(Пароль)+"""";
    КонецЕсли;  
                
    Попытка
        Подключение = СомСоединение.Connect(СтрокаСоединения);
    Исключение
        ткошибка = ОписаниеОшибки();
        Если ПустаяСтрока(ткошибка) Тогда
            ткошибка = НСтр("ru='ошибка подключения';uk='помилка підключення'");
        КонецЕсли;    
        Подключение = Неопределено;
        СомСоединение = Неопределено;
        ПодклУстановлено = Ложь;
    КонецПопытки;
    
    Возврат ПодклУстановлено;
    
КонецФункции


Profi_1C77 @ Сегодня, 9:48 * ,
запрос так само як звичайний
Запрос = Подключение.NewObject("Запрос");

Автор: Slon747 27.05.25, 10:32

После успешного соединения со сторонней базой:

ЗапросВнешнейБазы = ВнешняяБаза.NewObject("Запрос");
ЗапросВнешнейБазы.Текст = ""; //тут текст запроса, как бы он выглядел в бухгалтерии
ЗапросВнешнейБазы.УстановитьПараметр(.....);
Выборка = ЗапросВнешнейБазы.Выполнить().Выбрать();


P.S. уже ответили

Автор: Profi_1C77 27.05.25, 10:36

Slon747 @ Сегодня, 11:32 * ,
После этого Запрос в ТЗ , и в модуле объекта отчета ПриКомпоновкеРезультата ?

Автор: Slon747 27.05.25, 10:40

Цитата(Profi_1C77 @ 27.05.25, 11:36) *
После этого Запрос в ТЗ , и в модуле объекта отчета ПриКомпоновкеРезультата ?

Тут не скажу. Не загружал данные в СКД.

Автор: TohaMonster 27.05.25, 11:13

Выборка - это будет COM-объект. Если Вы сделаете ТЗ = ЗапросВнешнейБазы.Выполнить().Выгрузить(), то ТЗ - ето тоже COM-объект, если я ничего не путаю. И, если это не примитивные типы, колонки будут тоже COM-объектом.
Поэтому, если Вам нужна, например, Номенклатура в Вашей Базе, нужно потом еще полученную ТЗ обработать и сопоставить её элементы элементам в Вашей Базе

Автор: andytg 27.05.25, 11:54

Profi_1C77 @ Сегодня, 11:36 * ,
вам, как я понимаю, надо сравнить данные управленческого учета (УТ) с бухгалтерским (КОРП), так?

ну вот и делайте как выше написали, сперва в бухии КОРП через com-объект получаете данные из УТ и кладете их в одну таблицу значений (назовем Тз1), затем закрываем подключение и удаляем com-объект за ненадобностью, затем то же самое в УТ и результат кладете в другую таблицу (Тз2), затем сравниваете эти таблицы, перед сравнением постройте в каждой из таблиц поисковый индекс (чтоб удобнее и быстрее было искать) такого примерно вида (колонку "Ключ" добавьте)

Ключ = [код].[артикул].[штрихкод]

таблицы перед добавлением индекса сворачиваем по кодам/артикулам/штрихкодам

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

и потом сравнение двух таблиц по этому индексу -- есть / нет

ну и результат -- в отчет


TohaMonster @ Сегодня, 12:13 * ,
колонки в ТЗ нужно делать примитивными типами (строка/число), т.е. код/артикул/наименование/количество/стоимость -- для сравнения остатков в двух базах будет достаточно

Автор: xlmel 28.05.25, 9:13

В Бухгалтерии КОРП можно создать webservice, опубликовать его на web-сервере, и опубликовать метод, который будет возвращать таблицу значений. Я везде, где мог, уходил от COM в пользу webservice.
Во-первых существенно быстрее устанавливается соединение.
Во-вторых запросы пишутся в родной базе, а если через COM, то приходится делать запрос в консоли запросов в одной базе, потом его переносить во вторую. Это дополнительная работа.
В-третьих, при возврате через COM приходится использовать пару функций ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр, или перегонять в JSON. С JSON проблема в том, что для обработки таблицы в запросе, она должна быть типизирована. То есть надо на стороне приемника создать таблицу, заполнить ее из JSON. Касательно 2 функций - вендор не рекомендует их использовать, о причине не знаю. А проверить получится ли работать с СериализаторXDTO через COM у меня как-то руки не дошли. В webservice, если добавите пакет XDTO https://pro1c.org.ua/redirect.php?http://v8.1c.ru/8.1/data/core, то станет доступен тип ValueTable и сможете на стороне приемника использовать СериализаторXDTO.ПрочитатьXDTO(), а на стороне источника СериализаторXDTO.ЗаписатьXDTO();
В расширение можно добавить webservice, режим совместимости 8.3.12 вроде как позволяет это сделать.

Автор: andytg 28.05.25, 13:12

Цитата(xlmel @ 28.05.25, 10:13) *
В расширение можно добавить webservice, режим совместимости 8.3.12 вроде как позволяет это сделать

оно-то так, но как показывает отечественная практика, практически везде для бухий и подач документов в налоговые (особенно в массовом режиме) уже больше 12 лет используется что-то из серии Медок/Фредо, а оно существует только под винду (ибо написано на net framework), поэтому на буховских машинах 100% будет именно винда, так что эквилибристика с линуксами, апачами, веб-сервисами и тому подобным imho в наших условиях излишня, разве что если специально не попросят smile.gif

а при взаимодействии через com надо только не забывать, что передать можно только простые типы, и в другой базе нужны будут дополнительные поиски и сопоставления (клиенты, номенклатура и т.д.), но и тут все решается поисками по ЕДРПОУ, артикулам, штрих-кодам и т.д. (которые и задаются именно простыми типами -- строка/чиало), так что в итоге не проблема



Цитата(xlmel @ 28.05.25, 10:13) *
Касательно 2 функций - вендор не рекомендует их использовать, о причине не знаю.

если это про ЗначениеВСтрокуВнутр(), то в мануалах написано, что оставлено только для совместимости с клюшками (как по мне, отличная функция, крайне удобная и нужная smile.gif)

Автор: xlmel 28.05.25, 14:45

andytg @ Сегодня, 13:12 * ,
так я не возражаю, каждый ищет то, что ему удобнее. У меня 4 базы на Винде, которые должны обмениваться данными и все реализовано через веб-сервисы. Можно было сделать через COM, но открытие COM обычно в 5-7 раз медленнее, чем веб-сервис. И сделаны аналогичные отчеты, которые собирают данные из разных баз и удалось добиться разумных времен ожидания

Автор: andytg 28.05.25, 15:10

Цитата(xlmel @ 28.05.25, 15:45) *
но открытие COM обычно в 5-7 раз медленнее

тут соглашусь для случая, когда com на разных серверах, удаленных друг от друга
в нашем случае тоже 4 базы (3 бух корп и 1 типа управленческая унф), обмен идет из унф в бух, на com в пределах локалки 100 мбит -- соединение за пару секунд
в роли "серверов" -- i7 3770k и i5 2320, винда, postgresql
а вот если базы находятся в разных местах и соединение через интернет -- тогда соглашусь, да, com сильно тупит, веб-сервис наверное будет быстрее (не пробовал, лень переписывать smile.gif)

Автор: xlmel 28.05.25, 15:31

andytg @ Сегодня, 15:10 * ,
пока простые запросы, еще терпимо, когда нужно использовать МенеджерВременныхТаблиц, то я лучше буду через сервисы делать

Автор: Profi_1C77 03.06.25, 11:30

UmbertoVasyl`ovich @ 27.05.25, 11:30 * ,
Хелп.

&НаСервере

Функция ПодключениеВыполнено(ткошибка) Экспорт
    ПодклУстановлено = Истина;
    СомСоединение = Новый COMОбъект("V83.ComConnector");    
     // параметры
     ПутьКБазе  = "C:\BAS бух\";
     Логин         = "Ольга";
     Пароль     = "261080";
     Серверная = Ложь;
     Подключение = Неопределено;
    СтрокаСоединения = ПутьКБазе+"Usr = """+СокрЛП(Логин)+"""; Pwd = """+СокрЛП(Пароль)+"""";
    Если НЕ Серверная Тогда                
        СтрокаСоединения = "File = """+СокрЛП(ПутьКБазе)+"""; Usr = """+СокрЛП(Логин)+"""; Pwd = """+СокрЛП(Пароль)+"""";
    КонецЕсли;  
                
    Попытка
        Подключение = СомСоединение.Connect(СтрокаСоединения);
    Исключение
        ткошибка = ОписаниеОшибки();
        Если ПустаяСтрока(ткошибка) Тогда
            ткошибка = НСтр("ru='ошибка подключения';uk='помилка підключення'");
        КонецЕсли;    
        Подключение = Неопределено;
        СомСоединение = Неопределено;
        ПодклУстановлено = Ложь;
    КонецПопытки;
    
    Возврат ПодклУстановлено;
    
КонецФункции

такое вышло , не создает и все, все время в отладке на исключение уходит ;
Что может быть не так?

Автор: Vofka 03.06.25, 11:41

Цитата(Profi_1C77 @ 03.06.25, 12:30) *
ОписаниеОшибки()

Так а что здесь возвращается?

Автор: Profi_1C77 03.06.25, 12:11

Vofka @ Сегодня, 12:41 * ,
СтрокаСоединения = File = "C:\BAS бух\"; Usr = "Ольга"; Pwd = "261080"
СомСоединение = COMОбъект
Ошибка = {ВнешнийОтчет.ОстаткиТоваровUT_BAS.МодульОбъекта(17)}: Метод об’єкта не виявлено (Connect)

может права / не установлена длл?

Автор: andytg 03.06.25, 12:12

Цитата(Profi_1C77 @ 03.06.25, 12:30) *
Что может быть не так?


всё smile.gif

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

Автор: Profi_1C77 03.06.25, 12:18

andytg @ Сегодня, 13:12 * ,
Я код потом код перенесу ""правильно" " мне важно что что б Подключение было

Автор: andytg 03.06.25, 12:23

Цитата(Profi_1C77 @ 03.06.25, 13:11) *
Метод об’єкта не виявлено (Connect)

в этом случае надо зарегистрировать comcntrl.dll в системе (причем, если их несколько, то надо именно от нужной версии платформы)



Цитата(Profi_1C77 @ 03.06.25, 13:18) *
Я код потом код перенесу ""правильно" " мне важно что что б Подключение было

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

https://pro1c.org.ua/redirect.php?https://forum.infostart.ru/forum9/topic106278/

        V7 = _V7.Connect(СтрокаСоединения);

        _СтруктураCOM = Новый Структура;
        _СтруктураCOM.Вставить("COMОбъект", V7);
        _КонтейнерCOM = ПоместитьВоВременноеХранилище(_СтруктураCOM, Новый УникальныйИдентификатор);

Автор: Profi_1C77 03.06.25, 12:56

andytg @ Сегодня, 13:23 * ,
эта зараза не регается
Regsvr32 comcntr.dll

Profi_1C77 @ Сегодня, 13:41 * ,
regsvr32 /i "C:\Program Files\1cv8\8.3.23.2236\bin\comcntr.dll"
так прошло

Автор: andytg 03.06.25, 12:59

Цитата(Profi_1C77 @ 03.06.25, 13:56) *
так прошло

так полный путь надо указывать же!

upd: можете через com+ https://pro1c.org.ua/redirect.php?https://infostart.ru/1c/tools/610960/
у меня так зарегистрирована 8.5 (для тестов) и 8.3 с ней прекрасно работает, т.к. ком-коннекторы разных версий v83.ComConnector и v85.ComConnector

Автор: Profi_1C77 03.06.25, 15:02

И еще вопрос

Попытка 
        V8BAS = СомСоединение.Connect(СтрокаСоединения);
    Исключение
        ткошибка = ОписаниеОшибки();
        
        Подключение = Неопределено;
        СомСоединение = Неопределено;
        ПодклУстановлено = Ложь;
         Возврат Неопределено;
    КонецПопытки;    
    
    
    
    // получаем ТЗ из базы BAS
    ТекстЗапроса = "
        |ВЫБРАТЬ
        |    ХозрасчетныйОстатки.Субконто1 КАК Номенклатура,
        |    ХозрасчетныйОстатки.Субконто3 КАК Склад,
        |    ХозрасчетныйОстатки.КоличествоОстатокДт КАК КоличествоОстатокДт
        |ИЗ
        |    РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаИтогов, Счет = &Счет, , ) КАК ХозрасчетныйОстатки
        |";

        
    ЗапросВнешнейБазы = V8BAS.NewObject("Запрос");
    ЗапросВнешнейБазы.Текст = ТекстЗапроса;
    
    
    // Присвоение значений переменным параметров.
    ДатаИтогов = Дата(2025, 06, 03, 00, 00, 00);
    
    V8ПланСчетов = V8BAS.NewObject("ПланыСчетов");
    
    Счет = V8ПланСчетов.Хозрасчетный.ТоварыНаСкладе;

    // Установка параметров.
    ЗапросВнешнейБазы.УстановитьПараметр("ДатаИтогов", ДатаИтогов);
    ЗапросВнешнейБазы.УстановитьПараметр("Счет", Счет);


    //ТЗОстаткиБух = ЗапросВнешнейБазы.Выполнить().Выгрузить();


V8ПланСчетов = V8BAS.NewObject("ПланыСчетов");

Счет = V8ПланСчетов.Хозрасчетный.ТоварыНаСкладе;
не отрабатывает
пытался также
| РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаИтогов, Счет.Код = "281", , ) КАК ХозрасчетныйОстатки
|";
тоже не хочет , помогите

Автор: andytg 03.06.25, 15:24

Цитата(Profi_1C77 @ 03.06.25, 16:02) *
V8ПланСчетов = V8BAS.NewObject("ПланыСчетов");


не так

ЕМНИП, NewObject -- это для всевозможных таблиц значений, списков значений, запросов и т.д.

пробуйте так:

V8BAS = СомСоединение.Connect(СтрокаСоединения);
// ...
V8BAS.ПланыСчетов.Хозрасчетный.ТоварыНаСкладе  // или .НайтиПоКоду("281")

Автор: xlmel 03.06.25, 15:26

Profi_1C77 @ Сегодня, 15:02 * ,
NewObject("ПланыСчетов") - это для всего, что создается через конструктор Новый в языке 1с, например, Новый запрос, Новый Структура и так далее.
Счет = V8BAS.ПланыСчетов.Хозрасчетный.ТоварыНаСкладе;
Обращение таким должно быть

Автор: andytg 03.06.25, 15:28

Цитата(Profi_1C77 @ 03.06.25, 16:02) *
Счет = V8ПланСчетов.Хозрасчетный.ТоварыНаСкладе;

потому что вот тут у вас ком-объект в той базе, а не счет
надо
Счет = V8BAS.ПланыСчетов.Хозрасчетный.ТоварыНаСкладе;

это для вашего второго случая

Автор: Profi_1C77 03.06.25, 15:58

Всем спасибо парни!
В итоге получил ТЗ которую 2 этапом засуну в отчет СКД и свяжу остатки
Код вышел примерно такой, новичкам на будущее ( это жестяк) :

&НаСервере
Функция ПолучитьТаблицуДанных(НачальнаяДата,КонечнаяДата) Экспорт
    ТЗОстаткиБух = Неопределено;
    СомСоединение = Новый COMОбъект("V83.ComConnector");    
    // параметры
    ПутьКБазе  = "***";
    Логин         = "**";
    Пароль     = "**";
    Серверная = Ложь;
    ткошибка ="";
    Подключение = Неопределено;
    СтрокаСоединения = ПутьКБазе+"Usr = """+СокрЛП(Логин)+"""; Pwd = """+СокрЛП(Пароль)+"""";
    Если НЕ Серверная Тогда                
        СтрокаСоединения = "File = """+СокрЛП(ПутьКБазе)+"""; Usr = """+СокрЛП(Логин)+"""; Pwd = """+СокрЛП(Пароль)+"""";
    КонецЕсли;  
    
    Попытка
        V8BAS = СомСоединение.Connect(СтрокаСоединения);
    Исключение
        ткошибка = ОписаниеОшибки();
        
        Подключение = Неопределено;
        СомСоединение = Неопределено;
        ПодклУстановлено = Ложь;
        Возврат ТЗОстаткиБух;
    КонецПопытки;    
    
    
    // получаем ТЗ из базы BAS
    ТекстЗапроса = "
    |ВЫБРАТЬ
    |    ХозрасчетныйОстатки.Субконто1 КАК Номенклатура,
    |    ХозрасчетныйОстатки.Субконто3 КАК Склад,
    |    ХозрасчетныйОстатки.КоличествоОстатокДт КАК Остаток
    |ИЗ
    |    РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаИтогов, Счет.Код = &КодСчета, , ) КАК ХозрасчетныйОстатки
    |";
    
    
    ЗапросВнешнейБазы = V8BAS.NewObject("Запрос");
    ЗапросВнешнейБазы.Текст = ТекстЗапроса;
    
    //// Присвоение значений переменным параметров.
    //ДатаИтогов = Дата(2025, 06, 03, 00, 00, 00);
    ЗапросВнешнейБазы.УстановитьПараметр("ДатаИтогов", КонечнаяДата);
    ЗапросВнешнейБазы.УстановитьПараметр("КодСчета", "281");
    
    Выборка = ЗапросВнешнейБазы.Выполнить().Выбрать();
    
    ТЗОстаткиБух  = Новый ТаблицаЗначений;
    ТЗОстаткиБух.Колонки.Добавить("Наименование",ОбщегоНазначения.ОписаниеТипаСтрока(100));
    ТЗОстаткиБух.Колонки.Добавить("Код",ОбщегоНазначения.ОписаниеТипаСтрока(11));
    ТЗОстаткиБух.Колонки.Добавить("Склад",ОбщегоНазначения.ОписаниеТипаСтрока(50));        
    ТЗОстаткиБух.Колонки.Добавить("Остаток",ОбщегоНазначения.ОписаниеТипаЧисло(15,3));        
    
    Пока Выборка.Следующий() Цикл
        НС = ТЗОстаткиБух.Добавить();
        НС.Наименование =  Выборка.Номенклатура.НаименованиеПолное;
        НС.Код        =  Выборка.Номенклатура.Code;
        НС.Склад   =  Выборка.Склад.Description;
        НС.Остаток =  Выборка.Остаток;
        
    КонецЦикла;    
    
    Возврат ТЗОстаткиБух;
    
    
КонецФункции

Автор: andytg 03.06.25, 16:33

Цитата(Profi_1C77 @ 03.06.25, 16:58) *
    
// получаем ТЗ из базы BAS
    ТекстЗапроса = "
    |ВЫБРАТЬ
    |    ХозрасчетныйОстатки.Субконто1 КАК Номенклатура,
    |    ХозрасчетныйОстатки.Субконто3 КАК Склад,
    |    ХозрасчетныйОстатки.КоличествоОстатокДт КАК Остаток
    |ИЗ
    |    РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаИтогов, Счет.Код = &КодСчета, , ) КАК ХозрасчетныйОстатки
    |";


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

    // получаем ТЗ из базы BAS
    ТекстЗапроса = "
    |ВЫБРАТЬ
    |    ВЫРАЗИТЬ(ХозрасчетныйОстатки.Субконто1.НаименованиеПолное КАК СТРОКА(100)) КАК Номенклатура,
    |    ВЫРАЗИТЬ(ХозрасчетныйОстатки.Субконто3.Наименование КАК СТРОКА(50)) КАК Склад,
    |    ХозрасчетныйОстатки.КоличествоОстатокДт КАК Остаток
    |ИЗ
    |    РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаИтогов, Счет.Код = &КодСчета, , ) КАК ХозрасчетныйОстатки
    |";
// ну и так далее, т.е. определяем все нужные поля сразу в запросе как вам надо


далее делаем так (без циклов):

ТЗОстаткиБух = ЗначениеИзСтрокиВнутр( V8BAS.ЗначениеВСтрокуВнутр(ЗапросВнешнейБазы.Выполнить().Выгрузить()));


не пробовал, но должно работать wink.gif

Автор: Profi_1C77 03.06.25, 16:50

andytg @ Сегодня, 17:33 * ,
Работает, да это оптимальное icon_beer17.gif

Автор: andytg 03.06.25, 16:55

Profi_1C77 @ Сегодня, 17:50 * ,
ну и дальше ставьте проверку обазательно

Если ТипЗнч(ТЗОстаткиБух ) = Тип("ТаблицаЗначений") Тогда
        // потому что если в ком-базе запрос почему-то там не выполнился, то вернется пустая строка

....

Автор: xlmel 04.06.25, 6:56

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

Автор: Profi_1C77 04.06.25, 21:48

Итог , склеил строковые Номенклатура ( код) - Склад - Наименование в СКД , вообщем пока задержка до 2 мин норм

Автор: andytg 05.06.25, 8:50

Profi_1C77 @ Вчера, 22:48 * ,
можете ключ для "склейки" бух. данных с управленческими строить еще в запросе в com-базе и сразу выгружать готовую колонку -- будет еще быстрее, плюс аналогичный ключ в запросе по управленческим данным уже в СКД и в этом же запросе левое соединение с бух.данными -- будет все строиться за один проход в одном запросе, не?

andytg @ Сегодня, 9:41 * ,
и групппировки по номенклатуре с суммами в com-запрос добавьте

Автор: Profi_1C77 05.06.25, 8:57

andytg @ Сегодня, 9:50 * ,
Там в скд может быть вариант с запросам к бух остаткам и без, потому так пока удобнее;

Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua