feat: automatické sledování doručení objednávky přes Bolt Food
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 21s
CI / Build server (push) Successful in 24s
CI / Build client (push) Successful in 36s
CI / Playwright E2E tests (push) Successful in 1m25s
CI / Build and push Docker image (push) Successful in 43s
CI / Notify (push) Successful in 2s

Zakladatel skupiny může na stránce objednání vložit sdílecí odkaz
Bolt Food. Server pak každou minutu dotazuje veřejné Bolt API
a automaticky aktualizuje čas doručení skupiny (deliveryAt).
Sledování se samo ukončí po doručení, zrušení objednávky nebo
opakovaných chybách. Leader lease vytažena do znovupoužitelného
modulu leaderLease.ts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 12:22:07 +02:00
co-authored by Claude Fable 5
parent 1df21edc1a
commit 491ec25b52
12 changed files with 559 additions and 52 deletions
+18
View File
@@ -3,6 +3,7 @@ import getStorage from "./storage";
import { getClientData, getToday, initIfNeeded } from "./service";
import { getStores } from "./stores";
import { removePendingQrsByGroupId } from "./pizza";
import { extractBoltToken } from "./boltTracking";
import { ClientData, GroupState, MealSlot, OrderGroup, OrderGroupMember } from "../../types/gen/types.gen";
import { formatDate } from "./utils";
@@ -150,6 +151,7 @@ export async function setGroupState(login: string, groupId: string, newState: Gr
group.orderedAt = undefined;
group.deliveryAt = undefined;
group.qrGenerated = undefined;
group.boltTrackingToken = undefined;
for (const ml of memberLogins) {
group.members[ml] = { ...group.members[ml], paid: undefined };
}
@@ -199,3 +201,19 @@ export async function updateGroupTimes(login: string, groupId: string, orderedAt
if (deliveryAt !== undefined) group.deliveryAt = deliveryAt || undefined;
return saveExtraData(data, date);
}
export async function setGroupBoltTracking(login: string, groupId: string, shareUrl?: string, date?: Date): Promise<ClientData> {
const data = await getExtraData(date);
const group = findGroup(data, groupId);
if (!group) throw new Error('Skupina nebyla nalezena');
if (group.creatorLogin !== login) throw new Error('Sledování Bolt může nastavit pouze zakladatel');
if (!shareUrl) {
group.boltTrackingToken = undefined;
} else {
if (group.state !== GroupState.ORDERED) throw new Error('Sledování Bolt lze nastavit pouze ve stavu "objednáno"');
const token = extractBoltToken(shareUrl);
if (!token) throw new Error('Neplatný odkaz na sledování objednávky Bolt');
group.boltTrackingToken = token;
}
return saveExtraData(data, date);
}