Передача данных из SAP в .NET с помощью ERPConnect
ОГЛАВЛЕНИЕ
Описание инструмента программирования интерфейса для объединения SAP и .NET
• Скачать пример 1 (C#) - 7.35 Кб
• Скачать пример 1 (VB.NET) - 12.57 Кб
• Скачать пример 2 (C#) - 15.14 Кб
• Скачать пример 2 (VB.NET) - 16.38 Кб
Введение
В проекте для последнего заказчика пришлось реализовать своего рода "программу быстрого заказа" для компании-производителя машин. Целью этого проекта было дать возможность инженерам-строителям отправлять автоматически сгенерированный список заказов отделу закупок. Отдел строительства использует систему управления данными об изделии на базе SQL Server 2000 с клиентом Access, тогда как отдел закупок и другие экономические отделы используют систему SAP. Главной задачей проекта была реализация интерфейса для этих двух систем, особенно для приема необходимых данных из системы SAP в приложении .NET. После короткого поиска в Интернете был найден ERPConnect от Theobald Software. Данный инструмент позволил напрямую подключаться к нужным данным из BAPI(интерфейс программирования бизнес-приложений) и таблиц в системе SAP.
Было найдено всего несколько статей о Соединителе .NET от SAP, но ни одной статьи касательно ERPConnect, поэтому мы подумали, что другим пользователям будет интересно почитать об использовании, функциях и личном опыте с другим инструментом для программирования интерфейса SAP. По понятным причинам не публикуем код проекта заказчика, поэтому написали два примера, объясняющие использование ERPConnect. Первый пример рассматривает подключение к BAPI, а второй пример касается чтения прямо из таблиц SAP.
Два примера на VB.NET и C# были включены в раздел загрузок выше. Из проектов были убраны данные входа в систему и подключения к SAP; чтобы опробовать примеры, заполните их своими собственными данными подключения и входа в систему.
Краткая информация о SAP
Для тех, кто не имел дела с SAP, объясним самые важные понятия SAP для программирования интерфейса.
Функциональные модули: Функциональный модуль равноценен нормальной функции/процедуре в любом обычном языке программирования. Функциональные модули являются встроенными модулями SAP, написанными на ABAP(программирование передовых бизнес-приложений), и доступны из любой другой программы ABAP в системе. Как функция в любом ином языке программирования, функциональные модули принимают параметры импорта и экспорта. Функциональные модули также позволяют использовать двунаправленные таблицы. Подключиться извне SAP можно только к функциональному модулю с поддержкой RFC (как в нашем случае). Способ подключения к функциональному модулю без поддержки RFC описан далее в статье.
BAPI: BAPI работает как функциональный модуль, единственное отличие состоит в том, что он является интерфейсом программирования (API) для репозитария бизнес-объектов SAP.
IDocs: IDocs используются для обмена данными между двумя системами SAP или системой SAP и подсистемой. Можно представить IDocs как электронный чек, написанный на бумаге. IDoc однозначно определяется по его имени (и по имени его расширения). IDocs хорошо структурированы, они имеют заголовок, содержащий административную информацию, такую как: отправитель, информация о принимающей системе и средство передачи данных. Кроме заголовка, IDoc имеет иерархические сегменты, подобные древовидной структуре. Каждый сегмент имеет одно или больше полей, содержащих экономические данные.
Запросы SAP: Запросы SAP работают так же, как и любой иной запрос. Для однозначной идентификации запроса SAP нужны три части информации: область пользователя (глобальная или локальная); группа пользователей и имя запроса.
Как использовать ERPConnect
После установки ERPConnect на компьютер надо лишь добавить ссылку (ERPConnect.dll используется с .NET Framework 1.1, а ERPConnect20.dll используется .NET Framework 2.0) в проект и добавить оператор using ERPConnect; в заголовок – вот и все.
Пример 1: Чтение данных из BAPI с помощью объекта RFCFunction
В этом коротком примере показано, как получить значение BANK_KEY клиента 0000001172 и отобразить результат на консоли.
После создания объекта R3Connection и открытия соединения создаем объект RFCFunction для соединения, вызывая BAPI. Затем заполняем параметр Exports объекта-функции RFC параметром Import BAPI. То есть отправляем значение Импорт в BAPI. Сделав это, исполняем функцию и извлекаем искомые данные из таблицы с результатами. Вот и все.
class Program
{
static void Main(string[] args)
{
Connect();
}
static void Connect()
{
//получаем лицензию
ERPConnect.LIC.SetLic("licence code");
//создание объекта соединения
R3Connection con = new R3Connection("name of the application server",
"system number",
"user",
"password",
"language",
"client");
//открытие соединения
con.Open();
//создание объекта RFCFunction
RFCFunction func = con.CreateFunction("BAPI_CUSTOMER_GETDETAIL2");
//отправка параметра импорта в BAPI
func.Exports["CUSTOMERNO"].ParamValue = "0000001172";
try
{
//исполняем функцию
func.Execute();
}
catch (ERPException e)
{
Console.WriteLine(e.Message);
}
/*Чтение BANK_KEY из func и сохранение его в строку.
В таблице с результатами есть лишь один ряд, так как
номеру заказчика соответствует только один заказчик,
поэтому выбираем нужный столбец из таблицы с результатами*/
string Bank_Key =
Convert.ToString(func.Tables["CUSTOMERBANKDETAIL"].Rows[0, "BANK_KEY"]);
//в конце не забудьте закрыть соединение
con.Close();
//отображаем данные
Console.WriteLine("Customer: 0000001172");
Console.WriteLine("Bank Key: {0}", Bank_Key);
Console.ReadLine();
}
}
Результат должен выглядеть так:
Можно сохранить результат в DataTable, добавив строку...
DataTable dt = func.Tables["CUSTOMERBANKDETAIL"].ToADOTable();
... после блока Try Catch, затем получаем все данные из CUSTOMERBANKDETAIL согласно номеру заказчика 0000001172.
В данном примере было показано базовое использование ERPConnect для связи с функциональными модулями, но есть ряд более интересных функций (описанных далее в статье) обработки взаимодействия RFC и IDoc и даже чтения прямо из таблиц SAP.
Пример 2: Чтение прямо из таблицы SAP с помощью класса ReadTable
На мой взгляд, ReadTable класс является одним из самых полезных специальных классов, потому что он дает возможность непосредственно читать из таблицы SAP. Для проекта моего заказчика это было очень важно для извлечения данных из таблиц SAP в. NET DataSet, так что этот класс был очень полезен для меня.
Данный пример показывает, как использовать класс ReadTable с помощью оператора "где - как", чтобы получить адрес всех заказчиков в таблице KNA1, соответствующих введенному условию имени, и отобразить результат в DataGridView.
Логика примера инкапсулирована в класс по имени SAPConnect. Как в примере выше, оператор using ERPConnect; и using ERPConnect.Utils; для использования класса ReadTable должны быть добавлены в заголовок.
Нужны следующие закрытые свойства:
private string _userName;
private string _password;
private string _client;
private R3Connection _con;
Параметры для конструктора - username, password и client, хранящиеся в локальных свойствах.
public SAPConn(string userName, string password, string client)
{
_userName = userName;
_password = password;
_client = client;
}
Так как адрес сервера приложений, номер системы и язык чаще всего имеют одно и то же значение, можно ввести эти параметры прямо в код или сохранить их в конфигурационном файле. В проекте заказчика было много методов, использующих одинаковую строку подключения, поэтому процедура открытия соединения хранилась в отдельной закрытой функции по имени openConnection:
private void openConnection()
{
ERPConnect.LIC.SetLic("licence code");
R3Connection con = new R3Connection("name of the application server",
"system number",
_userName,
_password,
"language",
_client);
try
{
connection.Open();
}
catch (ERPException e)
{
MessageBox.Show(e.Message);
}
_con = connection;
}
Нужен метод закрытия соединения:
private void closeConnection()
{
_con.Close();
}
Теперь можно реализовать метод для чтения прямо из таблицы SAP и возвращать результат в DataSet. Сначала разберем, как работает эта функция:
Для начала надо создать объект ReadTable и заполнить свойство TableName именем таблицы SAP, из которой надо читать. Затем добавляем нужные поля с помощью метода AddField. Сделав это, заполняем WhereClause строкой Like. В этом примере было задано дополнительное свойство RowCount на 100, чтобы получить только 100 рядов в результате. После выполнения запроса имеем результат Result в виде DataTable.
public DataTable WhereLikeSearch(string sapTable, string nameCriteria)
{
openConnection();
//создание объекта ReadTable
ReadTable table = new ReadTable(_con);
//Задание имени таблицы, из которой надо читать
table.TableName = sapTable;
//добавление полей, отображаемых в DataTable
table.AddField("NAME1");
table.AddField("STRAS");
table.AddField("ORT01");
table.AddField("PSTLZ");
table.AddField("TELF1");
table.AddField("TELFX");
//это есть…
table.WhereClause = string.Format("NAME1 LIKE '%{0}%'", nameCriteria);
//это дополнительное свойство
table.RowCount = 100;
//исполнение запроса
try
{
table.Run();
}
catch(ERPException e)
{
MessageBox.Show(e.Message);
}
DataTable dt = table.Result;
closeConnection();
return dt;
}
Вместо оператора like можно использовать оператор = для поиска результатов, точно совпадающих с nameCriteria, тогда table.WhereClause выглядит так:
table.WhereClause = string.Format("NAME1 = '{0}'", nameCriteria);
В этом операторе важно соблюдать правильный синтаксис, особенно пробелы до и после =, иначе сгенерируется ERPException.
Чтобы отобразить данные в DataGridView, надо добавить следующий код в обработчик события button1_Click. После нажатия кнопки содержимым textBox1 будет nameCriteria.
private void button1_Click(object sender, EventArgs e)
{
string nameCriteria = textBox1.Text;
SAPConn sapConn = new SAPConn("userName", "password", "client");
DataTable dt = sapConn.WhereLikeSearch("KNA1", nameCriteria);
dataGridView1.DataSource = dt;
}
После исполнения программы надо заполнить DataGridView 100 заказчиками, соответствующими условию (например, ввод t в TextBox возвращает всех заказчиков с t в их имени).
Другие возможности ERPConnect
ERPConnect имеет куда больше возможностей, чем классы, использованные в двух примерах выше. Мы еще не использовали их все, но работали со следующими классами в проекте заказчика.
Функциональные модули без поддержки RFC: Если функциональный модуль не поддерживает RFC, ERPConnect предоставляет решение для подключения к этим функциональным модулям и использования их как функциональные модули с поддержкой RFC путем создания внутренней обертки вокруг функционального модуля, неявно исполняющего этот функциональный модуль. В приложении .NET вы лишь должны задать свойству UseRFCWrapper объекта RFCFunction значение true(истина).
ASP.NET: ERPConnect также можно включить в приложение ASP.NET. Чтобы использовать ERPConnect в веб-приложении, добавьте ссылки на ERPConnect20.dll и libfcr32.dll, расположенные в каталоге System32 клиентского компьютера SAP. После добавления этих ссылок можно использовать ERPConnect, описанный выше.
Запросы SAP: Также можно обращаться к любому виду запросов SAP с помощью пространства имен ERPConnect.Queries.
Чтобы исполнить запрос, нужны следующие шаги:
• Создать объект R3Connection и открыть соединение (как в примерах выше)
• Создать объект запроса Query q = con.CreateQuery("user area","user group","query name");
• Добавить условие q.SelectionParameters["the parameter"].Ranges.Add(Sign.Include, RangeOption.Equals, "criteria");
• Исполнить запрос q.Execute
• Теперь результаты находятся в DataTable dt = q.Result;
В этом пространстве имен также есть очень полезный класс ERPConnect.Query.QueryHelper.QueryHelper, предоставляющий функции "поиска запросов".
IDocs: Еще одна интересная возможность - отправка IDocs с помощью метода CreateIDoc. Разберем это на основе короткого листинга, взятого из онлайн-документации ERPConnect. Этот пример отправляет STATUS IDoc. STATUS IDoc предназначен для манипулирования статусом другого IDoc. STATUS IDoc может применяться для подтверждения успешной обработки получения другого IDoc.
static void Main(string[] args)
{
R3Connection con = new R3Connection("hamlet", 11,"Theobald",
"pw", "DE", "800");
con.Open(false);
Console.WriteLine("Which Idocnumber would you like to manipulate?");
string IdocNo = Console.ReadLine();
Idoc i = con.CreateIdoc("SYSTAT01", "");
// Заполняем тип сообщения
i.MESTYP = "STATUS";
// Заполняем информацию о получателе Idoc
i.RCVPRN = "PT4_800"; // Partner number
i.RCVPRT = "LS"; // Partner type
// Заполняем информацию об отправителе idoc
i.SNDPOR = "ERPCONNECT"; // порт партнера
i.SNDPRN = "ERPCONNECT"; // номер партнера
i.SNDPRT = "LS";// тип партнера
// Заполняем нужные поля в сегментах
i.Segments["E1STATS", 0].Fields["LOGDAT"].FieldValue = "20060101";
i.Segments["E1STATS", 0].Fields["LOGTIM"].FieldValue = "152301";
i.Segments["E1STATS", 0].Fields["STATUS"].FieldValue = "12";
i.Segments["E1STATS", 0].Fields["DOCNUM"].FieldValue = IdocNo;
i.Send();
Console.WriteLine("Idoc sent");
Console.ReadLine();
}
Получение IDocs немного отличается от отправки IDocs. Для получения IDocs надо реализовать маленький сервер IDoc путем задания свойству CanReceiveIdocs true и захвата входящих IDocs:
//создаем объект RFCServer
RFCServer s = new RFCServer();
s.Logging = true;
//задание свойств (надо заполнить пустые строки
//конкретными значениями)
s.GatewayHost = "";
s.GatewayService = "";
s.ProgramID = "";
//это свойство важно
s.CanReceiveIdocs = true;
//здесь захватываем входящие Idocs, чтобы обработать их в функции s_IncomingIdoc
s.IncomingIdoc += new ERPConnect.RFCServer.OnIncomingIdocs(s_IncomingIdoc);
//запускаем сервер
s.Start;
//позволяем серверу работать
//В конце останавливаем сервер
s.Stop;
В этом коротком листинге показано, как получить IDOCTYPE полученного IDoc:
private static void s_IncomingIdoc(RFCServer Sender, Idoc idoc)
{
Console.WriteLine(idoc.IDOCTYP);
}
Конечно, можно прочитать все содержимое полученного IDoc, но подробности смотрите в документации. Для реализации сервера в продуктивной области надо реализовать нечто вроде поточной обработки, чтобы управлять множеством входящих IDocs.
Классы IDoc также позволяют обрабатывать IDocs как файлы XML. Например, можно создать схему XML, определяющую, как должен выглядеть IDoc, или файл XML, хранящий данные IDoc.
Специальные классы: Для повторяющихся задач ERPConnect предоставляет специальные классы, инкапсулированные в пространство имен ERPConnect.Utils, как класс ReadTable, показанный в примере 2.
Еще один специальный класс - класс ABAPCode, позволяющий оперативно генерировать код ABAP в приложении .NET. Вместо написания функционального модуля в системе SAP вы можете написать код ABAP в приложении .NET без объявления нового функционального модуля в системе SAP.
Как написано выше, у ERPConnect есть еще возможности, такие как протокол SOAP/HTTP на базе XML или RFC-сервер, чтобы можно было решить почти любую задачу программирования интерфейса.
Вывод
Одна из главных задач для консультантов и разработчиков ПО в наши дни – разработка интерфейсов для разных информационных систем, таких как системы ERP(планирование ресурсов предприятия), PDM(управление данными об изделии) или CRM(управление связями с заказчиками). Одна из наиболее используемых систем ERP в крупных компаниях - SAP. С учетом этого, очень важно знать легкий способ программирования интерфейса для SAP. ERPConnect очень полезен для данной задачи, так как он поддерживает возможности каркаса .NET, такие как ASP.NET или Compact Framework, также ERPConnect поддерживает любую IDE(интегрированная среда разработки) типа SharpDevelop. В комплект ПО входит понятная документация с множеством примеров, объясняющих использование классов.