Пролог
Потребовалось сделать выгрузку из 1С в куда-то еще. 1С версии 8.2, но подобным же образом можно получить данные из 7.7, 8.0, 8.1 и думается 8.3 — только названия документов другие.
Данные будем получать через COM — на сколько я знаю, у 1Сников это довольно распростаненный способ, и документации довольно много.
Для работы с COM на питоне потребуется модуль win32com — установка ничем необычным не отличается.
Для напримера, из стандартной конфигурации 1C Бухгалтерия 2.0 забирать список выставленных счетов и отправлять на некий сайт.
Глава 1. Подключение к 1С.
Для подключение потребуется создать объект V82.COMConnector, и подключить соответствующую базу. Путь до базы, логин и пароль для доступа прописываются в соответсвующей строке подключения:
import win32com.client CONSTR='File="C:\\DB\\";Usr="com";Pwd="com"' v82 = win32com.client.Dispatch("V82.COMConnector").Connect(CON_STR) |
Тут сразу возможна проблема, 32х-битная 1С не прописывается в 64-разрядной системе. Исправить не сложно: Администрирование->Службы компонентов. Компьютеры->Мой Компьютер->Приложения COM+. Создать новое приложение — серверное приложение — название V82_COMConnector. После, на вкладке «компонетны» созданного приложения добавить новый компонент: (установка новых компонентов) и указать на файлик comcntr.dll в комплекте 1С.
Если никаких эксцепшенов не выкинуло — продолжаем. 1С создана очень умными людьми, для других не очень умных людей, поэтому все в 1С через жопу. Например все объекты конфигурации называются кириллицей, что из-за наличия множества кодировок, вообще-то не очень удобно. Но это не самое печальное. Печальней то, что при работе с COM/1C используются сразу две кодировки. 1С хочет видеть запросы в CP-1251, а результаты возвращать в UTF8. Так что простым coding: cp1251 не обойтись, и потребуются пляски.
Для доступа к COM объектами с русскими названиями использоваться точку (.) не получится, будем использовать функцию getattr(). И немного модифицируем её, второй параметр она будет транслировать в cp1251
get = lambda obj,attr: getattr(obj, attr.encode('cp1251')) |
Глава 2. Доступ к данным
Подготовительная работа закончилась, начинаем получать результаты.
Всю структуру данных можно невозбранно подсмотреть в конфигураторе 1С. И это единственный приятный момент, хотя нет: все встроенные типы, объекты, методы имеют так же названия на английском языке, и это тоже экономит нервы и время. Имена эти можно также подсмотреть в конфигураторе, в соответсвующем разделе справочной системы.
Например объект конфигурации «Документы», имеет английское название Documents и соответственно будет доступен через точку:
v82.Documents. А вот сами документы называются по-русски, и начинается небольшое извращение:
invoices = get(v82.Documents, u"СчетНаОплатуПокупателю") |
Это «Менеджер документов» по внутренней терминологии 1С, для того, чтобы получить сами документы необходимо их выбрать, например методом Select(), которому можно передать несколько необязательных параметров в виде периода выборки.
После чего, можно пролистать выборку методом Next() этого менеджера, а сам документ получить с помощью метода GetObject()
Упрощено, получается так:
sel = get(v82.Documents, u"СчетНаОплатуПокупателю").Select(d_start, d_end) while sel.Next(): doc = sel.GetObject() ... |
Данные из текущего документа вытаскиваем так же, с помощью getattr() или нашей get():
amount = get(doc, u"СуммаДокумента") |
А некоторые обязательные поля, например дату и номер документа имеют англоязычные аналоги, и можно по-нормальному:
number = doc.Number date = doc.Date |
Эпилог
На этом все шаманства заканчиваются — дальше пишем скрипт используя вышеизложенные знания:
import win32com.client from datetime import date, datetime, timedelta from json import dumps from httplib import HTTPConnection from urllib import urlencode SERVER = "192.168.0.1" URL = "/post/" KEY="SecretKey" days_upload=10 con_str = 'File="C:\\DB";Usr="com";Pwd="com"' v82 = win32com.client.Dispatch("V82.COMConnector").Connect(con_str) get = lambda obj,attr: getattr(obj, attr.encode('cp1251')) d_start = date.today()-timedelta(days=days_upload) d_end = date.today() invoices = [] contractors = {} sel = get(v82.Documents, u"СчетНаОплатуПокупателю").Select(d_start, d_end) while sel.Next(): doc = sel.GetObject() contr = get(doc,u"Контрагент") if not get(contr, u'Код') in contractors: c = { 'code': get(contr, u'Код'), 'name': get(contr, u"Наименование"), } contractors[c['code']] = c dt = { "number": doc.Number, "date": "%s" % doc.Date, "amount": get(doc, u"СуммаДокумента"), "contr": get(contr, u"Код"), "text": get(doc, u'Комментарий') } invoices.append(dt) params ={"invoices": dumps(invoices), "contractors": dumps(contractors), "key":KEY} con = HTTPConnection(SERVER) con.request("POST", URL, urlencode(params)) r = con.getresponse() print r.status, r.reason f = open("response.html","w+") f.write(r.read()) f.close() con.close() |