Skip to content

feat(Bank Transaction): auto-book included bank fees#346

Open
barredterra wants to merge 23 commits intoversion-15-hotfixfrom
split/included-bank-fees
Open

feat(Bank Transaction): auto-book included bank fees#346
barredterra wants to merge 23 commits intoversion-15-hotfixfrom
split/included-bank-fees

Conversation

@barredterra
Copy link
Copy Markdown
Member

@barredterra barredterra commented Feb 17, 2026

Summary

Auto-book included bank fees on Bank Transaction submit (withdrawals) and at reconciliation time (deposits).

Withdrawals: On submit, a Journal Entry is created (Dr Bank Fees / Cr Bank) and allocated against the Bank Transaction, partially reconciling the fee portion.

Deposits: Fee booking is deferred to reconciliation, where the correct counter-account (e.g. receivable) is known. The reconciliation tool matches deposits using deposit + included_fee as the target amount, so the right vouchers are found. At reconciliation:

  • Single-currency: A Journal Entry settles both the fee and the invoice in one entry (Dr Bank, Dr Bank Fees / Cr Receivable)
  • Multi-currency: A Payment Entry is created with a deduction row for the fee. The system exchange rate determines exchange gain/loss separately from the fee.

Configuration

  • New Bank Fee Account field on Bank Account (Link to Expense account, same currency)
  • New Enable Automatic Journal Entries for Bank Fees checkbox in Banking Settings
  • All company Bank Accounts must have a fee account before the feature can be enabled

Depends on

Test plan

  • Submit withdrawal with included fee → fee JE created and allocated
  • Submit deposit with included fee → no fee JE created
  • Reconcile single-currency deposit with fee against Sales Invoice → JE with bank + fee rows, invoice fully cleared
  • Reconcile multi-currency deposit with fee against foreign invoice → PE with fee deduction, exchange gain/loss handled separately
  • Feature disabled → no fee JE on submit, no fee handling at reconciliation
  • Bank Account without fee account rejects save when feature is enabled
  • Currency mismatch between bank account and fee account is rejected
  • Cancel Bank Transaction → linked fee JEs are cancelled
  • Fee larger than withdrawal is rejected

barredterra and others added 5 commits February 17, 2026 22:29
Add bank fee account configuration and create fee Journal Entries on bank transaction submission so included fees are recognized immediately and reconciled correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>
Guard included-fee Journal Entry creation behind a Banking Settings flag so existing sites without bank fee account setup continue to work until the feature is explicitly enabled.

Co-authored-by: Cursor <cursoragent@cursor.com>
Update the DocType JSON modified timestamp so the controller change is picked up reliably during model sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reject withdrawal transactions where included fee exceeds withdrawal amount, while still allowing fee handling when deposit is not set.

Co-authored-by: Cursor <cursoragent@cursor.com>
@barredterra

This comment was marked as resolved.

@barredterra barredterra mentioned this pull request Feb 18, 2026
3 tasks
@0xD0M1M0

This comment was marked as outdated.

@greptile-apps

This comment was marked as resolved.

Comment thread banking/overrides/bank_transaction.py Outdated
Comment thread banking/overrides/bank_transaction.py Outdated
Comment thread banking/overrides/bank_transaction.py Outdated
Comment thread banking/overrides/test_bank_transaction_included_fees.py Outdated
barredterra and others added 9 commits March 21, 2026 15:19
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Ensure a Bank Transaction can be submitted without a bank fee account
when automatic bank fee journal entries are disabled, and assert that
no linked fee Journal Entry is created.
Prevent automatic bank fee journal entries from being enabled until every company Bank Account has a bank fee account, and reject company bank accounts without one while the feature is enabled.
Create fee Journal Entries for deposit Bank Transactions with included fees, but do not add them to payment entries because the fee is already deducted before the bank credits the deposit. Semantically, a row in Bank Transaction would say "this JE is allocatable against the bank amount later", which is exactly what we don’t want for a deposit fee. Add regression coverage for included-fee deposit and withdrawal flows.
Keep cheque_no-linked custom journal entries hidden from matching while
excluding standard fee journal entries only for deposit transactions.

This lets unreconciled withdrawal fee journal entries be offered again.
@barredterra

This comment was marked as resolved.

Recompute `allocated_amount` and `unallocated_amount` from `payment_entries` after appending the fee journal entry, so prior allocations are not lost. Add a regression test covering fee entry creation when an allocation already exists.
@barredterra barredterra self-assigned this Mar 30, 2026
@barredterra

This comment was marked as resolved.

@barredterra
Copy link
Copy Markdown
Member Author

barredterra commented Apr 13, 2026

@greptileai

Since we no longer create fee JEs for deposits, there's nothing to exclude from matching. The test was validating behavior that no longer exists.
This test now creates its own GL account (_Test Bank Fee Reco GL) instead of reusing self.gl_account, avoiding the "account already used by another bank account" error.
Comment on lines +715 to +729
def get_deposit_included_fee(bt: "CustomBankTransaction") -> float:
"""Return the included fee amount when deposit-side fee handling is enabled.

Deposit-side fees are only settled during reconciliation when the global
feature flag is enabled and the bank account provides a fee account.
Returns 0.0 when the legacy pre-feature behavior should be preserved.
"""
if not (flt(bt.deposit) > 0 and flt(bt.included_fee) > 0):
return 0.0

if not flt(
frappe.db.get_single_value("Banking Settings", "enable_automatic_journal_entries_for_bank_fees")
):
return 0.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Fee double-booked on sequential partial reconciliation

get_deposit_included_fee always returns the full bt.included_fee regardless of how many times the deposit has already been partially reconciled. If a user reconciles a deposit of 75 with included_fee=5 against two invoices in separate steps, the fee account is debited twice (2×5=10 instead of 5), and the BT can never be fully reconciled because 5 remains permanently unallocated.

Concretely: step 1 creates JE Dr Bank 45 / Dr Fee 5 / Cr SI1 50, allocating 45 against the BT (unallocated→30). Step 2 again sees included_fee=5, creates JE Dr Bank 25 / Dr Fee 5 / Cr SI2 30, allocating 25 (unallocated→5). The BT remains 5 short and the fee expense is overstated by 5.

A guard is needed before returning included_fee to check whether a fee JE was already booked for this BT — for example by checking whether a JE already exists where is_system_generated=1 and JEA.reference_name = bt.name AND has a bank_fee_account row, or alternatively by only returning the fee when bt.unallocated_amount == bt.deposit (i.e., the first reconciliation step).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants