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:
@@ -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)
|
||||||
|
|||||||
@@ -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 = (
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user