Из Python в 1С через COM

Python; 1C; программист; programmer; код; модуль; простое решение; COM; ООП;

Не перестаю удивляться возможностям Python. И да, я смог немного подружить Python c 1C. По крайней мере тот минимум, который мне был нужен – работал хорошо. Сразу скажу, что зная Python, но не зная синтаксиса 1С – статья с большой вероятностью не сможет вам помочь. Но если вы представляете как устроена конфигурация 1С и знаете как писать запросы к БД на языке 1С – читайте дальше, возможно эта статья будет вам полезной.

Возможно, при современном развитии ПО использовать старую технологию COM, может, и не рационально, но смотря для каких задач. У меня же задача была простая. Мне нужно было вытаскивать определенные данные, хранящиеся в системе 1С, а дальше сравнивать их с внешним источником, или уведомлять пользователей, что они где-то напортачили. Некоторые скажут, что это можно сделать и в 1С. Конечно можно, но я не 1С программист, но зато я умею писать SQL запросы – в 1С синтаксис этих запросов не сильно отличается. Чтобы не ждать, когда у программиста появится время на мои маленькие «хотелки» — я решал поступающие бизнес-задачи на своем уровне. И делал это вполне успешно. А в меняющихся потребностях бизнеса делать фундаментальные запросы к программисту 1С, порой просто не рентабельно.

Разобраться с подключением к 1С из Python через Com мне помогла статья «Моя интеграция с 1С»

В итоге я написал вот такой маленький модуль, который использовал в дальнейших своих маленьких скриптах:  

# -*- coding: cp1251 -*-

import pythoncom
import win32com.client

class oneC(object):
    def __init__(self):
        self.DBconnect()
    
    def DBconnect(self):
        Connection_Str = "Srvr=Server:Port;Ref=UTWork;Usr=Login;Pwd=Password;"
        pythoncom.CoInitialize()
        self.V83 = win32com.client.Dispatch("V83.COMConnector").Connect(Connection_Str)
        print("DBconnect done")
    
    def query_run_unify(self, querytxt):
        query = self.V83.NewObject("Query", querytxt)
        self.query_result=query.Execute().Choose()
        
    def get_GUID(self,link_obj):
        return self.V83.String(link_obj.link.UUID())

Теперь пройдемся по основным блокам модуля. В объекте oneC я создал несколько методов и атрибутов, которые я использовал для всех своих программ. Этот модуль — единая точка входа для обмена данными через Python.

def DBconnect(self):

Метод класса для подключения к БД.

Connection_Str = "Srvr=Server:Port;Ref=UTWork;Usr=Login;Pwd=Password;"

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

pythoncom.CoInitialize()

Смысл этой строчки не очень мне понятен – оставил как в исходнике.

self.V83 = win32com.client.Dispatch("V83.COMConnector").Connect(Connection_Str)

Атрибут объекта oneC, в котором будет храниться соединение с 1С. Определение COM объекта осуществляется по имени «V83.COMConnector». Для каждой версии 1С свое имя: «V82.COMConnector», «V81.COMConnector». Возможно даже что-то такое: «(«V83.COMConnector.1″» — нужно смотреть в настройках клиентской версии 1С.

def query_run_unify(self, querytxt):

Метод класса для получения результатов SQL запроса. В переменную «querytxt» передается SQL запрос на языке 1C.

query = self.V83.NewObject("Query", querytxt)

Передаем запрос в 1С.

self.query_result=query.Execute().Choose()

Выполняем запрос и сохраняем результат в атрибут класса self.query – из этой переменной уже достается результат SQL запроса.

def get_GUID(self,link_obj):

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

Теперь о том как использовать этот маленький модуль. Тут все просто – предназначен он для получения данных из SQL запроса. Поэтому сначала пишем запрос, например такой:

 q = '''
 ВЫБРАТЬ
     Код КАК Code,
     НаименованиеПолное КАК Name,
 ИЗ
     Справочник.Номенклатура КАК item
 '''

Создаем экземпляр класса, инициализируем подключение к модулю и к 1С:

с=oneC()

После успешного подключение появится строчка:

DBconnect done

Передаем запрос в 1С

c.query_run_unify(q)

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

 CodeName
Line 1Code 1Name 1
Line 2Code 2Name 2
Line NCode NName N

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

q = '''
 ВЫБРАТЬ
     Код,
     НаименованиеПолное,
 ИЗ
     Справочник.Номенклатура
 '''

То в c.query_result данные будут в таком виде:

 КодНаименованиеПолное
Line 1Code 1Name 1
Line 2Code 2Name 2
Line NCode NName N

В обоих случаях сами данные в Python можно вытащить. К сожалению, мне известен только один способ вытащить сами данные — путем перебора всех строчек объекта, хранящегося в атрибуте c.query_result в цикле while, а именно вот так:

while c.query_result.next():
     print(c.query_result.Code) 

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

while c.query_result.next():
     print(c.query_result.Код, c.query_result.НаименованиеПолное) 

Далее, думаю, понятно как с этим работать. Думаю, при желании можно даже ежемесячно вытаскивать данные по продажам и крутить их в Pandas. Эх, жалко в ближайшее время у меня не будет под рукой 1С -–хотел сравнить что работает лучше: Python+1C+Pandas или 1С+PowerBI?

В целом мой модуль меня устраивал. Из минусов – долгое установление соединения с 1С по COM, особенно если ты сам подключаешься к корпоративной сети по VPN. Вот когда соединение установлено – данные достаются уже быстрее.

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

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

Вот самые распространённые проблемы и их решения:

  1. Ошибка: (-2147221005, ‘Недопустимая строка с указанием класса’, None, None)

Природа ошибки: попытка использовать несоответствующее имя объекта подключения к 1С (то самое имя «V83.COMConnector») – тут или имя не от корректно версии взято, или не зарегистрирована библиотека comcntr.dll, или зарегистрирована, но не та, что нужно – особенно, когда на компьютере установлено много разных версий клиента 1С

Решение: определяем какой версии клиент используется при подключении к интересующей нас БД 1С. Регистрируем библиотеку следующим образом:

Нажмите на Win+R, в появившемся окне «Выполнить» введите следующую строку (возможно потребуются права администратора):

C:\Windows\SysWOW64\regsvr32 «c:\Program Files(x86)\1cv8\8.3.12.1469\bin\comcntr.dll»

Где вместо 8.3.12.1469 нужно указать нужную вам версию 1С клиента

  • Ошибка: pywintypes.com_error: (-2147352567, ‘Ошибка.’, (0, ‘V83.COMConnector.1’, ‘Неверные или отсутствующие параметры соединения с информационной базой’, None, 0, -2147467259), None)

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

Решение: в моём случае проблема была в логине – я сделал себе в 1С обычный логин в дополнение к доменной учетной записи и использовал её – главное, чтобы в логине не было пробелов. Вот как раз из-за пробела у меня и вылетала эта ошибка.

Пользуйтесь на здоровье 🙂


Комментарии:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *