familyHub/api/family_settings_save.php
Louis Whittington 6d10cb4726 Implement banking system features and enhancements
- Added banking mode with checking, savings, and charity accounts, including auto-split options for income.
- Introduced banking transaction management, including transfers and charity outflows.
- Updated family settings to allow configuration of banking features and interest rates.
- Enhanced data export functionality to include bank transactions.
- Improved user interface to display banking information and donation goals.
- Updated documentation to reflect new banking features and settings.
2026-03-31 11:03:53 -05:00

126 lines
5.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once __DIR__ . '/../includes/api_bootstrap.php';
require_once __DIR__ . '/../includes/family_settings.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
sendJson(['success' => false, 'error' => 'Method not allowed'], 405);
}
$people = normalizePeopleList(readJsonFile('people.json'));
if (count($people) > 0) {
assertHoHCanManagePeople($people);
}
$body = readJsonBody();
$merged = loadFamilySettings();
$allowedPermanence = ['permanent', 'weekly', 'biweekly', 'monthly', 'quarterly', 'yearly'];
if (isset($body['currency_symbol'])) {
$merged['currency_symbol'] = trim((string) $body['currency_symbol']);
}
if (isset($body['currency_name'])) {
$merged['currency_name'] = trim((string) $body['currency_name']);
}
if (isset($body['currency_permanence'])) {
$p = (string) $body['currency_permanence'];
if (!in_array($p, $allowedPermanence, true)) {
sendJson(['success' => false, 'error' => 'Invalid currency_permanence'], 400);
}
$merged['currency_permanence'] = $p;
}
if (array_key_exists('banking_enabled', $body)) {
$merged['banking_enabled'] = !empty($body['banking_enabled']);
}
if (array_key_exists('banking_auto_split_enabled', $body)) {
$merged['banking_auto_split_enabled'] = !empty($body['banking_auto_split_enabled']);
}
if (array_key_exists('banking_auto_split_savings_pct', $body)) {
if (!is_numeric($body['banking_auto_split_savings_pct'])) {
sendJson(['success' => false, 'error' => 'banking_auto_split_savings_pct must be numeric'], 400);
}
$pct = round((float) $body['banking_auto_split_savings_pct'], 2);
if ($pct < 0 || $pct > 100) {
sendJson(['success' => false, 'error' => 'banking_auto_split_savings_pct must be 0-100'], 400);
}
$merged['banking_auto_split_savings_pct'] = $pct;
}
if (array_key_exists('banking_auto_split_charity_pct', $body)) {
if (!is_numeric($body['banking_auto_split_charity_pct'])) {
sendJson(['success' => false, 'error' => 'banking_auto_split_charity_pct must be numeric'], 400);
}
$pct = round((float) $body['banking_auto_split_charity_pct'], 2);
if ($pct < 0 || $pct > 100) {
sendJson(['success' => false, 'error' => 'banking_auto_split_charity_pct must be 0-100'], 400);
}
$merged['banking_auto_split_charity_pct'] = $pct;
}
if (array_key_exists('banking_savings_monthly_interest_rate', $body)) {
if (!is_numeric($body['banking_savings_monthly_interest_rate'])) {
sendJson(['success' => false, 'error' => 'banking_savings_monthly_interest_rate must be numeric'], 400);
}
$rate = round((float) $body['banking_savings_monthly_interest_rate'], 6);
if ($rate < 0) {
sendJson(['success' => false, 'error' => 'banking_savings_monthly_interest_rate must be >= 0'], 400);
}
$merged['banking_savings_monthly_interest_rate'] = $rate;
}
if (array_key_exists('banking_roundup_destination', $body)) {
$dest = trim((string) $body['banking_roundup_destination']);
if (!in_array($dest, ['off', 'savings', 'charity'], true)) {
sendJson(['success' => false, 'error' => 'banking_roundup_destination must be off, savings, or charity'], 400);
}
$merged['banking_roundup_destination'] = $dest;
}
if (isset($body['timezone'])) {
$tz = trim((string) $body['timezone']);
if (!in_array($tz, familyHubUsTimezoneIdentifiers(), true)) {
sendJson(['success' => false, 'error' => 'Invalid timezone'], 400);
}
$merged['timezone'] = $tz;
}
if (array_key_exists('calendar_two_way_google', $body)) {
$merged['calendar_two_way_google'] = !empty($body['calendar_two_way_google']);
}
if (isset($body['calendar_bill_days'])) {
$merged['calendar_bill_days'] = normalizeCalendarBillDaysRaw($body['calendar_bill_days']);
}
if (isset($body['week_starts_on'])) {
$w = (int) $body['week_starts_on'];
if ($w < 0 || $w > 6) {
sendJson(['success' => false, 'error' => 'week_starts_on must be 06'], 400);
}
$merged['week_starts_on'] = $w;
}
if (array_key_exists('nfc_base_url', $body)) {
$baseUrl = trim((string) $body['nfc_base_url']);
if ($baseUrl !== '' && !preg_match('#^https?://#i', $baseUrl)) {
sendJson(['success' => false, 'error' => 'nfc_base_url must start with http:// or https://'], 400);
}
$merged['nfc_base_url'] = rtrim($baseUrl, '/');
}
if (array_key_exists('nfc_show_confirmation', $body)) {
$merged['nfc_show_confirmation'] = !empty($body['nfc_show_confirmation']);
}
if (array_key_exists('nfc_scan_cooldown_seconds', $body)) {
$cooldown = (int) $body['nfc_scan_cooldown_seconds'];
if ($cooldown < 0 || $cooldown > 600) {
sendJson(['success' => false, 'error' => 'nfc_scan_cooldown_seconds must be 0-600'], 400);
}
$merged['nfc_scan_cooldown_seconds'] = $cooldown;
}
if (
((float) ($merged['banking_auto_split_savings_pct'] ?? 0) + (float) ($merged['banking_auto_split_charity_pct'] ?? 0)) > 100
) {
sendJson(['success' => false, 'error' => 'banking auto split percentages cannot exceed 100 total'], 400);
}
$merged = normalizeLoadedFamilySettings($merged);
if (!writeJsonFile('family_settings.json', $merged)) {
sendJson(['success' => false, 'error' => 'Failed to save settings'], 500);
}
sendJson(['success' => true, 'settings' => $merged]);