fix: value of depreciable assets not updating after manual depr entry [develop] (#35020)

* fix: value of depreciable assets not updating after manual depr entry

* chore: add asset depr schedule to jv's ignore_doctypes_on_cancel_all
This commit is contained in:
Anand Baburajan 2023-04-25 12:45:05 +05:30 committed by GitHub
parent 04902e1b60
commit ca388ed9cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 55 deletions

View File

@ -297,7 +297,7 @@ def _make_test_records(verbose=None):
# fixed asset depreciation # fixed asset depreciation
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None], ["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None], ["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None],
["_Test Depreciations", "Expenses", 0, None, None], ["_Test Depreciations", "Expenses", 0, "Depreciation", None],
["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None], ["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None],
# Receivable / Payable Account # Receivable / Payable Account
["_Test Receivable", "Current Assets", 0, "Receivable", None], ["_Test Receivable", "Current Assets", 0, "Receivable", None],

View File

@ -8,7 +8,7 @@ frappe.provide("erpnext.journal_entry");
frappe.ui.form.on("Journal Entry", { frappe.ui.form.on("Journal Entry", {
setup: function(frm) { setup: function(frm) {
frm.add_fetch("bank_account", "account", "account"); frm.add_fetch("bank_account", "account", "account");
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger"]; frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset Depreciation Schedule'];
}, },
refresh: function(frm) { refresh: function(frm) {

View File

@ -69,6 +69,7 @@ class JournalEntry(AccountsController):
self.validate_empty_accounts_table() self.validate_empty_accounts_table()
self.set_account_and_party_balance() self.set_account_and_party_balance()
self.validate_inter_company_accounts() self.validate_inter_company_accounts()
self.validate_depr_entry_voucher_type()
if self.docstatus == 0: if self.docstatus == 0:
self.apply_tax_withholding() self.apply_tax_withholding()
@ -130,6 +131,13 @@ class JournalEntry(AccountsController):
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit: if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry")) frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
def validate_depr_entry_voucher_type(self):
if (
any(d.account_type == "Depreciation" for d in self.get("accounts"))
and self.voucher_type != "Depreciation Entry"
):
frappe.throw(_("Journal Entry type should be set as Depreciation Entry for asset depreciation"))
def validate_stock_accounts(self): def validate_stock_accounts(self):
stock_accounts = get_stock_accounts(self.company, self.doctype, self.name) stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
for account in stock_accounts: for account in stock_accounts:
@ -233,25 +241,30 @@ class JournalEntry(AccountsController):
self.remove(d) self.remove(d)
def update_asset_value(self): def update_asset_value(self):
if self.voucher_type != "Depreciation Entry": if self.flags.planned_depr_entry or self.voucher_type != "Depreciation Entry":
return return
processed_assets = []
for d in self.get("accounts"): for d in self.get("accounts"):
if ( if (
d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets d.reference_type == "Asset"
and d.reference_name
and d.account_type == "Depreciation"
and d.debit
): ):
processed_assets.append(d.reference_name)
asset = frappe.get_doc("Asset", d.reference_name) asset = frappe.get_doc("Asset", d.reference_name)
if asset.calculate_depreciation: if asset.calculate_depreciation:
continue fb_idx = 1
if self.finance_book:
depr_value = d.debit or d.credit for fb_row in asset.get("finance_books"):
if fb_row.finance_book == self.finance_book:
asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value) fb_idx = fb_row.idx
break
fb_row = asset.get("finance_books")[fb_idx - 1]
fb_row.value_after_depreciation -= d.debit
fb_row.db_update()
else:
asset.db_set("value_after_depreciation", asset.value_after_depreciation - d.debit)
asset.set_status() asset.set_status()
@ -316,42 +329,47 @@ class JournalEntry(AccountsController):
if self.voucher_type != "Depreciation Entry": if self.voucher_type != "Depreciation Entry":
return return
processed_assets = []
for d in self.get("accounts"): for d in self.get("accounts"):
if ( if (
d.reference_type == "Asset" and d.reference_name and d.reference_name not in processed_assets d.reference_type == "Asset"
and d.reference_name
and d.account_type == "Depreciation"
and d.debit
): ):
processed_assets.append(d.reference_name)
asset = frappe.get_doc("Asset", d.reference_name) asset = frappe.get_doc("Asset", d.reference_name)
if asset.calculate_depreciation: if asset.calculate_depreciation:
je_found = False je_found = False
for row in asset.get("finance_books"): for fb_row in asset.get("finance_books"):
if je_found: if je_found:
break break
depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book) depr_schedule = get_depr_schedule(asset.name, "Active", fb_row.finance_book)
for s in depr_schedule or []: for s in depr_schedule or []:
if s.journal_entry == self.name: if s.journal_entry == self.name:
s.db_set("journal_entry", None) s.db_set("journal_entry", None)
row.value_after_depreciation += s.depreciation_amount fb_row.value_after_depreciation += d.debit
row.db_update() fb_row.db_update()
asset.set_status()
je_found = True je_found = True
break break
if not je_found:
fb_idx = 1
if self.finance_book:
for fb_row in asset.get("finance_books"):
if fb_row.finance_book == self.finance_book:
fb_idx = fb_row.idx
break
fb_row = asset.get("finance_books")[fb_idx - 1]
fb_row.value_after_depreciation += d.debit
fb_row.db_update()
else: else:
depr_value = d.debit or d.credit asset.db_set("value_after_depreciation", asset.value_after_depreciation + d.debit)
asset.set_status()
asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value)
asset.set_status()
def unlink_inter_company_jv(self): def unlink_inter_company_jv(self):
if ( if (

View File

@ -114,28 +114,6 @@ def get_assets(filters):
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.asset_category, from (SELECT a.asset_category,
ifnull(sum(case when ds.schedule_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
ds.depreciation_amount
else
0
end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
ds.depreciation_amount
else
0
end), 0) as depreciation_eliminated_during_the_period,
ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
ds.depreciation_amount
else
0
end), 0) as depreciation_amount_during_the_period
from `tabAsset` a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and ads.asset = a.name and ads.docstatus=1 and ads.name = ds.parent and ifnull(ds.journal_entry, '') != ''
group by a.asset_category
union
SELECT a.asset_category,
ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
gle.debit gle.debit
else else
@ -160,7 +138,7 @@ def get_assets(filters):
aca.parent = a.asset_category and aca.company_name = %(company)s aca.parent = a.asset_category and aca.company_name = %(company)s
join `tabCompany` company on join `tabCompany` company on
company.name = %(company)s company.name = %(company)s
where a.docstatus=1 and a.company=%(company)s and a.calculate_depreciation=0 and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account) where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
group by a.asset_category group by a.asset_category
union union
SELECT a.asset_category, SELECT a.asset_category,

View File

@ -157,6 +157,7 @@ def make_depreciation_entry(asset_depr_schedule_name, date=None):
je.append("accounts", debit_entry) je.append("accounts", debit_entry)
je.flags.ignore_permissions = True je.flags.ignore_permissions = True
je.flags.planned_depr_entry = True
je.save() je.save()
if not je.meta.get_workflow(): if not je.meta.get_workflow():
je.submit() je.submit()

View File

@ -1511,7 +1511,7 @@ class TestDepreciationBasics(AssetSetup):
) )
self.assertEqual(asset.status, "Submitted") self.assertEqual(asset.status, "Submitted")
self.assertEqual(asset.get("value_after_depreciation"), 100000) self.assertEqual(asset.get_value_after_depreciation(), 100000)
jv = make_journal_entry( jv = make_journal_entry(
"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False "_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
@ -1524,12 +1524,68 @@ class TestDepreciationBasics(AssetSetup):
jv.submit() jv.submit()
asset.reload() asset.reload()
self.assertEqual(asset.get("value_after_depreciation"), 99900) self.assertEqual(asset.get_value_after_depreciation(), 99900)
jv.cancel() jv.cancel()
asset.reload() asset.reload()
self.assertEqual(asset.get("value_after_depreciation"), 100000) self.assertEqual(asset.get_value_after_depreciation(), 100000)
def test_manual_depreciation_for_depreciable_asset(self):
asset = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
purchase_date="2020-01-30",
available_for_use_date="2020-01-30",
expected_value_after_useful_life=10000,
total_number_of_depreciations=10,
frequency_of_depreciation=1,
submit=1,
)
self.assertEqual(asset.status, "Submitted")
self.assertEqual(asset.get_value_after_depreciation(), 100000)
jv = make_journal_entry(
"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
)
for d in jv.accounts:
d.reference_type = "Asset"
d.reference_name = asset.name
jv.voucher_type = "Depreciation Entry"
jv.insert()
jv.submit()
asset.reload()
self.assertEqual(asset.get_value_after_depreciation(), 99900)
jv.cancel()
asset.reload()
self.assertEqual(asset.get_value_after_depreciation(), 100000)
def test_manual_depreciation_with_incorrect_jv_voucher_type(self):
asset = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
purchase_date="2020-01-30",
available_for_use_date="2020-01-30",
expected_value_after_useful_life=10000,
total_number_of_depreciations=10,
frequency_of_depreciation=1,
submit=1,
)
jv = make_journal_entry(
"_Test Depreciations - _TC", "_Test Accumulated Depreciations - _TC", 100, save=False
)
for d in jv.accounts:
d.reference_type = "Asset"
d.reference_name = asset.name
d.account_type = "Depreciation"
jv.voucher_type = "Journal Entry"
self.assertRaises(frappe.ValidationError, jv.insert)
def create_asset_data(): def create_asset_data():