Skip to content

Commit

Permalink
Merge pull request #38383 from frappe/version-15-hotfix
Browse files Browse the repository at this point in the history
chore: release v15
  • Loading branch information
rohitwaghchaure authored Nov 28, 2023
2 parents 33869a2 + c101855 commit 4bfdab9
Show file tree
Hide file tree
Showing 74 changed files with 916 additions and 624 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,9 @@ def reconcile_vouchers(bank_transaction_name, vouchers):
vouchers = json.loads(vouchers)
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
transaction.add_payment_entries(vouchers)
return frappe.get_doc("Bank Transaction", bank_transaction_name)
transaction.save()

return transaction


@frappe.whitelist()
Expand Down
17 changes: 13 additions & 4 deletions erpnext/accounts/doctype/bank_transaction/bank_transaction.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"status",
"bank_account",
"company",
"amended_from",
"section_break_4",
"deposit",
"withdrawal",
Expand All @@ -25,10 +26,10 @@
"transaction_id",
"transaction_type",
"section_break_14",
"column_break_oufv",
"payment_entries",
"section_break_18",
"allocated_amount",
"amended_from",
"column_break_17",
"unallocated_amount",
"party_section",
Expand Down Expand Up @@ -138,10 +139,12 @@
"fieldtype": "Section Break"
},
{
"allow_on_submit": 1,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"label": "Allocated Amount",
"options": "currency"
"options": "currency",
"read_only": 1
},
{
"fieldname": "amended_from",
Expand All @@ -157,10 +160,12 @@
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"fieldname": "unallocated_amount",
"fieldtype": "Currency",
"label": "Unallocated Amount",
"options": "currency"
"options": "currency",
"read_only": 1
},
{
"fieldname": "party_section",
Expand Down Expand Up @@ -225,11 +230,15 @@
"fieldname": "bank_party_account_number",
"fieldtype": "Data",
"label": "Party Account No. (Bank Statement)"
},
{
"fieldname": "column_break_oufv",
"fieldtype": "Column Break"
}
],
"is_submittable": 1,
"links": [],
"modified": "2023-06-06 13:58:12.821411",
"modified": "2023-11-18 18:32:47.203694",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",
Expand Down
139 changes: 61 additions & 78 deletions erpnext/accounts/doctype/bank_transaction/bank_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,73 @@
# For license information, please see license.txt

import frappe
from frappe import _
from frappe.utils import flt

from erpnext.controllers.status_updater import StatusUpdater


class BankTransaction(StatusUpdater):
def after_insert(self):
self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit))
def before_validate(self):
self.update_allocated_amount()

def on_submit(self):
self.clear_linked_payment_entries()
def validate(self):
self.validate_duplicate_references()

def validate_duplicate_references(self):
"""Make sure the same voucher is not allocated twice within the same Bank Transaction"""
if not self.payment_entries:
return

pe = []
for row in self.payment_entries:
reference = (row.payment_document, row.payment_entry)
if reference in pe:
frappe.throw(
_("{0} {1} is allocated twice in this Bank Transaction").format(
row.payment_document, row.payment_entry
)
)
pe.append(reference)

def update_allocated_amount(self):
self.allocated_amount = (
sum(p.allocated_amount for p in self.payment_entries) if self.payment_entries else 0.0
)
self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit)) - self.allocated_amount

def before_submit(self):
self.allocate_payment_entries()
self.set_status()

if frappe.db.get_single_value("Accounts Settings", "enable_party_matching"):
self.auto_set_party()

_saving_flag = False

# nosemgrep: frappe-semgrep-rules.rules.frappe-modifying-but-not-comitting
def on_update_after_submit(self):
"Run on save(). Avoid recursion caused by multiple saves"
if not self._saving_flag:
self._saving_flag = True
self.clear_linked_payment_entries()
self.update_allocations()
self._saving_flag = False
def before_update_after_submit(self):
self.validate_duplicate_references()
self.allocate_payment_entries()
self.update_allocated_amount()

def on_cancel(self):
self.clear_linked_payment_entries(for_cancel=True)
self.set_status(update=True)

def update_allocations(self):
"The doctype does not allow modifications after submission, so write to the db direct"
if self.payment_entries:
allocated_amount = sum(p.allocated_amount for p in self.payment_entries)
else:
allocated_amount = 0.0
for payment_entry in self.payment_entries:
self.clear_linked_payment_entry(payment_entry, for_cancel=True)

amount = abs(flt(self.withdrawal) - flt(self.deposit))
self.db_set("allocated_amount", flt(allocated_amount))
self.db_set("unallocated_amount", amount - flt(allocated_amount))
self.reload()
self.set_status(update=True)

def add_payment_entries(self, vouchers):
"Add the vouchers with zero allocation. Save() will perform the allocations and clearance"
if 0.0 >= self.unallocated_amount:
frappe.throw(frappe._("Bank Transaction {0} is already fully reconciled").format(self.name))
frappe.throw(_("Bank Transaction {0} is already fully reconciled").format(self.name))

added = False
for voucher in vouchers:
# Can't add same voucher twice
found = False
for pe in self.payment_entries:
if (
pe.payment_document == voucher["payment_doctype"]
and pe.payment_entry == voucher["payment_name"]
):
found = True

if not found:
pe = {
self.append(
"payment_entries",
{
"payment_document": voucher["payment_doctype"],
"payment_entry": voucher["payment_name"],
"allocated_amount": 0.0, # Temporary
}
child = self.append("payment_entries", pe)
added = True

# runs on_update_after_submit
if added:
self.save()
},
)

def allocate_payment_entries(self):
"""Refactored from bank reconciliation tool.
Expand All @@ -90,6 +85,7 @@ def allocate_payment_entries(self):
- clear means: set the latest transaction date as clearance date
"""
remaining_amount = self.unallocated_amount
to_remove = []
for payment_entry in self.payment_entries:
if payment_entry.allocated_amount == 0.0:
unallocated_amount, should_clear, latest_transaction = get_clearance_details(
Expand All @@ -99,49 +95,39 @@ def allocate_payment_entries(self):
if 0.0 == unallocated_amount:
if should_clear:
latest_transaction.clear_linked_payment_entry(payment_entry)
self.db_delete_payment_entry(payment_entry)
to_remove.append(payment_entry)

elif remaining_amount <= 0.0:
self.db_delete_payment_entry(payment_entry)
to_remove.append(payment_entry)

elif 0.0 < unallocated_amount and unallocated_amount <= remaining_amount:
payment_entry.db_set("allocated_amount", unallocated_amount)
elif 0.0 < unallocated_amount <= remaining_amount:
payment_entry.allocated_amount = unallocated_amount
remaining_amount -= unallocated_amount
if should_clear:
latest_transaction.clear_linked_payment_entry(payment_entry)

elif 0.0 < unallocated_amount and unallocated_amount > remaining_amount:
payment_entry.db_set("allocated_amount", remaining_amount)
elif 0.0 < unallocated_amount:
payment_entry.allocated_amount = remaining_amount
remaining_amount = 0.0

elif 0.0 > unallocated_amount:
self.db_delete_payment_entry(payment_entry)
frappe.throw(frappe._("Voucher {0} is over-allocated by {1}").format(unallocated_amount))

self.reload()
frappe.throw(_("Voucher {0} is over-allocated by {1}").format(unallocated_amount))

def db_delete_payment_entry(self, payment_entry):
frappe.db.delete("Bank Transaction Payments", {"name": payment_entry.name})
for payment_entry in to_remove:
self.remove(to_remove)

@frappe.whitelist()
def remove_payment_entries(self):
for payment_entry in self.payment_entries:
self.remove_payment_entry(payment_entry)
# runs on_update_after_submit
self.save()

self.save() # runs before_update_after_submit

def remove_payment_entry(self, payment_entry):
"Clear payment entry and clearance"
self.clear_linked_payment_entry(payment_entry, for_cancel=True)
self.remove(payment_entry)

def clear_linked_payment_entries(self, for_cancel=False):
if for_cancel:
for payment_entry in self.payment_entries:
self.clear_linked_payment_entry(payment_entry, for_cancel)
else:
self.allocate_payment_entries()

def clear_linked_payment_entry(self, payment_entry, for_cancel=False):
clearance_date = None if for_cancel else self.date
set_voucher_clearance(
Expand All @@ -162,11 +148,10 @@ def auto_set_party(self):
deposit=self.deposit,
).match()

if result:
party_type, party = result
frappe.db.set_value(
"Bank Transaction", self.name, field={"party_type": party_type, "party": party}
)
if not result:
return

self.party_type, self.party = result


@frappe.whitelist()
Expand Down Expand Up @@ -198,9 +183,7 @@ def get_clearance_details(transaction, payment_entry):
if gle["gl_account"] == gl_bank_account:
if gle["amount"] <= 0.0:
frappe.throw(
frappe._("Voucher {0} value is broken: {1}").format(
payment_entry.payment_entry, gle["amount"]
)
_("Voucher {0} value is broken: {1}").format(payment_entry.payment_entry, gle["amount"])
)

unmatched_gles -= 1
Expand All @@ -221,7 +204,7 @@ def get_clearance_details(transaction, payment_entry):

def get_related_bank_gl_entries(doctype, docname):
# nosemgrep: frappe-semgrep-rules.rules.frappe-using-db-sql
result = frappe.db.sql(
return frappe.db.sql(
"""
SELECT
ABS(gle.credit_in_account_currency - gle.debit_in_account_currency) AS amount,
Expand All @@ -239,7 +222,6 @@ def get_related_bank_gl_entries(doctype, docname):
dict(doctype=doctype, docname=docname),
as_dict=True,
)
return result


def get_total_allocated_amount(doctype, docname):
Expand Down Expand Up @@ -365,6 +347,7 @@ def set_voucher_clearance(doctype, docname, clearance_date, self):
if clearance_date:
vouchers = [{"payment_doctype": "Bank Transaction", "payment_name": self.name}]
bt.add_payment_entries(vouchers)
bt.save()
else:
for pe in bt.payment_entries:
if pe.payment_document == self.doctype and pe.payment_entry == self.name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def generate_data_from_csv(file_doc, as_dict=False):
if as_dict:
data.append({frappe.scrub(header): row[index] for index, header in enumerate(headers)})
else:
if not row[1]:
if not row[1] and len(row) > 1:
row[1] = row[0]
row[3] = row[2]
data.append(row)
Expand Down
2 changes: 1 addition & 1 deletion erpnext/accounts/doctype/journal_entry/journal_entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ frappe.ui.form.on("Journal Entry", {
}, __('Make'));
}

erpnext.accounts.unreconcile_payments.add_unreconcile_btn(frm);
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
},
before_save: function(frm) {
if ((frm.doc.docstatus == 0) && (!frm.doc.is_system_generated)) {
Expand Down
12 changes: 10 additions & 2 deletions erpnext/accounts/doctype/journal_entry/journal_entry.json
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,16 @@
"icon": "fa fa-file-text",
"idx": 176,
"is_submittable": 1,
"links": [],
"modified": "2023-08-10 14:32:22.366895",
"links": [
{
"is_child_table": 1,
"link_doctype": "Bank Transaction Payments",
"link_fieldname": "payment_entry",
"parent_doctype": "Bank Transaction",
"table_fieldname": "payment_entries"
}
],
"modified": "2023-11-23 12:11:04.128015",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
Expand Down
4 changes: 2 additions & 2 deletions erpnext/accounts/doctype/journal_entry/journal_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def validate_against_jv(self):
).format(d.reference_name, d.account)
)
else:
dr_or_cr = "debit" if d.credit > 0 else "credit"
dr_or_cr = "debit" if flt(d.credit) > 0 else "credit"
valid = False
for jvd in against_entries:
if flt(jvd[dr_or_cr]) > 0:
Expand Down Expand Up @@ -868,7 +868,7 @@ def set_print_format_fields(self):
party_account_currency = d.account_currency

elif frappe.get_cached_value("Account", d.account, "account_type") in ["Bank", "Cash"]:
bank_amount += d.debit_in_account_currency or d.credit_in_account_currency
bank_amount += flt(d.debit_in_account_currency) or flt(d.credit_in_account_currency)
bank_account_currency = d.account_currency

if party_type and pay_to_recd_from:
Expand Down
Loading

0 comments on commit 4bfdab9

Please sign in to comment.