fix(Asset Capitalization): update code for changes in depreciation logic
This commit is contained in:
parent
2d9da22721
commit
dc3c27fd1b
@ -27,7 +27,6 @@ from erpnext.assets.doctype.asset.depreciation import (
|
|||||||
get_disposal_account_and_cost_center,
|
get_disposal_account_and_cost_center,
|
||||||
get_gl_entries_on_asset_disposal,
|
get_gl_entries_on_asset_disposal,
|
||||||
get_gl_entries_on_asset_regain,
|
get_gl_entries_on_asset_regain,
|
||||||
make_depreciation_entry,
|
|
||||||
)
|
)
|
||||||
from erpnext.controllers.selling_controller import SellingController
|
from erpnext.controllers.selling_controller import SellingController
|
||||||
from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
|
from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
|
||||||
@ -924,7 +923,7 @@ class SalesInvoice(SellingController):
|
|||||||
asset.db_set("disposal_date", None)
|
asset.db_set("disposal_date", None)
|
||||||
|
|
||||||
if asset.calculate_depreciation:
|
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)
|
self.reset_depreciation_schedule(asset)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -980,89 +979,6 @@ class SalesInvoice(SellingController):
|
|||||||
self.check_finance_books(item, asset)
|
self.check_finance_books(item, asset)
|
||||||
return 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
|
@property
|
||||||
def enable_discount_accounting(self):
|
def enable_discount_accounting(self):
|
||||||
if not hasattr(self, "_enable_discount_accounting"):
|
if not hasattr(self, "_enable_discount_accounting"):
|
||||||
|
@ -75,12 +75,12 @@ class Asset(AccountsController):
|
|||||||
if self.is_existing_asset and self.purchase_invoice:
|
if self.is_existing_asset and self.purchase_invoice:
|
||||||
frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
|
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:
|
if self.calculate_depreciation:
|
||||||
self.value_after_depreciation = 0
|
self.value_after_depreciation = 0
|
||||||
self.set_depreciation_rate()
|
self.set_depreciation_rate()
|
||||||
self.make_depreciation_schedule(date_of_sale)
|
self.make_depreciation_schedule(date_of_disposal)
|
||||||
self.set_accumulated_depreciation(date_of_sale, date_of_return)
|
self.set_accumulated_depreciation(date_of_disposal, date_of_return)
|
||||||
else:
|
else:
|
||||||
self.finance_books = []
|
self.finance_books = []
|
||||||
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
|
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.rate_of_depreciation = flt(self.get_depreciation_rate(d, on_validate=True),
|
||||||
d.precision("rate_of_depreciation"))
|
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'):
|
if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.get('schedules'):
|
||||||
self.schedules = []
|
self.schedules = []
|
||||||
|
|
||||||
@ -227,14 +227,14 @@ class Asset(AccountsController):
|
|||||||
monthly_schedule_date = add_months(schedule_date, - d.frequency_of_depreciation + 1)
|
monthly_schedule_date = add_months(schedule_date, - d.frequency_of_depreciation + 1)
|
||||||
|
|
||||||
# if asset is being sold
|
# if asset is being sold
|
||||||
if date_of_sale:
|
if date_of_disposal:
|
||||||
from_date = self.get_from_date(d.finance_book)
|
from_date = self.get_from_date(d.finance_book)
|
||||||
depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
|
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:
|
if depreciation_amount > 0:
|
||||||
self.append("schedules", {
|
self.append("schedules", {
|
||||||
"schedule_date": date_of_sale,
|
"schedule_date": date_of_disposal,
|
||||||
"depreciation_amount": depreciation_amount,
|
"depreciation_amount": depreciation_amount,
|
||||||
"depreciation_method": d.depreciation_method,
|
"depreciation_method": d.depreciation_method,
|
||||||
"finance_book": d.finance_book,
|
"finance_book": d.finance_book,
|
||||||
|
@ -375,8 +375,8 @@ class AssetCapitalization(StockController):
|
|||||||
else:
|
else:
|
||||||
if asset.calculate_depreciation:
|
if asset.calculate_depreciation:
|
||||||
self.depreciate_asset(asset)
|
self.depreciate_asset(asset)
|
||||||
|
asset.reload()
|
||||||
|
|
||||||
asset.reload()
|
|
||||||
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset,
|
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset,
|
||||||
item.asset_value, item.get('finance_book') or self.get('finance_book'))
|
item.asset_value, item.get('finance_book') or self.get('finance_book'))
|
||||||
asset.db_set("disposal_date", self.posting_date)
|
asset.db_set("disposal_date", self.posting_date)
|
||||||
|
@ -118,11 +118,11 @@ class TestAssetCapitalization(unittest.TestCase):
|
|||||||
depreciation_before_disposal_amount = 15_000
|
depreciation_before_disposal_amount = 15_000
|
||||||
accumulated_depreciation = 45_000
|
accumulated_depreciation = 45_000
|
||||||
|
|
||||||
# to accomodate for depreciation on disposal calculation bugs TODO remove this when bug is fixed
|
# to accomodate for depreciation on disposal calculation minor difference
|
||||||
consumed_asset_value_before_disposal = 60_082.19
|
consumed_asset_value_before_disposal = 55_123.29
|
||||||
target_incoming_rate = 6008.219
|
target_incoming_rate = 5512.329
|
||||||
depreciation_before_disposal_amount = 9917.81
|
depreciation_before_disposal_amount = 14_876.71
|
||||||
accumulated_depreciation = 39_917.81
|
accumulated_depreciation = 44_876.71
|
||||||
|
|
||||||
# Create assets
|
# Create assets
|
||||||
consumed_asset = create_depreciation_asset(
|
consumed_asset = create_depreciation_asset(
|
||||||
|
@ -38,7 +38,7 @@ from erpnext.accounts.party import (
|
|||||||
validate_party_frozen_disabled,
|
validate_party_frozen_disabled,
|
||||||
)
|
)
|
||||||
from erpnext.accounts.utils import get_account_currency, get_fiscal_years, validate_fiscal_year
|
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.buying.utils import update_last_purchase_rate
|
||||||
from erpnext.controllers.print_settings import (
|
from erpnext.controllers.print_settings import (
|
||||||
set_print_templates_for_item_table,
|
set_print_templates_for_item_table,
|
||||||
@ -1516,17 +1516,16 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
def depreciate_asset(self, asset):
|
def depreciate_asset(self, asset):
|
||||||
asset.flags.ignore_validate_update_after_submit = True
|
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()
|
asset.save()
|
||||||
|
|
||||||
post_depreciation_entries(self.posting_date, commit=False)
|
make_depreciation_entry(asset.name, self.posting_date)
|
||||||
|
|
||||||
def reset_depreciation_schedule(self, asset):
|
def reset_depreciation_schedule(self, asset):
|
||||||
asset.flags.ignore_validate_update_after_submit = True
|
asset.flags.ignore_validate_update_after_submit = True
|
||||||
|
|
||||||
# recreate original depreciation schedule of the asset
|
# recreate original depreciation schedule of the asset
|
||||||
self.delete_depreciation_entry_made_after_disposal(asset)
|
asset.prepare_depreciation_data(date_of_return=self.posting_date)
|
||||||
asset.prepare_depreciation_data()
|
|
||||||
|
|
||||||
self.modify_depreciation_schedule_for_asset_repairs(asset)
|
self.modify_depreciation_schedule_for_asset_repairs(asset)
|
||||||
asset.save()
|
asset.save()
|
||||||
@ -1544,10 +1543,10 @@ class AccountsController(TransactionBase):
|
|||||||
asset_repair.modify_depreciation_schedule()
|
asset_repair.modify_depreciation_schedule()
|
||||||
asset.prepare_depreciation_data()
|
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
|
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
|
row = -1
|
||||||
finance_book = asset.get('schedules')[0].get('finance_book')
|
finance_book = asset.get('schedules')[0].get('finance_book')
|
||||||
@ -1558,19 +1557,19 @@ class AccountsController(TransactionBase):
|
|||||||
else:
|
else:
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
if schedule.schedule_date == posting_date_of_original_invoice:
|
if schedule.schedule_date == posting_date_of_original_disposal:
|
||||||
if not self.disposal_was_made_on_original_schedule_date(asset, schedule, row,
|
if not self.disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_disposal) \
|
||||||
posting_date_of_original_invoice) or getdate(schedule.schedule_date) > getdate(today()):
|
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 = make_reverse_journal_entry(schedule.journal_entry)
|
||||||
reverse_journal_entry.posting_date = nowdate()
|
reverse_journal_entry.posting_date = nowdate()
|
||||||
|
frappe.flags.is_reverse_depr_entry = True
|
||||||
for d in reverse_journal_entry.accounts:
|
|
||||||
d.reference_type = "Asset"
|
|
||||||
d.reference_name = asset.name
|
|
||||||
|
|
||||||
reverse_journal_entry.submit()
|
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):
|
def get_posting_date_of_disposal_entry(self):
|
||||||
if self.doctype == "Sales Invoice" and self.return_against:
|
if self.doctype == "Sales Invoice" and self.return_against:
|
||||||
@ -1579,16 +1578,22 @@ class AccountsController(TransactionBase):
|
|||||||
return self.posting_date
|
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
|
# 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'):
|
for finance_book in asset.get('finance_books'):
|
||||||
if schedule.finance_book == finance_book.finance_book:
|
if schedule.finance_book == finance_book.finance_book:
|
||||||
orginal_schedule_date = add_months(finance_book.depreciation_start_date,
|
orginal_schedule_date = add_months(finance_book.depreciation_start_date,
|
||||||
row * cint(finance_book.frequency_of_depreciation))
|
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 True
|
||||||
return False
|
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()
|
@frappe.whitelist()
|
||||||
def get_tax_rate(account_head):
|
def get_tax_rate(account_head):
|
||||||
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
|
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
|
||||||
|
Loading…
Reference in New Issue
Block a user