Baza wiedzy LINKSPOT › Wskazówki

Robotyzacja na punktach ACD typu „Import dokumentów zakupu z KSeF” – przykład

Wskazówki · Opublikowano 2026-03-06

Zastosowanie

Skrypt RPA umożliwia automatyzację procesu pobierania faktur z platformy Krajowego Systemu e-Faktur KSeF bezpośrednio do systemu Comarch BPM. Rozwiązanie to eliminuje konieczność ręcznego importu, zapewniając ciągłość zasilania punktów ACD nowymi dokumentami oraz odpowiednią reakcję na limity wydajnościowe serwerów ministerialnych.

Zawartość przykładu

Kliknij, aby pobrać przykład

Uwaga

Funkcjonalność obsługi limitów ministerialnych (reakcja na błąd 429) jest wspierana od wersji Comarch BPM 2026.0.0.2.

Zasada działania

Głównym zadaniem skryptu jest nawiązanie połączenia z serwerami ministerialnymi i przekazanie dokumentów do zdefiniowanego punktu ACD oraz określonego typu obiegu.

Skrypt działa w oparciu o pętlę sterowaną odpowiedziami z API KSeF:

Parametry konfiguracyjne

Zmienna Opis
maxRetries Maksymalna liczba prób w przypadku wystąpienia błędów tymczasowych (domyślnie: 3).
baseWaitTimeSeconds Podstawowy czas oczekiwania (90s) używany do wyliczania pauzy po otrzymaniu limitu żądań.
punktACD Nazwa punktu wejścia dla dokumentów w systemie.
nazwaObiegu Nazwa procesu, w którym pojawią się zaimportowane faktury.

Techniczne aspekty kodu

Konfiguracja przykładu

Aby skrypt mógł poprawnie realizować automatyczny import, niezbędna jest odpowiednia konfiguracja:

Przyklad

Przykład wpisu: .

Uwaga

Brak poprawnie zdefiniowanej ścieżki uniemożliwi przekompilowanie i zapisanie skryptu C#.

Przekompilowany Skrypt C#

Gotowy Skrypt C#

using System;
using System.Threading;
using System.Net;
using System.Net.Mail;

// --- KONFIGURACJA AUTOMATU ---
int lastErrorId = 0;
ACDError[] errorsArray = null;
string nazwaPunktuKSeF = "Dokumenty z KseF - (A)FZ"; 
string nazwaObiegu = "Faktura kosztowa (Elementy)_KSEF"; // <-- WPISZ TUTAJ NAZWĘ OBIEGU

Globals.ACD.Show();
Globals.Common.Trace("=== START: Automatyczny nadzór KSeF (Cykl 5 min) ===");

try
{
    while (true)
    {
        // 1. Monitorowanie błędów na punkcie ACD
        Globals.ACD.GetErrorList(ref errorsArray);
        if (errorsArray != null && errorsArray.Length > 0)
        {
            if (lastErrorId != errorsArray[0].Id)
            {
                lastErrorId = errorsArray[0].Id;
                string errorMsg = "Błąd techniczny ACD: " + errorsArray[0].Message;
                Globals.Common.Trace(errorMsg);
                SendMail("Alert ACD", errorMsg); 
            }
        }

        // 2. Ustawienie punktu ACD
        Globals.ACD.SetPoint(nazwaPunktuKSeF, 1);

        // --- NOWA METODA: Ustawienie typu obiegu ---
        int flowResult = Globals.ACD.SetDocumentFlow(nazwaObiegu);
        if (flowResult == 0)
        {
            Globals.Common.Trace("Pomyślnie ustawiono obieg: " + nazwaObiegu);
        }
        else if (flowResult == -2)
        {
            Globals.Common.Trace("BŁĄD: Obieg '" + nazwaObiegu + "' nie istnieje!");
        }
        else
        {
            Globals.Common.Trace("BŁĄD: Nieoczekiwany błąd przy ustawianiu obiegu (kod: " + flowResult + ")");
        }

        // 3. Proces importu z KSeF z obsługą limitów 
        try 
        {
            Globals.Common.Trace("Próba pobrania dokumentów z KSeF...");

            int maxRetries = 3;
            int retryCount = 0;
            int waitTimeSeconds = 300; // 5 minut
            bool importSuccess = false;

            while (!importSuccess && retryCount < maxRetries)
            {
                int importResult = Globals.ACD.ImportKSeFDocuments();

                if (importResult == 0)
                {
                    Globals.Common.Trace("Import faktur z KSeF zakończony sukcesem");
                    importSuccess = true;

                    Globals.ACD.RefreshList();
                    // Sprawdzenie czy są jakiekolwiek dokumenty na liście
                    if (Globals.ACD.SelectDocument(0) >= 0)
                    {
                        Globals.Common.Trace("Wykryto dokumenty. Generowanie do DMS...");
                        Globals.ACD.GenerateDMSDocuments();
                        Globals.Common.Trace("Generowanie zakończone pomyślnie.");
                    }
                    else
                    {
                        Globals.Common.Trace("Brak nowych dokumentów w KSeF.");
                    }
                }
                else if (importResult == -2)
                {
                    retryCount++;

                    string retryMsg = $"Przekroczono limit żądań KSeF (429 Too Many Requests). " +
                                      $"Próba {retryCount}/{maxRetries}. " +
                                      $"Oczekiwanie {waitTimeSeconds} sekund (5 minut) przed ponowną próbą...";
                    Globals.Common.Trace(retryMsg);

                    if (retryCount < maxRetries)
                    {
                        Thread.Sleep(waitTimeSeconds * 1000);
                    }
                    else
                    {
                        string failMsg = "Osiągnięto maksymalną liczbę prób. " +
                                        "Import faktur z KSeF nie powiódł się. " +
                                        "Spróbuj ponownie później.";
                        Globals.Common.Trace(failMsg);
                        SendMail("KSeF Rate Limit", failMsg);
                    }
                }
                else
                {
                    string statusMsg = $"Błąd importu faktur z KSeF. Kod błędu: {importResult}";
                    Globals.Common.Trace(statusMsg);
                    SendMail("Błąd połączenia KSeF", statusMsg);
                    break;
                }
            }
        }
        catch (Exception exIn)
        {
            Globals.Common.Trace("Błąd podczas pętli importu: " + exIn.Message);
        }

        // --- USPRAWNIONE OCZEKIWANIE ---
        Globals.Common.Trace("Cykl zakończony. Następne sprawdzenie za 5 minut...");

        for (int i = 0; i < 300; i++) 
        {
            Thread.Sleep(1000); // Czekaj 1 sekundę (umożliwia responsywność interfejsu)
        }
    }
}
catch (Exception ex)
{
    Globals.Common.Trace("KRYTYCZNY BŁĄD SKRYPTU: " + ex.Message);
    SendMail("KSeF Fatal Error", ex.Message);
}

// --- FUNKCJA WYSYŁAJĄCA POWIADOMIENIA E-MAIL ---
string SendMail(string temat, string tresc)
{
    try
    {
        MailMessage mail = new MailMessage();
        mail.From = new MailAddress ("XXX@firma-klienta.pl"); // Adres e-mail nadawcy (automatu)
        mail.To.Add ("YYY@firma-klienta.pl");           // Adres e-mail do powiadomień o błędach
        mail.Subject = "DMS KSeF Alert: " + temat;
        mail.Body = "Zdarzenie zarejestrowane przez automat KSeF:\n\n" + tresc;
        mail.BodyEncoding = System.Text.Encoding.UTF8;

        SmtpClient smtp = new SmtpClient  ("smtp.serwer-klienta.pl"); // Serwer SMTP klienta
        smtp.Port = 587;   // Port serwera (standardowo 587 lub 465)
        smtp.Credentials = new NetworkCredential ("użytkownik", "hasło"); //Podać login i hasło
        smtp.EnableSsl = true;

        smtp.Send(mail);
        return "";
    }
    catch (Exception ex) 
    { 
        Globals.Common.Trace("Błąd wysyłki powiadomienia e-mail: " + ex.Message);
        return ex.Message; 
    }
}

Rozpoczynasz pracę z Comarch BPM (dawniej DMS) i chcesz dowiedzieć się, jak korzystać z programu? A może masz już podstawową wiedzę o Comarch BPM (dawniej DMS) i chcesz dowiedzieć się więcej?

Sprawdź Szkolenia Comarch BPM!

Powrót do początku artykułu

+ Mam problem z tym tematem Otwórz w portalu bazy wiedzy »