mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-24 15:39:20 +00:00
Merge pull request #43226 from aerele/reconcile-after-period-closing
fix: map rows on journal entry by validating account, party, debit and credit value
This commit is contained in:
@@ -195,6 +195,11 @@ class JournalEntry(AccountsController):
|
|||||||
self.update_booked_depreciation()
|
self.update_booked_depreciation()
|
||||||
|
|
||||||
def on_update_after_submit(self):
|
def on_update_after_submit(self):
|
||||||
|
# Flag will be set on Reconciliation
|
||||||
|
# Reconciliation tool will anyways repost ledger entries. So, no need to check and do implicit repost.
|
||||||
|
if self.flags.get("ignore_reposting_on_reconciliation"):
|
||||||
|
return
|
||||||
|
|
||||||
self.needs_repost = self.check_if_fields_updated(fields_to_check=[], child_tables={"accounts": []})
|
self.needs_repost = self.check_if_fields_updated(fields_to_check=[], child_tables={"accounts": []})
|
||||||
if self.needs_repost:
|
if self.needs_repost:
|
||||||
self.validate_for_repost()
|
self.validate_for_repost()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import qb
|
from frappe import qb
|
||||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||||
from frappe.utils import add_days, flt, nowdate
|
from frappe.utils import add_days, add_years, flt, getdate, nowdate, today
|
||||||
|
|
||||||
from erpnext import get_default_cost_center
|
from erpnext import get_default_cost_center
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
@@ -13,6 +13,7 @@ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_pay
|
|||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
||||||
from erpnext.stock.doctype.item.test_item import create_item
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
|
|
||||||
@@ -1845,6 +1846,78 @@ class TestPaymentReconciliation(FrappeTestCase):
|
|||||||
self.assertEqual(len(pr.invoices), 1)
|
self.assertEqual(len(pr.invoices), 1)
|
||||||
self.assertEqual(len(pr.payments), 1)
|
self.assertEqual(len(pr.payments), 1)
|
||||||
|
|
||||||
|
def test_reconciliation_on_closed_period_payment(self):
|
||||||
|
# create backdated fiscal year
|
||||||
|
first_fy_start_date = frappe.db.get_value("Fiscal Year", {"disabled": 0}, "min(year_start_date)")
|
||||||
|
prev_fy_start_date = add_years(first_fy_start_date, -1)
|
||||||
|
prev_fy_end_date = add_days(first_fy_start_date, -1)
|
||||||
|
create_fiscal_year(
|
||||||
|
company=self.company, year_start_date=prev_fy_start_date, year_end_date=prev_fy_end_date
|
||||||
|
)
|
||||||
|
|
||||||
|
# make journal entry for previous year
|
||||||
|
je_1 = frappe.new_doc("Journal Entry")
|
||||||
|
je_1.posting_date = add_days(prev_fy_start_date, 20)
|
||||||
|
je_1.company = self.company
|
||||||
|
je_1.user_remark = "test"
|
||||||
|
je_1.set(
|
||||||
|
"accounts",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": self.debit_to,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
"party_type": "Customer",
|
||||||
|
"party": self.customer,
|
||||||
|
"debit_in_account_currency": 0,
|
||||||
|
"credit_in_account_currency": 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": self.bank,
|
||||||
|
"cost_center": self.sub_cc.name,
|
||||||
|
"credit_in_account_currency": 0,
|
||||||
|
"debit_in_account_currency": 500,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": self.cash,
|
||||||
|
"cost_center": self.sub_cc.name,
|
||||||
|
"credit_in_account_currency": 0,
|
||||||
|
"debit_in_account_currency": 500,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
je_1.submit()
|
||||||
|
|
||||||
|
# make period closing voucher
|
||||||
|
pcv = make_period_closing_voucher(
|
||||||
|
company=self.company, cost_center=self.cost_center, posting_date=prev_fy_end_date
|
||||||
|
)
|
||||||
|
pcv.reload()
|
||||||
|
# check if period closing voucher is completed
|
||||||
|
self.assertEqual(pcv.gle_processing_status, "Completed")
|
||||||
|
|
||||||
|
# make journal entry for active year
|
||||||
|
je_2 = self.create_journal_entry(
|
||||||
|
acc1=self.debit_to, acc2=self.income_account, amount=1000, posting_date=today()
|
||||||
|
)
|
||||||
|
je_2.accounts[0].party_type = "Customer"
|
||||||
|
je_2.accounts[0].party = self.customer
|
||||||
|
je_2.submit()
|
||||||
|
|
||||||
|
# process reconciliation on closed period payment
|
||||||
|
pr = self.create_payment_reconciliation(party_is_customer=True)
|
||||||
|
pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = None
|
||||||
|
pr.get_unreconciled_entries()
|
||||||
|
invoices = [invoice.as_dict() for invoice in pr.invoices]
|
||||||
|
payments = [payment.as_dict() for payment in pr.payments]
|
||||||
|
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
|
||||||
|
pr.reconcile()
|
||||||
|
je_1.reload()
|
||||||
|
je_2.reload()
|
||||||
|
|
||||||
|
# check whether the payment reconciliation is done on the closed period
|
||||||
|
self.assertEqual(pr.get("invoices"), [])
|
||||||
|
self.assertEqual(pr.get("payments"), [])
|
||||||
|
|
||||||
|
|
||||||
def make_customer(customer_name, currency=None):
|
def make_customer(customer_name, currency=None):
|
||||||
if not frappe.db.exists("Customer", customer_name):
|
if not frappe.db.exists("Customer", customer_name):
|
||||||
@@ -1872,3 +1945,61 @@ def make_supplier(supplier_name, currency=None):
|
|||||||
return supplier.name
|
return supplier.name
|
||||||
else:
|
else:
|
||||||
return supplier_name
|
return supplier_name
|
||||||
|
|
||||||
|
|
||||||
|
def create_fiscal_year(company, year_start_date, year_end_date):
|
||||||
|
fy_docname = frappe.db.exists(
|
||||||
|
"Fiscal Year", {"year_start_date": year_start_date, "year_end_date": year_end_date}
|
||||||
|
)
|
||||||
|
if not fy_docname:
|
||||||
|
fy_doc = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Fiscal Year",
|
||||||
|
"year": f"{getdate(year_start_date).year}-{getdate(year_end_date).year}",
|
||||||
|
"year_start_date": year_start_date,
|
||||||
|
"year_end_date": year_end_date,
|
||||||
|
"companies": [{"company": company}],
|
||||||
|
}
|
||||||
|
).save()
|
||||||
|
return fy_doc
|
||||||
|
else:
|
||||||
|
fy_doc = frappe.get_doc("Fiscal Year", fy_docname)
|
||||||
|
if not frappe.db.exists("Fiscal Year Company", {"parent": fy_docname, "company": company}):
|
||||||
|
fy_doc.append("companies", {"company": company})
|
||||||
|
fy_doc.save()
|
||||||
|
return fy_doc
|
||||||
|
|
||||||
|
|
||||||
|
def make_period_closing_voucher(company, cost_center, posting_date=None, submit=True):
|
||||||
|
from erpnext.accounts.doctype.account.test_account import create_account
|
||||||
|
|
||||||
|
parent_account = frappe.db.get_value(
|
||||||
|
"Account", {"company": company, "account_name": "Current Liabilities", "is_group": 1}, "name"
|
||||||
|
)
|
||||||
|
surplus_account = create_account(
|
||||||
|
account_name="Reserve and Surplus",
|
||||||
|
is_group=0,
|
||||||
|
company=company,
|
||||||
|
root_type="Liability",
|
||||||
|
report_type="Balance Sheet",
|
||||||
|
account_currency="INR",
|
||||||
|
parent_account=parent_account,
|
||||||
|
doctype="Account",
|
||||||
|
)
|
||||||
|
pcv = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Period Closing Voucher",
|
||||||
|
"transaction_date": posting_date or today(),
|
||||||
|
"posting_date": posting_date or today(),
|
||||||
|
"company": company,
|
||||||
|
"fiscal_year": get_fiscal_year(posting_date or today(), company=company)[0],
|
||||||
|
"cost_center": cost_center,
|
||||||
|
"closing_account_head": surplus_account,
|
||||||
|
"remarks": "test",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
pcv.insert()
|
||||||
|
if submit:
|
||||||
|
pcv.submit()
|
||||||
|
|
||||||
|
return pcv
|
||||||
|
|||||||
@@ -685,6 +685,8 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
|
|||||||
|
|
||||||
# will work as update after submit
|
# will work as update after submit
|
||||||
journal_entry.flags.ignore_validate_update_after_submit = True
|
journal_entry.flags.ignore_validate_update_after_submit = True
|
||||||
|
# Ledgers will be reposted by Reconciliation tool
|
||||||
|
journal_entry.flags.ignore_reposting_on_reconciliation = True
|
||||||
if not do_not_save:
|
if not do_not_save:
|
||||||
journal_entry.save(ignore_permissions=True)
|
journal_entry.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user