Merge pull request #41320 from frappe/mergify/bp/version-15/pr-41279

fix: GL Entries against orders as an advance (#41279)
This commit is contained in:
Deepesh Garg
2024-05-03 23:01:18 +05:30
committed by GitHub
3 changed files with 114 additions and 92 deletions

View File

@@ -1131,88 +1131,71 @@ class PaymentEntry(AccountsController):
) )
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit" dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
if self.book_advance_payments_in_separate_party_account:
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy() gle = party_gl_dict.copy()
if self.payment_type == "Receive": allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
amount = self.base_paid_amount reverse_dr_or_cr = 0
else:
amount = self.base_received_amount if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if (
is_return
and self.party_type in receivable_party_types
and (self.payment_type == "Pay")
):
reverse_dr_or_cr = 1
elif (
is_return
and self.party_type in payable_party_types
and (self.payment_type == "Receive")
):
reverse_dr_or_cr = 1
if is_return and not reverse_dr_or_cr:
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
exchange_rate = self.get_exchange_rate()
amount_in_account_currency = amount * exchange_rate
gle.update( gle.update(
{ {
dr_or_cr: amount, dr_or_cr: abs(allocated_amount_in_company_currency),
dr_or_cr + "_in_account_currency": amount_in_account_currency, dr_or_cr + "_in_account_currency": abs(d.allocated_amount),
"against_voucher_type": "Payment Entry", "against_voucher_type": d.reference_doctype,
"against_voucher": self.name, "against_voucher": d.reference_name,
"cost_center": self.cost_center, "cost_center": cost_center,
} }
) )
gl_entries.append(gle) gl_entries.append(gle)
else:
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(
d.reference_doctype, d.reference_name, "cost_center"
)
gle = party_gl_dict.copy() if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference( gle = party_gl_dict.copy()
d gle.update(
) {
reverse_dr_or_cr = 0 dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]: }
is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return") )
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if (
is_return
and self.party_type in receivable_party_types
and (self.payment_type == "Pay")
):
reverse_dr_or_cr = 1
elif (
is_return
and self.party_type in payable_party_types
and (self.payment_type == "Receive")
):
reverse_dr_or_cr = 1
if is_return and not reverse_dr_or_cr:
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
if self.book_advance_payments_in_separate_party_account:
gle.update( gle.update(
{ {
dr_or_cr: abs(allocated_amount_in_company_currency), "against_voucher_type": "Payment Entry",
dr_or_cr + "_in_account_currency": abs(d.allocated_amount), "against_voucher": self.name,
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"cost_center": cost_center,
} }
) )
gl_entries.append(gle) gl_entries.append(gle)
if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
gl_entries.append(gle)
def make_advance_gl_entries( def make_advance_gl_entries(
self, entry: object | dict = None, cancel: bool = 0, update_outstanding: str = "Yes" self, entry: object | dict = None, cancel: bool = 0, update_outstanding: str = "Yes"
@@ -1227,7 +1210,7 @@ class PaymentEntry(AccountsController):
def add_advance_gl_entries(self, gl_entries: list, entry: object | dict | None): def add_advance_gl_entries(self, gl_entries: list, entry: object | dict | None):
""" """
If 'entry' is passed, GL enties only for that reference is added. If 'entry' is passed, GL entries only for that reference is added.
""" """
if self.book_advance_payments_in_separate_party_account: if self.book_advance_payments_in_separate_party_account:
references = [x for x in self.get("references")] references = [x for x in self.get("references")]
@@ -1239,8 +1222,6 @@ class PaymentEntry(AccountsController):
"Sales Invoice", "Sales Invoice",
"Purchase Invoice", "Purchase Invoice",
"Journal Entry", "Journal Entry",
"Sales Order",
"Purchase Order",
"Payment Entry", "Payment Entry",
): ):
self.add_advance_gl_for_reference(gl_entries, ref) self.add_advance_gl_for_reference(gl_entries, ref)

View File

@@ -1440,6 +1440,68 @@ class TestPaymentEntry(FrappeTestCase):
self.check_gl_entries() self.check_gl_entries()
self.check_pl_entries() self.check_pl_entries()
def test_advance_as_liability_against_order(self):
from erpnext.buying.doctype.purchase_order.purchase_order import (
make_purchase_invoice as _make_purchase_invoice,
)
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
company = "_Test Company"
advance_account = create_account(
parent_account="Current Liabilities - _TC",
account_name="Advances Paid",
company=company,
account_type="Liability",
)
frappe.db.set_value(
"Company",
company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_paid_account": advance_account,
},
)
po = create_purchase_order(supplier="_Test Supplier")
pe = get_payment_entry("Purchase Order", po.name, bank_account="Cash - _TC")
pe.save().submit()
pre_reconciliation_gle = [
{"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0},
{"account": advance_account, "debit": 5000.0, "credit": 0.0},
]
self.voucher_no = pe.name
self.expected_gle = pre_reconciliation_gle
self.check_gl_entries()
# Make Purchase Invoice against the order
pi = _make_purchase_invoice(po.name)
pi.append(
"advances",
{
"reference_type": pe.doctype,
"reference_name": pe.name,
"reference_row": pe.references[0].name,
"advance_amount": 5000,
"allocated_amount": 5000,
},
)
pi.save().submit()
# # assert General and Payment Ledger entries post partial reconciliation
self.expected_gle = [
{"account": pi.credit_to, "debit": 5000.0, "credit": 0.0},
{"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0},
{"account": advance_account, "debit": 5000.0, "credit": 0.0},
{"account": advance_account, "debit": 0.0, "credit": 5000.0},
]
self.voucher_no = pe.name
self.check_gl_entries()
def check_pl_entries(self): def check_pl_entries(self):
ple = frappe.qb.DocType("Payment Ledger Entry") ple = frappe.qb.DocType("Payment Ledger Entry")
pl_entries = ( pl_entries = (

View File

@@ -764,12 +764,7 @@ class TestPurchaseOrder(FrappeTestCase):
} }
).insert() ).insert()
else: else:
account = frappe.db.get_value( account = frappe.get_doc("Account", {"account_name": account_name, "company": company})
"Account",
filters={"account_name": account_name, "company": company},
fieldname="name",
pluck=True,
)
return account return account
@@ -800,22 +795,6 @@ class TestPurchaseOrder(FrappeTestCase):
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
pi = make_purchase_invoice(po_doc.name)
pi.append(
"advances",
{
"reference_type": pe.doctype,
"reference_name": pe.name,
"reference_row": pe.references[0].name,
"advance_amount": 5000,
"allocated_amount": 5000,
},
)
pi.save().submit()
pe.reload()
po_doc.reload()
self.assertEqual(po_doc.advance_paid, 0)
company_doc.book_advance_payments_in_separate_party_account = False company_doc.book_advance_payments_in_separate_party_account = False
company_doc.save() company_doc.save()