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álostiOrderShippedV1změ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