mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-29 19:48:27 +00:00
fix: Removed conflict
This commit is contained in:
@@ -34,7 +34,6 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_sched
|
||||
get_asset_depr_schedule_doc,
|
||||
get_depr_schedule,
|
||||
make_draft_asset_depr_schedules,
|
||||
make_draft_asset_depr_schedules_if_not_present,
|
||||
update_draft_asset_depr_schedules,
|
||||
)
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
@@ -131,30 +130,55 @@ class Asset(AccountsController):
|
||||
self.set_missing_values()
|
||||
self.validate_gross_and_purchase_amount()
|
||||
self.validate_finance_books()
|
||||
|
||||
if not self.split_from:
|
||||
self.prepare_depreciation_data()
|
||||
|
||||
if self.calculate_depreciation:
|
||||
update_draft_asset_depr_schedules(self)
|
||||
|
||||
if frappe.db.exists("Asset", self.name):
|
||||
asset_depr_schedules_names = make_draft_asset_depr_schedules_if_not_present(self)
|
||||
|
||||
if asset_depr_schedules_names:
|
||||
asset_depr_schedules_links = get_comma_separated_links(
|
||||
asset_depr_schedules_names, "Asset Depreciation Schedule"
|
||||
)
|
||||
frappe.msgprint(
|
||||
_(
|
||||
"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
|
||||
).format(asset_depr_schedules_links)
|
||||
)
|
||||
self.validate_expected_value_after_useful_life()
|
||||
self.set_total_booked_depreciations()
|
||||
self.total_asset_cost = self.gross_purchase_amount
|
||||
self.status = self.get_status()
|
||||
|
||||
def create_asset_depreciation_schedule(self):
|
||||
if self.split_from or not self.calculate_depreciation:
|
||||
return
|
||||
|
||||
self.set_depr_rate_and_value_after_depreciation()
|
||||
|
||||
schedules = []
|
||||
for row in self.get("finance_books"):
|
||||
self.validate_asset_finance_books(row)
|
||||
if not row.rate_of_depreciation:
|
||||
row.rate_of_depreciation = self.get_depreciation_rate(row, on_validate=True)
|
||||
|
||||
schedule_doc = get_asset_depr_schedule_doc(self.name, "Draft", row.finance_book)
|
||||
if not schedule_doc:
|
||||
schedule_doc = frappe.new_doc("Asset Depreciation Schedule")
|
||||
|
||||
schedule_doc.prepare_draft_asset_depr_schedule_data(self, row)
|
||||
schedule_doc.save()
|
||||
schedules.append(schedule_doc.name)
|
||||
|
||||
self.show_schedule_creation_message(schedules)
|
||||
|
||||
def set_depr_rate_and_value_after_depreciation(self):
|
||||
if self.calculate_depreciation:
|
||||
self.value_after_depreciation = 0
|
||||
self.set_depreciation_rate()
|
||||
else:
|
||||
self.finance_books = []
|
||||
self.value_after_depreciation = flt(self.gross_purchase_amount) - flt(
|
||||
self.opening_accumulated_depreciation
|
||||
)
|
||||
|
||||
def show_schedule_creation_message(self, schedules):
|
||||
if schedules:
|
||||
asset_depr_schedules_links = get_comma_separated_links(schedules, "Asset Depreciation Schedule")
|
||||
frappe.msgprint(
|
||||
_(
|
||||
"Asset Depreciation Schedules created/updated:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
|
||||
).format(asset_depr_schedules_links)
|
||||
)
|
||||
|
||||
def on_update(self):
|
||||
self.create_asset_depreciation_schedule()
|
||||
|
||||
def on_submit(self):
|
||||
self.validate_in_use_date()
|
||||
self.make_asset_movement()
|
||||
@@ -178,17 +202,17 @@ class Asset(AccountsController):
|
||||
self.db_set("booked_fixed_asset", 0)
|
||||
add_asset_activity(self.name, _("Asset cancelled"))
|
||||
|
||||
def after_insert(self):
|
||||
if self.calculate_depreciation and not self.split_from:
|
||||
asset_depr_schedules_names = make_draft_asset_depr_schedules(self)
|
||||
asset_depr_schedules_links = get_comma_separated_links(
|
||||
asset_depr_schedules_names, "Asset Depreciation Schedule"
|
||||
)
|
||||
frappe.msgprint(
|
||||
_(
|
||||
"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
|
||||
).format(asset_depr_schedules_links)
|
||||
)
|
||||
# def after_insert(self):
|
||||
# if self.calculate_depreciation and not self.split_from:
|
||||
# asset_depr_schedules_names = make_draft_asset_depr_schedules(self)
|
||||
# asset_depr_schedules_links = get_comma_separated_links(
|
||||
# asset_depr_schedules_names, "Asset Depreciation Schedule"
|
||||
# )
|
||||
# frappe.msgprint(
|
||||
# _(
|
||||
# "Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
|
||||
# ).format(asset_depr_schedules_links)
|
||||
# )
|
||||
if (
|
||||
not frappe.db.exists(
|
||||
{
|
||||
@@ -250,16 +274,6 @@ 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):
|
||||
if self.calculate_depreciation:
|
||||
self.value_after_depreciation = 0
|
||||
self.set_depreciation_rate()
|
||||
else:
|
||||
self.finance_books = []
|
||||
self.value_after_depreciation = flt(self.gross_purchase_amount) - flt(
|
||||
self.opening_accumulated_depreciation
|
||||
)
|
||||
|
||||
def validate_item(self):
|
||||
item = frappe.get_cached_value(
|
||||
"Item", self.item_code, ["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1
|
||||
@@ -344,6 +358,22 @@ class Asset(AccountsController):
|
||||
title=_("Missing Finance Book"),
|
||||
)
|
||||
|
||||
# def set_depreciation_start_date(self):
|
||||
# if not self.calculate_depreciation:
|
||||
# return
|
||||
|
||||
# for d in self.get("finance_books"):
|
||||
# if not d.depreciation_start_date:
|
||||
# if self.is_existing_asset and self.opening_number_of_booked_depreciations:
|
||||
|
||||
# months = d.frequency_of_depreciation * self.opening_number_of_booked_depreciations
|
||||
# else:
|
||||
# months = d.frequency_of_depreciation
|
||||
|
||||
# d.depreciation_start_date = get_last_day(
|
||||
# add_months(self.available_for_use_date, months)
|
||||
# )
|
||||
|
||||
def validate_precision(self):
|
||||
if self.gross_purchase_amount:
|
||||
self.gross_purchase_amount = flt(
|
||||
@@ -456,61 +486,65 @@ class Asset(AccountsController):
|
||||
frappe.throw(
|
||||
_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount").format(
|
||||
row.idx
|
||||
),
|
||||
title=_("Invalid Schedule"),
|
||||
)
|
||||
)
|
||||
|
||||
if not row.depreciation_start_date:
|
||||
if not self.available_for_use_date:
|
||||
frappe.throw(
|
||||
_("Row {0}: Depreciation Start Date is required").format(row.idx),
|
||||
title=_("Invalid Schedule"),
|
||||
)
|
||||
row.depreciation_start_date = get_last_day(self.available_for_use_date)
|
||||
self.validate_depreciation_start_date(row)
|
||||
|
||||
if not self.is_existing_asset:
|
||||
self.opening_accumulated_depreciation = 0
|
||||
self.opening_number_of_booked_depreciations = 0
|
||||
else:
|
||||
depreciable_amount = flt(
|
||||
flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life),
|
||||
self.precision("gross_purchase_amount"),
|
||||
)
|
||||
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
|
||||
frappe.throw(
|
||||
_("Opening Accumulated Depreciation must be less than or equal to {0}").format(
|
||||
depreciable_amount
|
||||
)
|
||||
)
|
||||
self.validate_opening_depreciation_values(row)
|
||||
|
||||
if self.opening_accumulated_depreciation:
|
||||
if not self.opening_number_of_booked_depreciations:
|
||||
frappe.throw(_("Please set Opening Number of Booked Depreciations"))
|
||||
else:
|
||||
self.opening_number_of_booked_depreciations = 0
|
||||
|
||||
if flt(row.total_number_of_depreciations) <= cint(self.opening_number_of_booked_depreciations):
|
||||
frappe.throw(
|
||||
_(
|
||||
"Row {0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations"
|
||||
).format(row.idx),
|
||||
title=_("Invalid Schedule"),
|
||||
)
|
||||
|
||||
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
|
||||
def validate_opening_depreciation_values(self, row):
|
||||
row.expected_value_after_useful_life = flt(
|
||||
row.expected_value_after_useful_life, self.precision("gross_purchase_amount")
|
||||
)
|
||||
depreciable_amount = flt(
|
||||
flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life),
|
||||
self.precision("gross_purchase_amount"),
|
||||
)
|
||||
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
|
||||
frappe.throw(
|
||||
_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date").format(
|
||||
row.idx
|
||||
_("Row #{0}: Opening Accumulated Depreciation must be less than or equal to {1}").format(
|
||||
row.idx, depreciable_amount
|
||||
)
|
||||
)
|
||||
|
||||
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(
|
||||
self.available_for_use_date
|
||||
):
|
||||
if self.opening_accumulated_depreciation:
|
||||
if not self.opening_number_of_booked_depreciations:
|
||||
frappe.throw(_("Please set opening number of booked depreciations"))
|
||||
else:
|
||||
self.opening_number_of_booked_depreciations = 0
|
||||
|
||||
if flt(row.total_number_of_depreciations) <= cint(self.opening_number_of_booked_depreciations):
|
||||
frappe.throw(
|
||||
_(
|
||||
"Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date"
|
||||
).format(row.idx)
|
||||
"Row #{0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations"
|
||||
).format(row.idx),
|
||||
title=_("Invalid Schedule"),
|
||||
)
|
||||
|
||||
def validate_depreciation_start_date(self, row):
|
||||
if row.depreciation_start_date:
|
||||
if getdate(row.depreciation_start_date) < getdate(self.purchase_date):
|
||||
frappe.throw(
|
||||
_("Row #{0}: Next Depreciation Date cannot be before Purchase Date").format(row.idx)
|
||||
)
|
||||
|
||||
if getdate(row.depreciation_start_date) < getdate(self.available_for_use_date):
|
||||
frappe.throw(
|
||||
_("Row #{0}: Next Depreciation Date cannot be before Available-for-use Date").format(
|
||||
row.idx
|
||||
)
|
||||
)
|
||||
else:
|
||||
frappe.throw(
|
||||
_("Row #{0}: Depreciation Start Date is required").format(row.idx),
|
||||
title=_("Invalid Schedule"),
|
||||
)
|
||||
|
||||
def set_total_booked_depreciations(self):
|
||||
@@ -530,15 +564,11 @@ class Asset(AccountsController):
|
||||
if not depr_schedule:
|
||||
continue
|
||||
|
||||
accumulated_depreciation_after_full_schedule = [
|
||||
d.accumulated_depreciation_amount for d in depr_schedule
|
||||
]
|
||||
accumulated_depreciation_after_full_schedule = max(
|
||||
[d.accumulated_depreciation_amount for d in depr_schedule]
|
||||
)
|
||||
|
||||
if accumulated_depreciation_after_full_schedule:
|
||||
accumulated_depreciation_after_full_schedule = max(
|
||||
accumulated_depreciation_after_full_schedule
|
||||
)
|
||||
|
||||
asset_value_after_full_schedule = flt(
|
||||
flt(self.gross_purchase_amount) - flt(accumulated_depreciation_after_full_schedule),
|
||||
self.precision("gross_purchase_amount"),
|
||||
@@ -820,53 +850,62 @@ class Asset(AccountsController):
|
||||
if isinstance(args, str):
|
||||
args = json.loads(args)
|
||||
|
||||
float_precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||
rate_field_precision = frappe.get_precision(args.doctype, "rate_of_depreciation") or 2
|
||||
|
||||
if args.get("depreciation_method") == "Double Declining Balance":
|
||||
return 200.0 / (
|
||||
return self.get_double_declining_balance_rate(args, rate_field_precision)
|
||||
elif args.get("depreciation_method") == "Written Down Value":
|
||||
return self.get_written_down_value_rate(args, rate_field_precision, on_validate)
|
||||
|
||||
def get_double_declining_balance_rate(self, args, rate_field_precision):
|
||||
return flt(
|
||||
200.0
|
||||
/ (
|
||||
(
|
||||
flt(args.get("total_number_of_depreciations"), 2)
|
||||
* flt(args.get("frequency_of_depreciation"))
|
||||
)
|
||||
/ 12
|
||||
),
|
||||
rate_field_precision,
|
||||
)
|
||||
|
||||
def get_written_down_value_rate(self, args, rate_field_precision, on_validate):
|
||||
if (
|
||||
args.get("rate_of_depreciation")
|
||||
and on_validate
|
||||
and not self.flags.increase_in_asset_value_due_to_repair
|
||||
):
|
||||
return args.get("rate_of_depreciation")
|
||||
|
||||
if args.get("rate_of_depreciation") and not flt(args.get("expected_value_after_useful_life")):
|
||||
return args.get("rate_of_depreciation")
|
||||
|
||||
if self.flags.increase_in_asset_value_due_to_repair:
|
||||
value = flt(args.get("expected_value_after_useful_life")) / flt(
|
||||
args.get("value_after_depreciation")
|
||||
)
|
||||
else:
|
||||
value = flt(args.get("expected_value_after_useful_life")) / (
|
||||
flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation)
|
||||
)
|
||||
|
||||
if args.get("depreciation_method") == "Written Down Value":
|
||||
if (
|
||||
args.get("rate_of_depreciation")
|
||||
and on_validate
|
||||
and not self.flags.increase_in_asset_value_due_to_repair
|
||||
):
|
||||
return args.get("rate_of_depreciation")
|
||||
|
||||
if args.get("rate_of_depreciation") and not flt(args.get("expected_value_after_useful_life")):
|
||||
return args.get("rate_of_depreciation")
|
||||
|
||||
if self.flags.increase_in_asset_value_due_to_repair:
|
||||
value = flt(args.get("expected_value_after_useful_life")) / flt(
|
||||
args.get("value_after_depreciation")
|
||||
)
|
||||
else:
|
||||
value = flt(args.get("expected_value_after_useful_life")) / (
|
||||
flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation)
|
||||
)
|
||||
|
||||
depreciation_rate = math.pow(
|
||||
value,
|
||||
1.0
|
||||
/ (
|
||||
depreciation_rate = math.pow(
|
||||
value,
|
||||
1.0
|
||||
/ (
|
||||
(
|
||||
(
|
||||
(
|
||||
flt(args.get("total_number_of_depreciations"), 2)
|
||||
- flt(self.opening_number_of_booked_depreciations)
|
||||
)
|
||||
* flt(args.get("frequency_of_depreciation"))
|
||||
flt(args.get("total_number_of_depreciations"), 2)
|
||||
- flt(self.opening_number_of_booked_depreciations)
|
||||
)
|
||||
/ 12
|
||||
),
|
||||
)
|
||||
* flt(args.get("frequency_of_depreciation"))
|
||||
)
|
||||
/ 12
|
||||
),
|
||||
)
|
||||
|
||||
return flt((100 * (1 - depreciation_rate)), float_precision)
|
||||
return flt((100 * (1 - depreciation_rate)), rate_field_precision)
|
||||
|
||||
|
||||
def has_gl_entries(doctype, docname, target_account):
|
||||
|
||||
@@ -34,6 +34,8 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_sched
|
||||
_get_pro_rata_amt,
|
||||
get_asset_depr_schedule_doc,
|
||||
get_depr_schedule,
|
||||
)
|
||||
from erpnext.assets.doctype.asset_depreciation_schedule.utils import (
|
||||
get_depreciation_amount,
|
||||
)
|
||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"column_break_8",
|
||||
"frequency_of_depreciation",
|
||||
"expected_value_after_useful_life",
|
||||
"value_after_depreciation",
|
||||
"depreciation_schedule_section",
|
||||
"depreciation_schedule",
|
||||
"details_section",
|
||||
@@ -38,6 +39,7 @@
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Asset",
|
||||
"link_filters": "[[\"Asset\",\"docstatus\",\"<\",\"2\"],[\"Asset\",\"company\",\"=\",\"eval:doc.company\"]]",
|
||||
"options": "Asset",
|
||||
"reqd": 1
|
||||
},
|
||||
@@ -202,12 +204,18 @@
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "value_after_depreciation",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Value After Depreciation",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:06:34.135004",
|
||||
"modified": "2024-12-02 17:54:20.635668",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Depreciation Schedule",
|
||||
|
||||
@@ -21,6 +21,9 @@ from frappe.utils import (
|
||||
|
||||
import erpnext
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.assets.doctype.asset_depreciation_schedule.utils import (
|
||||
get_depreciation_amount,
|
||||
)
|
||||
|
||||
|
||||
class AssetDepreciationSchedule(Document):
|
||||
@@ -32,9 +35,7 @@ class AssetDepreciationSchedule(Document):
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
from erpnext.assets.doctype.depreciation_schedule.depreciation_schedule import (
|
||||
DepreciationSchedule,
|
||||
)
|
||||
from erpnext.assets.doctype.depreciation_schedule.depreciation_schedule import DepreciationSchedule
|
||||
|
||||
amended_from: DF.Link | None
|
||||
asset: DF.Link
|
||||
@@ -51,12 +52,13 @@ class AssetDepreciationSchedule(Document):
|
||||
gross_purchase_amount: DF.Currency
|
||||
naming_series: DF.Literal["ACC-ADS-.YYYY.-"]
|
||||
notes: DF.SmallText | None
|
||||
opening_number_of_booked_depreciations: DF.Int
|
||||
opening_accumulated_depreciation: DF.Currency
|
||||
opening_number_of_booked_depreciations: DF.Int
|
||||
rate_of_depreciation: DF.Percent
|
||||
shift_based: DF.Check
|
||||
status: DF.Literal["Draft", "Active", "Cancelled"]
|
||||
total_number_of_depreciations: DF.Int
|
||||
value_after_depreciation: DF.Currency
|
||||
# end: auto-generated types
|
||||
|
||||
def before_save(self):
|
||||
@@ -145,50 +147,9 @@ class AssetDepreciationSchedule(Document):
|
||||
date_of_return=None,
|
||||
update_asset_finance_book_row=True,
|
||||
):
|
||||
have_asset_details_been_modified = self.have_asset_details_been_modified(asset_doc)
|
||||
not_manual_depr_or_have_manual_depr_details_been_modified = (
|
||||
self.not_manual_depr_or_have_manual_depr_details_been_modified(row)
|
||||
)
|
||||
|
||||
self.set_draft_asset_depr_schedule_details(asset_doc, row)
|
||||
|
||||
if self.should_prepare_depreciation_schedule(
|
||||
have_asset_details_been_modified, not_manual_depr_or_have_manual_depr_details_been_modified
|
||||
):
|
||||
self.make_depr_schedule(asset_doc, row, date_of_disposal, update_asset_finance_book_row)
|
||||
self.set_accumulated_depreciation(asset_doc, row, date_of_disposal, date_of_return)
|
||||
|
||||
def have_asset_details_been_modified(self, asset_doc):
|
||||
return (
|
||||
asset_doc.gross_purchase_amount != self.gross_purchase_amount
|
||||
or asset_doc.opening_accumulated_depreciation != self.opening_accumulated_depreciation
|
||||
or asset_doc.opening_number_of_booked_depreciations != self.opening_number_of_booked_depreciations
|
||||
)
|
||||
|
||||
def not_manual_depr_or_have_manual_depr_details_been_modified(self, row):
|
||||
return (
|
||||
self.depreciation_method != "Manual"
|
||||
or row.total_number_of_depreciations != self.total_number_of_depreciations
|
||||
or row.frequency_of_depreciation != self.frequency_of_depreciation
|
||||
or getdate(row.depreciation_start_date) != self.get("depreciation_schedule")[0].schedule_date
|
||||
or row.expected_value_after_useful_life != self.expected_value_after_useful_life
|
||||
)
|
||||
|
||||
def should_prepare_depreciation_schedule(
|
||||
self, have_asset_details_been_modified, not_manual_depr_or_have_manual_depr_details_been_modified
|
||||
):
|
||||
if not self.get("depreciation_schedule"):
|
||||
return True
|
||||
|
||||
old_asset_depr_schedule_doc = self.get_doc_before_save()
|
||||
|
||||
if self.docstatus != 0 and not old_asset_depr_schedule_doc:
|
||||
return True
|
||||
|
||||
if have_asset_details_been_modified or not_manual_depr_or_have_manual_depr_details_been_modified:
|
||||
return True
|
||||
|
||||
return False
|
||||
self.make_depr_schedule(asset_doc, row, date_of_disposal, update_asset_finance_book_row)
|
||||
self.set_accumulated_depreciation(asset_doc, row, date_of_disposal, date_of_return)
|
||||
|
||||
def set_draft_asset_depr_schedule_details(self, asset_doc, row):
|
||||
self.asset = asset_doc.name
|
||||
@@ -214,11 +175,11 @@ class AssetDepreciationSchedule(Document):
|
||||
update_asset_finance_book_row=True,
|
||||
value_after_depreciation=None,
|
||||
):
|
||||
if not self.get("depreciation_schedule"):
|
||||
self.depreciation_schedule = []
|
||||
# if not self.get("depreciation_schedule"):
|
||||
# self.depreciation_schedule = []
|
||||
|
||||
if not asset_doc.available_for_use_date:
|
||||
return
|
||||
# if not asset_doc.available_for_use_date:
|
||||
# return
|
||||
|
||||
start = self.clear_depr_schedule()
|
||||
|
||||
@@ -227,6 +188,9 @@ class AssetDepreciationSchedule(Document):
|
||||
)
|
||||
|
||||
def clear_depr_schedule(self):
|
||||
"""
|
||||
Clears the depreciation schedule preserving the depreciation entries that have been booked.
|
||||
"""
|
||||
start = 0
|
||||
num_of_depreciations_completed = 0
|
||||
depr_schedule = []
|
||||
@@ -254,7 +218,7 @@ class AssetDepreciationSchedule(Document):
|
||||
update_asset_finance_book_row,
|
||||
value_after_depreciation,
|
||||
):
|
||||
asset_doc.validate_asset_finance_books(row)
|
||||
# asset_doc.validate_asset_finance_books(row)
|
||||
|
||||
if not value_after_depreciation:
|
||||
value_after_depreciation = _get_value_after_depreciation_for_making_schedule(asset_doc, row)
|
||||
@@ -263,13 +227,7 @@ class AssetDepreciationSchedule(Document):
|
||||
if update_asset_finance_book_row:
|
||||
row.db_update()
|
||||
|
||||
final_number_of_depreciations = cint(row.total_number_of_depreciations) - cint(
|
||||
self.opening_number_of_booked_depreciations
|
||||
)
|
||||
|
||||
has_pro_rata = _check_is_pro_rata(asset_doc, row)
|
||||
if has_pro_rata:
|
||||
final_number_of_depreciations += 1
|
||||
final_number_of_depreciations, has_pro_rata = self.get_final_number_of_depreciations(asset_doc, row)
|
||||
|
||||
has_wdv_or_dd_non_yearly_pro_rata = False
|
||||
if (
|
||||
@@ -285,7 +243,7 @@ class AssetDepreciationSchedule(Document):
|
||||
|
||||
number_of_pending_depreciations = final_number_of_depreciations - start
|
||||
yearly_opening_wdv = value_after_depreciation
|
||||
current_fiscal_year_end_date = None
|
||||
self.current_fiscal_year_end_date = None
|
||||
prev_per_day_depr = True
|
||||
for n in range(start, final_number_of_depreciations):
|
||||
# If depreciation is already completed (for double declining balance)
|
||||
@@ -295,16 +253,12 @@ class AssetDepreciationSchedule(Document):
|
||||
schedule_date = get_last_day(
|
||||
add_months(row.depreciation_start_date, n * cint(row.frequency_of_depreciation))
|
||||
)
|
||||
if not current_fiscal_year_end_date:
|
||||
current_fiscal_year_end_date = get_fiscal_year(row.depreciation_start_date)[2]
|
||||
elif getdate(schedule_date) > getdate(current_fiscal_year_end_date):
|
||||
current_fiscal_year_end_date = add_years(current_fiscal_year_end_date, 1)
|
||||
|
||||
if self.has_fiscal_year_changed(row, n):
|
||||
yearly_opening_wdv = value_after_depreciation
|
||||
|
||||
if n > 0 and len(self.get("depreciation_schedule")) > n - 1:
|
||||
prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount
|
||||
else:
|
||||
prev_depreciation_amount = 0
|
||||
prev_depreciation_amount = self.get_prev_depreciation_amount(n)
|
||||
|
||||
depreciation_amount, prev_per_day_depr = get_depreciation_amount(
|
||||
self,
|
||||
asset_doc,
|
||||
@@ -317,146 +271,120 @@ class AssetDepreciationSchedule(Document):
|
||||
number_of_pending_depreciations,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
if not has_pro_rata or (
|
||||
n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2
|
||||
):
|
||||
schedule_date = add_months(
|
||||
row.depreciation_start_date, n * cint(row.frequency_of_depreciation)
|
||||
)
|
||||
|
||||
if should_get_last_day:
|
||||
schedule_date = get_last_day(schedule_date)
|
||||
schedule_date = self.get_next_schedule_date(
|
||||
row, n, schedule_date, has_pro_rata, should_get_last_day, final_number_of_depreciations
|
||||
)
|
||||
|
||||
# if asset is being sold or scrapped
|
||||
if date_of_disposal and getdate(schedule_date) >= getdate(date_of_disposal):
|
||||
from_date = add_months(
|
||||
getdate(asset_doc.available_for_use_date),
|
||||
(asset_doc.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
|
||||
self.get_depreciation_amount_for_disposal(
|
||||
asset_doc, row, n, schedule_date, date_of_disposal, depreciation_amount
|
||||
)
|
||||
if is_last_day_of_the_month(getdate(asset_doc.available_for_use_date)):
|
||||
from_date = get_last_day(from_date)
|
||||
if self.depreciation_schedule:
|
||||
from_date = add_days(self.depreciation_schedule[-1].schedule_date, 1)
|
||||
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
from_date,
|
||||
date_of_disposal,
|
||||
original_schedule_date=schedule_date,
|
||||
)
|
||||
depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount"))
|
||||
if depreciation_amount > 0:
|
||||
self.add_depr_schedule_row(date_of_disposal, depreciation_amount, n)
|
||||
|
||||
break
|
||||
|
||||
# For first row
|
||||
if (
|
||||
n == 0
|
||||
and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata)
|
||||
and not self.opening_accumulated_depreciation
|
||||
and not self.flags.wdv_it_act_applied
|
||||
):
|
||||
from_date = asset_doc.available_for_use_date
|
||||
# needed to calc depr amount for available_for_use_date too
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
from_date,
|
||||
row.depreciation_start_date,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
if n == 0:
|
||||
# Get pro rata amount for first row if available for use date is mid of the month
|
||||
depreciation_amount = self.get_depreciation_amount_for_first_row(
|
||||
asset_doc, row, n, depreciation_amount, has_pro_rata, has_wdv_or_dd_non_yearly_pro_rata
|
||||
)
|
||||
if flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")) <= 0:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Gross Purchase Amount Too Low: {0} cannot be depreciated over {1} cycles with a frequency of {2} depreciations."
|
||||
).format(
|
||||
frappe.bold(asset_doc.gross_purchase_amount),
|
||||
frappe.bold(row.total_number_of_depreciations),
|
||||
frappe.bold(row.frequency_of_depreciation),
|
||||
)
|
||||
)
|
||||
elif n == 0 and has_wdv_or_dd_non_yearly_pro_rata and self.opening_accumulated_depreciation:
|
||||
if not is_first_day_of_the_month(getdate(asset_doc.available_for_use_date)):
|
||||
from_date = get_last_day(
|
||||
add_months(
|
||||
getdate(asset_doc.available_for_use_date),
|
||||
(
|
||||
(self.opening_number_of_booked_depreciations - 1)
|
||||
* row.frequency_of_depreciation
|
||||
),
|
||||
)
|
||||
)
|
||||
else:
|
||||
from_date = add_months(
|
||||
getdate(add_days(asset_doc.available_for_use_date, -1)),
|
||||
(self.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
|
||||
)
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
from_date,
|
||||
row.depreciation_start_date,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
elif has_pro_rata and n == cint(final_number_of_depreciations) - 1: # for the last row
|
||||
depreciation_amount, schedule_date = self.get_depreciation_amount_for_last_row(
|
||||
asset_doc, row, n, depreciation_amount, schedule_date, has_wdv_or_dd_non_yearly_pro_rata
|
||||
)
|
||||
|
||||
# For last row
|
||||
elif has_pro_rata and n == cint(final_number_of_depreciations) - 1:
|
||||
if not asset_doc.flags.increase_in_asset_life:
|
||||
# In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission
|
||||
asset_doc.to_date = add_months(
|
||||
asset_doc.available_for_use_date,
|
||||
(n + self.opening_number_of_booked_depreciations)
|
||||
* cint(row.frequency_of_depreciation),
|
||||
)
|
||||
if is_last_day_of_the_month(getdate(asset_doc.available_for_use_date)):
|
||||
asset_doc.to_date = get_last_day(asset_doc.to_date)
|
||||
|
||||
depreciation_amount_without_pro_rata = depreciation_amount
|
||||
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
schedule_date,
|
||||
asset_doc.to_date,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
)
|
||||
|
||||
depreciation_amount = self.get_adjusted_depreciation_amount(
|
||||
depreciation_amount_without_pro_rata, depreciation_amount
|
||||
)
|
||||
|
||||
schedule_date = add_days(schedule_date, days - 1)
|
||||
|
||||
if not depreciation_amount:
|
||||
continue
|
||||
depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount"))
|
||||
break
|
||||
|
||||
|
||||
value_after_depreciation = flt(
|
||||
value_after_depreciation - flt(depreciation_amount),
|
||||
value_after_depreciation - flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")),
|
||||
asset_doc.precision("gross_purchase_amount"),
|
||||
)
|
||||
|
||||
# Adjust depreciation amount in the last period based on the expected value after useful life
|
||||
if (
|
||||
n == cint(final_number_of_depreciations) - 1
|
||||
and flt(value_after_depreciation) != flt(row.expected_value_after_useful_life)
|
||||
) or flt(value_after_depreciation) < flt(row.expected_value_after_useful_life):
|
||||
depreciation_amount += flt(value_after_depreciation) - flt(
|
||||
row.expected_value_after_useful_life
|
||||
)
|
||||
depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount"))
|
||||
skip_row = True
|
||||
depreciation_amount, skip_row = self.adjust_depr_amount_for_salvage_value(
|
||||
row, depreciation_amount, value_after_depreciation, final_number_of_depreciations, n, skip_row
|
||||
)
|
||||
|
||||
if flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")) > 0:
|
||||
self.add_depr_schedule_row(schedule_date, depreciation_amount, n)
|
||||
|
||||
# to ensure that final accumulated depreciation amount is accurate
|
||||
def get_final_number_of_depreciations(self, asset_doc, row):
|
||||
final_number_of_depreciations = cint(row.total_number_of_depreciations) - cint(
|
||||
self.opening_number_of_booked_depreciations
|
||||
)
|
||||
|
||||
has_pro_rata = _check_is_pro_rata(asset_doc, row)
|
||||
if has_pro_rata:
|
||||
final_number_of_depreciations += 1
|
||||
|
||||
return final_number_of_depreciations, has_pro_rata
|
||||
|
||||
def has_fiscal_year_changed(self, row, row_no):
|
||||
fiscal_year_changed = False
|
||||
|
||||
schedule_date = get_last_day(
|
||||
add_months(row.depreciation_start_date, row_no * cint(row.frequency_of_depreciation))
|
||||
)
|
||||
|
||||
if not self.current_fiscal_year_end_date:
|
||||
self.current_fiscal_year_end_date = get_fiscal_year(row.depreciation_start_date)[2]
|
||||
fiscal_year_changed = True
|
||||
elif getdate(schedule_date) > getdate(self.current_fiscal_year_end_date):
|
||||
self.current_fiscal_year_end_date = add_years(self.current_fiscal_year_end_date, 1)
|
||||
fiscal_year_changed = True
|
||||
|
||||
return fiscal_year_changed
|
||||
|
||||
def get_prev_depreciation_amount(self, n):
|
||||
prev_depreciation_amount = 0
|
||||
if n > 0 and len(self.get("depreciation_schedule")) > n - 1:
|
||||
prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount
|
||||
|
||||
return prev_depreciation_amount
|
||||
|
||||
def get_next_schedule_date(
|
||||
self, row, n, schedule_date, has_pro_rata, should_get_last_day, final_number_of_depreciations=None
|
||||
):
|
||||
if not has_pro_rata or (
|
||||
n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2
|
||||
):
|
||||
schedule_date = add_months(row.depreciation_start_date, n * cint(row.frequency_of_depreciation))
|
||||
|
||||
if should_get_last_day:
|
||||
schedule_date = get_last_day(schedule_date)
|
||||
|
||||
return schedule_date
|
||||
|
||||
def get_depreciation_amount_for_disposal(
|
||||
self, asset_doc, row, row_no, schedule_date, date_of_disposal, depreciation_amount
|
||||
):
|
||||
if self.depreciation_schedule: # if there are already booked depreciations
|
||||
from_date = add_days(self.depreciation_schedule[-1].schedule_date, 1)
|
||||
else:
|
||||
from_date = _get_modified_available_for_use_date_for_existing_assets(asset_doc, row)
|
||||
if is_last_day_of_the_month(getdate(asset_doc.available_for_use_date)):
|
||||
from_date = get_last_day(from_date)
|
||||
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
from_date,
|
||||
date_of_disposal,
|
||||
original_schedule_date=schedule_date,
|
||||
)
|
||||
|
||||
depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount"))
|
||||
if depreciation_amount > 0:
|
||||
self.add_depr_schedule_row(date_of_disposal, depreciation_amount, row_no)
|
||||
|
||||
def get_adjusted_depreciation_amount(
|
||||
self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row
|
||||
):
|
||||
# to ensure that final accumulated depreciation amount is accurate
|
||||
if not self.opening_accumulated_depreciation:
|
||||
depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row()
|
||||
depreciation_amount_for_first_row = self.get("depreciation_schedule")[0].depreciation_amount
|
||||
|
||||
if (
|
||||
depreciation_amount_for_first_row + depreciation_amount_for_last_row
|
||||
@@ -468,8 +396,84 @@ class AssetDepreciationSchedule(Document):
|
||||
|
||||
return depreciation_amount_for_last_row
|
||||
|
||||
def get_depreciation_amount_for_first_row(self):
|
||||
return self.get("depreciation_schedule")[0].depreciation_amount
|
||||
def get_depreciation_amount_for_first_row(
|
||||
self, asset_doc, row, n, depreciation_amount, has_pro_rata, has_wdv_or_dd_non_yearly_pro_rata
|
||||
):
|
||||
"""
|
||||
For the first row, if available for use date is mid of the month, then pro rata amount is needed
|
||||
"""
|
||||
if (
|
||||
(has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata)
|
||||
and not self.opening_accumulated_depreciation
|
||||
and not self.flags.wdv_it_act_applied
|
||||
): # if not existing asset
|
||||
from_date = asset_doc.available_for_use_date
|
||||
elif has_wdv_or_dd_non_yearly_pro_rata and self.opening_accumulated_depreciation: # if existing asset
|
||||
from_date = _get_modified_available_for_use_date_for_existing_assets(asset_doc, row)
|
||||
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
from_date,
|
||||
row.depreciation_start_date,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
)
|
||||
|
||||
self.validate_depreciation_amount_for_low_value_assets(asset_doc, row, depreciation_amount)
|
||||
|
||||
return depreciation_amount
|
||||
|
||||
def get_depreciation_amount_for_last_row(
|
||||
self, asset_doc, row, n, depreciation_amount, schedule_date, has_wdv_or_dd_non_yearly_pro_rata
|
||||
):
|
||||
if not asset_doc.flags.increase_in_asset_life:
|
||||
# In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission
|
||||
asset_doc.to_date = add_months(
|
||||
asset_doc.available_for_use_date,
|
||||
(n + self.opening_number_of_booked_depreciations) * cint(row.frequency_of_depreciation),
|
||||
)
|
||||
if is_last_day_of_the_month(getdate(asset_doc.available_for_use_date)):
|
||||
asset_doc.to_date = get_last_day(asset_doc.to_date)
|
||||
|
||||
if self.opening_accumulated_depreciation:
|
||||
depreciation_amount, days, months = _get_pro_rata_amt(
|
||||
row,
|
||||
depreciation_amount,
|
||||
schedule_date,
|
||||
asset_doc.to_date,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
)
|
||||
else:
|
||||
# if not existing asset, remaining amount of first row is depreciated in the last row
|
||||
depreciation_amount -= self.get("depreciation_schedule")[0].depreciation_amount
|
||||
|
||||
schedule_date = add_days(schedule_date, days - 1)
|
||||
return depreciation_amount, schedule_date
|
||||
|
||||
def adjust_depr_amount_for_salvage_value(
|
||||
row, depreciation_amount, value_after_depreciation, final_number_of_depreciations, row_no, skip_row
|
||||
):
|
||||
if (
|
||||
row_no == cint(final_number_of_depreciations) - 1
|
||||
and flt(value_after_depreciation) != flt(row.expected_value_after_useful_life)
|
||||
) or flt(value_after_depreciation) < flt(row.expected_value_after_useful_life):
|
||||
depreciation_amount += flt(value_after_depreciation) - flt(row.expected_value_after_useful_life)
|
||||
depreciation_amount = flt(depreciation_amount, row.precision("depreciation_amount"))
|
||||
skip_row = True
|
||||
return depreciation_amount, skip_row
|
||||
|
||||
def validate_depreciation_amount_for_low_value_assets(self, asset_doc, row, depreciation_amount):
|
||||
""" "
|
||||
If gross purchase amount is too low, then depreciation amount
|
||||
can come zero sometimes based on the frequency and number of depreciations.
|
||||
"""
|
||||
if flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")) <= 0:
|
||||
frappe.throw(
|
||||
_("Gross Purchase Amount {0} cannot be depreciated over {1} cycles.").format(
|
||||
frappe.bold(asset_doc.gross_purchase_amount),
|
||||
frappe.bold(row.total_number_of_depreciations),
|
||||
)
|
||||
)
|
||||
|
||||
def add_depr_schedule_row(self, schedule_date, depreciation_amount, schedule_idx):
|
||||
if self.shift_based:
|
||||
@@ -576,7 +580,7 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
|
||||
days = date_diff(prev_depreciation_start_date, from_date) + 1
|
||||
total_days = get_total_days(prev_depreciation_start_date, row.frequency_of_depreciation)
|
||||
else:
|
||||
from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False)
|
||||
from_date = _get_modified_available_for_use_date_for_existing_assets(asset_doc, row)
|
||||
days = date_diff(row.depreciation_start_date, from_date) + 1
|
||||
total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation)
|
||||
if days <= 0:
|
||||
@@ -595,11 +599,12 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
|
||||
return has_pro_rata
|
||||
|
||||
|
||||
def _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False):
|
||||
def _get_modified_available_for_use_date_for_existing_assets(asset_doc, row):
|
||||
"""
|
||||
if Asset has opening booked depreciations = 9,
|
||||
if Asset has opening booked depreciations = 3,
|
||||
frequency of depreciation = 3,
|
||||
available for use date = 17-07-2023,
|
||||
depreciation start date = 30-04-2024
|
||||
depreciation start date = 30-06-2024
|
||||
then from date should be 01-04-2024
|
||||
"""
|
||||
if asset_doc.opening_number_of_booked_depreciations > 0:
|
||||
@@ -641,359 +646,6 @@ def get_total_days(date, frequency):
|
||||
return date_diff(date, period_start_date)
|
||||
|
||||
|
||||
def get_depreciation_amount(
|
||||
asset_depr_schedule,
|
||||
asset,
|
||||
depreciable_value,
|
||||
yearly_opening_wdv,
|
||||
fb_row,
|
||||
schedule_idx=0,
|
||||
prev_depreciation_amount=0,
|
||||
has_wdv_or_dd_non_yearly_pro_rata=False,
|
||||
number_of_pending_depreciations=0,
|
||||
prev_per_day_depr=0,
|
||||
):
|
||||
if fb_row.depreciation_method in ("Straight Line", "Manual"):
|
||||
return get_straight_line_or_manual_depr_amount(
|
||||
asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations
|
||||
), None
|
||||
else:
|
||||
return get_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
yearly_opening_wdv,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
|
||||
|
||||
def get_straight_line_or_manual_depr_amount(
|
||||
asset_depr_schedule, asset, row, schedule_idx, number_of_pending_depreciations
|
||||
):
|
||||
if row.shift_based:
|
||||
return get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx)
|
||||
|
||||
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
|
||||
if asset.flags.increase_in_asset_life:
|
||||
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
|
||||
date_diff(asset.to_date, asset.available_for_use_date) / 365
|
||||
)
|
||||
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
|
||||
elif asset.flags.increase_in_asset_value_due_to_repair:
|
||||
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt(
|
||||
number_of_pending_depreciations
|
||||
)
|
||||
# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
|
||||
elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
|
||||
if row.daily_prorata_based:
|
||||
amount = flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
|
||||
|
||||
return get_daily_prorata_based_straight_line_depr(
|
||||
asset,
|
||||
row,
|
||||
schedule_idx,
|
||||
number_of_pending_depreciations,
|
||||
amount,
|
||||
)
|
||||
else:
|
||||
return (
|
||||
flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
|
||||
) / number_of_pending_depreciations
|
||||
# if the Depreciation Schedule is being prepared for the first time
|
||||
else:
|
||||
if row.daily_prorata_based:
|
||||
amount = flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
|
||||
return get_daily_prorata_based_straight_line_depr(
|
||||
asset, row, schedule_idx, number_of_pending_depreciations, amount
|
||||
)
|
||||
else:
|
||||
depreciation_amount = (
|
||||
flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
|
||||
) / flt(row.total_number_of_depreciations)
|
||||
return depreciation_amount
|
||||
|
||||
|
||||
def get_daily_prorata_based_straight_line_depr(
|
||||
asset, row, schedule_idx, number_of_pending_depreciations, amount
|
||||
):
|
||||
daily_depr_amount = get_daily_depr_amount(asset, row, schedule_idx, amount)
|
||||
|
||||
from_date, total_depreciable_days = _get_total_days(
|
||||
row.depreciation_start_date, schedule_idx, row.frequency_of_depreciation
|
||||
)
|
||||
return daily_depr_amount * total_depreciable_days
|
||||
|
||||
|
||||
def get_daily_depr_amount(asset, row, schedule_idx, amount):
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "calculate_depr_using_total_days")):
|
||||
total_days = (
|
||||
date_diff(
|
||||
get_last_day(
|
||||
add_months(
|
||||
row.depreciation_start_date,
|
||||
flt(
|
||||
row.total_number_of_depreciations
|
||||
- asset.opening_number_of_booked_depreciations
|
||||
- 1
|
||||
)
|
||||
* row.frequency_of_depreciation,
|
||||
)
|
||||
),
|
||||
add_days(
|
||||
get_last_day(
|
||||
add_months(
|
||||
row.depreciation_start_date,
|
||||
(
|
||||
row.frequency_of_depreciation
|
||||
* (asset.opening_number_of_booked_depreciations + 1)
|
||||
)
|
||||
* -1,
|
||||
),
|
||||
),
|
||||
1,
|
||||
),
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
|
||||
return amount / total_days
|
||||
else:
|
||||
total_years = (
|
||||
flt(
|
||||
(row.total_number_of_depreciations - row.total_number_of_booked_depreciations)
|
||||
* row.frequency_of_depreciation
|
||||
)
|
||||
/ 12
|
||||
)
|
||||
|
||||
every_year_depr = amount / total_years
|
||||
|
||||
depr_period_start_date = add_days(
|
||||
get_last_day(add_months(row.depreciation_start_date, row.frequency_of_depreciation * -1)), 1
|
||||
)
|
||||
|
||||
year_start_date = add_years(
|
||||
depr_period_start_date, ((row.frequency_of_depreciation * schedule_idx) // 12)
|
||||
)
|
||||
year_end_date = add_days(add_years(year_start_date, 1), -1)
|
||||
|
||||
return every_year_depr / (date_diff(year_end_date, year_start_date) + 1)
|
||||
|
||||
|
||||
def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx):
|
||||
if asset_depr_schedule.get("__islocal") and not asset.flags.shift_allocation:
|
||||
return (
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
|
||||
|
||||
asset_shift_factors_map = get_asset_shift_factors_map()
|
||||
shift = (
|
||||
asset_depr_schedule.schedules_before_clearing[schedule_idx].shift
|
||||
if len(asset_depr_schedule.schedules_before_clearing) > schedule_idx
|
||||
else None
|
||||
)
|
||||
shift_factor = asset_shift_factors_map.get(shift) if shift else 0
|
||||
|
||||
shift_factors_sum = sum(
|
||||
flt(asset_shift_factors_map.get(schedule.shift))
|
||||
for schedule in asset_depr_schedule.schedules_before_clearing
|
||||
)
|
||||
|
||||
return (
|
||||
(
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
)
|
||||
/ flt(shift_factors_sum)
|
||||
) * shift_factor
|
||||
|
||||
|
||||
def get_asset_shift_factors_map():
|
||||
return dict(frappe.db.get_all("Asset Shift Factor", ["shift_name", "shift_factor"], as_list=True))
|
||||
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
yearly_opening_wdv,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
):
|
||||
return get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
|
||||
|
||||
def get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
):
|
||||
if not fb_row.daily_prorata_based or cint(fb_row.frequency_of_depreciation) == 12:
|
||||
return _get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
), None
|
||||
else:
|
||||
return _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
|
||||
|
||||
def _get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
):
|
||||
if cint(fb_row.frequency_of_depreciation) == 12:
|
||||
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
|
||||
else:
|
||||
if has_wdv_or_dd_non_yearly_pro_rata:
|
||||
if schedule_idx == 0:
|
||||
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
|
||||
elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1:
|
||||
return (
|
||||
flt(depreciable_value)
|
||||
* flt(fb_row.frequency_of_depreciation)
|
||||
* (flt(fb_row.rate_of_depreciation) / 1200)
|
||||
)
|
||||
else:
|
||||
return prev_depreciation_amount
|
||||
else:
|
||||
if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0:
|
||||
return (
|
||||
flt(depreciable_value)
|
||||
* flt(fb_row.frequency_of_depreciation)
|
||||
* (flt(fb_row.rate_of_depreciation) / 1200)
|
||||
)
|
||||
else:
|
||||
return prev_depreciation_amount
|
||||
|
||||
|
||||
def _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
):
|
||||
if has_wdv_or_dd_non_yearly_pro_rata: # If applicable days for ther first month is less than full month
|
||||
if schedule_idx == 0:
|
||||
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None
|
||||
|
||||
elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: # Year changes
|
||||
return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
|
||||
else:
|
||||
return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
|
||||
else:
|
||||
if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: # year changes
|
||||
return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
|
||||
else:
|
||||
return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
|
||||
|
||||
|
||||
def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value):
|
||||
"""
|
||||
Returns monthly depreciation amount when year changes
|
||||
1. Calculate per day depr based on new year
|
||||
2. Calculate monthly amount based on new per day amount
|
||||
"""
|
||||
from_date, days_in_month = _get_total_days(
|
||||
fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
|
||||
)
|
||||
per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date)
|
||||
return (per_day_depr * days_in_month), per_day_depr
|
||||
|
||||
|
||||
def get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr):
|
||||
""" "
|
||||
Returns monthly depreciation amount based on prev per day depr
|
||||
Calculate per day depr only for the first month
|
||||
"""
|
||||
from_date, days_in_month = _get_total_days(
|
||||
fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
|
||||
)
|
||||
return (prev_per_day_depr * days_in_month), prev_per_day_depr
|
||||
|
||||
|
||||
def get_per_day_depr(
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
from_date,
|
||||
):
|
||||
to_date = add_days(add_years(from_date, 1), -1)
|
||||
total_days = date_diff(to_date, from_date) + 1
|
||||
per_day_depr = (flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days
|
||||
return per_day_depr
|
||||
|
||||
|
||||
def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_depreciation):
|
||||
from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation)
|
||||
to_date = add_months(from_date, frequency_of_depreciation)
|
||||
if is_last_day_of_the_month(depreciation_start_date):
|
||||
to_date = get_last_day(to_date)
|
||||
from_date = add_days(get_last_day(from_date), 1)
|
||||
return from_date, date_diff(to_date, from_date) + 1
|
||||
|
||||
|
||||
def make_draft_asset_depr_schedules_if_not_present(asset_doc):
|
||||
asset_depr_schedules_names = []
|
||||
|
||||
for row in asset_doc.get("finance_books"):
|
||||
asset_depr_schedule = get_asset_depr_schedule_name(
|
||||
asset_doc.name, ["Draft", "Active"], row.finance_book
|
||||
)
|
||||
|
||||
if not asset_depr_schedule:
|
||||
name = make_draft_asset_depr_schedule(asset_doc, row)
|
||||
asset_depr_schedules_names.append(name)
|
||||
|
||||
return asset_depr_schedules_names
|
||||
|
||||
|
||||
def make_draft_asset_depr_schedules(asset_doc):
|
||||
asset_depr_schedules_names = []
|
||||
|
||||
|
||||
351
erpnext/assets/doctype/asset_depreciation_schedule/utils.py
Normal file
351
erpnext/assets/doctype/asset_depreciation_schedule/utils.py
Normal file
@@ -0,0 +1,351 @@
|
||||
import frappe
|
||||
from frappe.utils import (
|
||||
add_days,
|
||||
add_months,
|
||||
add_years,
|
||||
cint,
|
||||
date_diff,
|
||||
flt,
|
||||
get_last_day,
|
||||
is_last_day_of_the_month,
|
||||
)
|
||||
|
||||
import erpnext
|
||||
|
||||
|
||||
def get_depreciation_amount(
|
||||
asset_depr_schedule,
|
||||
asset,
|
||||
depreciable_value,
|
||||
yearly_opening_wdv,
|
||||
fb_row,
|
||||
schedule_idx=0,
|
||||
prev_depreciation_amount=0,
|
||||
has_wdv_or_dd_non_yearly_pro_rata=False,
|
||||
number_of_pending_depreciations=0,
|
||||
prev_per_day_depr=0,
|
||||
):
|
||||
if fb_row.depreciation_method in ("Straight Line", "Manual"):
|
||||
return get_straight_line_or_manual_depr_amount(
|
||||
asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations
|
||||
), None
|
||||
else:
|
||||
return get_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
yearly_opening_wdv,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
|
||||
|
||||
def get_straight_line_or_manual_depr_amount(
|
||||
asset_depr_schedule, asset, row, schedule_idx, number_of_pending_depreciations
|
||||
):
|
||||
if row.shift_based:
|
||||
return get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx)
|
||||
|
||||
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
|
||||
if asset.flags.increase_in_asset_life:
|
||||
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
|
||||
date_diff(asset.to_date, asset.available_for_use_date) / 365
|
||||
)
|
||||
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
|
||||
elif asset.flags.increase_in_asset_value_due_to_repair:
|
||||
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt(
|
||||
number_of_pending_depreciations
|
||||
)
|
||||
# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
|
||||
elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
|
||||
if row.daily_prorata_based:
|
||||
amount = flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
|
||||
|
||||
return get_daily_prorata_based_straight_line_depr(
|
||||
asset,
|
||||
row,
|
||||
schedule_idx,
|
||||
number_of_pending_depreciations,
|
||||
amount,
|
||||
)
|
||||
else:
|
||||
return (
|
||||
flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
|
||||
) / number_of_pending_depreciations
|
||||
# if the Depreciation Schedule is being prepared for the first time
|
||||
else:
|
||||
if row.daily_prorata_based:
|
||||
amount = flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
|
||||
return get_daily_prorata_based_straight_line_depr(
|
||||
asset, row, schedule_idx, number_of_pending_depreciations, amount
|
||||
)
|
||||
else:
|
||||
depreciation_amount = (
|
||||
flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
|
||||
) / flt(row.total_number_of_depreciations)
|
||||
return depreciation_amount
|
||||
|
||||
|
||||
def get_daily_prorata_based_straight_line_depr(
|
||||
asset, row, schedule_idx, number_of_pending_depreciations, amount
|
||||
):
|
||||
daily_depr_amount = get_daily_depr_amount(asset, row, schedule_idx, amount)
|
||||
|
||||
from_date, total_depreciable_days = _get_total_days(
|
||||
row.depreciation_start_date, schedule_idx, row.frequency_of_depreciation
|
||||
)
|
||||
return daily_depr_amount * total_depreciable_days
|
||||
|
||||
|
||||
def get_daily_depr_amount(asset, row, schedule_idx, amount):
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "calculate_depr_using_total_days")):
|
||||
total_days = (
|
||||
date_diff(
|
||||
get_last_day(
|
||||
add_months(
|
||||
row.depreciation_start_date,
|
||||
flt(
|
||||
row.total_number_of_depreciations
|
||||
- asset.opening_number_of_booked_depreciations
|
||||
- 1
|
||||
)
|
||||
* row.frequency_of_depreciation,
|
||||
)
|
||||
),
|
||||
add_days(
|
||||
get_last_day(
|
||||
add_months(
|
||||
row.depreciation_start_date,
|
||||
(
|
||||
row.frequency_of_depreciation
|
||||
* (asset.opening_number_of_booked_depreciations + 1)
|
||||
)
|
||||
* -1,
|
||||
),
|
||||
),
|
||||
1,
|
||||
),
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
|
||||
return amount / total_days
|
||||
else:
|
||||
total_years = (
|
||||
flt(
|
||||
(row.total_number_of_depreciations - row.total_number_of_booked_depreciations)
|
||||
* row.frequency_of_depreciation
|
||||
)
|
||||
/ 12
|
||||
)
|
||||
|
||||
every_year_depr = amount / total_years
|
||||
|
||||
depr_period_start_date = add_days(
|
||||
get_last_day(add_months(row.depreciation_start_date, row.frequency_of_depreciation * -1)), 1
|
||||
)
|
||||
|
||||
year_start_date = add_years(
|
||||
depr_period_start_date, ((row.frequency_of_depreciation * schedule_idx) // 12)
|
||||
)
|
||||
year_end_date = add_days(add_years(year_start_date, 1), -1)
|
||||
|
||||
return every_year_depr / (date_diff(year_end_date, year_start_date) + 1)
|
||||
|
||||
|
||||
def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx):
|
||||
if asset_depr_schedule.get("__islocal") and not asset.flags.shift_allocation:
|
||||
return (
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
|
||||
|
||||
asset_shift_factors_map = get_asset_shift_factors_map()
|
||||
shift = (
|
||||
asset_depr_schedule.schedules_before_clearing[schedule_idx].shift
|
||||
if len(asset_depr_schedule.schedules_before_clearing) > schedule_idx
|
||||
else None
|
||||
)
|
||||
shift_factor = asset_shift_factors_map.get(shift) if shift else 0
|
||||
|
||||
shift_factors_sum = sum(
|
||||
flt(asset_shift_factors_map.get(schedule.shift))
|
||||
for schedule in asset_depr_schedule.schedules_before_clearing
|
||||
)
|
||||
|
||||
return (
|
||||
(
|
||||
flt(asset.gross_purchase_amount)
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(row.expected_value_after_useful_life)
|
||||
)
|
||||
/ flt(shift_factors_sum)
|
||||
) * shift_factor
|
||||
|
||||
|
||||
def get_asset_shift_factors_map():
|
||||
return dict(frappe.db.get_all("Asset Shift Factor", ["shift_name", "shift_factor"], as_list=True))
|
||||
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
yearly_opening_wdv,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
):
|
||||
return get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
|
||||
|
||||
def get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
):
|
||||
if not fb_row.daily_prorata_based or cint(fb_row.frequency_of_depreciation) == 12:
|
||||
return _get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
), None
|
||||
else:
|
||||
return _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
)
|
||||
|
||||
|
||||
def _get_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
):
|
||||
if cint(fb_row.frequency_of_depreciation) == 12:
|
||||
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
|
||||
else:
|
||||
if has_wdv_or_dd_non_yearly_pro_rata:
|
||||
if schedule_idx == 0:
|
||||
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
|
||||
elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1:
|
||||
return (
|
||||
flt(depreciable_value)
|
||||
* flt(fb_row.frequency_of_depreciation)
|
||||
* (flt(fb_row.rate_of_depreciation) / 1200)
|
||||
)
|
||||
else:
|
||||
return prev_depreciation_amount
|
||||
else:
|
||||
if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0:
|
||||
return (
|
||||
flt(depreciable_value)
|
||||
* flt(fb_row.frequency_of_depreciation)
|
||||
* (flt(fb_row.rate_of_depreciation) / 1200)
|
||||
)
|
||||
else:
|
||||
return prev_depreciation_amount
|
||||
|
||||
|
||||
def _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
|
||||
asset,
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
schedule_idx,
|
||||
prev_depreciation_amount,
|
||||
has_wdv_or_dd_non_yearly_pro_rata,
|
||||
asset_depr_schedule,
|
||||
prev_per_day_depr,
|
||||
):
|
||||
if has_wdv_or_dd_non_yearly_pro_rata: # If applicable days for ther first month is less than full month
|
||||
if schedule_idx == 0:
|
||||
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None
|
||||
|
||||
elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: # Year changes
|
||||
return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
|
||||
else:
|
||||
return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
|
||||
else:
|
||||
if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: # year changes
|
||||
return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
|
||||
else:
|
||||
return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
|
||||
|
||||
|
||||
def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value):
|
||||
"""
|
||||
Returns monthly depreciation amount when year changes
|
||||
1. Calculate per day depr based on new year
|
||||
2. Calculate monthly amount based on new per day amount
|
||||
"""
|
||||
from_date, days_in_month = _get_total_days(
|
||||
fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
|
||||
)
|
||||
per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date)
|
||||
return (per_day_depr * days_in_month), per_day_depr
|
||||
|
||||
|
||||
def get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr):
|
||||
""" "
|
||||
Returns monthly depreciation amount based on prev per day depr
|
||||
Calculate per day depr only for the first month
|
||||
"""
|
||||
from_date, days_in_month = _get_total_days(
|
||||
fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
|
||||
)
|
||||
return (prev_per_day_depr * days_in_month), prev_per_day_depr
|
||||
|
||||
|
||||
def get_per_day_depr(
|
||||
fb_row,
|
||||
depreciable_value,
|
||||
from_date,
|
||||
):
|
||||
to_date = add_days(add_years(from_date, 1), -1)
|
||||
total_days = date_diff(to_date, from_date) + 1
|
||||
per_day_depr = (flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days
|
||||
return per_day_depr
|
||||
|
||||
|
||||
def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_depreciation):
|
||||
from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation)
|
||||
to_date = add_months(from_date, frequency_of_depreciation)
|
||||
if is_last_day_of_the_month(depreciation_start_date):
|
||||
to_date = get_last_day(to_date)
|
||||
from_date = add_days(get_last_day(from_date), 1)
|
||||
return from_date, date_diff(to_date, from_date) + 1
|
||||
@@ -61,6 +61,7 @@
|
||||
{
|
||||
"fieldname": "depreciation_start_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Depreciation Posting Date",
|
||||
"mandatory_depends_on": "eval:parent.doctype == 'Asset'"
|
||||
@@ -100,7 +101,7 @@
|
||||
"default": "0",
|
||||
"fieldname": "daily_prorata_based",
|
||||
"fieldtype": "Check",
|
||||
"label": "Depreciate based on daily pro-rata"
|
||||
"label": "Depreciate based on days per period"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
|
||||
@@ -16,9 +16,9 @@ from frappe.utils import (
|
||||
from erpnext.assets.doctype.asset_activity.asset_activity import add_asset_activity
|
||||
from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
|
||||
get_asset_depr_schedule_doc,
|
||||
get_asset_shift_factors_map,
|
||||
get_temp_asset_depr_schedule_doc,
|
||||
)
|
||||
from erpnext.assets.doctype.asset_depreciation_schedule.utils import get_asset_shift_factors_map
|
||||
|
||||
|
||||
class AssetShiftAllocation(Document):
|
||||
|
||||
Reference in New Issue
Block a user