Молочников Олег Spb. 2016.
Интеграция 1С и C#. Обращение к 1С через COM. Создание номенклатуры и выполнение запроса к 1С из C# на примере интеграции с Союз-PLM (система информационной поддержки жизненного цикла изделий). Обработка «Загрузка заказа на сборку». (ERP) (загрузка через EXCEL)
Что такое Союз-PLM. Согласно брошюрке это:
Союз-PLM представляет собой полнофункциональный программный комплекс для решения широкого спектра задач управления инженерной технической информацией наукоемких изделий и сложных инженерных объектов в области машиностроения, приборостроения, архитектуры, строительства.
На практике, это управление конструкторской документацией, интегрированное с САПР, бизнес-процессы, файловый архив. Все это работает в SQL и шевелится с помощью скриптов на C#. Скрипты свободно отлаживаются в MS Visual Studio. Подробнее смотрите на их сайте: http://www.programsoyuz.ru/products/system-soyuz-plm.html Редактирование, конструирование и использование бизнес-процессов на порядок лучше систем на базе 1С из тех, что я изучил.
Пример кода выполняющего на стороне C# запрос в 1С:
public override void Invoke( EntityAttribute attr, IEnumerable<CollectionElement> selectedElements ) { string connectionString = "srvr='192.168.0.999'; ref='с_copy'; usr='External'; pwd='123456';"; Type oType = Type.GetTypeFromProgID("V83.COMConnector"); if (oType != null) { //Создаем COMConnector, соединяемся с базой object V8 = Activator.CreateInstance(oType); object connection; try { connection = oType.InvokeMember("Connect", BindingFlags.Public | BindingFlags.InvokeMethod, null, V8, new object[] { connectionString }); } catch (Exception e) { Marshal.ReleaseComObject(V8); Service.UI.ShowMessage(string.Format("Ошибка подключения к 1С \'{0}\'", (e.InnerException.ToString()), e.Message)); return; } //Создаем и выполняем запрос (получение списка документов в заданном интервале) object query = oType.InvokeMember("NewObject", BindingFlags.Public | BindingFlags.InvokeMethod, null, connection, new object[] { "Query" }); oType.InvokeMember("Текст", BindingFlags.Public | BindingFlags.SetProperty, null, query, new object[] { "ВЫБРАТЬ РеализацияТоваровУслуг.Дата, РеализацияТоваровУслуг.Номер, РеализацияТоваровУслуг.СуммаДокумента ИЗ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг ГДЕ РеализацияТоваровУслуг.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата1, ДЕНЬ) И КОНЕЦПЕРИОДА(&Дата2, ДЕНЬ)" }); oType.InvokeMember("УстановитьПараметр", BindingFlags.Public | BindingFlags.InvokeMethod, null, query, new object[] { "Дата1", new DateTime(2016, 3, 1, 0, 0, 0) }); oType.InvokeMember("УстановитьПараметр", BindingFlags.Public | BindingFlags.InvokeMethod, null, query, new object[] { "Дата2", new DateTime(2016, 10, 1, 0, 0, 0) }); object queryResult = oType.InvokeMember("Выполнить", BindingFlags.Public | BindingFlags.InvokeMethod, null, query, new object[] { }); object queryResultSelection = oType.InvokeMember("Выбрать", BindingFlags.Public | BindingFlags.InvokeMethod, null, queryResult, new object[] { }); StringBuilder sb = new StringBuilder(); sb.Length = 0; while ((bool)oType.InvokeMember("Следующий", BindingFlags.Public | BindingFlags.InvokeMethod, null, queryResultSelection, new object[] { })) { object field_date = oType.InvokeMember("Дата", BindingFlags.Public | BindingFlags.GetProperty, null, queryResultSelection, new object[] { }); object field_num = oType.InvokeMember("Номер", BindingFlags.Public | BindingFlags.GetProperty, null, queryResultSelection, new object[] { }); object field_sum = oType.InvokeMember("СуммаДокумента", BindingFlags.Public | BindingFlags.GetProperty, null, queryResultSelection, new object[] { }); sb.Append("Дата:"); sb.Append(field_date); sb.Append(",\t№ "); sb.Append(field_num); sb.Append("\t - "); sb.Append(field_sum); sb.Append("\n"); } Service.UI.ShowMessage(sb.ToString()); //Освобождаем память Marshal.ReleaseComObject(queryResultSelection); Marshal.ReleaseComObject(queryResult); Marshal.ReleaseComObject(query); Marshal.ReleaseComObject(connection); Marshal.ReleaseComObject(V8); } } }
Пример кода создающего на стороне C# номенклатуру в 1С:
public override void Invoke(EntityAttribute attr, IEnumerable<CollectionElement> selectedElements) { string connectionString = "srvr='192.168.0.999'; ref='с_copy'; usr='External'; pwd='External';"; Type oType = Type.GetTypeFromProgID("V83.COMConnector"); if (oType != null) { //Создаем COMConnector, соединяемся с базой object V8 = Activator.CreateInstance(oType); object connection; try { connection = oType.InvokeMember("Connect", BindingFlags.Public | BindingFlags.InvokeMethod, null, V8, new object[] { connectionString }); } catch (Exception e) { Marshal.ReleaseComObject(V8); Service.UI.ShowMessage(string.Format("Ошибка подключения к 1С \'{0}\'", (e.InnerException.ToString()), e.Message)); return; } string NameOfItem1C = "Тест создания номенклатуры из C#3"; object Items1C = oType.InvokeMember("NewObject", BindingFlags.Public | BindingFlags.InvokeMethod, null, connection, new object[] { "СправочникМенеджер.Номенклатура" }); object FindItem1C = oType.InvokeMember("НайтиПоНаименованию", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, Items1C, new object[] { NameOfItem1C }); bool IfItem1CExist = Convert.ToBoolean(oType.InvokeMember("ЗначениеЗаполнено", BindingFlags.Public | BindingFlags.InvokeMethod, null, connection, new object[] { FindItem1C })); if (IfItem1CExist==false) { object NewItem1C = oType.InvokeMember("СоздатьЭлемент", BindingFlags.Public | BindingFlags.InvokeMethod, null, Items1C, new object[] { }); object SpeciesOfItems1C = oType.InvokeMember("NewObject", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, connection, new object[] { "СправочникМенеджер.ВидыНоменклатуры" }); object Material_SpeciesOfItems1C = oType.InvokeMember("НайтиПоНаименованию", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, SpeciesOfItems1C, new object[] { "Материал" }); NewItem1C.GetType().InvokeMember("ВидНоменклатуры", BindingFlags.PutDispProperty | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, NewItem1C, new object[] { Material_SpeciesOfItems1C }); oType.InvokeMember("ЗаполнитьРеквизитыПоВидуНоменклатуры", BindingFlags.Public | BindingFlags.InvokeMethod, null, Items1C, new object[] { NewItem1C }); NewItem1C.GetType().InvokeMember("Наименование", BindingFlags.PutDispProperty | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, NewItem1C, new object[] { NameOfItem1C }); NewItem1C.GetType().InvokeMember("НаименованиеПолное", BindingFlags.PutDispProperty | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, NewItem1C, new object[] { NameOfItem1C }); try { NewItem1C.GetType().InvokeMember("Записать", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, NewItem1C, new object[] { }); } catch (Exception e) { Marshal.ReleaseComObject(Items1C); Marshal.ReleaseComObject(connection); Marshal.ReleaseComObject(V8); Service.UI.ShowMessage(string.Format("Ошибка записи номенклатуры \'{0}\'", (e.InnerException.ToString()), e.Message)); return; } } //Освобождаем память Marshal.ReleaseComObject(Items1C); Marshal.ReleaseComObject(connection); Marshal.ReleaseComObject(V8); } } }
Для работы этого кода вам придется в свойствах конфигурации в окне "Заголовок для скриптов" дописать:
using System.Reflection;
using System.Runtime.InteropServices;
В случае, если у вас возникает ошибка несоответсвия версий , рекомедую поискать comcntr.dll в regedit и поправить пути.
В случае, если у вас возникает ошибка 800700c1 не является приложением Win32то весьма рекомендую статью //infostart.ru/public/197627/ ("Ошибка V82.COMConnector на сервере 64. Решение проблемы")
По дополнительному запросу Союз-PLM высылает шаблон документа “Сводная спецификация”. Мы слегка модифицируем этот документ, добавив в шаблон в табличную часть поле “Покупной / IsPurchased” (Bool). Этот атрибут нам нужен, для того что бы мы знали какие детали мы купим в виде готового узла, а какие подузлы будем собирать сами из комплектующих, которые, в свою очередь, тоже надо обеспечить (купить или сделать) для сборки.
В скрипте формирования табличной части в процедуре public void ParseItem( ) меняем одну строку для заполнения нового атрибута.
// Однотипно заполняемые атрибуты
Line[ "IsPurchased" ] = IsPurchased; // Эту строку мы добавили
Line[ "Order" ] = attr.CollectionElements.Count;
Больше ничего менять не надо, нам вполне подойдет штатная выгрузка в Excel, прямо в документе, для передачи данных в 1С.
Подключаем обработку в ERP (НСИ и администрирование -> Печатные формы -> Дополнительные отчеты и обработки.) В документе “Заказ на сборку” в меню заполнение появится кнопка “Загрузить заказ на сборку из файла”.
Выбираем файл данных, которые будем загружать. Указываем схему обеспечения и папку по умолчанию для вновь созданной номенклатуры. Нажимаем кнопку прочитать файл.
К статье прилагается пример excel файла для загрузки, на случай если вы будете формировать его в другой системе. После нажатия кнопки строится дерево узлов комплектующих.
Если для узла есть соответствие в ERP, то по сочетанию Обозначение+” ”+Наименование подбирается номенклатура из ERP. Производится визуальный контроль заполнения колонки “Номенклатура ERP”. Если есть номенклатура, которая названа по другому чем в PLM, но которую надо привести к стандарту, она выбирается в этой колонке вручную.
После нажатия кнопки “Создать/обновить номенклатуру в ERP” будет создана недостающая номенклатура, а указанная приведена к стандарту. В созданной номенклатуре артикул будет заполнен Обозначением.
Нажатие кнопки “Добавить в документ” выгружает данные в документ. Количество комплектующих умножается на количество изделий, которые надо собрать в заказе на сборку. Если для узла стоит флаг “Покупной”, то он выгружается без подузлов.
К статье прилагается скрипт на C# для выгрузки всех актуальных чертежей в форматах “tiff” и “pdf” для шаблона “исполнение изделия в версии (ЭСИ ГОСТ 2.053)”. К теме имеет отношение слабое, но вдруг кому пригодиться.
Обработка гарантированно работает на платформе 8.3 (тестировано на релизе 8.3.8.1652) с конфигурациями 1С:ERP Управление предприятием 2 (тестировано на релизе 2.1.3.136) только на управляемых формах.
Акция! Вы можете скачать эту разработку в составе архива всех моих разработок, которые я предлагаю за StartMone, по Специальной цене: //infostart.ru/public/960899/#archive
P.S.: Надеюсь, вам понравится эта и другие мои статьи и разработки на //infostart.ru/profile/48714/.
Очень жду ваших комментариев и пожеланий.
Молочников Олег Spb. 2016.