Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions banking/custom_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,48 @@ def get_custom_fields():
fieldtype="Data",
insert_after="transaction_id",
),
dict(
fieldname="reserved_voucher_type",
label=_("Reserved Voucher Type"),
fieldtype="Link",
options="DocType",
insert_after="subtransaction_id",
read_only=1,
allow_on_submit=1,
no_copy=1,
),
dict(
fieldname="reserved_voucher",
label=_("Reserved Voucher"),
fieldtype="Dynamic Link",
options="reserved_voucher_type",
insert_after="reserved_voucher_type",
read_only=1,
allow_on_submit=1,
no_copy=1,
),
],
"Journal Entry": [
dict(
fieldname="created_from_bank_transaction",
label=_("Created From Bank Transaction"),
fieldtype="Link",
options="Bank Transaction",
insert_after="cheque_no",
read_only=1,
no_copy=1,
),
],
"Payment Entry": [
dict(
fieldname="created_from_bank_transaction",
label=_("Created From Bank Transaction"),
fieldtype="Link",
options="Bank Transaction",
insert_after="reference_no",
read_only=1,
no_copy=1,
),
],
"Bank Account": [
dict(
Expand Down
8 changes: 8 additions & 0 deletions banking/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@
"before_submit": "banking.overrides.bank_transaction.before_submit",
"on_cancel": "banking.overrides.bank_transaction.on_cancel",
},
"Journal Entry": {
"on_submit": "banking.overrides.voucher_reconciliation.reconcile_created_from_bank_transaction",
"on_trash": "banking.overrides.voucher_reconciliation.release_bank_transaction_reservation",
},
"Payment Entry": {
"on_submit": "banking.overrides.voucher_reconciliation.reconcile_created_from_bank_transaction",
"on_trash": "banking.overrides.voucher_reconciliation.release_bank_transaction_reservation",
},
"Bank Account": {
"before_validate": "banking.overrides.bank_account.before_validate",
"validate": "banking.overrides.bank_account.validate",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ frappe.ui.form.on("Bank Reconciliation Tool Beta", {

build_reconciliation_area: function (frm) {
frappe.require("bank_reconciliation_beta.bundle.js", () => {
if (frm.panel_manager?.cleanup_voucher_watches) {
frm.panel_manager.cleanup_voucher_watches();
}
frm.panel_manager = new erpnext.accounts.bank_reconciliation.PanelManager(
{
frm: frm,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def get_bank_transactions(
to_date: str | datetime.date | None = None,
order_by: str | None = "date asc",
):
"""Return bank transactions for a bank account"""
"""Return bank transactions for a bank account, including reserved drafts."""
filters = [
["docstatus", "=", 1],
["status", "not in", ["Reconciled", "Cancelled"]],
Expand All @@ -132,27 +132,58 @@ def get_bank_transactions(
bank_accounts = frappe.get_list("Bank Account", filters={"bank": bank}, pluck="name")
filters.append(["bank_account", "in", bank_accounts])

return frappe.get_list(
"Bank Transaction",
fields=[
"date",
"deposit",
"withdrawal",
"currency",
"description",
"name",
"bank_account",
"company",
"unallocated_amount",
"reference_number",
"party_type",
"party",
"bank_party_name",
"bank_party_account_number",
"bank_party_iban",
],
filters=filters,
order_by=get_bank_transaction_order_by(order_by),
fields = [
"date",
"deposit",
"withdrawal",
"currency",
"description",
"name",
"bank_account",
"company",
"unallocated_amount",
"reference_number",
"party_type",
"party",
"bank_party_name",
"bank_party_account_number",
"bank_party_iban",
"reserved_voucher_type",
"reserved_voucher",
]
order_by = get_bank_transaction_order_by(order_by)

return {
"transactions": frappe.get_list(
"Bank Transaction",
fields=fields,
filters=filters,
order_by=order_by,
),
}


def _reserve_bank_transaction(
bank_transaction: "CustomBankTransaction", voucher_type: str, voucher_name: str
):
if bank_transaction.reserved_voucher:
frappe.throw(
_(
"Bank Transaction {0} is already reserved by draft {1} {2}. "
"Submit or delete that voucher before creating another."
).format(
frappe.bold(bank_transaction.name),
_(bank_transaction.reserved_voucher_type),
frappe.bold(bank_transaction.reserved_voucher),
)
)

bank_transaction.db_set(
{
"reserved_voucher_type": voucher_type,
"reserved_voucher": voucher_name,
},
update_modified=False,
)


Expand Down Expand Up @@ -182,8 +213,10 @@ def create_journal_entry_bts(
if isinstance(allow_edit, str):
allow_edit = sbool(allow_edit)

bank_transaction: CustomBankTransaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
bank_transaction.check_permission("read")
bank_transaction: CustomBankTransaction = frappe.get_doc(
"Bank Transaction", bank_transaction_name, for_update=allow_edit
)
bank_transaction.check_permission("write" if allow_edit else "read")

if bank_transaction.deposit and bank_transaction.withdrawal:
frappe.throw(_("Cannot create Journal Entry for a Bank Transaction with both Deposit and Withdrawal"))
Expand Down Expand Up @@ -220,6 +253,8 @@ def create_journal_entry_bts(
"user_remark": bank_transaction.description,
}
)
if allow_edit:
journal_entry.created_from_bank_transaction = bank_transaction.name

account_rows = [
{
Expand Down Expand Up @@ -253,6 +288,7 @@ def create_journal_entry_bts(
journal_entry.insert()

if allow_edit:
_reserve_bank_transaction(bank_transaction, "Journal Entry", journal_entry.name)
return journal_entry # Return saved document

# This check happens here because the user should be able to make
Expand Down Expand Up @@ -297,12 +333,11 @@ def create_payment_entry_bts(
allow_edit = sbool(allow_edit)

# Create a new payment entry based on the bank transaction
bank_transaction: CustomBankTransaction = frappe.db.get_values(
"Bank Transaction",
bank_transaction_name,
fieldname=["name", "unallocated_amount", "deposit", "bank_account"],
as_dict=True,
)[0]
bank_transaction: CustomBankTransaction = frappe.get_doc(
"Bank Transaction", bank_transaction_name, for_update=allow_edit
)
bank_transaction.check_permission("write" if allow_edit else "read")

paid_amount = bank_transaction.unallocated_amount
payment_type = "Receive" if bank_transaction.deposit > 0.0 else "Pay"

Expand All @@ -322,6 +357,8 @@ def create_payment_entry_bts(
payment_entry = frappe.new_doc("Payment Entry")

payment_entry.update(payment_entry_dict)
if allow_edit:
payment_entry.created_from_bank_transaction = bank_transaction.name

if mode_of_payment:
payment_entry.mode_of_payment = mode_of_payment
Expand All @@ -342,6 +379,7 @@ def create_payment_entry_bts(
payment_entry.insert()

if allow_edit:
_reserve_bank_transaction(bank_transaction, "Payment Entry", payment_entry.name)
return payment_entry # Return saved document

payment_entry.submit()
Expand Down Expand Up @@ -450,8 +488,11 @@ def auto_reconcile_vouchers(

bank_transactions = get_bank_transactions(
company=company, bank=bank, bank_account=bank_account, from_date=from_date, to_date=to_date
)
)["transactions"]
for transaction in bank_transactions:
# Skip transactions reserved by an Edit-in-Full-Page draft voucher
if transaction.reserved_voucher:
continue
linked_payments = get_linked_payments(
transaction.name,
["payment_entry", "journal_entry"],
Expand Down
Loading
Loading