Workforce locations: derive from teams since /api/v2/locations may be billing-locked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-07 13:11:17 +00:00
parent 5a9a05bb62
commit c862c1f9e3

View file

@ -112,7 +112,7 @@ export async function integrationRoutes(app) {
})
// POST /settings/api/integrations/newbook/sync-rooms
// GET /settings/api/integrations/workforce/locations — fetch location list from Tanda for the picker
// GET /settings/api/integrations/workforce/locations — derive locations from teams list
app.get('/integrations/workforce/locations', { preHandler: requireAdmin }, async (req, reply) => {
const { rows: [row] } = await pool.query(`SELECT * FROM integrations WHERE slug = 'workforce'`)
if (!row?.enabled) return reply.status(400).send({ error: 'Workforce integration not enabled' })
@ -120,10 +120,11 @@ export async function integrationRoutes(app) {
if (!creds.bearer_token) return reply.status(400).send({ error: 'Workforce bearer token not configured' })
const baseUrl = creds.base_url || 'https://my.tanda.co'
const locations = []
// /api/v2/locations may be locked by billing tier — derive from teams instead
const teams = []
let page = 1
while (true) {
const res = await fetch(`${baseUrl}/api/v2/locations?page=${page}&page_size=100`, {
const res = await fetch(`${baseUrl}/api/v2/departments?page=${page}&page_size=100`, {
headers: { Authorization: `Bearer ${creds.bearer_token}` },
signal: AbortSignal.timeout(8000),
})
@ -133,12 +134,26 @@ export async function integrationRoutes(app) {
return reply.status(502).send({ error: msg || `Workforce API error (${res.status})` })
}
const data = await res.json()
const items = Array.isArray(data) ? data : (data.locations ?? [])
locations.push(...items.map(l => ({ id: String(l.id), name: l.name, short_name: l.short_name ?? null })))
const items = Array.isArray(data) ? data : (data.departments ?? [])
teams.push(...items)
if (items.length < 100) break
page++
}
return locations
// Group team names by location_id
const locMap = {}
for (const t of teams) {
if (!t.location_id) continue
const id = String(t.location_id)
if (!locMap[id]) locMap[id] = []
locMap[id].push(t.name)
}
return Object.entries(locMap).map(([id, teamNames]) => ({
id,
name: `Location ${id}`,
team_names: teamNames.sort(),
}))
})
app.post('/integrations/newbook/sync-rooms', { preHandler: requireAdmin }, async (req, reply) => {