Expedice objednávky

Balení, odeslání a doručení – odeslání je událost, podle které sklad sám vydá rezervaci (choreografie).

Na této stránce

Shrnutí: Admin na stránce Expedice (/Admin/Fulfilment) objednávku zabalí, odešle (kurýr: dopravce a číslo zásilky) a nakonec označí jako doručenou. Odeslání je fakt, který zajímá víc stran: sklad podle integrační události OrderShippedV1 změní rezervaci na výdej, zákazník dostane e-mail s číslem zásilky. Sága jen zaznamená, že zboží už nevrací.

Odeslání

sequenceDiagram
    autonumber
    actor A as Admin
    participant P as Stránka Expedice
    participant S as OrderService
    participant ODB as ordering.db
    participant OW as OutboxWorker
    participant SG as OrderSagaOrchestrator
    participant H as Handlery (e-mail, překladač)
    participant MQ as RabbitMQ
    participant I as Inventory.Api

    A->>P: Začít balit (vybrané objednávky)
    P->>S: StartPackingAsync(id)
    S->>ODB: COMMIT: Order Packing (+ historie, Version+1) + Outbox[OrderPackingStarted]
    A->>P: Odeslat (dopravce, číslo zásilky)
    P->>S: ShipAsync(id, carrier, trackingNumber)
    S->>S: order.Ship() – jen z Packing; kurýr bez čísla zásilky = DomainException
    S->>ODB: COMMIT: Order Shipped + Outbox[OrderShipped]
    OW->>SG: OrderShipped
    SG->>SG: saga Reserved → Shipped (žádný příkaz)
    OW->>H: OrderShipped → e-mail „na cestě“ + OrderShippedV1
    OW->>MQ: OrderShippedV1 (událost, fanout)
    MQ->>I: OrderShippedV1 → FulfilReservationHandler
    I->>I: StockReservation.Fulfil() – rezervace „vydaná“, zásoba beze změny

Doručení

„Doručeno“ zatím kliká admin (simulace dopravce – skutečný by poslal webhook, e-shop krok 8): CompleteAsync → order.MarkDelivered() (jen ze Shipped) → OrderCompleted → sága Shipped → Completed, e-mail „doručeno“ a integrační OrderCompletedV1 (kontrakt zůstal stejný, jen teď znamená „doručeno“).

Proč událost, a ne příkaz

Rezervaci řídí sága příkazem (ReserveStockV1) a čeká na odpověď – rezervace může selhat (málo zboží) a sága podle výsledku rozhoduje. Výdej odeslaného zboží selhat nemůže: zboží už je fyzicky pryč. Stačí proto oznámit fakt a každý, koho zajímá, si ho zpracuje sám (choreografie). Sklad dnes, notifikace v e-shop kroku 7 – Ordering kvůli novému odběrateli nic měnit nemusí.

Souběh: odeslat × zrušit

Zákazník může zrušit i během balení. Když ve stejné chvíli admin odesílá, oba načtou objednávku se stejnou Version. První uložení projde a verzi zvýší, druhé narazí na UPDATE … WHERE Version = původní → žádný řádek → ConcurrencyConflictException. Nic se nepřepíše: buď je objednávka zrušená (zboží se vrátí), nebo odeslaná (rezervace vydaná) – nikdy obojí. Adminovi stránka ukáže „Objednávka se mezitím změnila“.

Co si všimnout

  • Po odeslání zrušit nejde – pravidlo hlídá Order.Cancel, tlačítko na stránce je jen pohodlí.
  • Vydanou rezervaci nejde uvolnit – kdyby přece jen přišel ReleaseStockV1, sklad ji přeskočí (hledá jen aktivní rezervace).
  • Osobní odběr má stejné stavy s jinými popisky („Připravujeme“, „K vyzvednutí“, „Vyzvednutá“) a bez dopravce.

Kód

Order · OrderService · Expedice (stránka) · FulfilReservationHandler · StockReservation · OrderShippedV1