Wprowadzenie
System Comarch ERP XL może pracować jako serwer aplikacji udostępniając innym aplikacjom swoje funkcje. Dzięki zaimplementowaniu funkcji API (Application Programming Interface) dowolna aplikacja może w prosty sposób korzystać z mechanizmów, którymi dysponuje Comarch ERP XL. Daje to niespotykaną w rozwiązaniach konkurencyjnych otwartość systemu, pozwalając zarówno na integrację ze standardowymi narzędziami programistycznymi, (np. Microsoft Office i Visual Basic) jak i możliwość integracji z dowolnym systemem informatycznym eksploatowanym w firmie.
System Comarch ERP XL oferuje kilkadziesiąt funkcji pozwalających na zdalną pracę w systemie. Funkcje te są zgromadzone w bibliotece CDN_API.DLL, która jest instalowana łącznie z całym systemem Comarch ERP XL.
Hermetyczność
Duży nacisk przy tworzeniu funkcji XL API położony został na bezpieczeństwo i integralność danych wprowadzanych poprzez te funkcje. Wynikiem tego jest funkcja weryfikująca Użytkownika (XLLogin) oraz wewnętrzny mechanizm Comarch ERP XL kontrolujący poprawność zakończenia działania funkcji API.
Program Comarch ERP XL bardzo dokładnie śledzi wszelkie zmiany w bazie, dokonywane przy pomocy funkcji API. Jeżeli wystąpi błąd, który spowoduje niepoprawne przerwanie działania aplikacji wykorzystującej API, to wszystkie zmiany przez nią wprowadzone, które nie zostały poprawnie zakończone, zostają bezwzględnie wycofane. Warunkiem poprawności zmian wprowadzanych przez API jest albo zakończenie wprowadzania obiektu, który stanowi logiczną całość albo wylogowanie się z systemu funkcją XLLogout.
Wersjonowanie
Ponieważ zakładamy, iż funkcjonalność XL API będzie stale rozszerzana, funkcje te zostały wyposażone w mechanizm wersjonowania. Zapewni on kompatybilność z poprzednimi wersjami API, czyli pozwoli na uniknięcie sytuacji, w których po zmodyfikowaniu (rozszerzeniu) funkcji API Użytkownicy i Integratorzy byliby zmuszeni do wprowadzania odpowiednich zmian w napisanych przez siebie aplikacjach wspomagających.
Ponieważ Comarch ERP XL musi zawsze działać na najnowszych strukturach danych, mechanizm wersjonowania będzie pełnił rolę translatora pomiędzy strukturami API przekazanymi z zewnętrznej aplikacji, a strukturami wykorzystywanymi wewnątrz Comarch ERP XL. Po wartości przekazanej w polu: Wersja, zostanie rozpoznana struktura przekazana do funkcji i dokonane zostanie odpowiednie przepisanie wartości do struktury wewnętrznie wykorzystywanej przez Comarch ERP XL. W momencie, gdy struktury wewnętrzne i zewnętrzne są różne, pola niewykorzystywane zostaną wypełnione domyślnymi wartościami.
Ponieważ struktury danych wykorzystywane przez API służą również do zwracania danych z programu Comarch ERP XL, mechanizm wersjonowania jest mechanizmem działającym w obie strony (dokonana zostanie odpowiednia translacja danych wewnętrznych do struktury przekazywanej na zewnątrz).
Dzięki temu aplikacje napisane w aktualnej wersji API będą działały poprawnie również w kolejnych wersjach Comarch ERP XL, bez potrzeby dokonywania w nich przeróbek (z wyjątkiem sytuacji, w której chcemy rozszerzyć funkcjonalność aplikacji o nowe możliwości Comarch ERP XL API).
Po każdorazowej zmianie struktur, publikowana będzie nowa wersja XL API oznaczona kolejnym numerem. Numer ten będzie nadawany równolegle dla wszystkich struktur API niezależnie od tego, czy została ona zmieniona (np. zmiana tylko w strukturze XLLoginInfo spowoduje zmianę numeru wersji dla wszystkich pozostałych struktur API).
Algorytm postępowania
Typowy scenariusz wykorzystujący funkcje XL-API najprościej jest prześledzić na przykładzie faktury sprzedaży.
Kolejność wywoływanych funkcji jest następująca:
- XLLogin - inicjalizacja bibliotek Comarch ERP XL, login operatora do bazy danych;
- XLNowyDokument – otwarcie nagłówka nowego dokumentu; powoduje zapisanie w bazie danych otwartego nagłówka dokumentu (w omawianym przypadku jest to faktura sprzedaży);
- XLDodajPozycje – dodanie pozycji do faktury; wywołanie tej funkcji może nastąpić wielokrotnie, jeżeli do dokumentu chcemy dopisać więcej niż jedną pozycję;
- XLDodajPlatnosc – zapis płatności do tworzonej faktury; wywołanie tej funkcji jest opcjonalne – jeżeli nie zostanie wywołana, system automatycznie wygeneruje płatność domyślną przy zamykaniu faktury; funkcja może być wołana wielokrotnie – np. w przypadku specyfikacji płatności ratalnej;
- XLZamknijDokument – zakończenie edycji i zamknięcie dokumentu; dokument może być zamykany w trybie normalnym (zapis bez możliwości późniejszej modyfikacji) lub w trybie „do bufora";
- XLLogout – w obrębie jednej sesji otwartej funkcją XLLogin możemy wystawić dowolną ilość dokumentów. Wystawienie każdego z nich powinno zaczynać się wywołaniem funkcji XLNowyDokument i kończyć wywołaniem funkcji XLZamknijDokument.
Przykłady zastosowań
Import dokumentu z pliku .TXT
Jest to szczególnie istotne dla firm wprowadzających bardzo długie transakcje zakupu. Często wraz z towarem jego dostawca dostarcza dyskietkę ze specyfikacją dostawy. Korzystając np. z programu Microsoft Excel można napisać prosty program wczytujący taki plik tekstowy do arkusza, a następnie łączący się poprzez XL API z systemem Comarch ERP XL i generujący odpowiedni dokument zakupu.
Wsadowy import transakcji
Firmy wielooddziałowe często importują poprzez łącza modemowe transakcje ze swoich oddziałów do centrali, gdzie mają one być następnie wprowadzone do bazy danych. Program importujący transakcje może za pośrednictwem XL API połączyć się z systemem Comarch ERP XL i zapisywać w jego bazie danych zaimportowane z oddziałów dokumenty.
Przykładowe kody
Poniżej przedstawione zostały przykładowe kody wykorzystujące XL API.
Dadanie ZS z jednym elementem (VBA)
Sub Dodaj_Zamowienie()
Dim Sesja As Long
Dim Wynik As Long
Dim Login As XLLoginInfo_12
Dim IDDokumentu As Long
Dim Naglowek As XLDokumentZamNagInfo_12
Dim Element As XLDokumentZamElemInfo_12
Dim Zamkniecie As XLZamkniecieDokumentuZamInfo_12
Sesja = 0
IDDokumentu = 0
With Login
.Wersja = 12
.programID = "TestXL"
.Baza = "CDNXL_Test"
.OpeIdent = "ADMIN"
.OpeHaslo = ""
End With
Wynik = XLlogin_12(Login, Sesja)
If Wynik <> 0 Then
MsgBox("Błąd logowania: " & Wynik)
End If
With Naglowek
.Wersja = 12
.Typ = 6
.Akronim = "Test"
End With
Wynik = XLNowyDokumentZam_12(Sesja, IDDokumentu, Naglowek)
If Wynik <> 0 Then
MsgBox("Błąd dodawania nagłówka: " & Wynik)
End If
With Element
.Wersja = 12
.Ilosc = 10
.CenaKatalogowa = 1
.Towar = "Test"
End With
Wynik = XLDodajPozycjeZam_12(IDDokumentu, Element)
If Wynik <> 0 Then
MsgBox("Błąd dodawania pozycji: " & Wynik)
End If
With Zamkniecie
.Wersja = 12
.TrybZamkniecia = 2
End With
Wynik = XLZamknijDokumentZam_12(IDDokumentu, Zamkniecie)
If Wynik <> 0 Then
MsgBox("Błąd zamykania nagłówka: " & Wynik)
End If
Wynik = XLlogout_12(Sesja)
If Wynik <> 0 Then
MsgBox("Błąd wylogowania: " & Wynik)
End If
End Sub
Przekształcenie ZS do FS (VBA)
Public Sesja As Long
Public IDDokumentu As Long
Public Wynik As Long
Public ElemInfo As XLDokumentElemInfo_12
Sub Zaloguj()
Dim Login As XLLoginInfo_12
Sesja = 0
Wynik = 0
With Login
.Wersja = 12
.ProgramId = "X:VBA"
.Baza = "CDN_XL_Test"
.OpeIdent = ""
.OpeHaslo = ""
End With
Wynik = XLLogin_12(Login, Sesja)
If Wynik <> 0 Then
Wynik = MsgBox("Błąd logowania: " & Wynik)
Exit Sub
End If
End Sub
Sub DodajNaglowek()
Dim NagInfo As XLDokumentNagInfo_12
Worksheets("Nagłówek ZS").Select
Wersja = 12
With NagInfo
.Wersja = 12
.Typ = 4
.ZamFirma = Range("b2").Value
.ZamNumer = Range("c2").Value
.ZamTyp = Range("a2").Value
End With
Wynik = 0
Wynik = XLNowyDokument_12(Sesja, IDDokumentu, NagInfo)
If Wynik <> 0 Then
Wynik = MsgBox("Błąd dodawania nagłówka: " & Wynik)
Exit Sub
End If
End Sub
Sub ZamknijNaglowek()
Dim ZamkniecieInfo As XLZamkniecieDokumentuInfo_12
ZamkniecieInfo.Wersja = 12
ZamkniecieInfo.Tryb = 0
Wynik = 0
Wynik = XLZamknijDokument_12(IDDokumentu, ZamkniecieInfo)
If Wynik <> 0 Then
Wynik = MsgBox("Błąd zamykania nagłówka: " & Wynik)
Exit Sub
Else
Wynik = MsgBox("Poprawnie dodano dokument WZ.")
End If
End Sub
Function Pierwszy_wolny_rekord() As Integer
Dim licznik As Long
licznik = 2
Do
If Range("A" & licznik).Value = "" Then
Pierwszy_wolny_rekord = licznik
Exit Function
Else
licznik = licznik + 1
End If
Loop
Stop
End Function
Sub DodajPozycje()
Worksheets("Pozycja ZS").Select
licznik = Pierwszy_wolny_rekord()
For x = 2 To licznik - 1
With ElemInfo
.Wersja = 12
.ZamFirma = Range("b" & x).Value
.ZamTyp = Range("a" & x).Value
.ZamNumer = Range("c" & x).Value
.ZamLp = Range("d" & x).Value
End With
Wynik = 0
Wynik = XLDodajPozycje_12(IDDokumentu, ElemInfo)
If Wynik <> 0 Then
Wynik = MsgBox("Błąd dodawania pozycji: " & Wynik)
Exit Sub
End If
Next x
End Sub
Sub Wyloguj()
Wynik = 0
Wynik = XLLogout_12(Sesja)
If Wynik <> 0 Then
Wynik = MsgBox("Błąd wylogowywania: " & Wynik)
Exit Sub
End If
End Sub
Sub Przeksztalc_ZS()
Zaloguj
DodajNaglowek
DodajPozycje
ZamknijNaglowek
Wyloguj
End Sub
Dodaj Kontrahenta (.NET)
Dla programistów wykorzystujących platformę MS .NET został przygotowany plik assembly, zawierający deklaracje struktur oraz funkcji używanych w XL API. Plik jest dostępny na stronie Comarch (w zasobach Comarch ERP XL). Obecna wersja jest wersją testową, ciągle rozwijaną. Plik należy dołączyć w referencjach projektu (w Microsoft Visual Studio .NET można to zrobić wybierając w menu Project/Add Reference).
using System;
using cdn_api;
namespace XLNowyKontrahent
{
class APIDodajKontrahenta
{
[STAThread]
static void Main(string[] args)
{
XLLoginInfo_12 Login = new XLLoginInfo_12();
Login.Wersja = 12;
Login.ProgramID = "API.NET";
Login.Baza = "maciek4n";
Login.OpeIdent = "ADMIN";
Login.OpeHaslo = "";
Int32 SesjaID = 0;
Int32 KontrahentID = 0;
int LoginResult = cdn_api.cdn_api.XLLogin(Login, ref
SesjaID);
if (LoginResult == 0)
{
XLKontrahentInfo_12 Kontrahent = new XLKontrahentInfo_12();
Kontrahent.Wersja = 12;
Kontrahent.Akronim = "Nowy Kontrahent";
int KontrahentResult =
cdn_api.cdn_api.XLNowyKontrahent(SesjaID,ref KontrahentID,Kontrahent);
}
cdn_api.cdn_api.XLLogout(SesjaID);
}
}
Wskazówki do API w C8
Ogólne wytyczne w zakresie konfiguracji
1. Do sprawdzenia są elementy związane z wymogami systemowymi.
- Zainstalowany i włączony .NET 4.0.
2. Warunki związane z samym systemem ERP XL dla wszystkich systemów operacyjnych:
- Baza systemu ERP XL musi być podpięta dla wszystkich użytkowników komputera
(wpis o bazie musi być w rejestrze w gałęzi HKEY_LOCAL_MACHINE:
[HKEY_LOCAL_MACHINE\SOFTWARE\CDN\CDNXL\MSSQL\Bazy] – 32bit [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\CDN\CDNXL\MSSQL\Bazy] 64 bit)- Musi być wpisany klucz HASP
Lub
[HKEY_LOCAL_MACHINE\SOFTWARE\CDN\HASP]“Serwer”=”Tu nazwa serwera HASP”
- Ścieżka do systemu ERP XL musi być w globalnej zmiennej środowiskowej PATH -widzianej przez wszystkich użytkowników systemu, a w szczególności przez ASPNET
- Operator, na którego jest logowanie przez API nie może mieć pustego hasła
- Wymagania związane z użytkownikami Windowsów:
Użytkownik ASPNET musi być w grupie użytkownicy, użytkownik na którym działa
IIS i ASP musi mieć prawa do katalogu z systemem ERP XL - chodzi o to żeby ten
użytkownik miał uprawnienia do uruchomienia ERP XL. [/su_list]
3. Na systemach serwerowych (2003,2008, 2012) i VISTA, Win 7, 8 najlepiej utworzyć dla takiej aplikacji osobną pulę aplikacji. Użytkownik, na którym działa pula (domyślnie Usługa Sieciowa) musi mieć prawo do katalogu z systemem Comarch ERP XL, aby miał uprawnienia do uruchomienia systemu.
4. Dodatkowo funkcje API powinny być wołane w trybie wsadowym.
5. Na C8 – nowy interfejs – przed logowaniem do API trzeba zawołać poniższy kod.
//jeśli C8 wołana jest metoda z ClaRUN.dll
public class Cdnsys
{
[DllImport(“ClaRUN.dll”)]static extern void AttachThreadToClarion(int _flag);
public void AttachThread()
{
try
{
AttachThreadToClarion(1);
}
catch (Exception){}
}
}
Powyższe AttachThreadToClarion trzeba wołać przy każdym podnoszeniu nowego wątku.
6. W zmiennej środowiskowej Path powinno być wskazanie w ścieżce na jeden folder z systemem ERP XL (jeżeli jest zawarte odwołanie do innych folderów z wcześniejszymi wersjami należy je usunąć a następnie zapisać zmiany i zrestartować komputer).
7. Trzeba wołać attachthread wg wskazań w dokumentacji (lub jak powyżej) do każdego
nowego wątku i nie używać async’a. Jeżeli XLLogin jest wołane w innym wątku niż
pozostałe funkcje API to ten wątek musi pozostać aktywny tak długo jak wołamy funkcje
API – nie można po jego zakończeniu wołać funkcji API.
8. AttachThreadToClarion woła się 1 raz po utworzeniu wątku .net ( w tymże utworzonym wątku) – czyli 1 raz na wątek (teoretycznie nie ma ograniczenia na ilość wywołań AttachThread). Po wywołaniu AttachThreadToClarion wątek .net i wątek Clariona to jest jeden i ten sam wątek, nie ma więc operacji odwrotnej do AttachThreadToClarion. Jak zakończy się wątek utworzony w .net to zakończy się również w Clarionie i obiekty wątkowe zostaną zwolnione.
Plik Konfiguracyjny
Plik konfiguracyjny aplikacji nie pojawia się automatycznie po stworzeniu projektu i należy go dodać samodzielnie. Wystarczy kliknąć prawym przyciskiem myszy na projekt, do którego chcemy dodać plik z konfiguracjami, następnie wybrać opcję “Add New Item” i w oknie wyboru typu pliku zaznaczyć “Application Configuration File”. Dalej podaje się jego nazwę – standardowo App.config i potwierdza wybór.
Logowanie do API poprzez usługę
Podczas startowania usługi ( np. realizacja zamówienia ZS dokumentem WZ) wołany jest XLLogin, czyli są ustawiane obiekty globalne m.in. kolekcje rodzajów kontrahentów, definicje dokumentów itd. (wszystkie rzeczy konfiguracyjne XL’a). Potem startuje nowy wątek, w którym są wystawiane dokumenty np. WZ. Podczas gdy startuje nowy wątek to część danych konfiguracyjnych kopiuje z wątku głównego (robiona jest kopia żeby wątki się nie blokowały na czas dostępu do danych w wątku głównym). Należy zwrócić uwagę na specyficzne zachowanie usług (jeżeli usługa zawiera metody OnStart, OnStop, AutoResetEvent, WaitOne) – przy jej uruchamianiu wołana jest metoda OnStart (jeśli w niej byłoby umieszczone logowanie do API) to wątek w którym OnStart został wywołany może być za chwilę zakończony, co pociąga za sobą zwolnienie obiektów globalnych ładowanych przy XLLogin. Od tego momentu nowo tworzone wątki generujące np. WZ nie mają skąd skopiować danych konfiguracyjnych.
Rozwiązaniem jest w metodzie OnStart uruchomienie nowego wątku, w którym jest logowanie do API i ustawienie po zalogowaniu aby wątek nie zakończył się. Można to zrobić za pomocą statycznego obiektu klasy AutoResetEvent i metody WaitOne. W metodzie OnStop usługi trzeba wtedy zawołać metodę Set na tym obiekcie (po wylogowaniu z API).
API a aplikacje działające w oparciu o webserwis
W architekturze serwera opartego o WCF i klienta, problemem dla clariona jest kończenie wątku głównego gdy proces się nie kończy – czyli z punktu widzenia systemu operacyjnego wszystko jest poprawnie, jest wątek główny samej usługi. Wątek ten nie jest jednak związany z clarionem, więc w clarionie dopiero wątek w którym następuje logowanie do API jest wątkiem głównym – po wylogowaniu wątek ten się kończy mimo iż proces nadal działa – czy z punktu widzenia clariona sytuacja niemożliwa do uzyskania – nie ma czegoś takiego jak proces bez żadnego wątku, dlatego tez z tego powodu co jakiś czas zgłaszane mogą być wyjątki.
Rozwiązaniem będzie przy starcie usługi wydzielenie jednego wątku, związanie go z clarionem (AttachThread…) i pozostawieniem aktywnym przez cały czas działania usługi. W wątku tym trzeba wywołać od razu XLLogin. I teraz można zrobić od razu XLLogout, lub pozostawić tą sesję aktywną i w niej wystawiać dokumenty z wątków tworzonych na żądanie klientów – będzie szybciej działać. Czyli teraz nie byłoby już wołania XLLogin,XLNowyDokument…, XLLogout za każdym razem, ale jedynie XLNowyDokument z ID sesji ustalonym w wątku pierwszym.
Trzeba tak zmodyfikować dodatek, żeby choć jeden wątek procesu był podłączony do wątku clarionowego, tak aby nie było sytuacji, w której proces jest aktywny a żaden wątek nie jest połączony z clarionem. To wymaganie nie dotyczy okresu aktywności przed pierwszym wywołaniem AttachThreadToClarion.
Możliwe problemy do weryfikacji:
- czy IIS po wylogowaniu z API od razu zamknie wątek czy zostawi w puli na pewien czas
- czy podczas pracy w innym wątku na API IIS nie zamknie takiego zużytego wątku z puli, bo już tam długo tkwił (wtedy zwolnione zostaną obiekty globalne z których może chcieć korzystać pracujący wątek – one pracują w ramach jednego procesu w3wp)
Connection string
Po zmianach w API XLPolaczenie nie zwraca automatycznie danych odnośnie połączenia. Funkcja API zwraca niezbędne dane do połączeń w aplikacji uzupełnione w tabeli cdn.Konfig i Kon_Numer = -137, Kon_Komentarz = ‘ConnectionString’.
Od wersji 2019.0 XLPolaczenie zwraca dane z funkcji skalarnej CDN.PodajDodatokwyConnectString – co pozwala na dynamiczną weryfikację połączenia, w przeciwieństwie do stałej danej wpisanej w CDN.Konfig.
Debugowanie od wersji XL 2021
Od wersji 2021.0 podłączenie się pod procesy XL debugerem zostało standardowo zablokowane ze względu na zalecenia działu bezpieczeństwa. W celu debugowania należy zastosować pakiet deweloperski dostępny na stronach walidowanych dla partnerów w sekcji dodatki dla wersji XL 2021 ( pliki z pakietu należy wgrać do katalogu XL następnie uruchomić rejestr.bat).