Tauschanfragen gegen offene Plätze erlauben und Lücken nachbesetzen
Ein Wunschtag ohne Tauschpartner bedeutet jetzt: die Person übernimmt dort einen offenen Platz; ihr alter Platz wird beim Ausführen sofort fair nachbesetzt, ohne sie selbst. Rollen werden bei allen Tauschformen geprüft. Bearbeiter können Person und Wunschtag einer Anfrage nachtragen, etwa aus der Notiz. Der Anfragedialog zeigt, was am Wunschtag los ist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e8ab95159e
commit
42d495c54e
7 files changed
+196
-30
No files matched your search
+38
-6
@@ -520,10 +520,27 @@ app.put('/api/requests/:id', (req, res) => {
|
||||
const st = S();
|
||||
const r = st.requests.find((x) => x.id === req.params.id);
|
||||
if (!r) return res.status(404).json({ error: 'Anfrage nicht gefunden.' });
|
||||
const status = String(req.body?.status || '');
|
||||
if (!REQUEST_STATUS.includes(status)) return bad(res, 'Unbekannter Status.');
|
||||
r.status = status;
|
||||
r.resolvedAt = status === 'offen' ? null : new Date().toISOString();
|
||||
const b = req.body || {};
|
||||
if (b.status !== undefined) {
|
||||
const status = String(b.status || '');
|
||||
if (!REQUEST_STATUS.includes(status)) return bad(res, 'Unbekannter Status.');
|
||||
r.status = status;
|
||||
r.resolvedAt = status === 'offen' ? null : new Date().toISOString();
|
||||
}
|
||||
// Bearbeiter dürfen den Wunsch nachtragen, z. B. aus dem Notizfeld
|
||||
if (b.partnerId !== undefined || b.partnerDate !== undefined) {
|
||||
const v = validateRequest({
|
||||
personId: r.personId,
|
||||
date: r.date,
|
||||
partnerId: b.partnerId !== undefined ? b.partnerId : r.partnerId,
|
||||
partnerDate: b.partnerDate !== undefined ? b.partnerDate : r.partnerDate,
|
||||
note: r.note,
|
||||
}, st.persons, st.assignments);
|
||||
if (v.error) return bad(res, v.error);
|
||||
r.partnerId = v.request.partnerId;
|
||||
r.partnerDate = v.request.partnerDate;
|
||||
r.role = v.request.role;
|
||||
}
|
||||
store.save();
|
||||
res.json(r);
|
||||
});
|
||||
@@ -534,11 +551,26 @@ app.post('/api/requests/:id/execute', (req, res) => {
|
||||
if (!r) return res.status(404).json({ error: 'Anfrage nicht gefunden.' });
|
||||
if (r.status !== 'offen') return bad(res, 'Diese Anfrage ist schon abgeschlossen.');
|
||||
try {
|
||||
const { changes } = applySwap(st.assignments, r);
|
||||
const { changes, vacated } = applySwap(st.assignments, r, personsForScheduling());
|
||||
let filled = null;
|
||||
if (vacated) {
|
||||
// Die frei gewordene Stelle gleich nachbesetzen – fair, ohne die anfragende Person
|
||||
const existing = { [vacated.date]: { ...st.assignments[vacated.date], fill: true } };
|
||||
const absences = [...st.absences, { personId: r.personId, from: vacated.date, to: vacated.date }];
|
||||
const history = { ...st.assignments };
|
||||
delete history[vacated.date];
|
||||
const generated = generateSchedule({ dates: [vacated.date], persons: personsForScheduling(), absences, existing, history, blocked: blockedDays(), historyWindowDays: st.settings.historyWindowDays });
|
||||
const picked = generated[vacated.date]?.[vacated.role] || null;
|
||||
if (picked) {
|
||||
st.assignments[vacated.date][vacated.role] = picked;
|
||||
changes.push({ date: vacated.date, role: vacated.role, from: null, to: picked });
|
||||
}
|
||||
filled = { date: vacated.date, role: vacated.role, personId: picked };
|
||||
}
|
||||
r.status = 'erledigt';
|
||||
r.resolvedAt = new Date().toISOString();
|
||||
store.save();
|
||||
res.json({ request: r, changes, assignments: st.assignments });
|
||||
res.json({ request: r, changes, filled, assignments: st.assignments });
|
||||
} catch (err) {
|
||||
bad(res, err.message);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user