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.
This commit is contained in:
2026-03-31 11:03:53 -05:00
parent f14de0b7e1
commit 6d10cb4726
21 changed files with 1337 additions and 41 deletions
+48
View File
@@ -30,6 +30,49 @@ if (isset($body['currency_permanence'])) {
}
$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)) {
@@ -67,6 +110,11 @@ if (array_key_exists('nfc_scan_cooldown_seconds', $body)) {
}
$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);