Не перестаю удивляться возможностям 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 будет результат запроса, который будет храниться как объект приблизительно вот в таком виде:
Code | Name | |
Line 1 | Code 1 | Name 1 |
Line 2 | Code 2 | Name 2 |
… | … | … |
Line N | Code N | Name N |
Если в текстовом запросе (переменная q) не создавать латинского алиаса, то данные в результатах запроса будут храниться в оригинальных названиях столбцов, т.е. если
q = '''
ВЫБРАТЬ
Код,
НаименованиеПолное,
ИЗ
Справочник.Номенклатура
'''
То в c.query_result данные будут в таком виде:
Код | НаименованиеПолное | |
Line 1 | Code 1 | Name 1 |
Line 2 | Code 2 | Name 2 |
… | … | … |
Line N | Code N | Name 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С – у меня просто таких потребностей не было.
Несмотря на простоту кода, скопировав его к себе в программу, при попытке запуска у вас могут возникнуть проблемы.
Вот самые распространённые проблемы и их решения:
- Ошибка: (-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С обычный логин в дополнение к доменной учетной записи и использовал её – главное, чтобы в логине не было пробелов. Вот как раз из-за пробела у меня и вылетала эта ошибка.
Пользуйтесь на здоровье 🙂
test