# Uniorder: jedno API pre každú zásielku

Uniorder je jediná sada endpointov, cez ktorú integrácia oceňuje, vytvára, tlačí, sleduje a ruší každú zásielku účtu bez ohľadu na spôsob jej vybavenia. Jedna cenová ponuka vráti doručenie samotnou firmou a na požiadanie aj každú službu štítkov dopravcu na účte, každú s `rate_id`. Objednávka sa vytvorí odoslaním zvoleného `rate_id`; službu nevyberá nič iné v požiadavke.

## 1. Čo môžete vytvoriť

- **Pokladňu, ktorá ponúkne všetky možnosti dopravy naraz.** Zákazník zadá adresu, pokladňa zavolá jeden endpoint a stránka zobrazí miestne doručenie vedľa UPS, Canada Post a každého ďalšieho dopravcu, ktorého účet používa, každé s cenou.
- **Konektor pre správu objednávok alebo ERP s jednou cestou v kóde.** Objednávky zo všetkých kanálov prechádzajú rovnakými volaniami na vytvorenie, čítanie, štítok, sledovanie a zrušenie. Konektor nepotrebuje samostatnú logiku pre miestne doručenie a pre štítky dopravcu.
- **Nočné hromadné spracovanie.** Až 500 zásielok sa ocení alebo vytvorí v jednej úlohe vo fronte a výsledky sa načítajú podľa id úlohy.
- **Obrazovku zákazníckeho servisu.** Pracovník vyhľadá objednávku, znova vytlačí jej štítok, načíta históriu sledovania a zruší ju, a to rovnakými štyrmi volaniami pre každú objednávku.

## 2. Čo za vás Uniorder rieši

| Bez Uniorder | S Uniorder |
|---|---|
| Jedno API pre objednávky miestneho doručenia a ďalšie pre štítky dopravcu, každé s vlastnými poľami a odpoveďami | Jeden tvar požiadavky (`from_*`, `to_*`, `packages`) a jeden tvar odpovede pre každú službu |
| Integrácia rozhoduje, ktoré API dopravcu zavolá | Cenová ponuka uvádza každú službu; rozhoduje `rate_id` zvolenej sadzby |
| Samostatné endpointy pre štítok, sledovanie a zrušenie pre každú službu | `GET /label`, `GET /tracking` a `POST /cancel` fungujú pre každú objednávku |
| Dávkové vytvorenie je dostupné iba pre miestne doručenie | Dávková cenová ponuka a dávkové vytvorenie pre každú službu, synchrónne alebo vo fronte |

Uniorder nenahrádza existujúce endpointy; zostávajú dostupné a nezmenené. Je to odporúčaný vstupný bod pre novú integráciu.

## 3. Prehľad endpointov v poradí, v akom ich integrácia používa

| Krok | Účel | REST | GraphQL |
|---|---|---|---|
| 1 | Získanie prístupového tokenu | `POST /api/v1/user/login` | `userLogin` |
| 2 | Cenová ponuka pre každú službu | `POST /api/v1/uniorder/rate` | `uniorderRate` |
| 3 | Vytvorenie objednávky za zvolenú sadzbu | `POST /api/v1/uniorder` | `uniorderCreate` |
| 4 | Tlač štítku | `GET /api/v1/uniorder/{orderId}/label` | `uniorderLabel` |
| 5 | Čítanie objednávky | `GET /api/v1/uniorder/{orderId}` | `uniorder` |
| 6 | Sledovanie objednávky | `GET /api/v1/uniorder/{orderId}/tracking` | `uniorderTracking` |
| 7 | Zrušenie objednávky | `POST /api/v1/uniorder/{orderId}/cancel` | `uniorderCancel` |
| — | Nákup štítku, ktorý sa pri vytvorení nepodarilo kúpiť | `POST /api/v1/uniorder/{orderId}/label` | `uniorderPurchaseLabel` |
| — | Cenová ponuka alebo vytvorenie až 20 riadkov naraz | `POST /api/v1/uniorder/rate/batch`, `POST /api/v1/uniorder/batch` | `uniorderRateBatch`, `uniorderCreateBatch` |
| — | Zaradenie až 500 riadkov do frontu | `POST /api/v1/uniorder/rate/batch-async`, `POST /api/v1/uniorder/batch-async`, `GET /api/v1/uniorder/jobs/{jobId}` | `uniorderRateBatchAsync`, `uniorderCreateBatchAsync`, `uniorderJob` |

[Príručka REST](/api/documentation#/paths/v1-uniorder-rate/post) · [Príručka GraphQL](/api/graphql/documentation#/orders/uniorderRate)

Požiadavky, odpovede a kontroly krok za krokom sú v príručke **Cenová ponuka a objednávka v jednom toku**.

## 4. Príklad: pokladňa, ktorá ponúka všetky možnosti

Kvetinárstvo v Montreale predáva online. Pri pokladni ocení balík raz, vrátane dopravcov štítkov:

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder/rate \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from_name": "Fleurs du Plateau", "from_telephone": "5145550100",
    "from_address": "4500 Rue Saint-Denis", "from_city": "Montreal", "from_province": "QC", "from_country": "CA", "from_postcode": "H2J2L3",
    "to_name": "Jane Recipient", "to_telephone": "5145550199",
    "to_address": "6841 Rue Saint-Denis", "to_city": "Montreal", "to_province": "QC", "to_country": "CA", "to_postcode": "H2S2S3",
    "quote_labels": true,
    "packages": [{ "weight": 1.2, "weight_unit": 2, "length": 40, "width": 25, "height": 25, "dimension_unit": 2 }]
  }'
```

Odpoveď uvádza jednu sadzbu `self_delivery` a jednu sadzbu `label_service` pre každú službu dopravcu. Pokladňa ich zobrazí ako možnosti; zákazník zvolí miestne doručenie v ten istý deň. Objednávka sa vytvorí s `rate_id` tejto sadzby a s rovnakými adresami a balíkmi:

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: checkout-10045" \
  -d '{
    "rate_id": "eyJpdiI6Ik1rT2Z...",
    "ref": "WEB-10045",
    "from_name": "Fleurs du Plateau", "from_telephone": "5145550100",
    "from_address": "4500 Rue Saint-Denis", "from_city": "Montreal", "from_province": "QC", "from_country": "CA", "from_postcode": "H2J2L3",
    "to_name": "Jane Recipient", "to_telephone": "5145550199",
    "to_address": "6841 Rue Saint-Denis", "to_city": "Montreal", "to_province": "QC", "to_country": "CA", "to_postcode": "H2S2S3",
    "packages": [{ "weight": 1.2, "weight_unit": 2, "length": 40, "width": 25, "height": 25, "dimension_unit": 2 }]
  }'
```

Odpoveď vráti `id` objednávky a jej sledovacie čísla. Obchod vytlačí štítok pomocou `GET /api/v1/uniorder/{orderId}/label` a na stránke objednávky zákazníka zobrazí históriu z `GET /api/v1/uniorder/{orderId}/tracking`.

## 5. Príklad: ERP, ktoré odosiela každú noc

ERP exportuje objednávky dňa o 22:00. Adresy odošle na `POST /api/v1/uniorder/rate/batch-async`, číta úlohu, kým `status` nie je `done`, pre každý riadok vyberie sadzbu podľa vlastných pravidiel a zvolené riadky odošle na `POST /api/v1/uniorder/batch-async`. Každý výsledok nesie `reference` riadku, takže ERP priradí každý výsledok k vlastnému riadku objednávky. `rate_id` platí 30 minút, preto sa úloha vytvorenia odosiela čoskoro po dokončení úlohy cenovej ponuky.

## 6. Príklad: obrazovka zákazníckeho servisu

Pri hovore zákazníka obrazovka pracovníka volá `GET /api/v1/uniorder/{orderId}` pre stav a adresy, `GET /api/v1/uniorder/{orderId}/tracking` pre históriu a doklad o doručení a `POST /api/v1/uniorder/{orderId}/cancel`, keď zákazník objednávku zruší. Rovnaké volania platia pre objednávku doručenia aj pre objednávku štítku; rozlišuje ich pole `type`.

```bash
curl https://YOUR_HOST/api/v1/uniorder/123456/tracking \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

Tá istá objednávka cez GraphQL ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorder)):

```graphql
query {
  uniorder(order_id: 123456)
}
```

## 7. Pravidlá, s ktorými treba pri návrhu počítať

- **Službu určuje `rate_id`.** Platí 30 minút a iba pre účet, ktorý cenovú ponuku vyžiadal.
- **Objednávka sa ocení pri vytvorení.** `shipping_price` je účtovaná cena; `quoted_price` je cena z cenovej ponuky. Tieto dve ceny sa môžu líšiť.
- **Objednávka štítku sa nikdy nestratí.** Ak štítok nemožno kúpiť pri vytvorení, objednávka sa zachová a odpoveď je `LABEL_PURCHASE_FAILED` s `id` objednávky; štítok sa kúpi neskôr pomocou `POST /api/v1/uniorder/{orderId}/label`.
- **Opakovanie požiadaviek je bezpečné.** Pri každom volaní vytvorenia pošlite hlavičku `Idempotency-Key`; zrušenie už zrušenej objednávky vráti `already_cancelled` `true`.
- **Stavy sú jednotné.** Objednávka doručenia hlási `pending`, `in_transit`, `out_for_delivery`, `delivered`, `exception` alebo `cancelled`; objednávka štítku hlási `label_pending`, `label_purchased` alebo `cancelled` a polohu balíka hlási sledovanie jej dopravcu.

## 8. Kontrolný zoznam pred spustením

- [ ] Účet má oprávnenie na API a token je uložený na serveri, nie v prehliadači.
- [ ] Cenové ponuky sa vyžadujú s úplnými adresami odosielateľa a príjemcu.
- [ ] Objednávky sa vytvárajú do 30 minút od cenovej ponuky a s `Idempotency-Key`.
- [ ] `LABEL_PURCHASE_FAILED` sa rieši neskorším nákupom štítku, nikdy opätovným vytvorením objednávky.
- [ ] Sledovanie sa číta z `GET /api/v1/uniorder/{orderId}/tracking` alebo prijíma cez webhooky.
- [ ] Zrušenie rieši `ORDER_STATUS_NOT_CANCELLABLE` a `ORDER_CANCEL_REFUSED` tak, že objednávku ponechá bez zmeny.
