# Prepravné služby

Použite vlastné prepravné služby logistickej firmy: zoznam služieb → načítanie konfigurácie služby → odhad → vytvorenie objednávky → platba → spätné čítanie → sledovanie → zrušenie testovacej objednávky.

Táto príručka dokumentuje iba nasledujúce operácie. Vykonajte ich v poradí. Overenie používa účet **zákazníka**.

Nahraďte `YOUR_HOST` a `ACCESS_TOKEN` hodnotami z vášho prostredia.

## 1. Prihlásenie (zákazník)

```bash
curl -X POST https://YOUR_HOST/api/v1/user/customer/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"your_password"}'
```

Použite `access_token` takto:

```
Authorization: Bearer ACCESS_TOKEN
```

GraphQL používa rovnakú hlavičku na `POST /api/graphql`.

**Overenie:** prihlásenie vráti `access_token`. Neskoršie volanie bez neho vráti `401`.

## 2. Zoznam služieb

**REST:** `GET /api/v1/customer/shipping-orders/services` — [Príručka REST](/api/documentation#/paths/v1-customer-shipping-orders-services/get)

```bash
curl https://YOUR_HOST/api/v1/customer/shipping-orders/services \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

**GraphQL:** `customerShippingOrderServices` ([Príručka GraphQL](/api/graphql/documentation#/customer/customerShippingOrderServices))

Každý riadok má `service_code`, `name`, `offer_pickup`, `allow_warehouse_delivery`. Prázdny zoznam znamená, že tomuto zákazníkovi nie je priradená žiadna služba.

**Overenie:** zaznamenali ste jeden `service_code` (príklad nižšie: `intl_express`).

## 3. Načítanie konfigurácie tejto služby

**REST:** `GET /api/v1/customer/shipping-orders/services/{serviceCode}/config` — [Príručka REST](/api/documentation#/paths/v1-customer-shipping-orders-services-serviceCode--config/get)

```bash
curl https://YOUR_HOST/api/v1/customer/shipping-orders/services/intl_express/config \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

**GraphQL:** `customerShippingOrderServiceConfig` ([Príručka GraphQL](/api/graphql/documentation#/customer/customerShippingOrderServiceConfig))

**Overenie:** máte aspoň jedno `id` skladu, ak táto služba umožňuje odovzdanie v sklade. `403` znamená, že tento zákazník túto službu nesmie používať.

## 4. Odhad

**REST:** `POST /api/v1/customer/shipping-orders/services/{serviceCode}/estimate-price`

```bash
curl -X POST https://YOUR_HOST/api/v1/customer/shipping-orders/services/intl_express/estimate-price \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "origin_type": "warehouse",
    "warehouse_id": 7,
    "delivery_postcode": "M5V2H1",
    "delivery_country": "CA",
    "packages": [{
      "weight": 2,
      "length": 30,
      "width": 20,
      "height": 15,
      "weight_unit": 2,
      "dimension_unit": 2
    }]
  }'
```

`origin_type`: `warehouse` (odovzdanie v sklade) alebo `pickup` (firma vyzdvihne). Musí zodpovedať tomu, čo krok 3 uviedol, že služba povoluje.

**Overenie:** `result` je true a máte cenu (alebo príznak „potrebuje ponuku“ pri ručnom oceňovaní). Zatiaľ nevytvárajte, ak je cieľ/balík odmietnutý.

## 5. Vytvorenie objednávky

**REST:** `POST /api/v1/customer/shipping-orders/services/{serviceCode}/orders`

Pošlite `Idempotency-Key`.

```bash
curl -X POST https://YOUR_HOST/api/v1/customer/shipping-orders/services/intl_express/orders \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: dev-ship-001" \
  -d '{
    "origin_type": "warehouse",
    "warehouse_id": 7,
    "reference": "DEV-SHIP-001",
    "delivery_name": "Jane Recipient",
    "delivery_telephone": "5555555555",
    "delivery_email": "jane@example.com",
    "delivery_address_1": "123 King St W",
    "delivery_city": "Toronto",
    "delivery_province": "ON",
    "delivery_country": "CA",
    "delivery_postcode": "M5V2H1",
    "package": [{
      "weight": 2,
      "length": 30,
      "width": 20,
      "height": 15,
      "weight_unit": 2,
      "dimension_unit": 2,
      "quantity": 1
    }]
  }'
```

**Overenie:** odpoveď má `id` objednávky. Uložte `id`, `tracking_number` / `reference_number`, ak sú prítomné.

## 6. Platba

**REST:** `POST /api/v1/customer/shipping-orders/{id}/pay`

```bash
curl -X POST https://YOUR_HOST/api/v1/customer/shipping-orders/9001/pay \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

Voliteľne: najprv `GET /api/v1/customer/shipping-orders/{id}/payment-info`. `402` znamená, že peňaženka sumu nepokrýva — dobite, potom skúste znova.

**Overenie:** objednávka už nie je splatná, alebo `remaining_balance` je `0`.

## 7. Načítanie objednávky a sledovanie

**REST:** `GET /api/v1/customer/shipping-orders/{id}` — [Príručka REST](/api/documentation#/paths/v1-customer-shipping-orders-id/get)

```bash
curl https://YOUR_HOST/api/v1/customer/shipping-orders/9001 \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

**GraphQL:** `customerShippingOrderShow` ([Príručka GraphQL](/api/graphql/documentation#/customer/customerShippingOrderShow))

Keď je na objednávke `tracking_number`, verejné sledovanie (bez tokenu):

```bash
curl https://YOUR_HOST/api/v1/tracking/SR123456789012
```

[Príručka REST](/api/documentation#/operations/getPublicTracking) · [Príručka GraphQL](/api/graphql/documentation#/tracking/trackingPublic)

**Overenie:** detail je objednávka tohto zákazníka. Verejné sledovanie ju nájde, hneď ako číslo existuje.

## 8. Konfigurácia oznámení o udalostiach

| Nastavenie | Udalosť | Kedy |
|---|---|---|
| `order_create_webhook_url` | `order.created` | Uložiť `id` a sledovacie čísla |
| `tracking_event_webhook_url` | `tracking.event` | Časová os |
| `order_status_change_webhook_url` | `order.status_change` | Stav vo vašom systéme |

**REST:** `PUT /api/v1/webhook-settings` — [Príručka REST](/api/documentation#/paths/v1-webhook-settings/put)

**GraphQL:** `webhookSettingsUpdate` ([Príručka GraphQL](/api/graphql/documentation#/webhooks/webhookSettingsUpdate)).

Overujte **v2** nad surovým telom: `HMAC_SHA256(timestamp + "." + raw_body, secret)` proti `X-Webhook-Signature-V2`. Deduplikujte podľa `X-Webhook-Event-Id`. Odpovedzte **2xx do 3 sekúnd**.

```php
$raw = file_get_contents('php://input');
$ts  = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_V2'] ?? '';
$expected = hash_hmac('sha256', $ts . '.' . $raw, $sharedSecret);
if (!hash_equals($expected, $sig)) {
    http_response_code(401);
    exit;
}
```

**Overenie:** jedno testovacie vytvorenie prinesie `order.created` s týmto `id`.

## 9. Zrušenie testovacej objednávky

**REST:** `POST /api/v1/customer/shipping-orders/{id}/cancel`

```bash
curl -X POST https://YOUR_HOST/api/v1/customer/shipping-orders/9001/cancel \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

**Overenie:** druhé zrušenie je bezpečné, alebo API povie, že objednávka je už zrušená. `422` znamená, že tento stav nemožno zrušiť.

## Zoznam testov

Použite testovacie `reference` ako `DEV-SHIP-001`:

- [ ] Zoznam služieb nie je prázdny; zaznamenali ste jeden `service_code`.
- [ ] Konfigurácia vráti sklady / balenia pre túto službu.
- [ ] Odhad vráti cenu (alebo jasný príznak potreby ponuky).
- [ ] Vytvorenie vráti `id`; rovnaký `Idempotency-Key` nevytvorí druhú objednávku.
- [ ] Platba uspeje, **alebo** ste potvrdili, že peňaženku treba dobiť (`402`).
- [ ] Detail ukáže objednávku tohto zákazníka.
- [ ] Verejné sledovanie zásielku nájde, hneď ako sledovacie číslo existuje.
- [ ] Zrušenie uspeje, **alebo** ste potvrdili, že tento stav nemožno zrušiť.
