Project

General

Profile

Partneru API (#19245)

Ticket #19245 ietvaros ieviesto/paplašināto softera API galapunktu dokumentācija: partnerorganizācijas izveide, organizāciju meklēšana, LOCCAT kataloga atrašanās vietu CRUD, organizācijas GLN maiņa.

Vispārīgi

  1. Pamaturl: https://api-test.docura.net/ap1/partner/api/
  2. Autentifikācija: galvene X-Authorization: <api_key> (lietotāja pilnvaru, lauks api_key tabulā users).
  3. Klienti neizmanto galveni X-App-Key — aizmugursistēmā šī pārbaude pašlaik nav savienota ar nevienu filtru ķēdi (nedarbojošs kods kopš 2023. gada), tāpēc to var izlaist.
  4. Formāts — JSON (izņemot gadījumus, kad tas ir skaidri norādīts citādi).
  5. Lomām (pilnvarām): SYSTEM_ADMIN, SYSTEM_SUPPORT, CLIENT_ADMIN, CLIENT_EDITOR, PROVIDER_ADMIN — par konkrētām atļautajām lomām skatīt katra galapunkta aprakstu.

1. Partnerorganizācijas izveide

POST /user/organization

Izveido jaunu organizāciju un pievieno tai izsaucošo lietotāju kā CLIENT_ADMIN (ar atsevišķu, agrāku soli izveides procesā).

Tiesības: nav lomu ierobežojumu — pieejams jebkuram autentificētam lietotājam. Tiesības tiek izteiktas nevis ar zvanītāja lomu, bet gan ar to, kurai organizācijai pieder pats zvanītājs (skat. operatorId loģiku zemāk).

Pieprasījuma pamatteksts:

Lauks Tips Obligāts Ierobežojumi
taxId string jā 2–20 rakstzīmes
registrationNumber string jā 2–50 rakstzīmes
name string jā 2–50 rakstzīmes
countryCode string jā 2 rakstzīmes
locale string jā 2 rakstzīmes, jābūt pieejamam lokalizāciju sarakstā
errorEmail string nē līdz 250 rakstzīmēm, e-pasta formāts
notes string nē līdz 255 rakstzīmēm
phones string nē līdz 50 rakstzīmēm
email string nē līdz 150 rakstzīmēm, e-pasta formāts

Lauks integrationProfileType, kas parādījās šīs funkcijas agrākajās iterācijās tajā pašā biļetē, tika noņemts no gala versijas — klients nevar skaidri izvēlēties profilu/connectionType (skat. zemāk).

Atbilde (200): tas pats lauku kopums + id (Long), iln (ģenerētais organizācijas GLN).

Kļūdas:

  1. 409 Conflict (organization.create.conflict.tax_id) — organizācija ar šo taxId jau pastāv.
  2. 400 — nederīgi pieprasījuma pamatteksta lauki (bean validācija), vai lokalizācija nav atrasta (not.exists.specified.organization.locale).

Loģika, lai noteiktu jaunās organizācijas operatoru (operatorId)

Tas tiek aprēķināts no IZSAUCĒJA lietotāja organizācijas pašas (callerIln — sesijas pašreizējās organizācijas ILN), bez skaidriem parametriem pieprasījumā:

  1. Ja zvanītāja organizācija ir pati softera (profile.softeraOrganizationIln) → jaunās organizācijas operators = pati softera. Turklāt šajā gadījumā jaunajai organizācijai kā CLIENT_ADMIN tiek pievienots noklusējuma softera lietotājs (profile.softeraDefaultUserId, ja ir iestatīts).
  2. Ja zvanītāja organizācija ir pakalpojumu sniedzējs (role='P', bet ne softera) → operators = paša zvanītāja organizācija.
  3. Citādi (ne softera, ne pakalpojumu sniedzējs) → operators = organizācija no profile.defaultOperatorOrganizationIln (atgriežas pie "noklusējuma operatora").
  4. Ja ne izsaucošā organizācija, ne rezerves organizācija netiek atrasta pēc ILN — 500 (IllegalStateException, parasti nevajadzētu notikt).

connectionType loģika jaunajai organizācijai

  1. Izsaucējs ir Softra → vienmēr Payment (cīti kodēts, neatkarīgi ne no kā).
  2. Citādi → connectionType = operatora organizācijas pašas connectionType (iepriekš aprēķinātais — pakalpojumu sniedzējs vai rezerves organizācija). Klients nevar skaidri norādīt connectionType/integrācijas profilu.

2. Organizāciju meklēšana

GET /organizations/search?query=<string>

Tiesības: SYSTEM_ADMIN, SYSTEM_SUPPORT, PROVIDER_ADMIN. Nav ierobežojumu pēc operatorId — pakalpojumu sniedzējs redz rezultātus visā organizāciju datubāzē, ne tikai savus klientus (apzināts lēmums, kas pieņemts šīs biļetes ietvaros).

Parametri:

Parametrs Tips Obligāts Apraksts
query string yes Meklēšanas virkne. Tukša/trūkstoša virkne → tukšs saraksts bez kļūdas.

Meklēšanas loģika DB — viens OR organizācijā:

  1. precīza atbilstība id (kā tekstam);
  2. precīza atbilstība iln (GLN);
  3. precīza atbilstība regNr (bez reģistra jutības);
  4. precīza atbilstība vatNr (bez reģistra jutības);
  5. apakšvirkne (ILIKE) organizācijas name;
  6. apakšvirkne (ILIKE) jebkuras tās LOCCAT atrašanās vietas name.

Atbilde (200): masīvs, katrs elements ietverts organization objektā:

[
  {
    "organization": {
      "id": 100099815,
      "name": "New brand sof",
      "iln": "2000005810008",
      "taxId": "...",
      "registrationNumber": "...",
      "countryCode": "EE",
      "locations": [ { "id": ..., "iln": "...", "name": "...", "formattedAddress": "...", ... } ]
    }
  }
]

Svarīga nianse: locations[] satur tikai tās atrašanās vietas, kuru nosaukums atbilda meklēšanas virknei — ne visas atrastās organizācijas atrašanās vietas. Ja organizācija tika atrasta pēc id/iln/regNr/vatNr/nosaukuma, un ne pēc atrašanās vietas nosaukuma, locations būs tukšs masīvs. Šī ir apzināta darbība, nevis kļūda.


3. LOCCAT organizācijas atrašanās vietas

Pamatceļš: /organization/{gln}/locations, kur {gln} ir organizācijas GLN (nevis ciparu ID).

Tiesības (kopīgas visām trim tālāk norādītajām metodēm):

  1. SYSTEM_ADMIN / SYSTEM_SUPPORT — bez ierobežojumiem.
  2. PROVIDER_ADMIN — tikai tad, ja zvanītāja organizācija = mērķa organizācijas operatorId (pakalpojumu sniedzējs pārvalda paša apkalpoto organizāciju atrašanās vietas).
  3. Citas lomas — 403 (not.have.access).
  4. Organizācija nav atrasta pēc GLN → 400 (organization.not.exists).

3.1 POST /organization/{gln}/locations — izveidot/atjaunināt atrašanās vietu

Upsert loģika:

  1. Ja id tiek nodots pamattekstā — esošās atrašanās vietas tieša atjaunināšana pēc tās iekšējā ID (tai jāpieder norādītajai organizācijai, pretējā gadījumā 404).
  2. Ja id netiek nodots, bet iln tiek nodots — tiek meklēta esoša organizācijas atrašanās vieta ar šo iln; ja tiek atrasta, tā tiek atjaunināta, ja nē, tiek izveidota jauna.
  3. Ja iln netiek nodots (vai ir "tukšs" saskaņā ar IlnHelper.isEmpty) — atrašanās vietas GLN tiek ģenerēts automātiski (skatīt zemāk).

Pieprasījuma pamatteksts (LoccatLocationWithIdData — LoccatLocationData + neobligāts id):

Lauks Tips Obligāts Ierobežojumi
id Long nē tiešai atjaunināšanai
iln virkne nē līdz 13 simboliem; ja nav — automātiski ģenerēts
codeBySender virkne jā līdz 70 simboliem
codeByReceiver virkne nē līdz 70 simboliem
name virkne jā līdz 175 simboliem
legal boolean nē "juridiskās adreses" karodziņš
formattedAddress virkne nē līdz 300 simboliem
streetAndNumber virkne nē līdz 140 simboliem
streetAndNumber2 virkne nē līdz 140 simboliem
city virkne nē līdz 175 simboliem
state virkne nē līdz 175 simboliem
postalCode virkne nē līdz 9 simboliem
countryCode virkne nē līdz 2 simboliem
latitude / longitude double nē
remarks virkne nē līdz 350 simboliem
phoneNumber virkne nē līdz 175 simboliem
email virkne nē līdz 350 simboliem, e-pasta formāts
web virkne nē līdz 175 simboliem

Atbilde (200): tas pats pamatteksts + izveidotās/atjauninātās atrašanās vietas id.

Atrašanās vietas GLN automātiska ģenerēšana (ja iln netiek nodots)

Tā atkārtoti izmanto mantoto algoritmu UserWebController.getNextLocalizationCatalogGln (pamata):

  1. Ja organizācijai jau ir atrašanās vietas (maxIln atrasts) → nākamais GLN = pēdējā ģenerētā GLN pamatteksts + 1.
  2. Ja nav atrašanās vietu un organizācija ir testa organizācija (isTest) → GLN tiek veidots no organizācijas glnPrefix, papildināts ar nullēm.
  3. Ja nav atrašanās vietu, organizācija nav testa organizācija un nav "juridiskās" atrašanās vietas → tiek atgriezts pašas organizācijas GLN.
  4. Ja ir juridiskā atrašanās vieta, bet nav citu (robežgadījums) → GLN tiek veidots no glnPrefix.

Papildus (izmaiņas no šīs biļetes): ja šādi ģenerētais GLN sakrīt ar pašas organizācijas GLN (iepriekš minētās 2. un 3. sadaļas) — tas tiek palielināts par 1, lai tas nekad nepārklātos ar organizācijas GLN.

Zināmie ierobežojumi (pieņemti tādi, kādi tie ir, bez papildu aizsardzības):

  1. Nav transakciju bloķēšanas starp "iegūt nākamo GLN" un "izveidot atrašanās vietu ar to" — ar paralēliem pieprasījumiem bez iln ir iespējama sacensība un 400 duplicate.line.iln.
  2. Pārpildes palielinājums (GLN pamatteksts = 999999999999) teorētiski varētu radīt GLN, kas ir par vienu rakstzīmi garāks nekā parasti — ārkārtīgi maz ticams robežgadījums, labojums netika pieprasīts.
  3. legal karogs NETIEK automātiski iestatīts pirmajā atrašanās vietā, kas izveidota bez iln — ja organizācijai nav juridiskās atrašanās vietas, atkārtots POST bez iln mēģinās atkārtoti ģenerēt to pašu organizācijas GLN un neizdosies ar 400 duplicate.line.iln. Klientam jāpasniedz iln vai nu skaidri otrajos un nākamajos pieprasījumos, vai arī jāpārvalda legal pats.

3.2 GET /organization/{gln}/locations — iegūt atrašanās vietas

Specifika: filtrs tiek nodots GET pieprasījuma pamattekstā (JSON); tie nav vaicājuma parametri. Ja pamatteksts ir tukšs (Content-Length <= 0) — tiek atgrieztas visas organizācijas atrašanās vietas.

Pieprasījuma pamatteksts (neobligāts):

Lauks Tips Apraksts
id Long precīza meklēšana pēc atrašanās vietas ID (plus neobligāta pārbaude pret GLN, ja tas ir nodots)
iln string filtrēt pēc GLN
name string filtrēt pēc nosaukuma (apakšvirkne)
address string filtrēt pēc adreses (apakšvirkne)

Prioritāte: ja id tiek nodots — tiek atgriezta (maksimums) viena atrašanās vieta pēc ID; citādi, ja vismaz viens no iln/name/address ir iestatīts — filtrēta meklēšana; citādi — visas organizācijas atrašanās vietas.

Atbilde (200): atrašanās vietu masīvs (tāds pats formāts kā POST atbildē).

3.3 DELETE /organization/{gln}/locations

Pieprasījuma pamatteksts (obligāts):

Lauks Tips Obligāts
id Long jā

Dzēšana tikai pēc iekšējā atrašanās vietas ID; dzēšana pēc iln netiek īstenota (tika apsvērta un atcelta šīs biļetes ietvaros).

Atbilde: 200 veiksmes gadījumā, 404, ja atrašanās vieta ar šādu ID netiek atrasta organizācijā, 400 location.id.should.be.specified, ja id netiek nodots.


4. Organizācijas GLN maiņa

PATCH /organization/{organizationId}/gln?gln=<new GLN>

Piezīme: šeit {organizationId} ir organizācijas skaitliskais iekšējais ID (atšķirībā no iepriekšminētajiem atrašanās vietas galapunktiem, kas ceļā izmanto GLN).

Tiesības:

  1. SYSTEM_ADMIN / SYSTEM_SUPPORT — nav ierobežojumu.
  2. PROVIDER_ADMIN — tikai tad, ja izsaucēja organizācija = mērķa organizācijas operatorId.
  3. Citi — 403 not.have.access.
  4. Organizācija nav atrasta pēc ID → 404 (tukšs korpuss).

Parametri:

Parametrs Tips Obligāts
gln string jā, vaicājuma parametrs

Kas notiek iekšpusē (tiek atkārtoti izmantots standarta organizācijas atjaunināšanas konveijers, OrganizationUpdateEvent → OrganizationCommonUpdateHandler):

  1. GLN formāta validācija + kontroldati → 400 kļūdas gadījumā.
  2. Dublikātu pārbaude — GLN nedrīkst piederēt citai organizācijai → 400 Duplicate ILN.
  3. Vecā vērtība tiek saglabāta previousIln.
  4. Ja organizācijai ir "juridiska" LOCCAT atrašanās vieta — tās iln tiek automātiski sinhronizēts ar organizācijas jauno GLN (loccatReconciliation). Ja nav juridiskas atrašanās vietas — solis tiek klusi izlaists.
  5. Standarta organizācijas atjaunināšanas saskaņošanas soļi (partneris/nosacījums/paziņojumi utt., nav specifiski šai funkcijai).

Atbilde (200): organizācijas korpuss (OrganizationWithIdData) ar jau piemērotu jauno GLN.


5. Beigu punktu kopsavilkuma tabula

Metode Ceļš Ceļa identifikators Lomas
POST /user/organization — jebkurš autentificēts
GET /organizations/search — SYSTEM_ADMIN, SYSTEM_SUPPORT, PROVIDER_ADMIN
POST /organization/{gln}/locations GLN SYSTEM_ADMIN, SYSTEM_SUPPORT, PROVIDER_ADMIN (operatorId-match)
GET /organization/{gln}/locations GLN SYSTEM_ADMIN, SYSTEM_SUPPORT, PROVIDER_ADMIN (operatorId-match)
DELETE /organization/{gln}/locations GLN SYSTEM_ADMIN, SYSTEM_SUPPORT, PROVIDER_ADMIN (operatorId-match)
PATCH /organization/{organizationId}/gln ciparu ID SYSTEM_ADMIN, SYSTEM_SUPPORT, PROVIDER_ADMIN (operatorId-match)

6. Piemēri

# Create an organisation
curl --location --request POST 'https://api-test.docura.net/ap1/partner/api/user/organization' \
--header 'X-Authorization: <token>' \
--header 'Content-Type: application/json' \
--data '{
  "taxId": "EE100000001",
  "registrationNumber": "12345678",
  "name": "Example OU",
  "countryCode": "EE",
  "locale": "en" 
}'

# Search organisations
curl --location 'https://api-test.docura.net/ap1/partner/api/organizations/search?query=Example' \
--header 'X-Authorization: <token>'

# Create a location without an explicit GLN (auto-generation)
curl --location --request POST 'https://api-test.docura.net/ap1/partner/api/organization/<org_gln>/locations' \
--header 'X-Authorization: <token>' \
--header 'Content-Type: application/json' \
--data '{
  "name": "Warehouse 1",
  "codeBySender": "WH1",
  "countryCode": "EE" 
}'

# Get all locations of an organisation
curl --location 'https://api-test.docura.net/ap1/partner/api/organization/<org_gln>/locations' \
--header 'X-Authorization: <token>'

# Delete a location by id
curl --location --request DELETE 'https://api-test.docura.net/ap1/partner/api/organization/<org_gln>/locations' \
--header 'X-Authorization: <token>' \
--header 'Content-Type: application/json' \
--data '{"id": 682021}'

# Change an organisation's GLN
curl --location --request PATCH 'https://api-test.docura.net/ap1/partner/api/organization/<numeric_id>/gln?gln=2000005819995' \
--header 'X-Authorization: <token>'

Source version: 3 · Status: fresh · Roman Startsev