ALBI B2B · interní zadání ← Rozcestník · verze 1.0 · 25. 9. 2026 · k revizi
F01 · fáze 1 · nové

Opakovaná objednávka - tlačítko Objednat znovu

Zákazník u kterékoli své objednávky klikne na Objednat znovu. Její položky se přidají do košíku v aktuálních cenách, zaokrouhlené na balení. Co už nesmí koupit, se vynechá a řekne mu to.

Jádro (FrontAPI) + SFX FrontAPI: 1 nový endpoint Administrace: beze změny PBS 121587 Autor: Hana Ortmannová
Co se dělá

Velkoobchodní odběratel opakuje většinu objednávek. Dnes musí každou položku znovu najít v katalogu. Starý B2B umí objednávku zkopírovat, ale jen pro hlavní účet, bez odkazu v šablonách a tak, že napřed vysype košík.

Kam patří. Jádro MasterShopu (větev front-api): endpoint, který z objednávky naplní košík. Opakovaná objednávka se hodí každému klientovi na headlessu, klasické jádro kopii objednávky už má. Obálka: tlačítko Objednat znovu a výsledkové okno v SFX. Názvy nových tabulek a endpointů jsou pracovní, v jádru je pojmenuje programátor.

Otevřené otázky

Nic z toho nebrání začít. K1 a D1 se dají rozhodnout během vývoje, D2 je nález mimo tuto funkci.

Klient

Rozhoduje ALBI

#Otázka a náš návrh
K1Smí Objednat znovu i podúčet, nebo jen hlavní účet jako dnes? Návrh: ano, každý účet u objednávek, které vidí. Podúčet vidí jen objednávky na své doručovací adresy, takže nic cizího nezkopíruje.
Vývojář

Rozhoduje vývoj

#Otázka
D1Zaokrouhlení na balení: jádro počet při vložení do košíku samo zaokrouhlí nahoru na násobek balení a vrátí varování s velikostí balení. Endpoint po vložení přečte skutečný počet z košíku a vrátí ho jako countAdded. Ověřeno čtením kódu, ne během: otestovat na B2B účtu, až padne bloker košíku.
D2Detail objednávky GET /api-orders/order/{hash} v jádře nevyžaduje JWT a neověřuje vlastníka. Nový endpoint to nesmí zopakovat. Oprava detailu v jádře je mimo tuto funkci, ale je to bezpečnostní nález k založení.
D3Seznam objednávek vrací plné detaily včetně položek, výchozí stránka 10. Pro tlačítko v seznamu to stačí. Pokud SFX bude načítat víc, zvážit odlehčené DTO.

Shrnutí

Workflow

Co se ukládá

Kroky

  1. Zákazník klikne na Objednat znovu u objednávky v seznamu nebo v jejím detailu. SFX zavolá nový endpoint s hashem objednávky a tokenem košíku.
    • Neúspěch: objednávka nepatří k uzlu zákazníka nebo ji podúčet nesmí vidět → 403, SFX zobrazí obecnou chybu. Košík se nemění.
    • Úspěch: pokračuje se krokem 2.
  2. Endpoint projde položky objednávky a vezme jen ty, které mají produkt. Dopravu, platbu, slevy a dárky přeskočí bez hlášení.
  3. U každé položky ověří, že produkt jde koupit. Načte produkt frontendovou cestou jádra, která respektuje zavřený katalog zákazníka, a ověří, že je prodejný.
    • Produkt neexistuje nebo ho zákazník nesmí vidět: položka se vynechá s důvodem NOT_AVAILABLE. Zákazník NEPOZNÁ rozdíl mezi „neexistuje" a „není ve vašem sortimentu". Je to záměr, sortiment jiných zákazníků se neprozrazuje.
    • Produkt existuje, ale nejde koupit (neprodejný, vyprodaný bez možnosti objednat): vynechá se s důvodem NOT_PURCHASABLE.
    • Produkt jde koupit: pokračuje se krokem 4.
  4. Spočítá množství. Původní počet kusů se zaokrouhlí nahoru na násobek balení. Když už je produkt v košíku, nové množství = stávající + zaokrouhlené původní. D1

    ⚠️ Dev: jádrový endpoint košíku množství u existující položky přepisuje, nesčítá. Součet musí udělat nový endpoint před zápisem.

  5. Zapíše položky do košíku po jedné přes službu jádra pro košík, ve stejném pořadí jako v objednávce. Když zápis jedné položky selže, ostatní se přidají a ta jedna se vynechá s důvodem NOT_PURCHASABLE.
  6. Vrátí výsledek: seznam přidaných položek (s výsledným množstvím a příznakem, zda se zaokrouhlovalo) a seznam vynechaných s důvodem.
    • Nic se nepřidalo: odpověď je stále 200, oba seznamy vyplněné podle skutečnosti. SFX řekne, že z objednávky nejde nic objednat. Košík je beze změny.
    • Přidalo se aspoň něco: SFX zobrazí výsledkové okno s tlačítkem do košíku.

Nesahat na jádrovou třídu kopírování objednávky ze starého frontu. Je svázaná se Smarty a vyprazdňuje košík. Nový endpoint ji NEPOUŽIJE, jen převezme pravidlo výběru položek.

Zobrazení na FE

Dvě místa v uživatelské zóně a jedno výsledkové okno. Vzhled podle design systému ALBI, chování podle prototypu, obrazovka Objednávky.

Kde tlačítko je

Stavy tlačítka a okna

StavCo zákazník vidí
KlidTlačítko „Objednat znovu".
NačítáníTlačítko neaktivní s indikátorem. Nelze kliknout dvakrát.
Vše přidánoOkno: „Přidáno 5 položek do košíku." Seznam položek s množstvím. Tlačítka „Přejít do košíku" (primární) a „Zavřít".
Část přidánaOkno: „Přidáno 4 z 5 položek." Dva bloky: přidané; vynechané s důvodem slovy („Není ve vašem sortimentu", „Momentálně nejde objednat"). U zaokrouhlených položek poznámka „upraveno na 12 ks, balení má 6 ks".
Nic nepřidánoOkno: „Z této objednávky teď nejde nic objednat." Seznam vynechaných s důvody. Jen „Zavřít". Košík se nezměnil.
ChybaHláška „Objednávku se nepodařilo zopakovat, zkuste to znovu." Košík se nezměnil.
Náhled FE: karta objednávky a výsledkové okno
WF-F1

Seznam objednávek, karta objednávky

Můj účet › Objednávky
2026‑1013 Přijato vaše č. OBJ‑1147 783 Kč
4 položky · 79 ks · Lípová 12, Praha 2 · 23. 9. 2026
Detail objednávkyObjednat znovu

Nový prvek: sekundární tlačítko v patičce karty. Zbytek karty je stávající SFX komponenta OrderCard.

WF-F2

Výsledkové okno, stav „část přidána"

Přidáno 4 z 5 položek do košíku
ProduktMnožstvíPoznámka
Puzzle Karak 500 dílků12 ks (2 bal.)
Hrnek Kočka 330 ml18 ks (3 bal.)
Přání k narozeninám25 ks (1 bal.)upraveno ze 7 ks, balení má 25
Dárková taška střední50 ks (1 bal.)
Vynecháno
Kalendář Kočky 2026Není ve vašem sortimentu
Přejít do košíkuZavřít

Důvody se překládají z kódů odpovědi: NOT_AVAILABLE → „Není ve vašem sortimentu", NOT_PURCHASABLE → „Momentálně nejde objednat". Texty jsou překladové klíče SFX ve čtyřech mutacích.

FrontAPI

Jeden nový endpoint v jádru MasterShopu, modul FrontApi vedle existujících endpointů košíku. Atribut #[AsRoute], vlastní DTO a registrace tagu v EndpointTagType.php. Bez registrace tagu endpoint tiše vypadne.

EndpointStavK čemu
POST /api-carts/carts/{cartToken}/reordernovýNaplní košík z objednávky. Tělo { "orderHash": "…" }, nebo { "items": [ { "productId", "count" } ] } pro blok Doobjednat vše na nástěnce (F03). Vyžaduje JWT zákazníka. Vrací přidané a vynechané položky, v obou případech stejně.
GET /api-orders/orders/{userId}existujeSeznam objednávek s položkami. SFX z něj má hash objednávky pro tlačítko. Filtr na datum a stav umí, řazení ne.
GET /api-orders/order/{hash}existujeDetail objednávky. Položky nesou objectId, objectCode, count a aktuální produktovou kartu s příznakem prodejnosti. V jádře bez JWT. D2
PUT /api-carts/carts/{cartToken}existujeVložení jedné položky. Nový endpoint ho NEVOLÁ přes HTTP, používá stejnou službu jádra pro košík uvnitř.

Odpověď nového endpointu

{
  "cartToken": "c3f1…",
  "added": [
    { "productId": 4412, "productCode": "P-4412", "name": "Puzzle Karak 500 dílků",
      "countOrdered": 12, "countAdded": 12, "rounded": false },
    { "productId": 6601, "productCode": "P-6601", "name": "Přání k narozeninám",
      "countOrdered": 7, "countAdded": 25, "rounded": true, "piecesInPackage": 25 }
  ],
  "skipped": [
    { "productCode": "D-2612", "name": "Kalendář Kočky 2026", "reason": "NOT_AVAILABLE" }
  ]
}

Co endpoint používá z jádra

Administrace

Nic nepřibývá. Funkce nemá nastavení, není co zapínat ani konfigurovat. Záměrně: každý přepínač je práce navíc a klient o žádný nežádal.

Pravidla a validace

Mimo rozsah a nasazení

Mimo rozsah

Nasazení

Kontrola po nasazení