# Cykl życia zamówienia

Zamówienie przesyłki przechodzi te same etapy niezależnie od przewoźnika:

`service_structure` → [`order_valuation`] → `order_send` →
`waybill` / `dispatch_code` / `turn_in` → opcjonalnie `cancel_order`

`order_valuation` jest **opcjonalne** — zobacz krok 2. Poniższe przykłady
używają [SDK PHP](/pl/sdk); każdy etap podaje nazwę metody API, więc przepływ
mapuje się 1:1 na surowe [żądania z kopertą](/pl/legacy/hmac-signing) z
dowolnego języka. Pełne kształty payloadów znajdziesz w
[referencji API v2](/pl/reference/v2-legacy).

:::tip[Nie wiesz, której usługi użyć?]

Jeśli nie przekazujesz stałego `service_id`, tylko chcesz wybrać spośród
usług, które faktycznie mogą przewieźć paczkę, zacznij od
[Wyboru usługi z oferty](/pl/guides/choosing-a-service) i wróć tutaj przy
`order_send`.

:::

## 1. Wybierz usługę — `service_structure`

Pobierz usługi dostępne na Twoim koncie i pozwól użytkownikowi (albo swojej
konfiguracji) wybrać —
[nie hardkoduj listy](/pl/guides/best-practices#nie-hardkoduj-przewoźników-i-usług):

```php
$structure = $client->getServiceStructure();
$services  = $structure->getServices();      // przewoźnicy + id usług
$packages  = $structure->getPackageTypes();  // PACZKA, PALETA, ...
$options   = $structure->getOptions();       // pobranie, ubezpieczenie, ...
```

## 2. (Opcjonalnie) Wyceń przesyłkę — `order_valuation`

Pobierz wycenę przed utworzeniem zamówienia. Ten sam obiekt zamówienia działa
dla wyceny i utworzenia:

```php
use AlsendoOne\SDK\DTO\Address;
use AlsendoOne\SDK\DTO\Request\OrderRequest;
use AlsendoOne\SDK\DTO\Request\PickupRequest;
use AlsendoOne\SDK\DTO\Request\ShipmentRequest;
use AlsendoOne\SDK\Type\Service;

$service = Service::from(Service::DpdCourier);

$order = OrderRequest::create()
    ->setService($service)
    ->setSenderAddress(new Address(/* ... */))
    ->setReceiverAddress(new Address(/* ... */))
    ->addShipment(new ShipmentRequest('PACZKA', 2.5, 40, 30, 20))
    ->setPickup(new PickupRequest('COURIER', '2026-08-19', '10:00', '16:00'));

$valuation = $client->getValuation($order);

foreach ($valuation->getPriceTable() as $price) {
    // Ceny są w groszach (1 PLN = 100 gr)
    printf("Usługa %d: %.2f PLN brutto\n",
        $price->getServiceId(), $price->getPriceGross() / 100);
}
```

:::note[Pomijasz wycenę całkowicie?]

Wiele integracji tworzy zamówienia bez wywoływania `order_valuation` — znają
usługę i przyjmują cenę z faktury. To w porządku. Pamiętaj tylko, że cena
ustala się dopiero **przy utworzeniu**: zmiany na poziomie zamówienia i
dopłaty (zobacz krok 2b) sprawiają, że zakładana cena może się różnić.
Rzeczywistą kwotę odczytaj po `order_send` z `getOrder()` / `getOrders()`
(`price` / `price_gross`, w groszach).

:::

## 2b. (Opcjonalnie) Wyceń ponownie finalny payload — `order_valuation`

Jeśli po wcześniejszej wycenie zmieniłeś zamówienie — dodałeś odbiór, usługi
dodatkowe, dane celne albo punkt — uruchom `order_valuation` ponownie na
**finalnym** payloadzie przed wysłaniem. Zmiany na poziomie zamówienia mogą
zmienić cenę, więc wcześniejsza wycena bywa nieaktualna:

- **odbiór kurierski zamówiony na ten sam dzień** może być objęty dopłatą,
- usługi dodatkowe / pobranie podnoszą koszt,
- trasa przez punkt albo obsługa celna mogą zmienić obowiązującą taryfę.

```php
// $order zawiera teraz wszystko, co zaraz wyślesz (usługa, odbiór, opcje, dane celne…)
$finalPrice = $client->getValuation($order)->getPriceForService($service);
// Pokaż/zapisz potwierdzoną cenę, potem w kroku 3 wyślij *ten sam* $order.
```

:::tip[Ten sam obiekt, zero niespodzianek]

Wyceniaj to, co zaraz wyślesz — wyceń finalny `$order`, a następnie przekaż
dokładnie ten obiekt do `order_send`.

:::

## 3. Utwórz zamówienie — `order_send`

```php
$created = $client->sendOrder($order);

$orderId = $created->getId();
$created->getWaybillNumber();   // numer śledzenia przewoźnika
$created->getTrackingUrl();     // publiczny link do śledzenia
$created->getStatus();          // np. NEW
```

:::caution

`order_send` **nie jest idempotentne** — ponowione żądanie po timeoucie może
utworzyć zduplikowane zamówienie. Zobacz
[dobre praktyki](/pl/guides/best-practices#ostrożnie-z-ponawianiem-żądań).

:::

Obiekt `pickup` decyduje, jak paczka trafi do przewoźnika (odbiór kurierski
vs. własne nadanie) — szczegóły mają osobny przewodnik:
[Typy odbioru](/pl/guides/pickups).

## 4. Dokumenty — `waybill`, `dispatch_code`, `turn_in`

Każdy dokument jest zwracany w base64:

```php
// Etykieta (PDF) — wymagana na paczce
$waybill = $client->getWaybill($orderId);
file_put_contents('label.pdf', base64_decode($waybill->getWaybill()));

// Kod nadania/zwrotu — część przewoźników wymaga go przy nadaniu;
// przewoźnicy, którzy go nie wydają, nie zwracają kodu
$dispatch = $client->getDispatchCode($orderId);

// Zbiorcze potwierdzenie nadania paczek przekazanych jednemu kurierowi
$turnIn = $client->getTurnIn([$orderId, $anotherOrderId]);
```

## 5. Śledź przesyłkę — `tracking`

Odpytuj `getTracking($waybillNumber)` albo odbieraj notyfikacje push —
zobacz [przewodnik śledzenia](/pl/guides/tracking).

## 6. W razie potrzeby anuluj — `cancel_order`

```php
$client->cancelOrder($orderId);   // rzuca ApiException, gdy nie można anulować
```

Zamówienie można anulować tylko do momentu przejęcia paczki przez
przewoźnika; później API zwraca kopertę błędu. Pamiętaj, że anulowane
zamówienie przestaje też udostępniać dokumenty — `waybill` i `turn_in`
zwracają dla niego błąd API, więc pobierz wszystko, czego potrzebujesz,
przed anulowaniem.

## Późniejszy wgląd w zamówienia

```php
$order  = $client->getOrder($orderId);        // pełne szczegóły (w tym price / price_gross, w groszach)
$orders = $client->getOrders(page: 1, limit: 25);  // lista z paginacją, max 25/stronę
```

---

**Zobacz też:** [Wybór usługi z oferty](/pl/guides/choosing-a-service) ·
[Typy odbioru](/pl/guides/pickups) · [Śledzenie](/pl/guides/tracking) ·
[Dobre praktyki](/pl/guides/best-practices)
