Scope manual sync buttons to current view dates only
Sync rota and pull timesheets now operate on the 7-day view window rather than rolling default windows — reduces API calls and allows backdating. Cron job still uses rolling defaults via runRotaSync()/runTimesheetSync(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9bfd14a082
commit
ffefa1914f
9 changed files with 81 additions and 60 deletions
|
|
@ -5,25 +5,37 @@ function fmtDate(d) {
|
|||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export async function runRotaSync() {
|
||||
function defaultRotaWindow() {
|
||||
const today = new Date()
|
||||
const from = new Date(today); from.setDate(from.getDate() - 7)
|
||||
const to = new Date(today); to.setDate(to.getDate() + 28)
|
||||
return { from: fmtDate(from), to: fmtDate(to) }
|
||||
}
|
||||
|
||||
function defaultTimesheetWindow() {
|
||||
const today = new Date()
|
||||
const from = new Date(today); from.setDate(from.getDate() - 7)
|
||||
return { from: fmtDate(from), to: fmtDate(today) }
|
||||
}
|
||||
|
||||
// from/to: 'YYYY-MM-DD' strings — defaults to rolling window if omitted
|
||||
export async function runRotaSync(from, to) {
|
||||
const deptIds = (await getConfig('workforce_departments', [])) || []
|
||||
if (!deptIds.length) throw new Error('No HK departments selected — configure in Category Settings')
|
||||
|
||||
const today = new Date()
|
||||
const fromDate = new Date(today); fromDate.setDate(fromDate.getDate() - 7)
|
||||
const toDate = new Date(today); toDate.setDate(toDate.getDate() + 28)
|
||||
const from = fmtDate(fromDate)
|
||||
const to = fmtDate(toDate)
|
||||
if (!from || !to) ({ from, to } = defaultRotaWindow())
|
||||
|
||||
const fromDate = new Date(from + 'T00:00:00')
|
||||
const toDate = new Date(to + 'T00:00:00')
|
||||
|
||||
// API limit: max 7 days per request — split into weekly chunks
|
||||
const chunks = []
|
||||
const cur = new Date(fromDate)
|
||||
while (cur <= toDate) {
|
||||
const chunkFrom = fmtDate(cur)
|
||||
const chunkToDate = new Date(cur)
|
||||
chunkToDate.setDate(chunkToDate.getDate() + 6)
|
||||
if (chunkToDate > toDate) chunkToDate.setTime(toDate.getTime())
|
||||
chunks.push({ from: chunkFrom, to: fmtDate(chunkToDate) })
|
||||
const chunkEnd = new Date(cur); chunkEnd.setDate(chunkEnd.getDate() + 6)
|
||||
if (chunkEnd > toDate) chunkEnd.setTime(toDate.getTime())
|
||||
chunks.push({ from: chunkFrom, to: fmtDate(chunkEnd) })
|
||||
cur.setDate(cur.getDate() + 7)
|
||||
}
|
||||
|
||||
|
|
@ -62,14 +74,15 @@ export async function runRotaSync() {
|
|||
return { ok: true, from, to, dates_synced: dailyRows.length }
|
||||
}
|
||||
|
||||
export async function runTimesheetSync(days = 7) {
|
||||
// from/to: 'YYYY-MM-DD' strings — defaults to last 7 days if omitted
|
||||
export async function runTimesheetSync(from, to) {
|
||||
const deptIds = (await getConfig('workforce_departments', [])) || []
|
||||
if (!deptIds.length) throw new Error('No HK departments selected — configure in Category Settings')
|
||||
|
||||
const today = new Date()
|
||||
const fromDate = new Date(today); fromDate.setDate(fromDate.getDate() - days)
|
||||
const from = fmtDate(fromDate)
|
||||
const to = fmtDate(today)
|
||||
if (!from || !to) ({ from, to } = defaultTimesheetWindow())
|
||||
|
||||
const fromDate = new Date(from + 'T00:00:00')
|
||||
const toDate = new Date(to + 'T00:00:00')
|
||||
|
||||
const staffList = await fetchTimesheetShifts(from, to, deptIds)
|
||||
|
||||
|
|
@ -83,7 +96,7 @@ export async function runTimesheetSync(days = 7) {
|
|||
|
||||
const dailyRows = []
|
||||
const day = new Date(fromDate)
|
||||
while (day <= today) {
|
||||
while (day <= toDate) {
|
||||
const d = fmtDate(day)
|
||||
dailyRows.push({ date: d, staff: byDate[d] || [], source: 'timesheet' })
|
||||
day.setDate(day.getDate() + 1)
|
||||
|
|
|
|||
|
|
@ -23,19 +23,21 @@ export async function workforceRoutes(app) {
|
|||
// ── POST /api/workforce/sync — rolling rota window: today-7 → today+28 ──────
|
||||
|
||||
app.post('/api/workforce/sync', { preHandler: requireCap('planner') }, async (req, reply) => {
|
||||
const { start, end } = req.query
|
||||
try {
|
||||
return await runRotaSync()
|
||||
return await runRotaSync(start, end)
|
||||
} catch (err) {
|
||||
req.log.error({ err: err.message }, 'rota sync failed')
|
||||
return reply.status(errStatus(err.message)).send({ error: err.message })
|
||||
}
|
||||
})
|
||||
|
||||
// ── POST /api/workforce/sync-timesheets — last 7 days of actual hours ────────
|
||||
// ── POST /api/workforce/sync-timesheets?start=&end= ──────────────────────────
|
||||
|
||||
app.post('/api/workforce/sync-timesheets', { preHandler: requireCap('planner') }, async (req, reply) => {
|
||||
const { start, end } = req.query
|
||||
try {
|
||||
return await runTimesheetSync()
|
||||
return await runTimesheetSync(start, end)
|
||||
} catch (err) {
|
||||
req.log.error({ err: err.message }, 'timesheet sync failed')
|
||||
return reply.status(errStatus(err.message)).send({ error: err.message })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue