# Uniorder: jedan API za svaku pošiljku

Uniorder je jedinstven skup endpoint-a preko kojeg integracija dobija ponudu, kreira, štampa, prati i otkazuje svaku pošiljku naloga, bez obzira na to kako se pošiljka izvršava. Jedna ponuda vraća dostavu koju obavlja sama firma i, na zahtev, svaku uslugu nalepnica prevoznika na nalogu, svaku sa `rate_id`. Porudžbina se kreira vraćanjem izabranog `rate_id`; ništa drugo u zahtevu ne bira uslugu.

## 1. Šta možete da izgradite

- **Plaćanje (checkout) koje nudi sve opcije slanja odjednom.** Kupac unosi adresu, checkout poziva jedan endpoint, a stranica prikazuje lokalnu dostavu pored UPS-a, Canada Post-a i svakog drugog prevoznika koga nalog koristi, svaku sa njenom cenom.
- **Konektor za upravljanje porudžbinama ili ERP sa jednom putanjom koda.** Porudžbine iz svih kanala prolaze kroz iste pozive za kreiranje, čitanje, nalepnicu, praćenje i otkazivanje. Konektoru nije potrebna posebna logika za lokalnu dostavu i za nalepnice prevoznika.
- **Noćna paketna obrada.** Do 500 pošiljki dobija ponudu ili se kreira u jednom poslu u redu čekanja, a rezultati se čitaju po ID-u posla.
- **Ekran korisničke podrške.** Agent pronalazi porudžbinu, ponovo štampa njenu nalepnicu, čita njenu vremensku liniju praćenja i otkazuje je, istim četirima pozivima za svaku porudžbinu.

## 2. Šta Uniorder radi za vas

| Bez Uniorder-a | Sa Uniorder-om |
|---|---|
| Jedan API za porudžbine lokalne dostave i drugi za nalepnice prevoznika, svaki sa sopstvenim poljima i odgovorima | Jedan oblik zahteva (`from_*`, `to_*`, `packages`) i jedan oblik odgovora za svaku uslugu |
| Integracija odlučuje koji API prevoznika poziva | Ponuda navodi svaku uslugu; odlučuje `rate_id` izabrane tarife |
| Posebni endpoint-i za nalepnicu, praćenje i otkazivanje za svaku uslugu | `GET /label`, `GET /tracking` i `POST /cancel` rade za svaku porudžbinu |
| Paketno kreiranje dostupno samo za lokalnu dostavu | Paketna ponuda i paketno kreiranje za svaku uslugu, sinhrono ili u redu čekanja |

Uniorder ne zamenjuje postojeće endpoint-e; oni ostaju dostupni i nepromenjeni. Uniorder je preporučena ulazna tačka za novu integraciju.

## 3. Mapa endpoint-a, redosledom kojim ih integracija koristi

| Korak | Namena | REST | GraphQL |
|---|---|---|---|
| 1 | Dobijanje pristupnog tokena | `POST /api/v1/user/login` | `userLogin` |
| 2 | Ponuda za svaku uslugu | `POST /api/v1/uniorder/rate` | `uniorderRate` |
| 3 | Kreiranje porudžbine po izabranoj tarifi | `POST /api/v1/uniorder` | `uniorderCreate` |
| 4 | Štampa nalepnice | `GET /api/v1/uniorder/{orderId}/label` | `uniorderLabel` |
| 5 | Čitanje porudžbine | `GET /api/v1/uniorder/{orderId}` | `uniorder` |
| 6 | Praćenje porudžbine | `GET /api/v1/uniorder/{orderId}/tracking` | `uniorderTracking` |
| 7 | Otkazivanje porudžbine | `POST /api/v1/uniorder/{orderId}/cancel` | `uniorderCancel` |
| — | Kupovina nalepnice koja nije mogla da se kupi pri kreiranju | `POST /api/v1/uniorder/{orderId}/label` | `uniorderPurchaseLabel` |
| — | Ponuda ili kreiranje do 20 redova odjednom | `POST /api/v1/uniorder/rate/batch`, `POST /api/v1/uniorder/batch` | `uniorderRateBatch`, `uniorderCreateBatch` |
| — | Stavljanje do 500 redova u red čekanja | `POST /api/v1/uniorder/rate/batch-async`, `POST /api/v1/uniorder/batch-async`, `GET /api/v1/uniorder/jobs/{jobId}` | `uniorderRateBatchAsync`, `uniorderCreateBatchAsync`, `uniorderJob` |

[REST priručnik](/api/documentation#/paths/v1-uniorder-rate/post) · [GraphQL priručnik](/api/graphql/documentation#/orders/uniorderRate)

Zahtevi, odgovori i provere korak po korak nalaze se u vodiču **Ponuda i porudžbina u jednom toku**.

## 4. Primer: checkout koji nudi sve opcije

Cvećara u Montrealu prodaje onlajn. Pri plaćanju jednom traži ponudu za paket, uključujući prevoznike nalepnica:

```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 }]
  }'
```

Odgovor navodi jednu tarifu `self_delivery` i jednu tarifu `label_service` po usluzi prevoznika. Checkout ih prikazuje kao opcije; kupac bira lokalnu dostavu istog dana. Porudžbina se kreira sa `rate_id` te tarife i istim adresama i paketima:

```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 }]
  }'
```

Odgovor vraća `id` porudžbine i njene brojeve za praćenje. Prodavnica štampa nalepnicu pomoću `GET /api/v1/uniorder/{orderId}/label` i prikazuje vremensku liniju iz `GET /api/v1/uniorder/{orderId}/tracking` na stranici porudžbine kupca.

## 5. Primer: ERP koji šalje svake noći

ERP izvozi porudžbine dana u 22:00. Adrese šalje na `POST /api/v1/uniorder/rate/batch-async`, čita posao dok `status` ne postane `done`, bira tarifu za svaki red prema sopstvenim pravilima i šalje izabrane redove na `POST /api/v1/uniorder/batch-async`. Svaki rezultat nosi `reference` reda, tako da ERP povezuje svaki rezultat sa sopstvenom stavkom porudžbine. `rate_id` važi 30 minuta, pa se posao kreiranja šalje ubrzo nakon što se posao ponude završi.

## 6. Primer: ekran korisničke podrške

Tokom poziva kupca, ekran agenta poziva `GET /api/v1/uniorder/{orderId}` za status i adrese, `GET /api/v1/uniorder/{orderId}/tracking` za vremensku liniju i dokaz o dostavi, i `POST /api/v1/uniorder/{orderId}/cancel` kada kupac otkaže. Isti pozivi važe za porudžbinu dostave i za porudžbinu nalepnice; polje `type` ih razlikuje.

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

Ista porudžbina preko GraphQL-a ([GraphQL priručnik](/api/graphql/documentation#/orders/uniorder)):

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

## 7. Pravila koja treba uzeti u obzir pri projektovanju

- **`rate_id` određuje uslugu.** Važi 30 minuta i samo za nalog koji je zatražio ponudu.
- **Cena porudžbine se određuje pri kreiranju.** `shipping_price` je naplaćena cena; `quoted_price` je cena iz ponude. Ove dve cene mogu da se razlikuju.
- **Porudžbina nalepnice se nikada ne gubi.** Kada nalepnica ne može da se kupi pri kreiranju, porudžbina se zadržava, a odgovor je `LABEL_PURCHASE_FAILED` sa `id` porudžbine; nalepnica se kupuje kasnije pomoću `POST /api/v1/uniorder/{orderId}/label`.
- **Ponovni pokušaji su bezbedni.** Pošaljite zaglavlje `Idempotency-Key` uz svaki poziv kreiranja; otkazivanje već otkazane porudžbine vraća `already_cancelled` `true`.
- **Statusi su ujednačeni.** Porudžbina dostave prijavljuje `pending`, `in_transit`, `out_for_delivery`, `delivered`, `exception` ili `cancelled`; porudžbina nalepnice prijavljuje `label_pending`, `label_purchased` ili `cancelled`, a praćenje njenog prevoznika pokazuje gde se paket nalazi.

## 8. Lista provera pre puštanja u rad

- [ ] Nalog ima API dozvolu, a token se čuva na serveru, ne u pregledaču.
- [ ] Ponude se traže sa potpunim adresama pošiljaoca i primaoca.
- [ ] Porudžbine se kreiraju u roku od 30 minuta od ponude, sa `Idempotency-Key`.
- [ ] `LABEL_PURCHASE_FAILED` se obrađuje kasnijom kupovinom nalepnice, nikada ponovnim kreiranjem porudžbine.
- [ ] Praćenje se čita iz `GET /api/v1/uniorder/{orderId}/tracking` ili prima putem webhook-ova.
- [ ] Otkazivanje obrađuje `ORDER_STATUS_NOT_CANCELLABLE` i `ORDER_CANCEL_REFUSED` tako što porudžbinu ostavlja nepromenjenu.
