Nordlet

← Documentatie / Ghiduri

Migrarea din alt sistem

Aduceți evidența contabilă a unei companii printr-un singur apel - planul de conturi, partenerii, soldurile de deschidere sau istoricul complet, facturile deschise, imobilizările și stocurile.

Atunci când o companie trece la Nordlet dintr-un alt program de contabilitate, evidența sa contabilă nu pornește de la zero. Instrumentul de import pentru registrele istorice preia tot ceea ce lasă vechiul sistem în urmă și înregistrează totul printr-un singur apel, într-o singură tranzacție de Baza de Date: dacă un singur rând eșuează la o verificare, nu se stochează nimic. Același pachet poate fi rulat mai întâi printr-un endpoint de testare (check-only), care efectuează toate validările și efectuează un rollback.

POST /v1/migration/books/validate   # verifică totul, nu scrie nimic
POST /v1/migration/books/import     # scrie totul sau nimic

Aplicația web are aceleași două butoane în secțiunea Cont → Migrare (lipiți codul JSON sau încărcați un fișier). Cheia API necesită permisiunea ledger:write plus dreptul de scriere pentru fiecare secțiune pe care o includeți (partners:write, catalog:write, sales:write, purchases:write, assets:write, inventory:write). Ambele endpointuri acceptă corpuri (bodies) de până la 32 MB.

Data tranziției

Alegeți data tranziției (cut-over date): prima zi în care compania este operată în Nordlet. Tot ce este înainte de această dată rămâne în vechiul sistem (sau este preluat ca istoric, a se vedea mai jos); tot ce este începând din acea zi este introdus în Nordlet prin intermediul endpointurilor normale. Toate sumele din pachet sunt „la data de dinaintea tranziției”: bilanțul de închidere, facturile încă neîncasate sau neplătite, stocurile aflate încă în stoc, imobilizările înregistrate încă în evidență.

Înainte de import, faceți următoarele în Nordlet:

  1. Creați compania și aplicați șablonul planului de conturi (ledger/accounts/apply-template) - sau listați conturile de care aveți nevoie în secțiunea accounts a pachetului.
  2. Creați cel puțin un depozit (inventory/warehouses/create) dacă importați stocuri.
  3. Rulați pachetul prin migration/books/validate până când acesta nu mai raportează nicio eroare și acceptați avertismentele generate.

Pachetul

Fiecare secțiune este opțională; includeți-le pe cele pe care le aveți. Toate referințele dintre secțiuni se fac prin cod (codul contului, codul partenerului, codul articolului, codul grupei de imobilizări, codul depozitului), iar un cod poate face referire fie la o înregistrare care există deja în Nordlet, fie la una creată de o secțiune anterioară a aceluiași pachet.

{
  "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" }
  ]
}

Sumele sunt reprezentate ca șiruri de caractere zecimale, ca peste tot în API. Câmpul source este o etichetă liberă care va apărea în descrierea tranzacției de sold de deschidere și în notele facturilor migrate.

accounts

Rândurile planului de conturi: code, name, type (asset, liability, equity, income, expense), câmpurile opționale parentCode și isPostable. Conturile care există deja sunt lăsate neschimbate și sunt contorizate ca existing. Folosiți această secțiune atunci când planul contabil din vechiul sistem diferă de șablon, sau săriți peste ea și aplicați mai întâi șablonul.

partners și items

Clienți, furnizori și articole din catalog, indexate după code. În Lituania, codul partenerului este de obicei codul de înregistrare a companiei; pentru persoanele fizice, folosiți orice cod care este unic în cadrul companiei. Codurile existente sunt omise, nu actualizate. Articolele acceptă type (product sau service), unit, barcode, vatRatePercent, salePriceExclVat, purchasePriceExclVat.

openingBalances

Bilanțul de verificare de închidere din vechiul sistem, un rând per cont: accountCode însoțit fie de debit, fie de credit. Rândurile sunt înregistrate ca o singură tranzacție de jurnal datată la openingBalances.date (valoarea implicită este data tranziției) cu tipul de document migration_opening. Rândurile trebuie să facă referire la conturi la care se pot efectua înregistrări contabile (postable accounts).

Tranzacția trebuie să fie în echilibru (șah). Dacă bilanțul de verificare din vechiul sistem nu este în echilibru - din cauza rotunjirilor, a unui profit care nu a fost niciodată închis în capitalurile proprii sau a unui cont lipsă - furnizați balancingAccountCode (de obicei rezultatul reportat, 3410 în șablonul lituanian), iar diferența este înregistrată acolo; răspunsul raportează această sumă ca balancingAmount.

O companie poate avea o singură tranzacție de solduri de deschidere. Un al doilea import care conține openingBalances va fi refuzat (cod de eroare 409). Corecțiile ulterioare se fac prin înregistrări manuale obișnuite în jurnal (ledger/journal/transactions/create); tranzacțiile validate sunt imuabile, astfel încât înregistrarea originală rămâne exact așa cum a fost importată.

journal - istoric complet în loc de solduri sau în plus față de acestea

Dacă doriți ca tranzacțiile din vechiul sistem să fie prezente în Nordlet (astfel încât rapoartele pentru perioadele anterioare să funcționeze), trimiteți-le aici: câte un obiect per tranzacție care conține date, câmpurile opționale description și reference, precum și elementul entries format din accountCode + debit/credit. Fiecare tranzacție trebuie să fie în echilibru în mod independent. Ele sunt înregistrate cu tipul de document migration.

Datele trebuie să fie anterioare datei tranziției. Atunci când pachetul conține și openingBalances, istoricul trebuie să fie datat la sau după openingBalances.date - modelul obișnuit presupune soldurile de la începutul exercițiului financiar anterior plus tranzacțiile aferente acelui an, tranziția având loc în prima zi a anului curent. Nu trimiteți atât solduri, cât și istoric pentru aceeași perioadă: soldurile ar fi contorizate de două ori.

Fiecare lună atinsă de soldurile de deschidere sau de istoric trebuie să fie o perioadă contabilă deschisă (în caz contrar, se va returna eroarea 409).

openReceivables și openPayables

Facturi care erau încă neîncasate sau neplătite (integral sau parțial) la data tranziției. Ele sunt create ca facturi de ieșire emise și facturi de intrare înregistrate având paidAmount = grossTotal − outstanding, astfel încât reconcilierea bancară (bank/transactions/match, bank/transactions/suggest-matches), raportul de vechime a datoriilor și webhook-urile pentru plăți să funcționeze pentru ele la fel ca pentru orice altă factură.

  • Valoarea implicită pentru outstanding este grossTotal; valoarea implicită pentru vatTotal este 0 (valoarea netă este dedusă automat).
  • Valoarea implicită pentru dueDate este data documentului.
  • Valoarea implicită pentru currency este moneda de facturare a companiei. Pentru orice monedă diferită de moneda de bază a companiei, este obligatoriu câmpul fxRate - reprezentând unitățile din acea monedă pentru 1 unitate din moneda de bază, respectând aceeași convenție ca în restul API-ului - acesta fiind stocat pe factură, astfel încât plățile ulterioare să calculeze corect diferența de curs valutar realizată.
  • Numărul facturii de ieșire (number) este numărul complet din vechiul sistem și trebuie să fie unic în cadrul companiei. Facturile de intrare sunt unice per partener și documentNumber.
  • Facturile nu sunt înregistrate din nou în contabilitate: soldul lor de creanțe/datorii face deja parte din soldurile de deschidere. Ele sunt legate de tranzacția de sold de deschidere, motiv pentru care openPayables necesită prezența openingBalances în același pachet.
  • Liniile facturilor nu sunt importate; factura conține doar totalurile. Vechiul sistem rămâne sursa pentru detaliul liniilor și pentru jurnalele de TVA aferente perioadelor anterioare tranziției.

Dacă vechiul sistem a urmărit soldurile clienților fără elemente deschise (fără facturi detaliate), creați câte o factură per partener pentru soldul respectiv (de exemplu, cu numărul OB-301111222), astfel încât acesta să poată fi stins.

Numerotarea continuă. Atunci când numărul unei facturi de ieșire importate are forma PREFIX-N și data sa de emitere se încadrează în anul tranziției, seria de numere pentru acel prefix și an este setată la N + 1 (fără a fi coborâtă niciodată). Răspunsul listează seria de numere rezultată numberSeries; pentru alte cazuri, setați seria dumneavoastră folosind reference/series/create ({ documentType: "sale_invoice", prefix, year, startAt }).

assetGroups și fixedAssets

Imobilizările corporale sunt preluate împreună cu amortizarea lor la zi: acquisitionCost, salvageValue, accumulatedDepreciation, depreciatedMonths și usefulLifeMonths (sau valoarea implicită a grupei). Calculul liniar (assets/depreciation/post) continuă pe baza valorii rămase pentru lunile rămase. Activele a căror amortizare acumulată egalează deja valoarea amortizabilă sunt create ca fully_depreciated (complet amortizate). Nu se înregistrează nimic suplimentar - costul și amortizarea acumulată fac parte din soldurile de deschidere.

Grupele sunt indexate după code și necesită assetAccountCode și depreciationAccountCode (contul de cheltuieli implicit fiind 6206).

stock

Stocul existent per articol: itemCode, quantity, unitCost (costul unitar în EUR) și, opțional, warehouseCode (valoarea implicită: depozitul implicit), lotNumber și expiryDate pentru articolele urmărite pe loturi sau numere de serie. Fiecare rând devine o mișcare de intrare în stoc datată la data tranziției, având tipul de document migration, și inițiază un strat FIFO la acel cost. Nu se înregistrează nimic în contabilitate - valoarea stocului face parte din soldurile de deschidere.

Verificări și avertismente

Endpointul de validare va eșua (cod de eroare 422) în caz de conturi lipsă, conturi la care nu se pot face înregistrări, tranzacții neechilibrate, coduri necunoscute de partener/articol/grupă/depozit, coduri sau numere duplicate în cadrul pachetului, sume restante care depășesc totalul brut, amortizare acumulată care depășește valoarea amortizabilă sau cursuri de schimb FX lipsă. Numerele sau codurile care există deja în Nordlet generează o eroare 409.

În plus, ambele endpointuri compară sub-registrele cu înregistrările din registrul contabil (ledger) din același pachet și returnează diferențele ca warnings (avertismente), mai degrabă decât ca erori:

  • totalul soldului din openReceivables comparativ cu soldul din contul de creanțe (regula de înregistrare sales.receivable, 2410 în mod implicit);
  • totalul soldului din openPayables comparativ cu contul de datorii (purchases.payables, 4430);
  • costul total al stock comparativ cu contul de stocuri (inventory.stock, 2040);
  • per grupă de imobilizări, costul activelor comparativ cu contul de active al grupei și amortizarea lor acumulată comparativ cu contul de amortizare.

Un avertisment indică faptul că sub-registrul din vechiul sistem și registrul general nu coincid. Corectați pachetul (sau acceptați în cunoștință de cauză diferența) înainte de a efectua importul.

Răspunsul

{
  "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": []
}

Valoarea dryRun: true marchează o rulare de validare; în acest caz, journalTransactionId va fi null. O operațiune de import este înregistrată în jurnalul de audit (audit log) ca migration.imported, însoțită de același sumar.

După import

  • Blocați perioadele anterioare datei tranziției (ledger/periods/lock), astfel încât să nu se poată înregistra nimic din greșeală în istoricul migrat.
  • Verificați balanța de verificare și bilanțul la data tranziției prin comparare cu rapoartele de închidere din vechiul sistem.
  • Continuați cu fluxul normal: emiteți facturi, importați extrasele bancare, reconciliați plățile - facturile deschise migrate se vor stinge la fel ca orice alte facturi.

Ce nu acoperă instrumentul de import: liniile facturilor și jurnalele de TVA din perioadele trecute (păstrați-le în vechiul sistem sau în arhiva acestuia), istoricul statului de plată (salarii) și alte documente în afară de facturi (comenzi, avize de însoțire a mărfii, contracte).