false, 'error' => 'Method not allowed'], 405); } $people = migrateAllPeople(normalizePeopleList(readJsonFile('people.json'))); $actor = requireActivePerson($people); $settings = loadFamilySettings(); if (empty($settings['banking_enabled'])) { sendJson(['success' => false, 'error' => 'Banking mode is not enabled'], 400); } $body = readJsonBody(); $goalRaw = $body['goal_monthly'] ?? null; if (!is_numeric($goalRaw)) { sendJson(['success' => false, 'error' => 'goal_monthly must be numeric'], 400); } $goal = round((float) $goalRaw, 2); if ($goal < 0) { sendJson(['success' => false, 'error' => 'goal_monthly must be >= 0'], 400); } $targetPersonId = trim((string) ($body['person_id'] ?? '')); $actorId = (string) ($actor['id'] ?? ''); $isHoh = (($actor['role'] ?? '') === ROLE_HEAD) && isHohVerified(); if ($targetPersonId === '') { $targetPersonId = $actorId; } if (!$isHoh && $targetPersonId !== $actorId) { sendJson(['success' => false, 'error' => 'Only verified Head of household can set goals for others'], 403); } $idx = null; foreach ($people as $i => $p) { if (($p['id'] ?? '') === $targetPersonId) { $idx = $i; break; } } if ($idx === null) { sendJson(['success' => false, 'error' => 'Person not found'], 404); } $people[$idx]['donation_goal_monthly'] = $goal; if (!writeJsonFile('people.json', $people)) { sendJson(['success' => false, 'error' => 'Failed to save goal'], 500); } sendJson(['success' => true, 'person' => $people[$idx]]);