fix(Asset Capitalization): update code for changes in depreciation logic

This commit is contained in:
Saif Ur Rehman 2021-11-04 13:47:33 +05:00
parent 2d9da22721
commit dc3c27fd1b
5 changed files with 37 additions and 116 deletions

View File

@ -27,7 +27,6 @@ from erpnext.assets.doctype.asset.depreciation import (
get_disposal_account_and_cost_center,
get_gl_entries_on_asset_disposal,
get_gl_entries_on_asset_regain,
make_depreciation_entry,
)
from erpnext.controllers.selling_controller import SellingController
from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
@ -924,7 +923,7 @@ class SalesInvoice(SellingController):
asset.db_set("disposal_date", None)
if asset.calculate_depreciation:
self.reverse_depreciation_entry_made_after_sale(asset)
self.reverse_depreciation_entry_made_after_disposal(asset)
self.reset_depreciation_schedule(asset)
else:
@ -980,89 +979,6 @@ class SalesInvoice(SellingController):
self.check_finance_books(item, asset)
return asset
def check_finance_books(self, item, asset):
if (len(asset.finance_books) > 1 and not item.finance_book
and asset.finance_books[0].finance_book):
frappe.throw(_("Select finance book for the item {0} at row {1}")
.format(item.item_code, item.idx))
def depreciate_asset(self, asset):
asset.flags.ignore_validate_update_after_submit = True
asset.prepare_depreciation_data(date_of_sale=self.posting_date)
asset.save()
make_depreciation_entry(asset.name, self.posting_date)
def reset_depreciation_schedule(self, asset):
asset.flags.ignore_validate_update_after_submit = True
# recreate original depreciation schedule of the asset
asset.prepare_depreciation_data(date_of_return=self.posting_date)
self.modify_depreciation_schedule_for_asset_repairs(asset)
asset.save()
def modify_depreciation_schedule_for_asset_repairs(self, asset):
asset_repairs = frappe.get_all(
'Asset Repair',
filters = {'asset': asset.name},
fields = ['name', 'increase_in_asset_life']
)
for repair in asset_repairs:
if repair.increase_in_asset_life:
asset_repair = frappe.get_doc('Asset Repair', repair.name)
asset_repair.modify_depreciation_schedule()
asset.prepare_depreciation_data()
def reverse_depreciation_entry_made_after_sale(self, asset):
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
posting_date_of_original_invoice = self.get_posting_date_of_sales_invoice()
row = -1
finance_book = asset.get('schedules')[0].get('finance_book')
for schedule in asset.get('schedules'):
if schedule.finance_book != finance_book:
row = 0
finance_book = schedule.finance_book
else:
row += 1
if schedule.schedule_date == posting_date_of_original_invoice:
if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice) \
or self.sale_happens_in_the_future(posting_date_of_original_invoice):
reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
reverse_journal_entry.posting_date = nowdate()
frappe.flags.is_reverse_depr_entry = True
reverse_journal_entry.submit()
frappe.flags.is_reverse_depr_entry = False
asset.flags.ignore_validate_update_after_submit = True
schedule.journal_entry = None
asset.save()
def get_posting_date_of_sales_invoice(self):
return frappe.db.get_value('Sales Invoice', self.return_against, 'posting_date')
# if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone
def sale_was_made_on_original_schedule_date(self, asset, schedule, row, posting_date_of_original_invoice):
for finance_book in asset.get('finance_books'):
if schedule.finance_book == finance_book.finance_book:
orginal_schedule_date = add_months(finance_book.depreciation_start_date,
row * cint(finance_book.frequency_of_depreciation))
if orginal_schedule_date == posting_date_of_original_invoice:
return True
return False
def sale_happens_in_the_future(self, posting_date_of_original_invoice):
if posting_date_of_original_invoice > getdate():
return True
return False
@property
def enable_discount_accounting(self):
if not hasattr(self, "_enable_discount_accounting"):

View File

@ -75,12 +75,12 @@ class Asset(AccountsController):
if self.is_existing_asset and self.purchase_invoice:
frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
def prepare_depreciation_data(self, date_of_sale=None, date_of_return=None):
def prepare_depreciation_data(self, date_of_disposal=None, date_of_return=None):
if self.calculate_depreciation:
self.value_after_depreciation = 0
self.set_depreciation_rate()
self.make_depreciation_schedule(date_of_sale)
self.set_accumulated_depreciation(date_of_sale, date_of_return)
self.make_depreciation_schedule(date_of_disposal)
self.set_accumulated_depreciation(date_of_disposal, date_of_return)
else:
self.finance_books = []
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
@ -181,7 +181,7 @@ class Asset(AccountsController):
d.rate_of_depreciation = flt(self.get_depreciation_rate(d, on_validate=True),
d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self, date_of_sale):
def make_depreciation_schedule(self, date_of_disposal):
if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.get('schedules'):
self.schedules = []
@ -227,14 +227,14 @@ class Asset(AccountsController):
monthly_schedule_date = add_months(schedule_date, - d.frequency_of_depreciation + 1)
# if asset is being sold
if date_of_sale:
if date_of_disposal:
from_date = self.get_from_date(d.finance_book)
depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
from_date, date_of_sale)
from_date, date_of_disposal)
if depreciation_amount > 0:
self.append("schedules", {
"schedule_date": date_of_sale,
"schedule_date": date_of_disposal,
"depreciation_amount": depreciation_amount,
"depreciation_method": d.depreciation_method,
"finance_book": d.finance_book,

View File

@ -375,8 +375,8 @@ class AssetCapitalization(StockController):
else:
if asset.calculate_depreciation:
self.depreciate_asset(asset)
asset.reload()
asset.reload()
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset,
item.asset_value, item.get('finance_book') or self.get('finance_book'))
asset.db_set("disposal_date", self.posting_date)

View File

@ -118,11 +118,11 @@ class TestAssetCapitalization(unittest.TestCase):
depreciation_before_disposal_amount = 15_000
accumulated_depreciation = 45_000
# to accomodate for depreciation on disposal calculation bugs TODO remove this when bug is fixed
consumed_asset_value_before_disposal = 60_082.19
target_incoming_rate = 6008.219
depreciation_before_disposal_amount = 9917.81
accumulated_depreciation = 39_917.81
# to accomodate for depreciation on disposal calculation minor difference
consumed_asset_value_before_disposal = 55_123.29
target_incoming_rate = 5512.329
depreciation_before_disposal_amount = 14_876.71
accumulated_depreciation = 44_876.71
# Create assets
consumed_asset = create_depreciation_asset(

View File

@ -38,7 +38,7 @@ from erpnext.accounts.party import (
validate_party_frozen_disabled,
)
from erpnext.accounts.utils import get_account_currency, get_fiscal_years, validate_fiscal_year
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries
from erpnext.assets.doctype.asset.depreciation import make_depreciation_entry
from erpnext.buying.utils import update_last_purchase_rate
from erpnext.controllers.print_settings import (
set_print_templates_for_item_table,
@ -1516,17 +1516,16 @@ class AccountsController(TransactionBase):
def depreciate_asset(self, asset):
asset.flags.ignore_validate_update_after_submit = True
asset.prepare_depreciation_data(self.posting_date)
asset.prepare_depreciation_data(date_of_disposal=self.posting_date)
asset.save()
post_depreciation_entries(self.posting_date, commit=False)
make_depreciation_entry(asset.name, self.posting_date)
def reset_depreciation_schedule(self, asset):
asset.flags.ignore_validate_update_after_submit = True
# recreate original depreciation schedule of the asset
self.delete_depreciation_entry_made_after_disposal(asset)
asset.prepare_depreciation_data()
asset.prepare_depreciation_data(date_of_return=self.posting_date)
self.modify_depreciation_schedule_for_asset_repairs(asset)
asset.save()
@ -1544,10 +1543,10 @@ class AccountsController(TransactionBase):
asset_repair.modify_depreciation_schedule()
asset.prepare_depreciation_data()
def delete_depreciation_entry_made_after_disposal(self, asset):
def reverse_depreciation_entry_made_after_disposal(self, asset):
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
posting_date_of_original_invoice = self.get_posting_date_of_disposal_entry()
posting_date_of_original_disposal = self.get_posting_date_of_disposal_entry()
row = -1
finance_book = asset.get('schedules')[0].get('finance_book')
@ -1558,19 +1557,19 @@ class AccountsController(TransactionBase):
else:
row += 1
if schedule.schedule_date == posting_date_of_original_invoice:
if not self.disposal_was_made_on_original_schedule_date(asset, schedule, row,
posting_date_of_original_invoice) or getdate(schedule.schedule_date) > getdate(today()):
if schedule.schedule_date == posting_date_of_original_disposal:
if not self.disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_disposal) \
or self.disposal_happens_in_the_future(posting_date_of_original_disposal):
reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
reverse_journal_entry.posting_date = nowdate()
for d in reverse_journal_entry.accounts:
d.reference_type = "Asset"
d.reference_name = asset.name
frappe.flags.is_reverse_depr_entry = True
reverse_journal_entry.submit()
schedule.db_set('journal_entry', None)
frappe.flags.is_reverse_depr_entry = False
asset.flags.ignore_validate_update_after_submit = True
schedule.journal_entry = None
asset.save()
def get_posting_date_of_disposal_entry(self):
if self.doctype == "Sales Invoice" and self.return_against:
@ -1579,16 +1578,22 @@ class AccountsController(TransactionBase):
return self.posting_date
# if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone
def disposal_was_made_on_original_schedule_date(self, asset, schedule, row, posting_date_of_original_disposal):
def disposal_was_made_on_original_schedule_date(self, asset, schedule, row, posting_date_of_disposal):
for finance_book in asset.get('finance_books'):
if schedule.finance_book == finance_book.finance_book:
orginal_schedule_date = add_months(finance_book.depreciation_start_date,
row * cint(finance_book.frequency_of_depreciation))
if orginal_schedule_date == posting_date_of_original_disposal:
if orginal_schedule_date == posting_date_of_disposal:
return True
return False
def disposal_happens_in_the_future(self, posting_date_of_disposal):
if posting_date_of_disposal > getdate():
return True
return False
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)