Nordlet

← Podstawy / Pakiety SDK

Migrowanie z innego systemu

Przenieś księgi rachunkowe firmy w jednym wywołaniu: plan kont, kontrahentów, bilans otwarcia lub pełną historię, otwarte faktury, środki trwałe oraz stany magazynowe.

Gdy firma przenosi się do Nordlet z innego programu księgowego, jej księgi nie zaczynają się od zera. Narzędzie importu danych historycznych pobiera wszystko, co pozostawił stary system, i zapisuje to w ramach jednego wywołania, w jednej transakcji bazy danych: jeśli chociaż jeden wiersz nie przejdzie walidacji, nic nie zostanie zapisane. Ten sam pakiet można najpierw przetestować w punkcie końcowym służącym wyłącznie do sprawdzania, który przeprowadza pełną walidację i wykonuje wycofanie zmian (rollback).

POST /v1/migration/books/validate   # sprawdza wszystko, nic nie zapisuje
POST /v1/migration/books/import     # zapisuje wszystko albo nic

Aplikacja webowa ma te same dwa przyciski w sekcji Konto → Migracja (wklej JSON lub wgraj plik). Klucz API musi posiadać uprawnienie ledger:write oraz uprawnienia zapisu dla każdej dołączonej sekcji (partners:write, catalog:write, sales:write, purchases:write, assets:write, inventory:write). Oba punkty końcowe akceptują ciała żądań o wielkości do 32 MB.

Data graniczna (cut-over)

Wybierz datę graniczną (cut-over date): pierwszy dzień prowadzenia księgowości firmy w Nordlet. Wszystko, co było przed nią, pozostaje w starym systemie (lub zostaje przeniesione jako historia, patrz niżej); wszystko od tego dnia wprowadzane jest w Nordlet przez standardowe punkty końcowe. Wszystkie kwoty w pakiecie są podane „na dzień poprzedzający datę graniczną”: zamykający bilans próbny (trial balance), wciąż nieuregulowane faktury, towary na stanie magazynowym oraz środki trwałe w ewidencji.

Przed rozpoczęciem importu wykonaj w Nordlet następujące czynności:

  1. Utwórz firmę i zastosuj szablon planu kont (ledger/accounts/apply-template) lub wylistuj konta, których potrzebujesz, w sekcji accounts pakietu.
  2. Utwórz co najmniej jeden magazyn (inventory/warehouses/create), jeśli importujesz stany magazynowe.
  3. Uruchom pakiet przez migration/books/validate, dopóki nie przestanie zgłaszać błędów, a Ty zaakceptujesz jego ostrzeżenia.

Pakiet danych

Każda sekcja jest opcjonalna; uwzględnij te, które posiadasz. Wszystkie powiązania między sekcjami odbywają się za pomocą kodów (kod konta, kod kontrahenta, kod pozycji, kod grupy środków trwałych, kod magazynu), przy czym kod może odnosić się do rekordu, który już istnieje w Nordlet, bądź do rekordu utworzonego w we wcześniejszej sekcji tego samego pakietu.

{
  "cutoverDate": "2026-01-01",
  "source": "Rivilė GAMA",
  "accounts": [
    { "code": "6210", "name": "Advertising expenses", "type": "expense", "parentCode": "6" }
  ],
  "partners": [
    { "code": "301111222", "name": "UAB Klientas", "vatCode": "LT100001112223", "isCustomer": true },
    { "code": "302222333", "name": "UAB Tiekėjas", "isCustomer": false, "isSupplier": true }
  ],
  "items": [
    { "code": "SKU-1", "name": "Widget", "type": "product", "unit": "vnt", "vatRatePercent": "21" }
  ],
  "assetGroups": [
    { "code": "TRANSP", "name": "Vehicles", "assetAccountCode": "1230", "depreciationAccountCode": "1239",
      "defaultUsefulLifeMonths": 60 }
  ],
  "openingBalances": {
    "balancingAccountCode": "3410",
    "entries": [
      { "accountCode": "2710", "debit": "5000.00" },
      { "accountCode": "2410", "debit": "1500.00" },
      { "accountCode": "2040", "debit": "300.00" },
      { "accountCode": "1230", "debit": "12000.00" },
      { "accountCode": "1239", "credit": "2400.00" },
      { "accountCode": "4430", "credit": "700.00" },
      { "accountCode": "3010", "credit": "10000.00" }
    ]
  },
  "openReceivables": [
    { "partnerCode": "301111222", "number": "SF-1050", "issueDate": "2025-12-10", "dueDate": "2026-01-09",
      "grossTotal": "1210.00", "vatTotal": "210.00" },
    { "partnerCode": "301111222", "number": "SF-1049", "issueDate": "2025-11-20",
      "grossTotal": "500.00", "outstanding": "290.00" }
  ],
  "openPayables": [
    { "partnerCode": "302222333", "documentNumber": "T-77", "documentDate": "2025-12-15", "grossTotal": "700.00" }
  ],
  "fixedAssets": [
    { "groupCode": "TRANSP", "code": "CAR-1", "name": "Delivery van", "acquisitionDate": "2025-01-01",
      "acquisitionCost": "12000.00", "accumulatedDepreciation": "2400.00", "depreciatedMonths": 12 }
  ],
  "stock": [
    { "itemCode": "SKU-1", "quantity": "30", "unitCost": "10" }
  ]
}

Kwoty są ciągami znaków reprezentującymi liczby dziesiętne, tak jak wszędzie w API. Pole source to dowolna etykieta tekstowa, która trafia do opisu transakcji bilansu otwarcia oraz do notatek w migrowanych fakturach.

accounts

Wiersze planu kont: code, name, type (asset, liability, equity, income, expense), opcjonalnie parentCode oraz isPostable. Istniejące już kody pozostają nienaruszone i są zliczane jako existing. Użyj tej opcji, gdy plan kont starego systemu różni się od szablonu, lub pomiń ją i najpierw zastosuj szablon.

partners oraz items

Klienci, dostawcy oraz pozycje katalogowe identyfikowane za pomocą pola code. Na Litwie kodem kontrahenta jest zazwyczaj kod rejestrowy firmy; w przypadku osób fizycznych użyj dowolnego kodu unikalnego w ramach firmy. Istniejące kody są pomijane, a nie aktualizowane. Pozycje przyjmują pola type (product lub service), unit, barcode, vatRatePercent, salePriceExclVat, purchasePriceExclVat.

openingBalances

Zamykający bilans próbny ze starego systemu, po jednym wierszu na konto: accountCode wraz z kwotą w kolumnie debit lub credit. Wiersze są księgowane jako jedna transakcja dziennika z datą openingBalances.date (domyślnie data graniczna) i typem dokumentu migration_opening. Wiersze muszą wskazywać konta, na które można księgować.

Transakcja musi się bilansować. Jeśli bilans próbny ze starego systemu się nie bilansuje (z powodu zaokrągleń, zysku, który nigdy nie został przeksięgowany na kapitał własny, lub brakującego konta), podaj balancingAccountCode (zazwyczaj zysk zatrzymany, 3410 w litewskim szablonie), a różnica zostanie zaksięgowana na tym koncie; odpowiedź raportuje tę kwotę jako balancingAmount.

Dla każdej firmy może istnieć tylko jedna transakcja bilansu otwarcia. Drugi import zawierający sekcję openingBalances zostanie odrzucony (kod 409). Korekty dokonywane po fakcie są zwykłymi ręcznymi transakcjami dziennika (ledger/journal/transactions/create); zaksięgowane transakcje są niezmienne, więc oryginał pozostaje w takiej postaci, w jakiej został zaimportowany.

journal - pełna historia zamiast sald lub w połączeniu z nimi

Jeśli chcesz przenieść transakcje ze starego systemu do Nordlet (aby raporty za wcześniejsze okresy działały poprawnie), prześlij je tutaj: po jednym obiekcie na transakcję, zawierającym pole date, opcjonalne pola description i reference, oraz tablicę entries składającą się z accountCode oraz debit/credit. Każda transakcja musi się samodzielnie bilansować. Są one księgowane z typem dokumentu migration.

Daty muszą być wcześniejsze niż data graniczna. Jeśli pakiet zawiera również sekcję openingBalances, historia musi mieć daty przypadające na dzień openingBalances.date lub późniejsze - typowym wzorcem są salda na początek poprzedniego roku obrotowego oraz transakcje z tego roku, przy czym data graniczna przypada na pierwszy dzień roku bieżącego. Nie wysyłaj sald i historii dla tego samego okresu, ponieważ salda zostałyby policzone podwójnie.

Każdy miesiąc, którego dotyczy bilans otwarcia lub historia, musi być otwartym okresem księgowym (w przeciwnym razie nastąpi błąd 409).

openReceivables oraz openPayables

Faktury, które na dzień graniczny pozostały nieuregulowane (w całości lub w części). Są one tworzone jako wystawione faktury sprzedaży oraz zarejestrowane faktury zakupu z polem paidAmount = grossTotal − outstanding, dzięki czemu dopasowywanie wyciągów bankowych (bank/transactions/match, bank/transactions/suggest-matches), raport wiekowania należności (debt-aging) oraz webhooki płatności działają na nich tak samo jak na każdej innej fakturze.

  • Pole outstanding domyślnie przyjmuje wartość grossTotal; vatTotal domyślnie wynosi 0 (kwota netto jest wyliczana automatycznie).
  • Pole dueDate domyślnie przyjmuje datę dokumentu.
  • Pole currency domyślnie przyjmuje walutę fakturowania firmy. W przypadku każdej waluty innej niż waluta bazowa firmy wymagane jest podanie pola fxRate - czyli liczby jednostek tej waluty przypadających na 1 jednostkę waluty bazowej, zgodnie z tą samą konwencją co w pozostałej części API - i jest ono zapisywane na fakturze, aby późniejsze płatności prawidłowo obliczały zrealizowane różnice kursowe.
  • number faktury sprzedaży to pełny numer ze starego systemu, który musi być unikalny w firmie. Faktury zakupu są unikalne w ramach kontrahenta i numeru dokumentu (documentNumber).
  • Faktury nie są księgowane ponownie: ich saldo należności/zobowiązań jest już częścią bilansu otwarcia. Są one powiązane z transakcją bilansu otwarcia, dlatego sekcja openPayables wymaga obecności sekcji openingBalances w tym samym pakiecie.
  • Pozycje faktur nie są importowane; faktura zawiera wyłącznie sumy. Stary system pozostaje źródłem szczegółów pozycji oraz rejestrów VAT for okresy sprzed daty granicznej.

Jeśli stary system śledził salda klientów bez otwartych dokumentów, utwórz jedną fakturę na kontrahenta dla danego salda (na przykład z numerem OB-301111222), aby można było je rozliczyć.

Numeracja jest kontynuowana. Jeśli numer importowanej faktury sprzedaży ma postać PREFIX-N, a jej data wystawienia przypada w roku granicznym, seria numeracji dla tego prefiksu i roku zostaje ustawiona na wartość N + 1 (nigdy nie jest obniżana). Odpowiedź zawiera listę wynikowych serii numeracji (numberSeries); w innych przypadkach skonfiguruj serię samodzielnie za pomocą punktu reference/series/create ({ documentType: "sale_invoice", prefix, year, startAt }).

assetGroups oraz fixedAssets

Środki trwałe są przenoszone wraz z dotychczasowym umorzeniem: acquisitionCost, salvageValue, accumulatedDepreciation, depreciatedMonths oraz usefulLifeMonths (lub wartością domyślną grupy). Metoda liniowa (assets/depreciation/post) jest kontynuowana na podstawie wartości pozostałej do umorzenia w rozłożeniu na pozostałe miesiące. Środki trwałe, których dotychczasowa amortyzacja zrównała się już z wartością podlegającą amortyzacji, są tworzone ze statusem fully_depreciated (w pełni umorzone). Nic nie jest księgowane - koszt historyczny oraz umorzenie kumulowane stanowią część bilansu otwarcia.

Grupy są identyfikowane za pomocą pola code i wymagają podania pól assetAccountCode oraz depreciationAccountCode (domyślne konto kosztowe to 6206).

stock

Stany magazynowe w podziale na pozycje: itemCode, quantity, unitCost (koszt jednostkowy w EUR) oraz opcjonalnie warehouseCode (domyślnie: magazyn domyślny), a także lotNumber i expiryDate dla pozycji śledzonych partiami lub seryjnie. Każdy wiersz staje się przychodowym ruchem magazynowym z datą graniczną, typem dokumentu migration i inicjuje warstwę FIFO według tego kosztu. Nic nie jest księgowane - wartość zapasów stanowi część bilansu otwarcia.

Sprawdzenia i ostrzeżenia

Punkt końcowy walidacji kończy się błędem (422) w przypadku brakujących kont, kont nieobsługujących księgowań, niezbilansowanych transakcji, nieznanych kodów kontrahentów, pozycji, grup lub magazynów, duplikatów kodów lub numerów wewnątrz pakietu, kwot otwartych przewyższających sumę brutto, umorzenia kumulowanego przewyższającego wartość podlegającą amortyzacji oraz brakujących kursów walut. Kody lub numery, które już istnieją w Nordlet, zwracają błąd 409.

Ponadto oba punkty końcowe porównują ewidencje analityczne (sub-ledgers) z zapisami księgowymi w tym samym pakiecie i zwracają różnice jako warnings (ostrzeżenia), a nie błędy:

  • łączna kwota otwartych należności w openReceivables w porównaniu do salda na koncie należności (reguła księgowania sales.receivable, domyślnie 2410);
  • łączna kwota otwartych zobowiązań w openPayables w porównaniu do konta zobowiązań (purchases.payables, 4430);
  • całkowity koszt stanów magazynowych w stock w porównaniu do konta zapasów (inventory.stock, 2040);
  • dla każdej grupy środków trwałych, koszt środków trwałych w porównaniu do konta majątkowego grupy oraz ich umorzenie kumulowane w porównaniu do konta umorzenia.

Ostrzeżenie oznacza, że ewidencja analityczna oraz księga główna (general ledger) starego systemu są ze sobą niezgodne. Popraw pakiet (lub świadomie zaakceptuj różnicę) przed przystąpieniem do importu.

Odpowiedź

{
  "dryRun": false,
  "cutoverDate": "2026-01-01",
  "accounts": { "created": 1, "existing": 0 },
  "partners": { "created": 2, "existing": 0 },
  "items": { "created": 1, "existing": 0 },
  "assetGroups": { "created": 1, "existing": 0 },
  "openingBalances": { "journalTransactionId": "…", "date": "2026-01-01", "entries": 8,
                        "debitTotal": "18800.00", "creditTotal": "18800.00", "balancingAmount": "5700.00" },
  "journal": { "transactions": 0, "entries": 0 },
  "openReceivables": { "created": 2, "outstandingTotal": "1500.00" },
  "openPayables": { "created": 1, "outstandingTotal": "700.00" },
  "fixedAssets": { "created": 1, "costTotal": "12000.00", "accumulatedDepreciationTotal": "2400.00" },
  "stock": { "movements": 1, "costTotal": "300.00" },
  "numberSeries": [],
  "warnings": []
}

Wartość dryRun: true oznacza przebieg testowy (walidację); w tym przypadku journalTransactionId ma wartość null. Operacja importu jest rejestrowana w dzienniku audytu jako migration.imported wraz z tym samym podsumowaniem.

Po imporcie

  • Zablokuj okresy przypadające przed datą graniczną (ledger/periods/lock), aby nic nie zostało przez pomyłkę zaksięgowane w zmigrowanej historii.
  • Sprawdź bilans próbny oraz bilans na dzień graniczny w zestawieniu z raportami zamknięcia ze starego systemu.
  • Przejdź do standardowego obiegu: wystawiaj faktury, importuj wyciągi bankowe, dopasowuj płatności - zmigrowane otwarte faktury rozliczają się tak samo jak wszystkie inne.

Czego narzędzie importu nie obejmuje: pozycji faktur oraz rejestrów VAT z minionych okresów (przechowuj je w starym systemie lub jego archiwum), historii list płac (payroll) oraz dokumentów innych niż faktury (zamówień, listów przewozowych, umów).