Konsultanci RXP i moc integracji

SAP & Coupa

RXP miało przyjemność być częścią „zespołu marzeń” w rocznym projekcie integracyjnym dla globalnej firmy tytoniowej jako podwykonawca technologiczny. Projekt obejmował uruchomienie opartej na chmurze platformy Coupa do celów obługi procesów zaopatrzenia.

Konsultanci RXP byli odpowiedzialni za integrację procesów procure-to-pay między platformą Coupa a SAP – budowali interfejsy w SAP PI umożliwiając automatyczny przepływ dokumentów, zmodyfikowali adapter HTTP na potrzeby połączenia z REST API, dla specyficznych wymagań klienta programowali rozszerzenia SAP w języku ABAP w obszarach SD, MM i FI. Zadania obejmowały również przygotowanie dokumentacji technicznej i budowę zaawansowanych raportów.

Adapter Specific Message Attributes (ASMA) – dynamiczna konfiguracja parametrów kanałów komunikacji

Podstawową funkcją mapowań w SAP PI jest budowanie zawartości docelowego komunikatu w oparciu o dane zawarte w komunikacie źródłowym. Parametry techniczne, takie jak np. nazwa pliku, ścieżka, adres serwera, konfiguruje się zwykle w kanale komunikacji.

Czasem jednak zachodzi potrzeba dynamicznego ustawienia tych parametrów w mapowaniu – również w zależności od przesyłanych danych. Dla najprostszych przypadków (jak zmiana nazwy docelowego pliku), można skorzystać z mechanizmu Variable Substitution, jednak o wiele większe możliwości daje funkcja ASMA (Adapter-Specific Message Attributes).

Dla większości adapterów istnieje zestaw atrybutów kanału komunikacji, który można zdefiniować w nagłówku komunikatu PI korzystając z obiektów konfiguracji dynamicznej (Dynamic Configuration). Dla poszczególnych atrybutów można włączyć konfigurację dynamiczną z ASMA w zakładce Advanced ustawień kanału komunikacji:

Adapter Specific Message Attributes (ASMA)

Adapter Specific Message Attributes (ASMA)

Konfiguracja dynamiczna ASMA w funkcjach użytkownika Java (UDF)

Atrybuty komunikatu w konfiguracji dynamicznej można ustawić za pomocą własnych funkcji użytkownika – UDF (User-Defined Functions). Każda definiowana przez użytkownika funkcja standardowo otrzymuje obiekt Container. Za pomocą jego metod, można pobrać obiekt konfiguracji dynamicznej:

[codesyntax lang=”java”]

DynamicConfiguration conf = (DynamicConfiguration) container
 .getTransformationParameters()
 .get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);

[/codesyntax]

Kolejnym krokiem jest utworzenie par klucz – wartość dla każdego konfigurowanego atrybutu. Należy przy tym pamiętać o przestrzeni nazw właściwej dla danego typu kanału komunikacji. Przykładowe atrybuty dostępne dla wybranych kanałów komunikacji:


 

File Adapter (pliki) – przestrzeń nazw: http://sap.com/xi/XI/System/File

  • FileName – nazwa pliku
  • Directory – katalog
  • TargetTempFileName – nazwa tymczasowego pliku (jeśli jest używany)

 

Mail Adapter (e-mail) – przestrzeń nazw: http://sap.com/xi/XI/System/Mail

  • THeaderFROM – nadawca
  • THeaderTO – odbiorca
  • THeaderCC – odbiorca kopii (DW)
  • THeaderBCC – odbiorca ukrytej kopii (UDW)
  • THeaderSUBJECT – tytuł e-maila

 

JMS Adapter – przestrzeń nazw: http://sap.com/xi/XI/System/JMS

  • DCJMSCorrelationID – Correlation ID
  • DCJMSMessageID – Message ID
  • DCJMSMessageQueue – Message Queue

HTTP Adapter – przestrzeń nazw: http://sap.com/xi/XI/System/HTTP

  • URL

Znając nazwę klucza i przestrzeń nazw, klucz tworzymy następującą metodą:

[codesyntax lang=”java”]

DynamicConfigurationKey key = DynamicConfigurationKey.create(
 “http://sap.com/xi/XI/System/File”,
 “FileName”);

[/codesyntax]

Pozostaje przypisanie pary klucz – wartość do konfiguracji dynamicznej. W poniższym przykładzie funkcja UDF ustawia atrybut – nazwę pliku – w oparciu o wejściowy ciąg znaków (parametr filename):

Adapter Specific Message Attributes (ASMA)

Adapter Specific Message Attributes (ASMA)

Listę atrybutów, jakie można ustawić dynamicznie dla danego kanału komunikacji, można znaleźć na stronie Using Adapter-Specific Message Attributes in the Message Header, przechodząc do interesującego nas typu kanału komunikacji, w sekcji Define Adapter-Specific Message Attributes.

Konfiguracja dynamiczna w mapowaniach XSLT

Alternatywą dla funkcji Java (UDF) w celu ustawienia atrubutów kanału komunikacji w konfiguracji dynamicznej, są mapowania XSLT. Mechanizm ten jest opisany w pomocy SAP na stronie XSLT Mapping of Adapter-Specific Message Attributes.

Zastosowanie

Dzięki temu, że konfiguracja dynamiczna jest dostępna z poziomu mapowania, otwierają się szerokie możliwości programowego ustawienia atrybutów kanału komunikacji. Możliwe zastosowania nie ograniczają się do przykładów:

  • ustawienie docelowego katalogu w zależności od numeru zakładu, składu SAP
  • wpisanie numeru zamówienia, faktury lub klienta w nazwie pliku
  • ustawienie odbiorcy e-maila wg adresu w komunikacie źródłowym
  • ustawienie tematu e-maila w zależności od zawartości komunikatu
  • dynamiczna budowa URL docelowej usługi HTTP

User Defined Functions – własne funkcje w mapowaniach SAP PI

User Defined Functions (UDF) to funkcje zdefiniowane przez programistę, które mogą być wykorzystywane w mapowaniach graficznych SAP PI. Funkcje te definiowane są w języku Java i umożliwiają uruchomienie dowolnego kodu na etapie mapowania pól komunikatów XML, znacznie rozszerzając zakres operacji, jakie można wykonać na polach i wartościach komunikatu.

W mapowaniach graficznych UDF reprezentowane są przez jeden blok. Dzięki im wykorzystaniu, można przykładowo uprościć realizację stosunkowo prostej logiki, której implementacja wymagałaby użycia dużej liczby standardowych bloków:

udf-01

UDF tworzy się przez kliknięcie w ikonę czystej kartki w lewym dolnym rogu edytora mapowań graficznych:

udf-02

W najprostszym wariancie wystarczy uzupełnić podstawowe dane – nazwę i etykietę funkcji, oraz nazwę argumentów wejściowych. Wartość argumentów będzie można przypisywać podobnie jak w przypadku standardowych bloków mapowania graficznego – za pomocą strzałek na wejściu i wyjściu funkcji:

udf-02a

Kolejnym krokiem jest implementacja funkcji w języku Java. Wejście i wyjście jest realizowane jak w innych funkcjach / metodach Java – poprzez argumenty i polecenie return. Na poniższej ilustracji znajduje się definicja UDF o takim samym działaniu jak na przykładzie mapowania graficznego powyżej.

udf-03

Parametry UDF

Wartości konfiguracyjne można określić jako parametry UDF. Będą również przekazywane do funkcji jak argumenty, lecz ich wartość przypisuje się na poziomie mapowania graficznego.

udf-04

udf-05

Testowanie UDF

Po zapisaniu funkcji, można jej użyć w mapowaniu graficznym, podłączając wejścia i wyjście. Podobnie jak w przypadku standardowych bloków, po uruchomieniu testu można prześledzić listę podawanych i zwracanych przez UDF wartości za pomocą funkcji Display Queue:

udf-06

W powyższym przykładzie UDF została wykorzystana do uproszczenia implementacji mapowania. W zależności od potrzeb, programista może wykorzystać szereg możliwości języka Java, które pozwolą na implementację bardziej złożonych mapowań, niż pozwalają na to standardowe bloki mapowania graficznego.

Przegląd nowych funkcji w SAP Process Integration 7.31

Ograniczenia wcześniejszych wersji: SAP PI 7.11

  • Adaptery Idoc oraz HTTP nie są dostępne dla Integrated Configuration
  • Mapowanie jednego komunikatu do wielu (1:n) nie jest możliwe w ICO
  • Reguły routingu na podstawie zawartości komunikatu nie mogą być użyte w ICO

Nowe mozliwości połączeń dla Advanced Adapter Engine

IDOC_AAE

  • Przesyłanie wielu Idoców jednocześnie (Idoc packaging), ale nie dla interfejsów wychodzących
  • Moduły adaptera mogą być dodane dla konfiguracji dla Idoców
  • Wsparcie dla ALEAUDIT

HTTP_AAE

  • Nowe funkcje: POST and Multipart document

SFTP adapter

  • dodatek dostępny od wersji PI 7.11 SP08

Ulepszenia dla Integrated Configuration

Mapowanie jeden do wielu możliwe w ICO

  • mapowanie 1:n
  • Reguły routingu na podstawie zawartości komunikatu przychodzącego

PI 7.31 ICO Multimapping

Narzędzia do monitorowania 

  • Monitoring komunikatów Idoc (zastępuje transakcję IDX5)

PI 7.31 Idoc Monitor

  • Monitoring metadanych

PI 7.31 Metadata Monitor

  • Nowy monitoring komunikatów

PI 7.31 Message Monitor

 

  • Opcja ‚Ping’ dla kanału komunikacyjnego
    • Sprawdzenie połączenia
    • Użytkownik/hasło
    • Uprawnienia (np. dostęp do FTP)
    • Ustawienia zapory sieciowej

PI 7.31 Ping 1

 

PI 7.31 Ping 2

Wyszukiwanie komunikatów po zawartości

  • Nie ma potrzeby użycia TREX
  • Zazwyczaj używane do przeszukiwania po polach kluczowych (Numer zamówienia, Numer partnera)
  • Osobne filtry definiowane dla poszczególnych interfejsów
  • Pozwala na przeszukiwanie dla klucza zdefiniowanego jako:
    • XPATH

      XPATH

    • Dynamic Header

      Dynamic Header

  • Indeksowanie jest możliwe dla komunikatów przetworzonych przed zdefiniowaniem filtra
  • Indeks jest usuwany kiedy komunikat jest zarchiwizowany

 

 

Konfiguracja połączenia IDOC_AAE dla PI 7.31 single stack

1. Ustalenie danych dla GatewayHostGatewayService 

  • Nalezy zalogować się do SLD i wybrać Administration -> Settings zakładka Parameters i tam z rozwijanej listy All:

SLD Gateway PI/PO 7.31 single stack

2. Utworzenie połączeń RFC do systemu SAP, z którego będą wysyłane Idoci

  • Po zalogowaniu się do SAP NetWeaver Administrator (NWA) należy przejść do Configuration -> Infrastructure -> Destinations

SAP NWA Destinations

 

  • Parametry połączenia:

Hosting System: Local Java System PID
Destination Name: XI_IDOC_DEFAULT_DESTINATION
Destination Type: RFC

SAP NWA Destinations step 1

 

W kolejnych krokach należy podać parametry połączenia do systemu SAP oraz dane logowania:

SAP NWA Destinations step 2

 

Aby upewnić się, że połączenie działa prawidłowo można skorzystać z opcji Ping Destination. Test powinien zakończyć się komunikatem Successfully connected to system <PID> as user <user>

Ping destination

3. Utworzenie połączenia JCo (Java Connector)

  • Po zalogowaniu się do SAP NetWeaver Administrator (NWA) należy przejść do Configuration -> Infrastructure -> Jco RFC Provider

JCo RFC Provider

 

  • Należy utworzyć nowe połączenie korzystając z opcji Create, parametry w pierwszym kroku:

Program ID: XI_IDOC_DEFAULT_PID
Gateway Host: z punktu 1
Gateway Service: z punktu 1

JCo step 1

 

  • W kolejnym kroku należy podać nazwę połączenia z punktu 2., w tym przypadku XI_IDOC_DEFAULT_DESTINATION

JCo step 2

 

Po zapisaniu należy uruchomić połączenie korzystając z opcji Start, prawidłowy komunikat to JCo servers started

4. Wprowadzenie parametrów dla Resource Adapter inboundRA

  • Po zalogowaniu się do SAP NetWeaver Administrator (NWA) należy przejść do Configuration -> Infrastructure -> Application Resources i przefiltrować listę zasobów po *inboundRA*

Resource Adapter step 1

  • W zakładce Properties należy wprowadzić następujące wartości lub upewnić się, że takie są tam już obecne:

GatewayServer – tak jak w punkcie 1.
ProgramID – tak jak w punkcie 3. – XI_IDOC_DEFAULT_PID
MaxReaderThreadCount – wartość pomiędzy 5 a 10
DestinationName – tak jak w punkcie 2. – XI_IDOC_DEFAULT_DESTINATION
GatewayService – tak jak w punkcie 1. – sapgw01
Local – true
BindingKey – PI_AAE_IDOC

Resource Adapter step 2

  • Po zapisaniu parametrów należy uruchomić aplikację: More Actions -> Start Applications i wybrać z listy com.sap.aii.adapter.idoc.sapjra.inboundRA

Resource Adapter step 3

5. Utworzenie połączenia RFC w systemie SAP wysyłającym Idoci do PI

  • W transakcji SM59 należy utworzyć nowe połączenie typu (T) TCP/IP Connection używając parametrów:

Activation Type: Registered Server Program
Program ID: tak jak w punkcie 3. – XI_IDOC_DEFAULT_PID
Gateway Host: tak jak w punkcie 1.
Gateway Service: tak jak w punkcie 1. – sapgw01

SM59 TCP/IP Connection

 

SM59 TCP/IP Connection

 

  • Po przetestowaniu połączenia powinien się pojawić komunikat:

SM59 RFC connection test

 

6. Utworzenie kanału komunikacyjnego na PI

  • W odróżnieniu do konfiguracji Idoc dla Integration Engine (ABAP) wymagany jest kanał komunikacyjny typu Sender, który będzie użyty w Integrated Configuration. 
  •  Parametr RFC Server Parameters należy ustawić na Default, a w Ack Destination podać połączenie z punktu 2. – XI_IDOC_DEFAULT_DESTINATION

Idoc_AAE sender channel

 

Po wykonaniu powyższych kroków system PI jest przygotowany na konfigurację scenariuszy dla Idoców przychodzących.

W trakcie tworzenia poradnika wykorzystane zostały informacje dostępne na stronach help.sap.com oraz scn.sap.com

Mapowanie XSLT do pliku płaskiego

W niektórych sytuacjach wymagane jest przesłanie pliku wynikowego jako płaskiego o określonej długości każdego pola. W przypadku adaptera plikowego można z powodzeniem skorzystać z File Content Conversion, jednak w przypadku na przykład wywołania usługi sieciowej najlepszym rozwiązaniem będzie przekształcenie XSLT. Dla przykładowego pliku wejściowego:

[codesyntax lang=”xml” lines=”normal”]

<Order>
   <Header>
      <DocumentNumber>001</DocumentNumber>
      <Date>20140401</Date>
   </Header>
   <Line>
      <ItemNumber>1</ItemNumber>
      <Material>1203040</Material>
      <Quantity>10</Quantity>
      <UOM>PCE</UOM>
   </Line>
   <Line>
      <ItemNumber>2</ItemNumber>
      <Material>2349040</Material>
      <Quantity>20</Quantity>
      <UOM>PCE</UOM>
   </Line>
</Order>

[/codesyntax]

Po zastosowaniu transformacji tworzącej nową linię dla każdego powtórzenia elementu <Line> i ustawiającej długości każdego pola na odpowiednio 20, 20, 3, 20, 5, 5:
[codesyntax lang=”xml” lines=”normal”]

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="text" indent="yes" encoding="UTF-8" />
   <xsl:variable name="DocumentNumber">
      <xsl:call-template name="padRightSide">
         <xsl:with-param name="stringToPad" select="Order/Header/DocumentNumber" />
         <xsl:with-param name="totalLength" select="20" />
      </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="Date">
      <xsl:call-template name="padRightSide">
         <xsl:with-param name="stringToPad" select="Order/Header/Date" />
         <xsl:with-param name="totalLength" select="20" />
      </xsl:call-template>
   </xsl:variable>
   <xsl:template match="/Order">
      <xsl:for-each select="Line">
         <!-- Repeat header data -->
         <xsl:copy-of select="$DocumentNumber" />
         <xsl:copy-of select="$Date" />
         <!-- Item data -->
         <xsl:call-template name="padRightSide">
            <xsl:with-param name="stringToPad" select="ItemNumber" />
            <xsl:with-param name="totalLength" select="3" />
         </xsl:call-template>
         <xsl:call-template name="padRightSide">
            <xsl:with-param name="stringToPad" select="Material" />
            <xsl:with-param name="totalLength" select="20" />
         </xsl:call-template>
         <xsl:call-template name="padRightSide">
            <xsl:with-param name="stringToPad" select="Quantity" />
            <xsl:with-param name="totalLength" select="5" />
         </xsl:call-template>
         <xsl:call-template name="padRightSide">
            <xsl:with-param name="stringToPad" select="UOM" />
            <xsl:with-param name="totalLength" select="5" />
         </xsl:call-template>
         <!-- End Line -->
         <xsl:text />
      </xsl:for-each>
   </xsl:template>
   <xsl:template name="padRightSide">
      <xsl:param name="totalLength" />
      <xsl:param name="padChar" select="' '" />
      <xsl:param name="stringToPad" />
      <xsl:param name="padBuffer" select="concat($padChar,$padChar,$padChar,$padChar,$padChar, $padChar,$padChar,$padChar,$padChar,$padChar )" />
      <xsl:variable name="vNewString" select="concat($stringToPad, $padBuffer)" />
      <xsl:choose>
         <xsl:when test="not(string-length($vNewString) &gt;= $totalLength)">
            <xsl:call-template name="padRightSide">
               <xsl:with-param name="stringToPad" select="$vNewString" />
               <xsl:with-param name="totalLength" select="$totalLength" />
               <xsl:with-param name="padChar" select="$padChar" />
               <xsl:with-param name="padBuffer" select="$padBuffer" />
            </xsl:call-template>
         </xsl:when>
         <xsl:otherwise>
            <xsl:variable name="output">
               <xsl:value-of disable-output-escaping="no" select="substring($vNewString,1,$totalLength)" />
            </xsl:variable>
            <xsl:value-of select="$output" />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

[/codesyntax]

otrzymujemy:
001 20140401 1 1203040 10 PCE
001 20140401 2 2349040 20 PCE