Log NetUP request/response body; fix reservation_id to be numeric

- reservation_id converted to integer (NetUP likely requires number not UUID string)
- Log requestBody sent to NetUP and responseBody received from NetUP
- Push event rows now expandable: click to see URL, request JSON, NetUP error response
- Same for checkout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 12:29:45 +03:00
parent d8f560ae12
commit c656d0c6ae
3 changed files with 75 additions and 31 deletions

View File

@@ -7,15 +7,17 @@ type SlugIdParam = { Params: { slug: string; id: string } }
// ── Push event log (check-in / check-out calls to NetUP) ─────────────────────
export type PushEvent = {
ts: string
action: 'check-in' | 'check-out' | 'message'
hotelId: string
roomNumber: string // PMS room number
netupRoom: string // NetUP room number
url: string
status: 'ok' | 'error' | 'skipped'
httpStatus?: number
error?: string
ts: string
action: 'check-in' | 'check-out' | 'message'
hotelId: string
roomNumber: string // PMS room number
netupRoom: string // NetUP room number
url: string
requestBody?: unknown // what we sent
status: 'ok' | 'error' | 'skipped'
httpStatus?: number
responseBody?: string // what NetUP replied
error?: string
}
const MAX_PUSH = 100
export const pushLog: PushEvent[] = []
@@ -366,24 +368,31 @@ async function notifyNetupCheckinInternal(
const url = `${base}/mw/api/hotel-room/${encodeURIComponent(mapping.netup_room_number)}/check-in`
const cred = Buffer.from(`${cfg.username}:${cfg.password}`).toString('base64')
// reservation_id must be a number in NetUP — convert UUID/string to integer
const resIdNum = parseInt(reservationId.replace(/\D/g, '').slice(-8), 10) || Date.now() % 1000000
const requestBody = { reservation_id: resIdNum, name: guestName, language: language ?? cfg.default_language }
try {
const res = await fetch(url, {
method: 'POST',
headers: { Authorization: `Basic ${cred}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ reservation_id: reservationId, name: guestName, language: language ?? cfg.default_language }),
body: JSON.stringify(requestBody),
signal: AbortSignal.timeout(6000),
})
const responseText = await res.text().catch(() => '')
const event: PushEvent = {
ts: new Date().toISOString(), action: 'check-in', hotelId,
roomNumber, netupRoom: mapping.netup_room_number, url,
requestBody,
status: res.ok ? 'ok' : 'error', httpStatus: res.status,
responseBody: responseText || undefined,
}
if (!res.ok) event.error = `HTTP ${res.status}`
recordPush(event)
return res.ok ? { ok: true, netupRoom: mapping.netup_room_number } : { ok: false, error: `HTTP ${res.status}` }
return res.ok ? { ok: true, netupRoom: mapping.netup_room_number } : { ok: false, error: `HTTP ${res.status}: ${responseText}` }
} catch (err) {
const error = err instanceof Error ? err.message : 'Ошибка соединения'
recordPush({ ts: new Date().toISOString(), action: 'check-in', hotelId, roomNumber, netupRoom: mapping.netup_room_number, url, status: 'error', error })
recordPush({ ts: new Date().toISOString(), action: 'check-in', hotelId, roomNumber, netupRoom: mapping.netup_room_number, url, requestBody, status: 'error', error })
return { ok: false, error }
}
}
@@ -419,10 +428,12 @@ export async function notifyNetupCheckout(hotelId: string, roomId: string) {
headers: { Authorization: `Basic ${cred}` },
signal: AbortSignal.timeout(6000),
})
const responseText = await res.text().catch(() => '')
recordPush({
ts: new Date().toISOString(), action: 'check-out', hotelId,
roomNumber, netupRoom: mapping.netup_room_number, url,
status: res.ok ? 'ok' : 'error', httpStatus: res.status,
responseBody: responseText || undefined,
error: res.ok ? undefined : `HTTP ${res.status}`,
})
} catch (err) {