Rest API dla ERP XL Comarchu

0

Hej, pytanie do tych, którzy znają ten system i jego API.
Przymierzam się do napisania Rest API co by rozmawiać z tym ERPem w obie strony. Pobieranie danych jest proste bo nie potrzeba ichniego API. Pytania dotyczą wrzucania czegoś w ten system.

  1. Czy spokojnie mogę użyć API XLa w aplikacji restowej? wiem, że to api jest jednowątkowe tzn. tak jakbyśmy posadzili tyłek przed kompem z tym systemem i działali na nim. Wielokrotne wołanie tego api może wyczerpać licencje, może po prostu wykrzaczyć się gdy w tym samym wątku wywołamy dwa razy logowanie itd.... nie do końca to czuję...

  2. Czy w związku z pkt 1 należałoby zrobić Rest Api, które zapisze dane do jakiejś pośredniej tabeli ( np. dane do wygenerowania faktury ) i dodatkowo napisać aplikację, która co X czasu sprawdza czy trzeba coś wrzucić do systemu, zrobić to, odhaczyć, że zrobione i done ?

  3. Znalazłem firmę, która takie API sprzedaje ( nie chce tutaj podawać co by nie zarzucić mi reklamy ), i ma je wykonane w .net core. Co mnie dziwi bo dll`ka Comarchu jest .net frameworkowa.
    Rozmawiałem z nimi i ichnie tłumaczenie jest co najmniej dziwne, twierdzą, że po prostu zrobili to w .net core. Aż spróbowałem, dodałem referencję tej dllki do projektu i oczywiście sypię się o niepoprawny format. Jak myślicie jakby to ogarnąć w .net 5,6, jak oni mogli to osiągnąć?

  4. Problem z pomysłem z punktu 2 .... co zwrócić do klienta kiedy chce on stworzyć coś w erp.

luźne pytania, dywagacje, konsternacje. Prośba do Was o opinie, doświadczenia, wskazówki.

1
john_doe napisał(a):

Hej, pytanie do tych, którzy znają ten system i jego API.

Przymierzam się do napisania Rest API co by rozmawiać z tym ERPem w obie strony. Pobieranie danych jest proste bo nie potrzeba ichniego API. Pytania dotyczą wrzucania czegoś w ten system.

XL ma api w postaci obiektów COM i moim zdaniem wszystkie zapytania powinny iść przez nie, żeby używać tej samej logiki biznesowej co użytkownik z frontu aplikacji.

  1. Czy spokojnie mogę użyć API XLa w aplikacji restowej? wiem, że to api jest jednowątkowe tzn. tak jakbyśmy posadzili tyłek przed kompem z tym systemem i działali na nim. Wielokrotne wołanie tego api może wyczerpać licencje, może po prostu wykrzaczyć się gdy w tym samym wątku wywołamy dwa razy logowanie itd.... nie do końca to czuję...

Nawet powinieneś, chyba że jesteś w stanie przepisać całą logikę biznesową aplikacji do api i ładować dane do bazy.

  1. Czy w związku z pkt 1 należałoby zrobić Rest Api, które zapisze dane do jakiejś pośredniej tabeli ( np. dane do wygenerowania faktury ) i dodatkowo napisać aplikację, która co X czasu sprawdza czy trzeba coś wrzucić do systemu, zrobić to, odhaczyć, że zrobione i done ?

To juz zależy co potrzebujesz. Jaki rodzaj integracji przewidujesz (w którym modelu). Czy potrzebujesz informacji zwrotnej, że udało się zrobić fakturę albo nie.

  1. Znalazłem firmę, która takie API sprzedaje ( nie chce tutaj podawać co by nie zarzucić mi reklamy ), i ma je wykonane w .net core. Co mnie dziwi bo dll`ka Comarchu jest .net frameworkowa.
    Rozmawiałem z nimi i ichnie tłumaczenie jest co najmniej dziwne, twierdzą, że po prostu zrobili to w .net core. Aż spróbowałem, dodałem referencję tej dllki do projektu i oczywiście sypię się o niepoprawny format. Jak myślicie jakby to ogarnąć w .net 5,6, jak oni mogli to osiągnąć?

Nie ma znaczenia, w czym to jest zrobione. .net Core wspiera obiekty COM. Nie wiem, o jakiej DLL piszesz. Poczytaj czym są obiekty COM.
Nie wiem jaki zakres funkcjonalności potrzebujesz i jak jest cena API, ale moim zdaniem lepiej kupić.

  1. Problem z pomysłem z punktu 2 .... co zwrócić do klienta kiedy chce on stworzyć coś w erp.

Dlatego potrzebujesz dwukierunkowej komunikacji i możesz zwrócić np numer faktury.

Możesz zawołać @AdamWox on tam się już chyba nauczył pływać w tym Comarchowym szambie.
Kiedyś podchodziłem do Rest API do Optimy i to był droga przez mękę, ale po dwóch dniach urodził się pomysł rozwiązania. Jest to do zrobienia, ale wymaga dużo pracy i cierpliwości do API systemu, bo czasem daje niespójne informacje (zwłaszcza jak się nie znam procesów biznesowych).

2

Z tego co wiem to XL nie ma COMów. Trzeba pobrać osobno plik .dll ze stron partnerskich, który jak nazwa pliku sugeruje jest w .net i nawet jak chce się prześwietlić za pomocą dotpeek to pokazuje, że to jest .NET Framework v4.0. Ale... Zrobiłem dla testów projekt ASP.NET Core Web App + Angular wybierając .NET 6 w Visual Studio 2022. We właściwościach projektu, w sekcji Build -> General -> Platform target, zmieniłem z Any CPU na x86. Podpiąłem DLLkę z XLa, dopisałem jakieś "logowanie" do predefiniowanego endpointa

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            cdn_api.XLLoginInfo_20211 login = new cdn_api.XLLoginInfo_20211();
            login.OpeIdent = "ADMIN";
            login.OpeHaslo = "TEST";

            int sesja = 0;

            cdn_api.cdn_api.XLLogin(login, ref sesja);
            
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }

BŁĄD - NIE jest błędem .NET Core -> .NET Framework

System.DllNotFoundException: 'Unable to load DLL 'cdn_api.dll' or one of its dependencies: Nie można odnaleźć określonego modułu. (0x8007007E)'

Zaznaczyć muszę, że nie mam zainstalowanego XLa u siebie. Jaki ty masz błąd? Dokładnie cały wyjątek 🤔 może uda się coś zdziałać. Wyjątek BadImageFormatException może świadczyć o tym, że próbujesz budować apkę 64 bit, a ani XL, ani Optima sobie z tym nie radzi, ponieważ obie są 32 bitowe.

0

Optima używa COM
XL dllki .netowej
Oczywiście, że trzeba użyć tego API.
@AdamWox przybywaj :)

0

Ostatnią apkę jaką robiłem dla XL'a zrobiłen w .netCore 3.1 i śmiga, nie odczułem żadnym problemów z tym. I robiłem to na dll'ce XL'owej, a nie developerskiej. Coś partner nie chce mi jej udostępnić :)
Fakt nie próbowałem robić RestAPI, aż tak bardzo nie chce mi się kombinować + wprowadzać dodatkową warstwę opóźnień. Mimo tego, że przez Clariona XL i tak działa jak kupa + ilość wywołań zapytań do bazy danych potrafi przytłoczyć.

Niby XL ma być oparty na RestAPI w wersji przeglądarkowej, ale coś boję się tego rozwiązania stworzonego przez Comarch. Jakoś nie chce mi się wierzyć w dwie rzeczy:

  • odetną się od wersji desktopowej
  • przeniosą inne funkcje niż podstawowe :)

screenshot-20211209173119.png

0

@Lilpri: "I robiłem to na dll'ce XL'owej, a nie developerskiej" - co to znaczy? api to jest jedna konkretna dll`ka, którą można sobie zabrać z katalogu z instalacją i to jest plik np. cdn_api20202.net.dll a nie cdn_api.dll
Jakich funkcjonalności API XLa używałeś?
Chodzi mi też o to, że to proces wygląda tak: loguję się do XL, robię coś tam, wylogowuję się. W tym kontekście łatwo:

  • wysycić licencje ( może nastąpić wiele razy loginXL ),
  • skoro to API jest jednowątkowe to łatwo również o błędy.

@AdamWox
Do działania tego API jest wymagany XL na kompie. Dostaję > BadImageFormatException ale faktycznie jak zmieniłem Build Properties z AnyCpu -> x86 api działa. Ślamazarnie strasznie - loguję się do systemu z 10 sekund.

0

Od wersji 2020 albo 2021, nie pamiętam już. Na dll z folderu instalacyjnego nie możne puścić debugera :) Wysypuje się.
Jeśli się chce debugować trzeba uzyskać dll dla developera, zbytnio nie różni się ona od tej z folderu z XL'em, ale pozwala na debug...

Co do używanych funkcjonalności, to logowanie i tworzenie różnych dokumentów.

I tak:

  • łatwo wysycić licencję, dlatego niektórzy robią to tak:
    Apkę, która trzyma cały czas login do XL'a i zbiera do swoich tabel/folderów dane i je wrzuca co jakiś czas do XL'a, np. co 10min. Czyli ona robi za Rest, a dopiero w jednowątkowym trybie wrzuca (spora część intergracji z panelami B2B/B2C tak wygląda.
  • błędy, oj tak. Pamiętam jak raz przywiesił mi się program i trzaskał MMki do wysycenia magazynu, bo mu licencji w trakcie brakło :D
0

Apkę, która trzyma cały czas login do XL'a i zbiera do swoich tabel/folderów dane i je wrzuca co jakiś czas do XL'a, np. co 10min. Czyli ona robi za Rest, a dopiero w jednowątkowym trybie wrzuca (spora część intergracji z panelami B2B/B2C tak wygląda.>
@Lilpri: możesz to rozwinąć? czy to to o czym ja piszę - aplikacja np. konsolowa działające w zaplanowanych zadaniach, cronach, etc...? Możesz konkretniej.

spotkałem się gdzieś w sieci z czymś takim jak aplikacja a`la socket serwer, do którego Rest Api podbija -> socket srv używa API Xl - coś tam generuje i odrzuca info.

0

Osobiście pisałem tylko apki consolowe odpalane z harmonogramu, np.:

  • komasacja zamówień, aby na produkcję wpadły jako jedne
  • przenoszenie dokumentów między bazami (zamówienia, WZ/PZ)
  • przenoszenie kartotek towarów/kontrahentów między bazami.

Aby się mniej bawić skorzystałem ostatnio z dwóch integratorów do obsługi B2B i B2C -> specyficzne wymagania, brak stanów towarowych itp.
I z tego co widzę działa to tak:

  • jest sobie apka, która odpala serwis od XL'a (i z tego co widzę w aktywnych sesjach trzyma sesję cały czas) oraz serwis RestAPI klienta do wymiany danych z panelami.
  • prowadzi logi + ewentualnie wyrzuca błędy na ekran. Zależy co ma włączone.
  • część logów jest po stronie serwera (ftp gdzie są panele), część logów po stronie apki.
    Sporo jest firm sprzedających takie bajerki, mi brakowało już czasu więc skorzystałem z oferty firmy CTI.
1

@john_doe: Ja mam na WinService + OwinSelfHost + TopShelf.

Musiałem zrobić taką magię. Bez tego cały czas magiczne błędy chyba jeszcze z czasów Clariona.

var config = new HttpConfiguration();
...
config.Services.Replace(typeof(IHttpActionInvoker), new StaThreadEnabledHttpActionInvoker());

public class StaThreadEnabledHttpActionInvoker : ApiControllerActionInvoker
    {
        public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext context, CancellationToken cancellationToken)
        {
            return Task.Factory.StartNewSta(() => base.InvokeActionAsync(context, cancellationToken).Result);
        }
    }

Logowanie długie, ale 10 s to przesada. Zobacz czy nie masz włączonego naprawiania plików (czerwonych). To znacznie spowalnia
XLLoginInfo.TrybNaprawy = 0;

Ja robię tak, że akcje wymagające zalogowania logują się prawdziwymi loginami XL-a (przesyłanymi razem z DTO do kontrolerów). Czyli xl user Jacek loguje się do XL-a jako Jacek. Załatwia to uruchomienie wewnętrznych mechanizmów XL-a dla użytkownika. Numerację, serie, kontrolę dostępu do magazynów, kto utworzył, edytował itd. Tylko w zamówieniach udało mi się ustawiać OpeNumerW i OpeNumerM (a OpeNumerM i tak się ustawia źle).

Trzeba łapać wszystkie wyjątki i wylogowywać sesję bo się zapamiętuje i następne logowanie przejmuje poprzednią sesję (co jest szybkie, ale wszystko potem leci na jednego użytkownika).

Inny sposób to kolejkowanie zadań np. w DB albo jakimś Mosquito. Wtedy WebApi zapisuje tylko do DB a jakiś winserwice w pętli odpytuje db i realizuje zadania. Z tym, że wtedy nie masz synchroniczności co u mnie było nie do przyjęcia.

0

jest sobie apka, która odpala serwis od XL'a (i z tego co widzę w aktywnych sesjach trzyma sesję cały czas) oraz serwis RestAPI klienta do wymiany danych z panelami.

Czy to jest odpalenie aplikacji w Task Scheduler Windowsa? Czy windows service?

Trzyma sesję - startując po prostu próbuje się od razu zalogować, jak się uda …. czyha 🧐 ? To jest trzymanie sesji?

@jacek.placek
Socket server może jest wart implementacji?

Strzał do rest api
-> wywołanie socketa po jakimś porcie
-> realizacja zadania ->
-> NIE logout - bo trzymam sesje? 😀

Ale tutaj też zdarzą się kłopoty wielokrotnym odpaleniem xlLogin

@jacek.placek

Z tym, że wtedy nie masz synchroniczności co u mnie było nie do przyjęcia.
Twoim zdaniem o jakich czasowo rozbieżnościach mówimy?

@jacek.placek
To masz topshelfem robisz win service, który jest selfHosted app (webApi) i i co jeszcze?

Kolejkowanie spina sie z moją teorią. Topshelf, win service, console app realizująca kolejne zadania z db, webapi.

0

Ja w winsevice mam owinselfhost. Self hosted web api.
Normalne kontrolery web api. Nie używam żadnego kolejkosania.
U mnie Android app, WinForms lub web app wysyła jakies dane do web api w tym serwisie. Taki rest api w winsevice.

Twoim zdaniem o jakich czasowo rozbieżnościach mówimy?

Zależy od operacji ok 8-10 s na dodanie dokumentu pw, rw czy zamowienia. W tym 5-6 na zalogowanie. Baza ma jakieś 50 GB.

U mnie człowiek musi zobaczyć od razu wyniki niektórych operacji. Tzn może i nie musi ale już mi się nie chciało dyskutować o tym z klientem.

Nie mam problemu z wielokrotnym logowanie bo akcje są w tym StaThread. To chyba ujednowątkawia uruchamianie akcji kontrolerów webapi.

0

@jacek.placek:
owinselfhost - rozumiem, że masz aplikację konsolową, gdzie w metodzie main startujesz jakieś nasłuchiwanie na porcie X, cała reszta aplikacji to np. osobne projekty w solucji ( webapi ) czy jakaś tam wariacja tego w sensie niekoniecznie osobne projekty tylko jakoś przez Ciebie ułożona struktura projektu.

to

var config = new HttpConfiguration();
...
config.Services.Replace(typeof(IHttpActionInvoker), new StaThreadEnabledHttpActionInvoker());

i to

public class StaThreadEnabledHttpActionInvoker : ApiControllerActionInvoker
    {
        public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext context, CancellationToken cancellationToken)
        {
            return Task.Factory.StartNewSta(() => base.InvokeActionAsync(context, cancellationToken).Result);
        }
    }

Natknąłem się gdzieś w sieci na hasło AttachThreadToClarion, czy to jest to czego używasz?
Czy możesz wrzucić cały konfig tego + controller przykładowy. Wydaje się to kluczowe.

0

Szablon projektu. Trzeba pododawać własne kontrolery API i serwisy z operacjami.

https://github.com/JacekCzapla/xlwinserviceapi.git

Uruchamianie wszystkiego jest w Program.cs
W projekcie jest folder Controllers i tam wrzucasz kontrolery API (zobacz PingController)

VS trzeba uruchomić jako administrator, żeby miał uprawnienia do portu IP (8090).

0

Masz jeszcze mój xl abstract service. Może się przyda.

Jak widzisz importuję AttachThreadToClarion z ClaRUN.dll ale nigdzie jej nie wywołuję z parametrem (1). Tylko podczas wylogowania wywołuję kontrolnie AttachThreadToClarion(0);. Nie wiem dlaczego. To całe "xl api" jak działa to nie wolno ruszać.

Konkretne serwisy dziedzicza po tym i uruchamiają ten konstruktor. W metodach dodawania - edycji dokumentów wywołują na początku Login() i na końcu Logout(). Logout() wywołuję ZAWSZE, po poprawnym zakończeniu, każdym błędzie itp.

Ja w konkretnych serwisach w metodach operujących na dokumentach często sprawdzam czystym SQLem różne rzeczy (jakaś walidacja danych lub sprawdzenie czy jest taki kontrahent, towar, czy jest aktywny itp.) przed wywołaniem Login() bo Login() zajmuje dużo czasu a jak dane są niepoprawne to API od razu zwróci jakiś komunikat z błędem.

using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace XLServices
{
    public abstract class XLAbstractService1
    {
        protected Logger logger = NLog.LogManager.GetCurrentClassLogger();

        [DllImport("ClaRUN.dll")]
        protected static extern void AttachThreadToClarion(int _flag);

        protected XLAbstractService1()
        {
        }

        public XLAbstractService1(string programId, string serwerKlucza, string login, string password, string bazaDanych, string plikLog = "", bool attachToClarion = true)
        {
            ProgramId = programId;
            SerwerKlucza = serwerKlucza;
            LoginName = login;
            Password = password;
            BazaDanych = bazaDanych;
            PlikLog = plikLog;

            AttachToClarion = attachToClarion;

        }

        protected int Wersja = 0;
        protected int Sesja = 0;
        protected int FrsId = 0;

        protected string ProgramId { get; set; }
        protected string SerwerKlucza { get; set; }
        protected string LoginName { get; set; }
        protected string Password { get; set; }
        protected string BazaDanych { get; set; }
        protected string PlikLog { get; set; }

        protected bool AttachToClarion { get; set; }


        protected void XLLogin()
        {

            //if (AttachToClarion)
            //    AttachThreadToClarion(1);

            int lLogowanie = 0;
            int lWersja = 20193;
            int lSesja = 0;

            int err = cdn_api.cdn_api.XLSprawdzWersje(ref lWersja);
            Wersja = lWersja;


            cdn_api.XLLoginInfo_20193 login = new cdn_api.XLLoginInfo_20193();
            login.UtworzWlasnaSesje = 1;
            login.Wersja = Wersja;
            login.ProgramID = ProgramId;// "TESTAPI";            
            login.SerwerKlucza = SerwerKlucza;
            login.Winieta = -1;
            login.OpeIdent = LoginName;            
            login.OpeHaslo = Password;
            login.TrybWsadowy = 1;
            login.PlikLog = PlikLog;
            login.TrybNaprawy = 0;
            //login.SesjaKlucza = ""; //???

            login.Baza = BazaDanych;
            
            lLogowanie = cdn_api.cdn_api.XLLogin(login, ref lSesja);
            
            Sesja = lSesja;
            if (lLogowanie != 0)
            {

                XLLogout(Sesja);
                AttachThreadToClarion(0);
                throw new XLServices.Exceptions.XLLoginException();
            }
        }

        protected void XLLogout(int session)
        {
            int res = cdn_api.cdn_api.XLLogout(session);
            Console.WriteLine($"XLLogout res: {res}");
        }

        public void XLLogout()
        {
            if (Sesja > 0)
            {
                AttachThreadToClarion(0);
                int res = cdn_api.cdn_api.XLLogout(Sesja);
                Console.WriteLine($"XLLogount res: {res}");
            }

        }
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1