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
+132 -15
View File
@@ -188,6 +188,12 @@
currency_symbol: $('#currency_symbol').val(),
currency_name: $('#currency_name').val(),
currency_permanence: $('#currency_permanence').val(),
banking_enabled: $('#banking_enabled').is(':checked'),
banking_auto_split_enabled: $('#banking_auto_split_enabled').is(':checked'),
banking_auto_split_savings_pct: Number($('#banking_auto_split_savings_pct').val()) || 0,
banking_auto_split_charity_pct: Number($('#banking_auto_split_charity_pct').val()) || 0,
banking_savings_monthly_interest_rate: Number($('#banking_savings_monthly_interest_rate').val()) || 0,
banking_roundup_destination: $('#banking_roundup_destination').val() || 'off',
week_starts_on: parseInt($('#week_starts_on').val(), 10),
nfc_base_url: ($('#nfc_base_url').val() || '').trim(),
nfc_show_confirmation: $('#nfc_show_confirmation').is(':checked'),
@@ -1014,32 +1020,143 @@
}
function bindCurrencyPage() {
var $form = $('#expenseForm');
if (!$form.length) {
var hasLegacyExpense = $('#expenseForm').length > 0;
var hasBanking = $('#bankTransferForm').length > 0
|| $('#bankAdjustForm').length > 0
|| $('#charityOutflowForm').length > 0;
if (!hasLegacyExpense && !hasBanking) {
return;
}
$form.on('submit', function (e) {
if (hasLegacyExpense) {
$('#expenseForm').on('submit', function (e) {
e.preventDefault();
var payload = {
title: $('#expense_title').val(),
description: $('#expense_description').val(),
date: $('#expense_date').val(),
value: Number($('#expense_value').val()),
assignee_id: $('#expense_assignee').val()
};
postJson('/expense_create.php', payload)
.then(function () {
var $fb = $('#expenseFormFeedback');
showAlert($fb, 'success', 'Expense recorded. Reloading…');
$fb.removeClass('d-none');
window.location.reload();
})
.catch(function (err) {
var $fb = $('#expenseFormFeedback');
showAlert($fb, 'danger', err.message || 'Could not record expense');
$fb.removeClass('d-none');
});
});
}
$('#bankTransferForm').on('submit', function (e) {
e.preventDefault();
var payload = {
title: $('#expense_title').val(),
description: $('#expense_description').val(),
date: $('#expense_date').val(),
value: Number($('#expense_value').val()),
assignee_id: $('#expense_assignee').val()
};
postJson('/expense_create.php', payload)
var from = $('#transfer_from_account').val();
var to = $('#transfer_to_account').val();
if (to === 'charity' && !window.confirm('Transfers into charity cannot be moved back out. Continue?')) {
return;
}
postJson('/bank_transfer.php', {
from_account: from,
to_account: to,
amount: Number($('#transfer_amount').val()) || 0,
category: $('#transfer_category').val(),
note: $('#transfer_note').val()
})
.then(function () {
var $fb = $('#expenseFormFeedback');
showAlert($fb, 'success', 'Expense recorded. Reloading…');
var $fb = $('#bankTransferFeedback');
showAlert($fb, 'success', 'Transfer saved. Reloading…');
$fb.removeClass('d-none');
window.location.reload();
})
.catch(function (err) {
var $fb = $('#expenseFormFeedback');
showAlert($fb, 'danger', err.message || 'Could not record expense');
var $fb = $('#bankTransferFeedback');
showAlert($fb, 'danger', err.message || 'Could not transfer');
$fb.removeClass('d-none');
});
});
$('#bankAdjustForm').on('submit', function (e) {
e.preventDefault();
postJson('/bank_adjust_checking.php', {
person_id: $('#bank_adjust_person').val(),
type: $('#bank_adjust_type').val(),
amount: Number($('#bank_adjust_amount').val()) || 0,
category: $('#bank_adjust_category').val(),
note: $('#bank_adjust_note').val()
})
.then(function () {
var $fb = $('#bankAdjustFeedback');
showAlert($fb, 'success', 'Checking transaction saved. Reloading…');
$fb.removeClass('d-none');
window.location.reload();
})
.catch(function (err) {
var $fb = $('#bankAdjustFeedback');
showAlert($fb, 'danger', err.message || 'Could not save transaction');
$fb.removeClass('d-none');
});
});
$('#charityOutflowForm').on('submit', function (e) {
e.preventDefault();
postJson('/bank_charity_outflow.php', {
person_id: $('#charity_outflow_person').val(),
amount: Number($('#charity_outflow_amount').val()) || 0,
category: $('#charity_outflow_category').val(),
note: $('#charity_outflow_note').val()
})
.then(function () {
var $fb = $('#charityOutflowFeedback');
showAlert($fb, 'success', 'Charity outflow logged. Reloading…');
$fb.removeClass('d-none');
window.location.reload();
})
.catch(function (err) {
var $fb = $('#charityOutflowFeedback');
showAlert($fb, 'danger', err.message || 'Could not log outflow');
$fb.removeClass('d-none');
});
});
$('#donationGoalForm').on('submit', function (e) {
e.preventDefault();
postJson('/bank_set_donation_goal.php', {
person_id: $('#donation_goal_person').val(),
goal_monthly: Number($('#donation_goal_monthly').val()) || 0
})
.then(function () {
var $fb = $('#donationGoalFeedback');
showAlert($fb, 'success', 'Donation goal saved. Reloading…');
$fb.removeClass('d-none');
window.location.reload();
})
.catch(function (err) {
var $fb = $('#donationGoalFeedback');
showAlert($fb, 'danger', err.message || 'Could not save goal');
$fb.removeClass('d-none');
});
});
$(document).on('click', '.btn-bank-reverse', function () {
var txid = $(this).data('id');
if (!txid) {
return;
}
if (!window.confirm('Create a reversal entry for this transaction? This keeps audit history intact.')) {
return;
}
postJson('/bank_reverse_transaction.php', { transaction_id: txid, note: 'Reversed by HoH' })
.then(function () {
window.location.reload();
})
.catch(function (err) {
window.alert(err.message || 'Could not reverse transaction');
});
});
}
function bindPeopleTable() {