feat: TTLock diagnostics — test cloud API button + fix api_server SELECT bug
- Fix: api_server was missing from SELECT in issue-card route (always fell back to EU default) - Add "Проверить API" button in Step 1 that calls ttlock:test_api via agent - Agent: testCloudApi() — gets OAuth token + lists locks, returns count - Agent: apiPost() now includes response body in error message (was just HTTP status) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -131,6 +131,45 @@ const ttlockRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
},
|
||||
)
|
||||
|
||||
// ── POST /api/hotels/:slug/ttlock/test-api ──────────────────────────────────
|
||||
// Проверяет подключение к TTLock Cloud API (OAuth + список замков)
|
||||
fastify.post<SlugParam & { Body: { workstation_id: string } }>(
|
||||
'/api/hotels/:slug/ttlock/test-api',
|
||||
{ onRequest: [fastify.authenticate] },
|
||||
async (req, reply) => {
|
||||
const { slug } = req.params
|
||||
if (!canManage(req.user.hotelSlug, req.user.role, slug))
|
||||
return reply.code(403).send({ error: 'Forbidden' })
|
||||
const hotelId = await getHotelId(slug)
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const { rows: cfgRows } = await db.query(
|
||||
'SELECT client_id, client_secret, api_server FROM hotel_ttlock_config WHERE hotel_id = $1',
|
||||
[hotelId],
|
||||
)
|
||||
const cfg = cfgRows[0]
|
||||
if (!cfg?.client_id) return reply.code(400).send({ error: 'client_id не заполнен' })
|
||||
|
||||
const workstationId = req.body.workstation_id
|
||||
if (!workstationId) return reply.code(400).send({ error: 'workstation_id required' })
|
||||
|
||||
try {
|
||||
const result = await sendCommandAndWait(workstationId, {
|
||||
type: 'ttlock:test_api',
|
||||
clientId: cfg.client_id,
|
||||
clientSecret: cfg.client_secret,
|
||||
apiServer: cfg.api_server ?? 'https://euopen.ttlock.com',
|
||||
}, 15_000) as { ok?: boolean; lockCount?: number; error?: string }
|
||||
|
||||
if (!result.ok) return reply.code(502).send({ error: result.error ?? 'Ошибка API' })
|
||||
return { ok: true, lockCount: result.lockCount }
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'Агент не ответил'
|
||||
return reply.code(502).send({ error: msg })
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// ── POST /api/hotels/:slug/ttlock/test ──────────────────────────────────────
|
||||
// Проверяем: агент онлайн, энкодер отвечает на COM-порту
|
||||
fastify.post<SlugParam & { Body: { workstation_id: string } }>(
|
||||
@@ -272,7 +311,7 @@ const ttlockRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
// Конфигурация TTHotel (client_id, card_sectors)
|
||||
const { rows: cfgRows } = await db.query(
|
||||
'SELECT client_id, client_secret, card_sectors, is_enabled FROM hotel_ttlock_config WHERE hotel_id = $1',
|
||||
'SELECT client_id, client_secret, card_sectors, is_enabled, api_server FROM hotel_ttlock_config WHERE hotel_id = $1',
|
||||
[hotelId],
|
||||
)
|
||||
const cfg = cfgRows[0]
|
||||
|
||||
Reference in New Issue
Block a user