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
+33
View File
@@ -103,6 +103,39 @@ function normalizePeopleList($raw): array {
* @return array<string, mixed>
*/
function migrateLegacyPersonRow(array $person): array {
$currencyBalance = is_numeric($person['currency_balance'] ?? null) ? (float) $person['currency_balance'] : 0.0;
$checkingBalance = array_key_exists('checking_balance', $person) && is_numeric($person['checking_balance'])
? (float) $person['checking_balance']
: $currencyBalance;
$person['checking_balance'] = round($checkingBalance, 2);
if (!array_key_exists('currency_balance', $person) || !is_numeric($person['currency_balance'])) {
$person['currency_balance'] = $person['checking_balance'];
} else {
$person['currency_balance'] = round((float) $person['currency_balance'], 2);
}
if (!array_key_exists('savings_balance', $person) || !is_numeric($person['savings_balance'])) {
$person['savings_balance'] = 0.0;
} else {
$person['savings_balance'] = round((float) $person['savings_balance'], 2);
}
if (!array_key_exists('charity_pending_balance', $person) || !is_numeric($person['charity_pending_balance'])) {
$person['charity_pending_balance'] = 0.0;
} else {
$person['charity_pending_balance'] = round((float) $person['charity_pending_balance'], 2);
}
if (!array_key_exists('charity_donated_total', $person) || !is_numeric($person['charity_donated_total'])) {
$person['charity_donated_total'] = 0.0;
} else {
$person['charity_donated_total'] = round((float) $person['charity_donated_total'], 2);
}
if (!array_key_exists('donation_goal_monthly', $person) || !is_numeric($person['donation_goal_monthly'])) {
$person['donation_goal_monthly'] = 0.0;
} else {
$person['donation_goal_monthly'] = max(0, round((float) $person['donation_goal_monthly'], 2));
}
if (!array_key_exists('banking_interest_last_applied_at', $person) || !is_string($person['banking_interest_last_applied_at'])) {
$person['banking_interest_last_applied_at'] = '';
}
if (!array_key_exists('nfc_submit_token_hash', $person) || !is_string($person['nfc_submit_token_hash'])) {
$person['nfc_submit_token_hash'] = '';
}