isPaired()) { try { $pairing = $api->pair( scope: 'restaurants:read staff:read staff:authenticate attendance:read attendance:punch', deviceName: 'Píchačka (příklad)', ); echo "Zařízení není spárované. Vedoucí potvrdí kód v administraci (Správa PC / zařízení → Připojit zařízení).\n"; echo "KÓD: {$pairing->userCode}\n"; echo "nebo otevřete: {$pairing->verificationUriComplete}\n"; $pairing->wait(); // ptá se podle intervalu, než vedoucí potvrdí } catch (OAuthError $e) { echo match ($e->error) { 'access_denied' => "Vedoucí párování odmítl.\n", 'expired_token' => "Kód vypršel (10 minut). Spusťte příklad znovu.\n", default => "Párování se nepovedlo: {$e->getMessage()}\n", }; exit(1); } } if ($api->restaurantId() === null) { $api->connection(); // zapamatuje provozovnu zařízení } $rid = $api->restaurantId(); echo "Provozovna $rid. Příkazy: p/o/pz/kz PIN, k = kdo je v práci, odparovat, q = konec.\n"; $types = ['p' => 'clock_in', 'o' => 'clock_out', 'pz' => 'break_start', 'kz' => 'break_end']; $states = ['working' => 'v práci', 'on_break' => 'na přestávce', 'off' => 'mimo práci']; // 2) píchnutí – id vznikne jednou na píchnutí; při opakování (výběr zaměstnance, výpadek) se posílá stejné function punch(Client $api, string $rid, string $type, string $pin, array $states): void { $body = ['id' => Client::uuid(), 'type' => $type, 'credential' => ['method' => 'pin', 'secret' => $pin]]; for (;;) { try { $r = $api->post("/restaurants/$rid/attendance/punches", $body); echo "OK: {$r['employee']['name']} – " . ($states[$r['state']] ?? $r['state']) . "\n"; return; } catch (ApiError $e) { switch ($e->errorCode) { case ErrorCode::STAFF_AMBIGUOUS: // stejný PIN má víc lidí – vybrat a poslat znovu echo "Tento PIN má víc lidí:\n"; foreach ($e->candidates as $i => $c) { echo ' ' . ($i + 1) . ") {$c['name']}\n"; } echo 'Číslo: '; $choice = (int)trim((string)fgets(STDIN)); if (!isset($e->candidates[$choice - 1])) { echo "Zrušeno.\n"; return; } $body['credential']['employee_id'] = $e->candidates[$choice - 1]['id']; continue 2; case ErrorCode::STAFF_CREDENTIALS_INVALID: echo "Neznámý PIN.\n"; return; case ErrorCode::STAFF_LOCKED: echo "Moc špatných pokusů – zkuste to za {$e->retryAfter} s.\n"; return; case ErrorCode::ATTENDANCE_STATE_CONFLICT: echo "Teď to nejde: {$e->title}\n"; return; case ErrorCode::NETWORK_ERROR: case ErrorCode::TIMEOUT: echo "Bez sítě – zkuste znovu.\n"; // skutečný terminál by píchnutí uložil a poslal dávkou return; default: echo "Chyba: {$e->title} ({$e->errorCode})\n"; return; } } } } // 3) smyčka příkazů while (($line = fgets(STDIN)) !== false) { $parts = preg_split('/\s+/', trim($line), 2); $cmd = strtolower($parts[0] ?? ''); try { if (isset($types[$cmd]) && isset($parts[1])) { punch($api, $rid, $types[$cmd], $parts[1], $states); } elseif ($cmd === 'k') { foreach ($api->all("/restaurants/$rid/attendance/presence") as $p) { echo " {$p['employee']['name']}: " . ($states[$p['state']] ?? $p['state']) . "\n"; } } elseif ($cmd === 'odparovat') { $api->unpair(); echo "Spárování zapomenuto.\n"; break; } elseif ($cmd === 'q') { break; } elseif ($cmd !== '') { echo "Příkazy: p/o/pz/kz PIN, k, odparovat, q\n"; } } catch (ApiError $e) { if ($e->errorCode === ErrorCode::NOT_PAIRED) { // vedoucí zařízení odpároval echo "Zařízení bylo odpárováno. Spusťte příklad znovu.\n"; exit(1); } echo "Chyba: {$e->title} ({$e->errorCode})\n"; } }