Praca KSeF-link w trybie http link-Server

Wpis #300 z dnia: 09-09-2025

Pobierz najnowszą aplikację testową (aktualizacja 25.12.10), która prezentuje większość funkcji dostępnych przez link-Server. Program wykonany w Visual Studio 2022 i C#. Zawiera pełny kod źródłowy oraz wersję skompilowaną.

https://tgsoft.pl/zip/KsefLinkClientTest.zip

Jeżeli jesteś integratorem i już tworzysz rozwiązanie do współpracy z naszym programem lub szukasz uniwersalnego rozwiązania, koniecznie zapoznaj się z tym przykładem. Aplikacja testowa będzie rozwijana o kolejne przykłady.

W poprzednich dokumentach opisaliśmy interaktywną pracę programu, gdzie użytkownik korzystał z wybranych funkcji do tworzenia faktur i komunikacji z KSeF.

Teraz zaprezentujemy możliwość pracy ad-hoc z innym programem ERP. W tym celu przygotujemy demonstracyjny projekt za pomocą Visual Studio i C#.

Aby program mógł przyjmować polecenia od aplikacji zewnętrznej, należy uruchomić link-Server przyciskiem [Start] z prawej strony głównej formy aplikacji. Po prawidłowym uruchomieniu usług http, napis Link Server zostanie wyświetlony kolorem niebieskim.

Generowanie faktur KSeF API z Json

Główny ekran programu po aktywacji Link Server

Programista (integrator) może skorzystać z naszego API i za pomocą prostych komend wykonywać szereg zaawansowanych poleceń do generowania faktur, wysyłania do KSeF, pobierania statusów, itp. Polecenia http dostępne są w trybie ad-hoc, co pozwoli na automatyzację procesów związanych z KSeF zaraz po wystawieniu faktury w systemie ERP.

W przykładzie poniżej skorzystaliśmy z klas *Dto (do serializacji Json) opisanych w dokumencie https://tgsoft.pl/Blog?id=294

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Windows.Forms;
using Newtonsoft.Json;

namespace KsefLinkClientTest
{
    public partial class FormDemo : Form
    {
        public FormDemo()
        {
            InitializeComponent();
        }

        private static string GetInvoiceStr(string nrFry)
        {
            FakturaDto faktura = new FakturaDto()
            {
                Nabywca = new KontrahentDto()
                {
                    NIP = "3333333333",
                    Nazwa = "FHU Trójka Sp. z o.o.",
                    AdresL1 = "ul. Nowy Świat 1",
                    AdresL2 = "00-001 Warszawa",
                },
                P_1 = string.Format("{0:yyyy-MM-dd}", DateTime.Today),
                P_2 = nrFry,
                P_13_1 = 1000,
                P_14_1 = 230,
                P_13_2 = 100,
                P_14_2 = 8,
                P_15 = 1338,
                FwItems = new List<FwItemDto>
                {
                    new FwItemDto() { NazwaTowaruUslugi = "Stawka podatkowa 23%", JednostkaMiary = "SZT", Ilosc = 1, CenaJednostkowaNetto = 1000, WartoscNetto = 1000, StrVAT="23"},
                    new FwItemDto() { NazwaTowaruUslugi = "Stawka podatkowa 8%", JednostkaMiary = "SZT", Ilosc = 1, CenaJednostkowaNetto = 100, WartoscNetto = 100, StrVAT="8"},
                }
            };

            return JsonConvert.SerializeObject(faktura);
        }


        static string baseAddress = "http://localhost:9000/";

        private async void button1_Click(object sender, EventArgs e)
        {
            try
            {
                HttpContent httpContent = new StringContent(GetInvoiceStr("0029/09/2025"), Encoding.UTF8, "application/json");

                using (HttpClient client = new HttpClient())
                {
                    HttpResponseMessage response = await client.PostAsync(baseAddress + "api/invoices/ImportJInvoice", httpContent);
                    if (response != null && response.Content != null)
                    {
                        textResponse.Text  = await response.Content.ReadAsStringAsync();
                        var x = JsonConvert.DeserializeObject<LinkResponse>(textResponse.Text);
                        textBoxID.Text = x.Id.ToString();
                        textBoxCode.Text = x.Code.ToString();
                        textBoxKey.Text = x.Key;
                        textBoxDescription.Text = x.Description;
                    }
                }
            }
            catch (Exception ex)
            {
                textException.Text = ex.Message;
            }
        }
    }
}

Przykład C# na wykorzystanie metody api/invoices/ImportJInvoice

Metoda ImportJInvoice przyjmuje strukturę Json faktury, generuje fakturę w formacie FA. Xml (3) i zapisuje do bazy faktur KSeF. Lista faktur dostępna jest w Menu/Kartoteki SQL/Faktury sprzedaży. Przed zapisem aplikacja sprawdza zgodność wygenerowanej faktury xml ze schematem XSD. Błędna faktura zostanie odrzucona, a komunikat przedstawia dokładne informacje o błędach. Poniższe zdjęcie przedstawia próbę wysłania nieprawidłowej faktury z błędnymi danymi:

  • Podano NIP 333333333X
  • Podano Kwotę w polu P_14_3 zamiast P_14_2

Generowanie faktur KSeF API z Json

Odpowiedź serwera na błędne dane w strukturze Json

Generowanie faktur KSeF API z Json

Poprawny zapis nowej faktury do bazy SQL

Wszystkie metody Link-Server zwracają odpowiedź wg tej samej struktury Json serializowanej klasy LinkResponse:

Po deserializacji Json, możemy odczytać poszczególne wartości. W przykładzie otrzymujemy Id=8607 nowego rekordu po dodaniu faktury do listy KSeF. Jeżeli to możliwe, zalecamy zapis tego Id w bazie danych własnego systemu ERP.

    public class LinkResponse
    {
        public bool Success { get; set; }
        public int Id { get; set; }
        public string Key { get; set; }
        public int Code { get; set; }
        public string Description { get; set; }
    }

Generowanie faktur KSeF API z Json

Widok listy faktur sprzedaży po dodaniu nowej faktury do bazy SQL

Faktura dodana przez system ERP, od razu widoczna jest w trybie interaktywnym dla użytkownika. Ikona w kolumnie [Status] informuje o nowej fakturze w systemie. Dokument nie został jeszcze wysłany do KSeF. Do wysłania można skorzystać z funkcji programu:

  • Przycisk [Wyślij/sprawdź] - wysyła serię faktur
  • Przycisk [Wyślij] - wysyła jedną (bieżącą) fakturę

Programista ma też kilka możliwości do dalszego przetwarzania dołączonej faktury:

  // Wysyła fakturę z bazy, nie czeka na status przetwarzania
  public static async Task<string> SimpleSendInvoiceAsync(int id)
  {
      using (HttpClient client = new HttpClient())
      {
          HttpResponseMessage response = await client.GetAsync(baseAddress + $"api/invoices/SimpleSendInvoice/{id}");
          string responseContent = await response.Content.ReadAsStringAsync();
          return $"{response.StatusCode} : {responseContent}";
      }
  }

  // Odczytuje aktualny status faktury, w razie konieczności pobiera niezbędne dane z KSeF
  public static async Task<string> GetInvoiceStatusAsync(int id)
  {
      using (HttpClient client = new HttpClient())
      {
          HttpResponseMessage response = await client.GetAsync(baseAddress + $"api/invoices/GetInvoiceStatus/{id}");
          string responseContent = await response.Content.ReadAsStringAsync();
          return $"{response.StatusCode} : {responseContent}";
      }
  }

  // Wysyła fakturę z bazy i odbiera status przetwarzania
  public static async Task<string> SendInvoiceAsync(int id)
  {
      using (HttpClient client = new HttpClient())
      {
          HttpResponseMessage response = await client.GetAsync(baseAddress + $"api/invoices/SendInvoice/{id}");
          string responseContent = await response.Content.ReadAsStringAsync();
          return $"{response.StatusCode} : {responseContent}";
      }
  }

  // Pobiera wygenerowaną strukturę Xml dla podanego Id i zapisuje w katalogu określonym w Parametrach Systemu
  public static async Task<string> GetInvoiceXmlAsync(int id)
  {
      using (HttpClient client = new HttpClient())
      {
          HttpResponseMessage response = await client.GetAsync(baseAddress + $"api/invoices/GetInvoiceXml/{id}");
          string responseContent = await response.Content.ReadAsStringAsync();
          return $"{response.StatusCode} : {responseContent}";
      }
  }

Zestaw metod: ImportJInvoice, SimpleSendInvoice, GetInvoiceStatus można zastąpić jednym wywołaniem, które importuje fakturę, wysyła, a następnie pobiera status przetwarzania w KSeF:

  // Importuje i od razu wysyła fakturę Json oraz pobiera status faktury.
  public static async Task<string> SendJInvoiceAsync(string json)
  {
      HttpContent httpContent = new StringContent(json, Encoding.UTF8, "application/json");

      using (HttpClient client = new HttpClient())
      {
          HttpResponseMessage response = await client.PostAsync(baseAddress + "api/invoices/SendJInvoice", httpContent);
          string responseContent = await response.Content.ReadAsStringAsync();
          return $"{response.StatusCode} : {responseContent}";
      }
  }

Jeżeli Twój system ERP posiada już możliwość generowania faktur w formacie FA.Xml (3), możesz skorzystać z metody dołączenia gotowego pliku Xml : ImportXmlInvoice, a następnie wysłać i pobrać status przetwarzania.

	// Import faktury z pliku Xml do bazy podstawowej
	public static async Task<string> ImportXmlInvoiceAsync(string filePath)
	{
	    string xmlContent = System.IO.File.ReadAllText(filePath);
	    HttpContent httpContent = new StringContent(xmlContent, Encoding.UTF8, "text/plain");
	
	    using (HttpClient client = new HttpClient())
	    {
	        HttpResponseMessage response = await client.PostAsync(baseAddress + "api/invoices/ImportXmlInvoice", httpContent);
	        return await response.Content.ReadAsStringAsync();
	    }
	}

Generowanie faktur KSeF API z Json

Otwarta faktura w trybie podglądu za pomocą przycisku [Faktura]

Generowanie faktur KSeF API z Json

Szczegóły wygenerowanej faktury w zakładce [Xml]



Następny dokument 301 : QR KOD I - Weryfikacja i pobieranie faktury z KSeF.