Integracja · LMS × KSeF 2.0

Instrukcja
integracji z KSeF

Krok po kroku — od certyfikatu do pierwszej faktury w Krajowym Systemie e-Faktur

Wersja LMS28-git (kwiecień 2026)
KSeF2.0 produkcja
Obowiązkowy od01.04.2026
Autor@cocoban78
Aktualna wersja paczki: 30.04.2026 · ↓ Pobierz

Słowo wstępne

Cześć! Na samym wstępie muszę się przyznać — jestem wieloletnim i oddanym fanem systemu LMS :D Poniższy projekt powstawał momentami w bólach, prawdopodobnie bywa pełen chaosu i z pewnością nie wygra konkursu na najlepiej udokumentowany kod w historii. Początkowo tworzyłem to wyłącznie na swoje własne, absolutnie prywatne potrzeby, żeby jakoś okiełznać nadchodzącego potwora zwanego KSeF. Nie ukrywam! W dużej mierze pomogła tutaj sztuczna inteligencja...

Jednak, ulegając presji tłumu i na prośbę wielu z Was, postanowiłem podzielić się tym dziełem zupełnie nieodpłatnie. Musicie jednak wiedzieć o jednym: nie działam w porozumieniu z autorami ani programistami oficjalnego LMS-a. Oznacza to, że wszelkie ich poprawki i aktualizacje mogą znacząco wpłynąć na (nie)działanie niniejszej integracji. Mój projekt nie jest oficjalną częścią systemu. Oczywiście bardzo się starałem, by całość była jak najbardziej spójna i niczego nie zepsuła, ale korzystacie z tego na własną odpowiedzialność! Oczywiście udostępniony kod może być także inspiracją dla innych, śmiało korzystacjie! Zachęcam również do dzielenia się :P

Szukasz rozwiązania w pełni profesjonalnego? Jeśli nie lubisz dreszczyku emocji i zależy Ci na stabilnym, w 100% profesjonalnie wspieranym zintegrowaniu KSeF z systemem LMS, z czystym sumieniem polecam zapoznanie się z ofertą LMS+ (https://lms.plus/).

Wymagania

SkładnikMinimalna wersjaSprawdź
LMS28-git, migracje ≥ 2026040800SELECT keyvalue FROM dbinfo WHERE keytype='dbversion'
PHP8.1+php -v
Composerdowolnacomposer --version
Biblioteka KSeFn1ebieski/ksef-php-clientls vendor/n1ebieski/
Certyfikat KSeFPlik .p12 tworzony z plików .crt, .key oraz hasła wygenerowanych w portalu KSeF
ext-zipwymagane przez PHPphp -m | grep zip

Jeśli brak biblioteki ksef-php-client:

cd /twoja/sciezka/lms
composer require n1ebieski/ksef-php-client

Krok 1 Certyfikat PKCS12

Aby uwierzytelnić się w systemie KSeF, potrzebujesz certyfikatu. W portalu KSeF Ministerstwa Finansów (Aplikacja Podatnika → Certyfikaty) generujesz parę plików o rozszerzeniach .crt oraz .key, a także podajesz dla nich hasło, które musisz zapamiętać i wpisać do pliku lms.ini. Z tych danych należy wygenerować docelowy plik .p12 (PKCS#12) przy użyciu poniższego polecenia:

# Połącz .crt i .key w plik .p12
openssl pkcs12 -export \
  -in certyfikat.crt \
  -inkey certyfikat.key \
  -out /etc/lms/ksef_cert.p12   # lub inna wybrana ścieżka \
  -passout pass:TwojeHaslo123!

# Zabezpiecz plik
chmod 640 /etc/lms/ksef_cert.p12
chown root:www-data /etc/lms/ksef_cert.p12
⚠ Bezpieczeństwo Plik .p12 i hasło do niego to dostęp do wystawiania faktur w Twoim imieniu. Upewnij się że plik nie jest dostępny publicznie ani dla innych użytkowników serwera. Zalecana lokalizacja: /etc/lms/ksef_cert.p12 z uprawnieniami 640.

Certyfikat offline (opcjonalny)

Ministerstwo Finansów może ogłosić awaryjny tryb offline KSeF — wtedy faktury wystawia się bez połączenia z systemem MF. W takim przypadku na każdej fakturze PDF pojawia się specjalny kod QR podpisany kluczem ECDSA, który można zweryfikować bez dostępu do internetu.

Do obsługi trybu offline potrzebny jest oddzielny certyfikat offline — generujesz go tak samo jak certyfikat do logowania, ale w portalu KSeF wybierasz przeznaczenie „Offline". Wygenerowane pliki .crt i .key łączysz w jeden plik .pem:

# Certyfikat offline musi być ECDSA (EC P-256) — nie RSA
cat ksef_offline.key ksef_offline.crt > /etc/lms/ksef_offline.pem
chmod 640 /etc/lms/ksef_offline.pem

# Weryfikacja że to EC (a nie RSA):
openssl pkey -in /etc/lms/ksef_offline.pem -text -noout | grep "EC\|prime256"
# Oczekiwany wynik: id-ecPublicKey, prime256v1

Po wygenerowaniu pliku dodaj do lms.ini w sekcji [ksef]:

offline_certificate = /etc/lms/ksef_offline.pem
offline_password    =       # hasło do pliku .pem (zazwyczaj puste)
offline_support     = 1     # zezwól na wysyłkę e-mail faktur bez numeru KSeF
ℹ Certyfikat offline nie jest obowiązkowy Do samego wystawienia faktury w trybie offline certyfikat offline nie jest wymagany. Integracja może działać również bez niego. Certyfikat KSeF typu 2 jest potrzebny wtedy, gdy chcesz wygenerować dodatkowy kod QR potwierdzający tożsamość wystawcy przy fakturach wystawianych w trybach szczególnych, takich jak offline24, niedostępność KSeF lub tryb awaryjny. Jeżeli certyfikat nie jest używany, faktura może nadal zostać wystawiona w trybie offline, ale PDF nie będzie zawierał drugiego kodu QR związanego z certyfikatem.
ℹ Tryb offline nie dotyczy wyłącznie awarii po stronie KSeF Tryb offline nie jest zarezerwowany tylko dla awarii Ministerstwa Finansów lub samego KSeF. Może być użyty również wtedy, gdy problem występuje po stronie użytkownika, na przykład przy braku dostępu do Internetu, problemach z łączem lub niestabilnej transmisji danych. W praktyce oznacza to, że faktura offline może być potrzebna zarówno w przypadku niedostępności systemu KSeF, jak i wtedy, gdy wystawca chwilowo nie ma możliwości połączenia się z siecią.
⚠ Ważne rozróżnienie trybów specjalnych Należy odróżniać kilka sytuacji: To są różne sytuacje operacyjne i mogą wiązać się z różnymi zasadami dalszego przekazania dokumentu do KSeF.
⚠ Funkcja nie była testowana w rzeczywistych warunkach produkcyjnych Obsługa certyfikatu offline oraz wystawiania faktur w trybach offline została zaimplementowana zgodnie z aktualną dokumentacją techniczną Ministerstwa Finansów oraz w oparciu o rozwiązania zastosowane w LMS. Nie była jednak testowana w rzeczywistych warunkach wystąpienia niedostępności lub awarii KSeF, ponieważ takie scenariusze nie były dotąd możliwe do praktycznego zweryfikowania w normalnej pracy systemu. Z tego powodu funkcja została przygotowana zgodnie ze specyfikacją, ale w realnej sytuacji może wymagać dodatkowych korekt lub dopasowania do faktycznego sposobu działania usług MF.

Krok 2 Konfiguracja lms.ini

Edytuj swój plik lms.ini (zazwyczaj /etc/lms/lms.ini lub inna ścieżka podana przy instalacji LMS) i dodaj / uzupełnij poniższe sekcje. Pamiętaj, by we wszystkich komendach zamienić /sciezka/do/lms.ini na własną ścieżkę:

[phpui]
plugins = KSeFSubmit           # dodaj do istniejącej listy pluginów

[ksef]
environment    = prod          # prod / test / demo
auth_method    = certificate   # certificate (zalecane) lub token
certificate    = /etc/lms/ksef_cert.p12
password       = "TwojeHaslo123!"
boundary_date  = 2026/04/01    # data od której wysyłamy faktury
encryption_key = Wpisz32ZnakowyLosowyKluczAES256!
encryption_iv  = 16ZnakowIV1234
debug          = 0              # 1 = loguj plugin do PHP error_log, 0 = cisza

[invoices]
issuer            = 'Dział obsługi rozliczeń'        ; podpis wystawcy na fakturze PDF
show_balance_summary = 0                              ; 0 = nie pokazuj salda klienta na fakturze PDF (zalecane dla ISP)
show_pricing_method  = 0
info_box_text     = '<center><b>Informacja</b>\nFaktura wystawiona w KSeF.\nDokument w KSeF stanowi fakturę właściwą.\nPDF ma charakter informacyjny.</center>'
;                  ↑ ramka na fakturach B2B — obsługuje HTML, \n = nowa linia
info_box_text_b2c = '<center>Dziękujemy za korzystanie z naszych usług</center>'
;                  ↑ ramka na fakturach B2C — jeśli brak: używana info_box_text

[sendinvoices]            ; faktury B2B — firmy, klienci z NIPem
smtp_host             = poczta.twojadomena.pl     ; serwer SMTP
smtp_port             = 587                       ; 587=STARTTLS, 465=SSL, 25=plain
smtp_auth             = PLAIN                     ; PLAIN lub LOGIN
smtp_user             = nadawca@twojadomena.pl    ; login SMTP
smtp_pass             = "HasloDoSMTP!"            ; haslo SMTP
smtp_ssl_verify_peer  = 0                        ; 0 = nie weryfikuj certyfikatu SSL (webstorage itp.)
smtp_ssl_verify_peer_name = 0
smtp_ssl_allow_self_signed = 0
lms_url              = https://adres.twojego.lms/ ; URL do LMS (do linkow w mailach)
lms_user             = uzytkownik_lms            ; uzytkownik LMS do generowania PDF
lms_password         = "HasloUzytkownikaLMS!"
customergroups       = nazwa-grupy               ; grupy klientow do wysylki (spacja = separator)
sender_name          = Nazwa Twojej Firmy
sender_email         = biuro@twojadomena.pl
invoice_filename     = Faktura_%number           ; nazwa pliku PDF w zalacznik
mail_subject         = Faktura VAT %invoice
mail_body            = /etc/lms/mail_body_b2b.txt
mail_format          = html
; debug_email = twoj@email.pl  ; jesli ustawione — mail idzie TYLKO na ten adres (do testow)

[sendinvoices-b2c]        ; faktury B2C — osoby fizyczne
smtp_host             = poczta.twojadomena.pl
smtp_port             = 587
smtp_auth             = PLAIN
smtp_user             = nadawca@twojadomena.pl
smtp_pass             = "HasloDoSMTP!"
smtp_ssl_verify_peer  = 0
smtp_ssl_verify_peer_name = 0
smtp_ssl_allow_self_signed = 0
lms_url              = https://adres.twojego.lms/
lms_user             = uzytkownik_lms
lms_password         = "HasloUzytkownikaLMS!"
customergroups       = nazwa-grupy
sender_name          = Nazwa Twojej Firmy
sender_email         = biuro@twojadomena.pl
invoice_filename     = Faktura_%number
mail_subject         = Faktura %invoice
mail_body            = /etc/lms/mail_body_b2c.txt
mail_format          = html

Przykładowe pliki treści maili

Pliki wskazane w mail_body to szablony HTML. Zmienne dostępne w treści:

ZmiennaZnaczenie
%invoiceNumer faktury (np. FV/001/04/2026)
%ksef-numberNumer KSeF (np. 8441240447-20260401-...)
%grossKwota brutto faktury
%bankaccountNumer konta bankowego
%paytimeTermin płatności
%customeridID klienta w LMS

/etc/lms/mail_body_b2b.txt — dla firm (B2B):

Szanowni Państwo,<br><br>
informujemy, że została wystawiona faktura VAT nr <b>%invoice</b>.<br><br>
<b>Numer KSeF: </b> %ksef-number<br>
Faktura została wystawiona w KSeF.<br>
Dokument dostępny w KSeF stanowi fakturę właściwą.<br><br>
Załączony plik PDF ma charakter poglądowy.<br><br>
W razie pytań prosimy o kontakt.<br><br>
Z poważaniem,<br>
<b>Twoja Firma</b>

/etc/lms/mail_body_b2c.txt — dla osób fizycznych (B2C):

Szanowny Kliencie,<br><br>
w załączniku przesyłamy fakturę nr <b>%invoice</b>.<br><br>
Dziękujemy za korzystanie z naszych usług.<br><br>
Pozdrawiamy,<br>
<b>Twoja Firma</b>
ℹ info_box_text — ramka na fakturze PDF Opcje info_box_text i info_box_text_b2c w sekcji [invoices] to nasza modyfikacja LMSTcpdfInvoice.php — nie ma ich w standardowym LMS. Ramka pojawia się na fakturach PDF wystawionych po dacie granicznej KSeF (boundary_date). Dla faktur starszych — nie wyświetla się. Obsługuje HTML: <b>, <center>, <i> oraz \n jako nową linię. Jeśli ustawiona tylko info_box_text — pojawia się dla wszystkich klientów. Jeśli ustawione oba — info_box_text dla B2B (firmy), info_box_text_b2c dla B2C (osoby fizyczne).

Generowanie kluczy szyfrowania

# encryption_key — 32 znaki losowe
openssl rand -base64 24 | tr -d '=+/' | head -c 32

# encryption_iv — 16 znaków losowych
openssl rand -base64 12 | tr -d '=+/' | head -c 16

Krok 3 Instalacja — skrypt automatyczny

Paczka zawiera skrypt lms-npi.sh (NETLink Patch Installer) który zrobi wszystko automatycznie: skopiuje pliki, naniesie poprawki i zaktualizuje bazę danych. To jest zalecany sposób instalacji.

Krok po kroku

# 1. Wgraj paczkę na serwer i rozpakuj
unzip lms-ksef-netlink-*.zip -d /tmp/ksef-pack

# 2. Dry-run — podgląd co zrobi instalator (nic nie zmienia)
bash /tmp/ksef-pack/lms-npi.sh -c /etc/lms/lms.ini --dry-run

# 3. Właściwa instalacja
bash /tmp/ksef-pack/lms-npi.sh -c /etc/lms/lms.ini
✓ Co robi lms-npi.sh automatycznie
  1. Odczytuje katalog LMS i parametry bazy z lms.ini
  2. Backup katalogu LMS → /tmp/lms-backup-TIMESTAMP/lms-dir.tar.gz
  3. Backup bazy danych → /tmp/lms-backup-TIMESTAMP/lms-db.sql.gz (MySQL i PostgreSQL)
  4. Kopiuje pliki na właściwe miejsca — stary plik zostaje jako plik.bak
  5. Nanosi poprawkę na lib/KSeF/KSeF.php (separator dziesiętny)
  6. Wykrywa użytkownika serwera www i ustawia właściciela + uprawnienia plików

Opcje instalatora

bash lms-npi.sh -c /etc/lms/lms.ini                      # instalacja (z backupem)
bash lms-npi.sh -c /etc/lms/lms.ini --dry-run             # tylko podgląd, nic nie zmienia
bash lms-npi.sh -c /etc/lms/lms.ini --no-backup           # bez backupu katalogu i bazy
bash lms-npi.sh -c /etc/lms/lms.ini --no-backup-dir       # bez backupu katalogu LMS
bash lms-npi.sh -c /etc/lms/lms.ini --no-backup-db        # bez backupu bazy danych
Instalacja ręczna — dla zaawansowanych

Jeśli wolisz kopiować pliki samodzielnie, oto pełna lista:

lms/
├── lib/KSeF/
│ └── KSeF.php ← zastępuje oryginał
├── lib/LMSDocuments/
│ └── LMSTcpdfInvoice.php ← szablon PDF faktury
├── plugins/KSeFSubmit/ ← NOWY katalog
│ ├── KSeFSubmit.php
│ ├── handlers/
│ │ └── KSeFSubmitHandler.php
│ └── lib/
│ └── KSeFApiService.php
└── bin/
├── lms-ksef.php ← batch wysyłka (cron)
├── lms-ksef-download.php ← pobieranie faktur zakupowych
├── lms-ksef-sync.php ← jednorazowy sync historyczny
└── lms-ksef-bulk-correct.php
PACK=/tmp/ksef-pack      # katalog z rozpakowaną paczką
LMS=/twoja/sciezka/lms      # katalog instalacji LMS

cp $PACK/lib/KSeF/KSeF.php                        $LMS/lib/KSeF/KSeF.php
cp $PACK/lib/LMSDocuments/LMSTcpdfInvoice.php     $LMS/lib/LMSDocuments/LMSTcpdfInvoice.php

mkdir -p $LMS/plugins/KSeFSubmit/handlers $LMS/plugins/KSeFSubmit/lib
cp $PACK/plugins/KSeFSubmit/KSeFSubmit.php                 $LMS/plugins/KSeFSubmit/
cp $PACK/plugins/KSeFSubmit/handlers/KSeFSubmitHandler.php $LMS/plugins/KSeFSubmit/handlers/
cp $PACK/plugins/KSeFSubmit/lib/KSeFApiService.php         $LMS/plugins/KSeFSubmit/lib/

cp $PACK/bin/lms-ksef.php              $LMS/bin/
cp $PACK/bin/lms-ksef-download.php     $LMS/bin/
cp $PACK/bin/lms-ksef-sync.php         $LMS/bin/
cp $PACK/bin/lms-ksef-bulk-correct.php $LMS/bin/
chmod +x $LMS/bin/lms-ksef*.php
Zajrzyj pod maskę: Jak dokładnie działają poszczególne skrypty i pliki?

Jak działa lms-ksef.php?

Zasada działania: Skrypt szuka w bazie wszystkich faktur bez numeru KSeF wystawionych od boundary_date (ustawiane w lms.ini). Nie wie nic o miesiącach ani datach uruchomienia — patrzy tylko na tabelę ksefdocuments i pyta: "czy ta faktura ma już numer KSeF?". Jeśli nie — wysyła.

FAZA 1 — Status oczekujących sesji

Zawsze najpierw sprawdza czy są otwarte sesje batch (status 0 lub 100) i pobiera dla nich numery KSeF od MF. To jest ważne — jeśli poprzednie uruchomienie wysłało faktury ale nie zdążyło odebrać numerów (np. skrypt się wysypał), ta faza je nadrobi.

FAZA 2 — Zbieranie faktur

Zapytanie SQL szuka faktur gdzie:

  • d.cdate >= boundary_date (np. 2026-04-01)
  • d.type IN (DOC_INVOICE, DOC_CNOTE, DOC_DNOTE)
  • kd.id IS NULL — brak rekordu w ksefdocuments = jeszcze nie wysłana

Potem filtruje B2B/B2C — firmy zawsze, osoby fizyczne tylko gdy mają zgodę.

Scenariusze:

Wystawiasz faktury 1. dnia, uruchamiasz skrypt 5. dnia tego miesiąca:
Działa dokładnie tak samo jak gdybyś uruchomił 1. dnia. Skrypt znajdzie wszystkie faktury z kd.id IS NULL — czyli wszystkie które w międzyczasie nie zostały wysłane — i wyśle je w jednej sesji batch. Nic się nie traci.

Nie uruchamiasz 2 miesiące:
Skrypt znajdzie faktury z obu miesięcy naraz i wyśle je wszystkie w jednym przebiegu. Przykład: masz 200 faktur za marzec i 200 za kwiecień → skrypt wyśle 400 faktur w jednej lub kilku paczkach ZIP (max 50MB per paczka). Jedyne ograniczenie: MF ma limit sesji batch — ale przy 400 fakturach ISP to żaden problem.

Co jeśli skrypt uruchomisz dwa razy z rzędu:
Drugie uruchomienie nic nie zrobi. Faktury już mają rekordy w ksefdocuments → warunek kd.id IS NULL zwróci pustą listę → skrypt zakończy się komunikatem "Brak nowych faktur".

Co jeśli MF odrzuci fakturę (status 400):
Faktura trafia do ksefdocuments ze statusem 400. Kolejne normalne uruchomienie jej nie ruszy — bo kd.id IS NULL już nie jest prawdą. Żeby ponownie wysłać — trzeba użyć flagi: --retry-errors:
./lms-ksef.php -C /sciezka/do/lms.ini --retry-errors

Co jeśli skrypt padnie w połowie wysyłki:
FAZA 1 przy następnym uruchomieniu sprawdzi otwarte sesje i odbierze numery KSeF dla tego co zdążyło dotrzeć do MF. Faktury które nie zostały w ogóle wysłane — mają nadal kd.id IS NULL i wejdą w kolejnym uruchomieniu.

--status-only (w cronie co godzinę):
Wykonuje tylko FAZĘ 1 — sprawdza otwarte sesje i odbiera numery KSeF. Nie wysyła nic nowego. Używaj tego w cronie między 1. a ostatnim dniem miesiąca, żeby faktury dostały numery KSeF szybciej niż czekając na kolejne miesięczne uruchomienie.

Podsumowanie jednym zdaniem:
Skrypt jest idempotentny i bezpieczny do wielokrotnego uruchamiania — zawsze wysyła tylko to czego jeszcze nie ma w KSeF, nigdy dwa razy to samo.

lms-ksef-download.php

Co robi: pobiera faktury które dostawcy wystawili NA Twój NIP i wrzucili do KSeF. To są Twoje faktury zakupowe — Shell, Orange, Allegro itp.

Opcje uruchomienia:

  • brak parametrów → pobiera wczoraj + dziś (overlap żeby nic nie pominąć)
  • --from=2026/04/01 → od konkretnej daty
  • --days=7 → ostatnie N dni
  • --full-sync → od boundary_date do dziś (pierwsze uruchomienie)

Jak działa krok po kroku:

  1. Wyznacza zakres dat i dzieli go na okresy max 3-miesięczne (limit API MF).
  2. Dla każdego oddziału z NIPem buduje klienta API.
  3. Odpytuje MF o listę faktur (POST /invoices/query/metadata) z paginacją po 100 sztuk — powtarza dopóki hasMore = true.
  4. Dla każdej faktury z listy sprawdza czy ksef_number już jest w bazie — jeśli tak, pomija.
  5. Dla każdej nowej faktury pobiera XML z adaptive delay (im szerszy zakres dat, tym dłuższa pauza między zapytaniami):
    • zakres ≤ 3 dni → 700ms (cron codzienny)
    • ≤ 30 dni → 3s
    • ≤ 90 dni → 7s
    • powyżej 90 dni → 10s
  6. Parsuje XML — wyciąga numer konta, termin płatności, formę płatności.
  7. Zapisuje rekord do ksefinvoices i plik XML na dysk.
  8. Na końcu uruchamia fillMissingXml() — dla faktur które dostały 429 przy pierwszym pobraniu i nie mają XML, próbuje jeszcze raz.

Idempotentny? Tak — sprawdza ksef_number w bazie, nigdy nie zapisze dwa razy tej samej faktury.
Przy 429: czyta Retry-After z odpowiedzi MF, czeka tyle ile MF każe + bufor, zwiększa globalny odstęp do minimum 5s na kolejne zapytania.

lms-ksef-sync.php

Co robi: to samo co download.php ale innym mechanizmem — przez Export API. Zamiast pobierać faktury jedna po drugiej (64 zapytania/h), prosi MF o spakowanie wszystkiego do jednego zaszyfrowanego ZIPa.

Kiedy używać: jednorazowo — do nadrobienia zaległości historycznych. Do crona codziennego używaj lms-ksef-download.php.

Jak działa krok po kroku:

  1. Dzieli zakres dat na okresy max 3-miesięczne.
  2. Dla każdego okresu: POST /invoices/exports → MF zaczyna pakować faktury asynchronicznie.
  3. Polling co 15 sekund (GET /invoices/exports/{ref}) aż MF powie że gotowe (status 200).
  4. Pobiera zaszyfrowany plik .zip.aes.
  5. Odszyfrowuje AES-256-CBC kluczem z lms.ini (encryption_key, encryption_iv).
  6. Rozpakowuje ZIP — w środku są pliki XML + _metadata.json (pomijany).
  7. Każdy XML parsuje i zapisuje do bazy identycznie jak lms-ksef-download.php.

Zaleta: brak throttlingu — zamiast setek pojedynczych zapytań MF pakuje wszystko do jednego zaszyfrowanego ZIPa (AES-256-CBC). Skrypt odszyfrowuje go kluczami z lms.ini (encryption_key + encryption_iv) i przetwarza wszystkie faktury lokalnie.

Plugin KSeFSubmit (GUI)

Aktywacja w lms.ini: plugin wymaga wpisu w sekcji [phpui]:

[phpui]
plugins = KSeFSubmit           ; dodaj do istniejącej listy pluginów

Aktywacja w GUI LMS: po wpisaniu do lms.ini przejdź do Administracja → Konfiguracja → KSeF — pojawi się zakładka konfiguracji pluginu. Poniżej widok przycisku wysyłki na fakturze:

Przycisk KSeF na fakturze w GUI LMS

Co robi: wysyła fakturę do KSeF natychmiast po zapisaniu jej w GUI — bez czekania na cron 1. dnia miesiąca. Klikasz "Zapisz fakturę" → w ciągu kilku sekund masz numer KSeF.

Jak jest zbudowany:

  • KSeFSubmit.php — rejestruje plugin i hooki
  • KSeFSubmitHandler.php — łapie zdarzenia z GUI
  • KSeFApiService.php — komunikacja z API

Które zdarzenia łapie: invoicenew_save_after_submit (nowa faktura), invoiceedit_save_after_submit (edycja faktury), invoicenote_save_after_submit (faktura korygująca).

Jak działa krok po kroku:

  1. Po zapisaniu faktury LMS wywołuje hook.
  2. Handler sprawdza: czy faktura jest po boundary_date? Czy to nie proforma? Czy klient B2B albo ma zgodę B2C? Czy KSeF jest dostępny (Latarnia)?
  3. Jeśli OK — wywołuje DB->UnLockTables() (faktura już zapisana, unlock bezpieczny).
  4. Sprawdza czy faktura nie była już wysłana (ksefdocuments).
  5. Pobiera pełne dane faktury przez GetInvoiceContent().
  6. Generuje XML przez KSeF::getInvoiceXml().
  7. Wysyła XML przez Batch APIsessions()->batch()->openAndSend().
  8. Zamyka sesję batch — sessions()->batch()->close() — wymagane żeby MF zaczął przetwarzać fakturę.
  9. Zapisuje sesję do ksefbatchsessions i fakturę do ksefdocuments (status 0 = oczekuje).
  10. Polling co 3 sekundy, max 15 prób (~45s) — sprawdza status sesji przez sessions()->status().
  11. Po otrzymaniu kodu 200 — pobiera UPO z URL z odpowiedzi MF, parsuje XML, wyciąga numer KSeF i zapisuje UPO na dysk.

Zarówno plugin jak i lms-ksef.php używają Batch API — plugin wysyła jedną fakturę na sesję, CLI może wysłać wiele faktur naraz.
Co jeśli plugin nie zdąży w 45s (MF wolno przetwarza): faktura zostaje w ksefdocuments ze statusem 0. FAZA 1 w lms-ksef.php --status-only odbierze numer i UPO przy kolejnym uruchomieniu crona.

Poprawki w lib/KSeF/KSeF.php

Plik lib/KSeF/KSeF.php jest dostarczany w paczce z nałożoną poprawką P1. Przy każdej aktualizacji LMS przez git pull plik jest nadpisywany — dlatego w paczce jest skrypt bin/patch-netlink.py, który automatycznie nanosi poprawkę ponownie. Instalator uruchamia go automatycznie jako KROK 4.

P1 — setlocale(LC_NUMERIC, 'C')

LMS przestawia separator dziesiętny na przecinek (locale pl_PL). KSeF wymaga kropki w XML — bez tej poprawki pola P_13_*, P_14_*, P_15 (podstawy VAT, kwoty VAT, suma) generowane przez sprintf('%.2f', ...) zawierają przecinki i MF odrzuca fakturę.

⚠ smartFormatNumber (od 22.04.2026) to NIE jest pełna zastępnia P1 Chilek dodał smartFormatNumber() z NumberFormatter('en_US'), ale używa go tylko dla ilości, cen jednostkowych i kursu waluty. Pola sum i podatków (P_13_*, P_14_*, P_15) nadal używają sprintf('%.2f', ...) — czyli są nadal wrażliwe na locale. Poprawka P1 (setlocale) jest nadal wymagana.
# Co robi poprawka P1:
public function getInvoiceXml(array $invoice)
{
    setlocale(LC_NUMERIC, 'C'); // NETLink P1
    ...
✓ P2 — ksef_balance_in_xml — nie jest już potrzebna Od wersji 13.04.2026 Chilek wprowadził własny mechanizm obsługi sekcji <Rozliczenie> przez tabelę ksefconfig i GUI LMS. Saldo klienta pojawia się tylko wtedy, gdy w konfiguracji oddziału w GUI LMS jest zaznaczony odpowiedni checkbox (showbalancesummary). Domyślnie jest wyłączone — co jest poprawnym zachowaniem. Zgodnie ze schematem FA(3) sekcja <Rozliczenie> ma minOccurs="0" — jest opcjonalna i MF jej nie wymaga.

Saldo na fakturze — jak skonfigurować?

Jeśli chcesz żeby faktury PDF i XML zawierały saldo klienta (sekcja <Rozliczenie>) — skonfiguruj to w GUI LMS:

Administracja → Konfiguracja → KSeF → Ustawienia oddziałów → Pokazuj rozliczenie salda

⚠ Nie dodawaj ksef_balance_in_xml do lms.ini Ta opcja nie istnieje w aktualnej wersji — jest ignorowana. Saldo sterowane jest wyłącznie przez GUI LMS.

Krok 4 Po instalacji — weryfikacja

Sprawdź czy patche zostały poprawnie nałożone:

# Uruchom z katalogu LMS
cd /twoja/sciezka/lms && bash bin/check-netlink-patches.sh
⚠ Co musisz zrobić ręcznie po instalacji
  1. Dodaj sekcję [ksef] do lms.ini ze środowiskiem (jeśli jeszcze nie ma): environment = prod
  2. Sprawdź tabelę ksefconfig — jeśli pusta, wstaw rekord (patrz sekcja Historia zmian → 18.04.2026)
  3. Jeśli używasz Composera w LMS: cd /twoja/sciezka/lms && composer dump-autoload

UPO — Urzędowe Poświadczenie Odbioru

UPO to dokument XML wystawiony przez MF potwierdzający że faktura przeszła walidację i została przyjęta przez KSeF. MF przechowuje UPO przez 10 lat — możesz je pobrać w każdej chwili, nie ma pośpiechu.

✓ Automatyczne zbieranie UPO przez lms-ksef.php Od wersji 2026-04-09 skrypt lms-ksef.php automatycznie zapisuje UPO na dysk podczas pobierania statusów sesji wsadowych. Pliki lądują w:
{sys_dir}/storage/ksef/upo/{NIP}/{YYYYMMDD}/{numerKSeF}.xml
⚠ Wymagany katalog UPO Katalog jest tworzony automatycznie przez upgradedb.php Chilka. Jeśli jest pusty lub go brakuje — sprawdź i utwórz ręcznie:
ls -la /twoja/sciezka/lms/storage/ksef/
# Powinno byc: drwxr-xr-x apache apache ... upo

# Jesli brak:
mkdir -p /twoja/sciezka/lms/storage/ksef/upo
chown apache:apache /twoja/sciezka/lms/storage/ksef/upo
chmod 750 /twoja/sciezka/lms/storage/ksef/upo

Plugin GUI (KSeFSubmit) od wersji 17.04.2026 fix3 pobiera i zapisuje UPO automatycznie — razem z numerem KSeF, w tym samym żądaniu HTTP co wysyłka faktury. UPO trafia do tego samego katalogu co przy wysyłce przez CLI:
{sys_dir}/storage/ksef/upo/{NIP}/{YYYYMMDD}/{numerKSeF}.xml
Jeśli plugin nie zdążył pobrać UPO (timeout 45s) — lms-ksef.php --status-only pobierze je automatycznie przy kolejnym uruchomieniu crona.

Krok 5 Sync historycznych faktur zakupowych

Pierwsze uruchomienie — pobierz wszystkie faktury które wystawcy przesłali do KSeF na Twój NIP. Skrypt używa Export API (jeden zaszyfrowany ZIP zamiast setek osobnych zapytań):

cd /twoja/twoja/sciezka/lms/bin

# Najpierw dry-run — sprawdź ile faktur zostanie pobranych
./lms-ksef-sync.php -C /sciezka/do/lms.ini --from=2026/01/01 --dry-run

# Właściwy sync (zakres maksymalnie 3 miesiące, podziel jeśli większy)
./lms-ksef-sync.php -C /sciezka/do/lms.ini --from=2026/01/01 --to=2026/03/31
./lms-ksef-sync.php -C /sciezka/do/lms.ini --from=2026/04/01
ℹ Skrypt czeka kilkanaście sekund MF przetwarza eksport asynchronicznie — skrypt odpytuje co 15 sekund aż eksport będzie gotowy, potem pobiera i rozpakowuje zaszyfrowany ZIP. Przy kilkudziesięciu fakturach trwa ok. 30 sekund.

Wysyłka historycznych faktur sprzedaży do KSeF

# Dry-run — sprawdź ile faktur do wysłania
./lms-ksef.php -C /sciezka/do/lms.ini --dry-run

# Właściwa wysyłka
./lms-ksef.php -C /sciezka/do/lms.ini

Krok 6 Konfiguracja Cron

Zamień /twoja/sciezka/lms i /sciezka/do/lms.ini na własne ścieżki.

ℹ Kiedy wystawiasz faktury — to zależy od Ciebie Skrypty nie wiedzą nic o miesiącach ani dniach — szukają wszystkich faktur bez numeru KSeF i je wysyłają. Możesz generować faktury i uruchamiać lms-ksef.php kiedy chcesz — 1. dnia, 5. dnia, codziennie. To wynika z Twojej konfiguracji taryf w LMS, nie ze skryptów.

Wariant A — faktury generowane 1. dnia miesiąca

Klasyczny model: LMS generuje faktury 1. dnia, skrypty wysyłają je do KSeF i e-mailem tego samego dnia. Ważne: lms-ksef.php startuje 20 minut po generowaniu — żeby faktury były już gotowe w bazie.

# crontab -e

# Generowanie faktur i płatności — 1. dnia o 02:00
 0  2 1 * *  /twoja/sciezka/lms/bin/lms-payments.php -C /sciezka/do/lms.ini

# Wysyłka do KSeF — 20 minut po generowaniu
20  2 1 * *  php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini >> /var/log/lms-ksef.log 2>&1

# Wysyłka e-mail B2B (tylko faktury z numerem KSeF)
40  2 1 * *  /twoja/sciezka/lms/bin/lms-sendinvoices.php -C /sciezka/do/lms.ini --ksef

# Wysyłka e-mail B2C (osoby fizyczne — nie wymagają KSeF)
45  2 1 * *  /twoja/sciezka/lms/bin/lms-sendinvoices.php -C /sciezka/do/lms.ini --without-ksef --section=sendinvoices-b2c

# Sprawdzanie statusów KSeF co godzinę (przez cały miesiąc)
 0  * * * *  php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini --status-only >> /var/log/lms-ksef.log 2>&1

# Pobieranie faktur zakupowych od dostawców — codziennie o 06:15
15  6 * * *  php /twoja/sciezka/lms/bin/lms-ksef-download.php -C /sciezka/do/lms.ini -q >> /var/log/lms-ksef-download.log 2>&1

Wariant B — faktury generowane codziennie (różne dni dla różnych klientów)

Jeśli Twoi klienci mają zobowiązania rozłożone na różne dni miesiąca, lms-payments.php generuje faktury codziennie tylko dla tych którzy mają zobowiązanie na dany dzień. Wtedy warto też codziennie wysyłać do KSeF:

# Generowanie faktur — codziennie o 02:00
 0  2 * * *  /twoja/sciezka/lms/bin/lms-payments.php -C /sciezka/do/lms.ini

# Wysyłka do KSeF — 20 min po generowaniu, codziennie
20  2 * * *  php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini >> /var/log/lms-ksef.log 2>&1

# Wysyłka e-mail B2B
40  2 * * *  /twoja/sciezka/lms/bin/lms-sendinvoices.php -C /sciezka/do/lms.ini --ksef

# Wysyłka e-mail B2C
45  2 * * *  /twoja/sciezka/lms/bin/lms-sendinvoices.php -C /sciezka/do/lms.ini --without-ksef --section=sendinvoices-b2c

# Sprawdzanie statusów KSeF co godzinę
 0  * * * *  php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini --status-only >> /var/log/lms-ksef.log 2>&1

# Pobieranie faktur zakupowych — codziennie
15  6 * * *  php /twoja/sciezka/lms/bin/lms-ksef-download.php -C /sciezka/do/lms.ini -q >> /var/log/lms-ksef-download.log 2>&1
⚠ Ważna kolejność: generowanie → KSeF → e-mail lms-payments.php generuje faktury w LMS.
lms-ksef.php wysyła je do KSeF (uruchom minimum 20 minut po generowaniu).
lms-sendinvoices.php --ksef wysyła e-maile tylko fakturom z numerem KSeF — musi startować po lms-ksef.php.

Jeśli MF przetwarza wolno — cron --status-only (co godzinę) odbierze numery automatycznie. E-mail pójdzie przy następnym uruchomieniu lms-sendinvoices.php.

Wariant C — bez crona (ręczne uruchamianie)

Możesz uruchamiać wszystkie skrypty ręcznie kiedy chcesz — cron tylko to automatyzuje:

php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini --dry-run  # sprawdź ile faktur czeka
php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini             # wyślij do KSeF
php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini --status-only # odbierz numery
/twoja/sciezka/lms/bin/lms-sendinvoices.php -C /sciezka/do/lms.ini --ksef  # wyślij e-maile
lms-payments.phpGeneruje faktury w LMS na dany dzień (wg taryf)zależy od taryf
lms-ksef.phpWysyła faktury do KSeF, odbiera numery KSeFpo generowaniu
lms-ksef.php --status-onlySprawdza statusy i odbiera numery KSeF dla oczekującychco godzinę
lms-sendinvoices.php --ksefWysyła e-mail z PDF do B2B (tylko z numerem KSeF)po wysyłce do KSeF
lms-sendinvoices.php --without-ksefWysyła e-mail z PDF do B2C (osoby fizyczne)po generowaniu
lms-ksef-download.phpPobiera faktury zakupowe od dostawcówcodziennie

Szablony e-mail

/sciezka/do/mail_body_b2b.txt — dla firm (B2B)

Szanowni Państwo,<br>
<br>
w załączniku faktura VAT <b>%invoice</b>.<br>
Numer KSeF: <b>%ksef-number</b><br>
Kwota do zapłaty: <b>%value PLN</b><br>
Numer konta: %bankaccount<br>
<br>
Z poważaniem

/sciezka/do/mail_body_b2c.txt — dla osób fizycznych (B2C)

Szanowny Kliencie,<br>
<br>
w załączniku faktura <b>%invoice</b>.<br>
Kwota do zapłaty: <b>%value PLN</b><br>
Numer konta: %bankaccount<br>
<br>
Dziękujemy!
ZmiennaZnaczenie
%invoiceNumer faktury (np. LMS_001/04/2026)
%ksef-numberNumer KSeF (po potwierdzeniu przez MF)
%valueKwota brutto
%bankaccountNumer konta bankowego
%customeridID klienta w LMS
%pinPIN klienta

Test generowania XML

Przed wysyłką do KSeF warto sprawdzić czy XML faktury wygląda poprawnie. Skrypt gen-xml.php generuje XML bez wysyłki:

cd /twoja/sciezka/lms
php bin/gen-xml.php -C /sciezka/do/lms.ini ID_FAKTURY

# XML zapisywany jest do /tmp/ID_FAKTURY.xml
cat /tmp/ID_FAKTURY.xml

Sprawdź w wygenerowanym XML:

Awarie KSeF i tryb offline

KSeF bywa niedostępny — czy to przez kilka godzin, czy przez kilka dni. Skrypty są zaprojektowane tak, żeby nic nie ginęło i żebyś nie musiał robić niczego ręcznie w większości przypadków.

Scenariusz 1 — KSeF chwilowo nie odpowiada (kilka godzin)

Co się dzieje automatycznie: skrypty przed wysyłką sprawdzają dostępność KSeF przez oficjalny endpoint MF (tzw. Latarnia). Jeśli KSeF nie działa — skrypt kończy pracę z komunikatem i faktury czekają w kolejce.

Co Ty robisz: nic. Po powrocie MF cron automatycznie wyśle wszystkie zaległe faktury i odbierze numery KSeF. Możesz też uruchomić ręcznie:

# Sprawdź ile faktur czeka
php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini --dry-run

# Wyślij zaległe i odbierz numery KSeF
php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini

Scenariusz 2 — MF ogłasza oficjalny tryb offline

Czasem Ministerstwo Finansów oficjalnie ogłasza tryb offline — oznacza to, że faktury można wystawiać bez wysyłania ich do KSeF, a po powrocie systemu masz kilka dni na uzupełnienie. W tym czasie:

# Wyślij e-mailem faktury które czekają na numer KSeF (tryb offline MF)
/twoja/sciezka/lms/bin/lms-sendinvoices.php -C /sciezka/do/lms.ini --ksef-offline

Jeśli masz skonfigurowany certyfikat offline — na fakturach PDF pojawi się specjalny kod QR podpisany Twoim kluczem ECDSA, który można zweryfikować bez internetu. Po powrocie KSeF wystarczy uruchomić lms-ksef.php — skrypt sam wyśle zaległe faktury.

ℹ Skąd wiedzieć że MF ogłosiło tryb offline? Oficjalne komunikaty pojawiają się na stronie ksef.podatki.gov.pl. Nasze skrypty sprawdzają dostępność automatycznie przed każdą wysyłką — przez tzw. Latarnię KSeF.

Co to jest Latarnia KSeF?

Latarnia (ang. lighthouse) to oficjalny publiczny endpoint Ministerstwa Finansów, który informuje o aktualnym stanie systemu KSeF. Nie wymaga logowania ani certyfikatu — każdy może go odpytać.

Nasze skrypty pytają Latarnię przed każdą próbą wysyłki faktur. Jeśli KSeF jest niedostępny — skrypt nie próbuje wysyłać, tylko loguje informację i kończy pracę. Faktury czekają bezpiecznie w bazie. Przy kolejnym uruchomieniu crona (lub ręcznym) — procedura powtarza się.

Możliwe stany Latarni:

StatusZnaczenieCo robi skrypt
Available KSeF działa normalnie Wysyła faktury
Planned_Maintenance Planowana przerwa techniczna Przerywa — cron nadrobi później
Unavailable Awaria nieplanowana Przerywa — cron nadrobi później
Error Błąd systemu MF Przerywa — cron nadrobi później
brak odpowiedzi Latarnia sama niedostępna (problem sieciowy) Próbuje wysyłać — jeśli KSeF też nie odpowie, obsługuje błąd normalnie
✓ Nie musisz nic robić przy awarii W każdym scenariuszu awaryjnym faktury są bezpieczne w bazie danych LMS. Skrypt nigdy nie zgubi faktury — albo wysyła, albo zostawia do następnej próby. Jedyna sytuacja wymagająca Twojej interwencji to faktura odrzucona przez KSeF z powodu błędnych danych (status 400).

Scenariusz 3 — Faktura odrzucona przez KSeF (błąd danych)

Jeśli MF odrzuci fakturę (np. brakujący NIP, błędna stawka VAT) — faktura trafia do bazy ze statusem błędu. Nie zniknie i nie zostanie wysłana ponownie automatycznie — musisz to naprawić ręcznie:

# Sprawdź które faktury mają błąd (w bazie danych)
SELECT d.fullnumber, kd.status, kd.statusdescription
FROM ksefdocuments kd
JOIN documents d ON d.id = kd.docid
WHERE kd.status >= 400
ORDER BY d.cdate DESC;

# Po poprawieniu danych klienta/faktury — ponów wysyłkę
php /twoja/sciezka/lms/bin/lms-ksef.php -C /sciezka/do/lms.ini --retry-errors

Tabela typowych problemów

SytuacjaRozwiązanie
Faktury wysłane, brak numerów KSeF (status 100) Poczekaj — cron --status-only odpytuje co godzinę. Lub ręcznie: lms-ksef.php --status-only
Faktury z błędem (status 400) Popraw dane klienta/faktury, potem: lms-ksef.php --retry-errors
Błąd 429 Too Many Requests MF limit zapytań na godzinę. Odczekaj. Do historycznego sync używaj lms-ksef-sync.php
Kwoty w XML z przecinkami (KSeF odrzuca) Brak poprawki P1. Uruchom: python3 bin/patch-netlink.py /twoja/sciezka/lms
Uwaga: smartFormatNumber w KSeF.php od 22.04.2026 nie zastępuje P1 — pola P_13_*/P_14_*/P_15 nadal używają sprintf i są wrażliwe na locale.
Błędna kwota w KSeF (niedopłata) Sprawdź ustawienia oddziału w GUI LMS (ksefconfig.showbalancesummary). Korekty: lms-ksef-bulk-correct.php --dry-run
Błąd certyfikatu openssl pkcs12 -in /etc/lms/ksef_cert.p12 -info — sprawdź ważność i hasło
Faktury sprzed boundary_date mają "BRAK NUMERU KSEF" na PDF Tabela ksefconfig ma boundarydate=0. Napraw SQL:
MySQL: UPDATE ksefconfig SET boundarydate=UNIX_TIMESTAMP('2026-04-01') WHERE boundarydate=0 OR boundarydate IS NULL;
PostgreSQL: UPDATE ksefconfig SET boundarydate=1775001600 WHERE boundarydate=0 OR boundarydate IS NULL;
Lub uruchom instalator ponownie — uzupełni automatycznie.
Po git pull przestały działać faktury lub KSeF REPO MASTER mógł zmienić lib/KSeF/KSeF.php — nasze poprawki P1/P2 znikają po każdej aktualizacji. Zawsze po git pull uruchom ponownie instalator:
bash /tmp/ksef-pack/lms-npi.sh -c /etc/lms/lms.ini
rm -rf /sciezka/lms/templates_c/*
Plugin wysyła fakturę ale timeout 45s — brak numeru KSeF w GUI, pojawia się dopiero po --status-only Najprawdopodobniej update biblioteki n1ebieski/ksef-php-client ze starszej wersji na v1.x — w v1.x kod statusu sesji jest w statusData->status->code, a starsze wersje używały statusData->processingCode. Plugin czyta zawsze null, polling nigdy nie widzi kodu 200, odpada timeoutem. Faktura i tak trafia do KSeF — tylko numer KSeF i UPO nie wróciły do GUI od razu.
Fix: zainstaluj paczkę 17.04.2026 fix3 lub nowszą — poprawka jest już w KSeFApiService.php.
Instalator wychodzi bez żadnego komunikatu Uruchamiasz sam plik .sh bez reszty paczki — brak version.txt obok skryptu. Zawsze rozpakowuj całą paczkę:
unzip lms-ksef-netlink-*.zip -d /tmp/ksef-pack
bash /tmp/ksef-pack/lms-npi.sh -c /etc/lms/lms.ini --dry-run
Instalator: configparser.ParsingError lub Brak nazwy bazy Stara wersja instalatora (przed v2026-04-09). Pobierz aktualną paczkę — nowy instalator czyta lms.ini przez grep, odporny na wieloliniowe wartości takie jak mail_body w sekcji [sendinvoices].
Instalator: Nie znaleziono katalogu LMS Skrypt nie może znaleźć katalogu LMS. Sprawdź czy w lms.ini jest:
[directories]
sys_dir = /sciezka/do/lms
check-netlink-patches.sh: BRAK P2 Stary checker z wersji przed 13.04.2026. Wgraj aktualną paczkę — nowy checker sprawdza showbalancesummary
lib/KSeF/KSeF.php lokalnie zmodyfikowany — instalator pomija, P1 nie jest naniesiona Instalator celowo nie nadpisuje plików zmienionych lokalnie. Po instalacji uruchom patcher który bezpiecznie naniesie tylko brakujące poprawki:
python3 /twoja/sciezka/lms/bin/patch-netlink.py /twoja/sciezka/lms
bash /twoja/sciezka/lms/bin/check-netlink-patches.sh
lib/LMSDocuments/LMSTcpdfInvoice.php lokalnie zmodyfikowany — instalator pomija, stary plik bez naszych zmian Sprawdź czy plik ma nasze modyfikacje:
grep -c "info_box_text" /twoja/sciezka/lms/lib/LMSDocuments/LMSTcpdfInvoice.php
Wynik 0 = stary plik, skopiuj ręcznie z paczki:
cp /tmp/ksef-pack/lib/LMSDocuments/LMSTcpdfInvoice.php /twoja/sciezka/lms/lib/LMSDocuments/

Historia zmian

30.04.2026

28.04.2026

24.04.2026

22.04.2026

21.04.2026

18.04.2026

Wymagane po instalacji — tabela ksefconfig

Jeśli tabela ksefconfig jest pusta, filtry KSeF w GUI LMS nie działają poprawnie. Wstaw rekord dla każdej dywizji (sprawdź ID w Ustawienia → Oddziały).

MySQL:

INSERT INTO ksefconfig (divisionid, delay, allconsumers, boundarydate, showbalancesummary, xmladdallvalues)
VALUES (1, 0, 0, UNIX_TIMESTAMP('2026-04-01'), 0, 0);

PostgreSQL:

INSERT INTO ksefconfig (divisionid, delay, allconsumers, boundarydate, showbalancesummary, xmladdallvalues)
VALUES (1, 0, 0, EXTRACT(EPOCH FROM TIMESTAMP '2026-04-01')::bigint, 0, 0);

Zmień divisionid = 1 jeśli masz inny ID dywizji. Jeśli masz więcej dywizji — wstaw wiersz dla każdej.

17.04.2026

Pobieranie plików

Pobierz wymagane paczki do prawidłowej instalacji i integracji:

Aktualna wersja: 30.04.2026
Merge z master 30.04:

Aktualizacja LMS z repo Chilka + ponowne nałożenie NETLink

Jeśli LMS jest zainstalowany z repo git, zwykły git pull często się burzy gdy masz lokalne zmiany (a masz — pliki NETLink). Poniższe komendy wymuszają czystą synchronizację z repo, a potem przywracają NETLink jednym poleceniem.

1. Wejdź do katalogu LMS i wymuś aktualizację do najnowszego repo:

cd /home/lms
git fetch --all
git reset --hard origin/master

2. Pobierz aktualną paczkę NETLink i uruchom instalator:

cd /tmp
wget -O lms-ksef-netlink-30042026.zip "https://ksef2lms.idzik.pl/?track=lms-ksef-netlink-30042026.zip"
unzip -o lms-ksef-netlink-30042026.zip -d ksef-pack
bash ksef-pack/lms-npi.sh -c /etc/lms/lms.ini

Co zostaje nieruszone przez git reset: Twoje własne pluginy i pliki których Chilek nie ma w repo (np. własny plugin SMS, moduły, szablony) — git ich nie widzi i nie tknie. Pliki NETLink zostaną nadpisane przez git, ale lms-npi.sh je przywróci w kroku 2.

⚠ Uwaga: Jeśli masz własne modyfikacje w plikach które są częścią repo Chilka (np. zmiany w szablonach, modułach LMS-a), git reset --hard usunie je bezpowrotnie. W takim przypadku nie używaj tych poleceń dosłownie — dostosuj je do swoich potrzeb (np. zrób wcześniej git stash albo ręcznie skopiuj zmienione pliki przed resetem).

Instalacja krok po kroku — instalacja manualna z paczki ZIP (bez git)

Dla tych którzy nie mają LMS-a z repo git — pobierają ZIP z oryginalnego repozytorium Chilka i wgrywają ręcznie. Wejdź SSH na serwer i wykonaj kolejno:

1. Pobierz obie paczki na serwer (podmień datę jeśli inna):

cd /tmp
wget -O lms-master-30042026.zip "https://ksef2lms.idzik.pl/?track=lms-master-30042026.zip"
wget -O lms-ksef-netlink-30042026.zip "https://ksef2lms.idzik.pl/?track=lms-ksef-netlink-30042026.zip"

2. Rozpakuj LMS-master i zaktualizuj pliki LMS (zamień /ścieżka/do/katalogu/lms na właściwą):

unzip -q lms-master-30042026.zip -d /tmp/lms-src
rsync -a /tmp/lms-src/lms-master/ /ścieżka/do/katalogu/lms/

3. Rozpakuj paczkę z poprawkami NETLink i uruchom instalator:

unzip -q lms-ksef-netlink-30042026.zip -d /tmp/ksef-pack
bash /tmp/ksef-pack/lms-npi.sh -c /etc/lms/lms.ini

Jeśli chcesz najpierw zobaczyć co zostanie zrobione (bez żadnych zmian):

bash /tmp/ksef-pack/lms-npi.sh -c /etc/lms/lms.ini --dry-run

Instalator sam odczyta katalog LMS z lms.ini, wykryje użytkownika Apache, skopiuje pliki (z backupem .bak) i nałoży patche na KSeF.php.

▸ Archiwum wcześniejszych wersji (10)
Data LMS-MASTER NETLink pack Zmiany
28.04.2026 lms-master-28042026.zip lms-ksef-netlink-28042026.zip Merge z master 28.04:
24.04.2026 lms-master-24042026.zip lms-ksef-netlink-24042026.zip Merge z master 24.04: KSeF.php — P_18A bazuje na DOC_FLAG_SPLIT_PAYMENT (bugfix Chilka). Latarnia pomijana na demo/test. Fix XSD JST: Podmiot3 nie generuje BrakID gdy brak NIP odbiorcy.
22.04.2026 lms-master-22042026.zip lms-ksef-netlink-22042026.zip Merge z master 22.04: KSeF.php — GROUPING_USED=false (fix separatora tysięcy w XML), KodKraju z bazy countries, lms-sendinvoices.php part=auto, bugfixy LMSEventManager/numberplanedit.
21.04.2026 lms-master-21042026.zip lms-ksef-netlink-21042026.zip Merge z master 21.04: smartFormatNumber (KSeF.php) + zachowany setlocale patch P1. lms-master-update-21042026.zip zawiera tylko 12 zmienionych plików (delta, nie pełny master).
18.04.2026 lms-master-18042026.zip lms-ksef-netlink-18042026.zip Faktura korygująca (plugin + bulk). PostgreSQL. lms-ksef.php: --from-date, TOTAL_FAILURE, czystszy log. Instrukcja INSERT ksefconfig.
17.04.2026 lms-master-17042026.zip lms-ksef-netlink-17042026.zip REPO MASTER 17.04. Plugin KSeFSubmit przepisany na Batch API. Migracja ksefallconsumers→ksefconfig.
15.04.2026 lms-master-15042026.zip lms-ksef-netlink-15042026.zip Chilek: bugfix pustego adresu w XML (AdresL1/AdresL2), bugfix INSERT ksefconfig.
14.04.2026 lms-master-14042026.zip lms-ksef-netlink-14042026.zip Chilek: xmladdallvalues (P_11/P_11A), bugfix ksefshowbalancesummary, lms-notify.
13.04.2026 lms-master-13042026.zip lms-ksef-netlink-13042026.zip KSeF.php: nowe Rozliczenie, NazwaBanku. Poprawka fill-xml po 429. P2 wycofana.
11.04.2026 lms-master-11042026.zip lms-ksef-netlink-11042026.zip Pierwsza publiczna wersja. UPO, plugin GUI, saveUpoFile w cron.

Weryfikacja po instalacji i po każdej aktualizacji LMS Uruchom skrypt weryfikujący czy wszystkie poprawki są na miejscu:
cd /twoja/sciezka/lms && bash check-netlink-patches.sh
⚠ Ważne: Kopia zapasowa Przed każdą instalacją integracji LMS z KSeF zaleca się zrobienie kopii zapasowej bieżącej instalacji oraz bazy danych.

Uwagi lub zapytania dotyczące działania integracji można zgłaszać na adres: cocoban78@gmail.com.


Warning: Cannot modify header information - headers already sent by (output started at /home/httpd/html/ksef2lms/index.php:60) in /home/httpd/html/ksef2lms/comments.php on line 112
{"error":"Nieznana akcja."}