fix: multiple fixes for advance payment accounting (backport #48341) (#48896)

* fix: multiple fixes for advance payment accounting

(cherry picked from commit e70caedddc)

# Conflicts:
#	erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
#	erpnext/accounts/doctype/payment_entry/payment_entry.py
#	erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
#	erpnext/accounts/utils.py
#	erpnext/controllers/accounts_controller.py
#	erpnext/patches/v15_0/create_advance_payment_ledger_records.py

* chore: resolve conflicts

* fix: do not execute patch if no advance doctypes

---------

Co-authored-by: Lakshit Jain <108322669+ljain112@users.noreply.github.com>
Co-authored-by: ljain112 <ljain112@gmail.com>
(cherry picked from commit cb0addc122)
This commit is contained in:
mergify[bot]
2025-08-01 15:30:30 +05:30
committed by Mergify
parent 396886c6e8
commit 52b9f92553
25 changed files with 650 additions and 362 deletions

View File

@@ -1,63 +1,28 @@
import frappe
from frappe import qb
from frappe.query_builder.custom import ConstantColumn
from frappe.model.naming import _generate_random_string
from frappe.query_builder import Case
from frappe.utils import now_datetime
from erpnext.accounts.utils import get_advance_payment_doctypes
def get_advance_doctypes() -> list:
return frappe.get_hooks("advance_payment_doctypes")
DOCTYPE = "Advance Payment Ledger Entry"
def get_payments_with_so_po_reference() -> list:
advance_payment_entries = []
advance_doctypes = get_advance_doctypes()
per = qb.DocType("Payment Entry Reference")
payments_with_reference = (
qb.from_(per)
.select(per.parent)
.distinct()
.where(per.reference_doctype.isin(advance_doctypes) & per.docstatus.eq(1))
.run()
)
if payments_with_reference:
pe = qb.DocType("Payment Entry")
advance_payment_entries = (
qb.from_(pe)
.select(ConstantColumn("Payment Entry").as_("doctype"))
.select(pe.name)
.where(pe.name.isin(payments_with_reference) & pe.docstatus.eq(1))
.run(as_dict=True)
)
return advance_payment_entries
def get_journals_with_so_po_reference() -> list:
advance_journal_entries = []
advance_doctypes = get_advance_doctypes()
jea = qb.DocType("Journal Entry Account")
journals_with_reference = (
qb.from_(jea)
.select(jea.parent)
.distinct()
.where(jea.reference_type.isin(advance_doctypes) & jea.docstatus.eq(1))
.run()
)
if journals_with_reference:
je = qb.DocType("Journal Entry")
advance_journal_entries = (
qb.from_(je)
.select(ConstantColumn("Journal Entry").as_("doctype"))
.select(je.name)
.where(je.name.isin(journals_with_reference) & je.docstatus.eq(1))
.run(as_dict=True)
)
return advance_journal_entries
def make_advance_ledger_entries(vouchers: list):
for x in vouchers:
frappe.get_doc(x.doctype, x.name).make_advance_payment_ledger_entries()
FIELDS = [
"name",
"creation",
"modified",
"owner",
"modified_by",
"company",
"voucher_type",
"voucher_no",
"against_voucher_type",
"against_voucher_no",
"amount",
"currency",
"event",
"delinked",
]
def execute():
@@ -65,9 +30,102 @@ def execute():
Description:
Create Advance Payment Ledger Entry for all Payments made against Sales / Purchase Orders
"""
frappe.db.truncate("Advance Payment Ledger Entry")
payment_entries = get_payments_with_so_po_reference()
make_advance_ledger_entries(payment_entries)
frappe.db.truncate(DOCTYPE)
advance_doctpyes = get_advance_payment_doctypes()
journals = get_journals_with_so_po_reference()
make_advance_ledger_entries(journals)
if not advance_doctpyes:
return
make_advance_ledger_entries_for_payment_entries(advance_doctpyes)
make_advance_ledger_entries_for_journal_entries(advance_doctpyes)
def make_advance_ledger_entries_for_payment_entries(advance_doctpyes) -> list:
pe = frappe.qb.DocType("Payment Entry")
per = frappe.qb.DocType("Payment Entry Reference")
entries = (
frappe.qb.from_(per)
.inner_join(pe)
.on(pe.name == per.parent)
.select(
pe.company,
per.parenttype.as_("voucher_type"),
per.parent.as_("voucher_no"),
per.reference_doctype.as_("against_voucher_type"),
per.reference_name.as_("against_voucher_no"),
per.allocated_amount.as_("amount"),
Case()
.when(pe.payment_type == "Receive", pe.paid_from_account_currency)
.else_(pe.paid_to_account_currency)
.as_("currency"),
)
.where(per.reference_doctype.isin(advance_doctpyes) & per.docstatus.eq(1))
.run(as_dict=True)
)
if not entries:
return
bulk_insert_advance_entries(entries)
def make_advance_ledger_entries_for_journal_entries(advance_doctpyes) -> list:
je = frappe.qb.DocType("Journal Entry")
jea = frappe.qb.DocType("Journal Entry Account")
entries = (
frappe.qb.from_(jea)
.inner_join(je)
.on(je.name == jea.parent)
.select(
je.company,
jea.parenttype.as_("voucher_type"),
jea.parent.as_("voucher_no"),
jea.reference_type.as_("against_voucher_type"),
jea.reference_name.as_("against_voucher_no"),
Case()
.when(jea.account_type == "Receivable", jea.credit_in_account_currency)
.else_(jea.debit_in_account_currency)
.as_("amount"),
jea.account_currency.as_("currency"),
)
.where(jea.reference_type.isin(advance_doctpyes) & jea.docstatus.eq(1))
.run(as_dict=True)
)
if not entries:
return
bulk_insert_advance_entries(entries)
def bulk_insert_advance_entries(entries):
details = []
user = frappe.session.user
now = now_datetime()
for entry in entries:
if entry.amount < 0:
continue
details.append(get_values(user, now, entry))
frappe.db.bulk_insert(DOCTYPE, fields=FIELDS, values=details)
def get_values(user, now, entry):
return (
_generate_random_string(10),
now,
now,
user,
user,
entry.company,
entry.voucher_type,
entry.voucher_no,
entry.against_voucher_type,
entry.against_voucher_no,
entry.amount * -1,
entry.currency,
"Submit",
0,
)

View File

@@ -0,0 +1,25 @@
import frappe
from erpnext.accounts.utils import get_advance_payment_doctypes
DOCTYPE = "Payment Ledger Entry"
def execute():
"""
Description:
Set against_voucher as entry for Payment Ledger Entry against advance vouchers.
"""
advance_payment_doctypes = get_advance_payment_doctypes()
if not advance_payment_doctypes:
return
ple = frappe.qb.DocType(DOCTYPE)
(
frappe.qb.update(ple)
.set(ple.against_voucher_type, ple.voucher_type)
.set(ple.against_voucher_no, ple.voucher_no)
.where(ple.against_voucher_type.isin(advance_payment_doctypes))
.run()
)