Skip to content

Commit 1b8551d

Browse files
committed
refactor: Asset module code for better readability
1 parent da5dba9 commit 1b8551d

File tree

7 files changed

+727
-667
lines changed

7 files changed

+727
-667
lines changed

erpnext/assets/doctype/asset/asset.py

+150-114
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
get_asset_depr_schedule_doc,
3434
get_depr_schedule,
3535
make_draft_asset_depr_schedules,
36-
make_draft_asset_depr_schedules_if_not_present,
3736
update_draft_asset_depr_schedules,
3837
)
3938
from erpnext.controllers.accounts_controller import AccountsController
@@ -127,30 +126,55 @@ def validate(self):
127126
self.set_missing_values()
128127
self.validate_gross_and_purchase_amount()
129128
self.validate_finance_books()
130-
131-
if not self.split_from:
132-
self.prepare_depreciation_data()
133-
134-
if self.calculate_depreciation:
135-
update_draft_asset_depr_schedules(self)
136-
137-
if frappe.db.exists("Asset", self.name):
138-
asset_depr_schedules_names = make_draft_asset_depr_schedules_if_not_present(self)
139-
140-
if asset_depr_schedules_names:
141-
asset_depr_schedules_links = get_comma_separated_links(
142-
asset_depr_schedules_names, "Asset Depreciation Schedule"
143-
)
144-
frappe.msgprint(
145-
_(
146-
"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
147-
).format(asset_depr_schedules_links)
148-
)
149129
self.validate_expected_value_after_useful_life()
150130
self.set_total_booked_depreciations()
151131
self.total_asset_cost = self.gross_purchase_amount
152132
self.status = self.get_status()
153133

134+
def create_asset_depreciation_schedule(self):
135+
if self.split_from or not self.calculate_depreciation:
136+
return
137+
138+
self.set_depr_rate_and_value_after_depreciation()
139+
140+
schedules = []
141+
for row in self.get("finance_books"):
142+
self.validate_asset_finance_books(row)
143+
if not row.rate_of_depreciation:
144+
row.rate_of_depreciation = self.get_depreciation_rate(row, on_validate=True)
145+
146+
schedule_doc = get_asset_depr_schedule_doc(self.name, "Draft", row.finance_book)
147+
if not schedule_doc:
148+
schedule_doc = frappe.new_doc("Asset Depreciation Schedule")
149+
150+
schedule_doc.prepare_draft_asset_depr_schedule_data(self, row)
151+
schedule_doc.save()
152+
schedules.append(schedule_doc.name)
153+
154+
self.show_schedule_creation_message(schedules)
155+
156+
def set_depr_rate_and_value_after_depreciation(self):
157+
if self.calculate_depreciation:
158+
self.value_after_depreciation = 0
159+
self.set_depreciation_rate()
160+
else:
161+
self.finance_books = []
162+
self.value_after_depreciation = flt(self.gross_purchase_amount) - flt(
163+
self.opening_accumulated_depreciation
164+
)
165+
166+
def show_schedule_creation_message(self, schedules):
167+
if schedules:
168+
asset_depr_schedules_links = get_comma_separated_links(schedules, "Asset Depreciation Schedule")
169+
frappe.msgprint(
170+
_(
171+
"Asset Depreciation Schedules created/updated:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
172+
).format(asset_depr_schedules_links)
173+
)
174+
175+
def on_update(self):
176+
self.create_asset_depreciation_schedule()
177+
154178
def on_submit(self):
155179
self.validate_in_use_date()
156180
self.make_asset_movement()
@@ -174,17 +198,17 @@ def on_cancel(self):
174198
self.db_set("booked_fixed_asset", 0)
175199
add_asset_activity(self.name, _("Asset cancelled"))
176200

177-
def after_insert(self):
178-
if self.calculate_depreciation and not self.split_from:
179-
asset_depr_schedules_names = make_draft_asset_depr_schedules(self)
180-
asset_depr_schedules_links = get_comma_separated_links(
181-
asset_depr_schedules_names, "Asset Depreciation Schedule"
182-
)
183-
frappe.msgprint(
184-
_(
185-
"Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
186-
).format(asset_depr_schedules_links)
187-
)
201+
# def after_insert(self):
202+
# if self.calculate_depreciation and not self.split_from:
203+
# asset_depr_schedules_names = make_draft_asset_depr_schedules(self)
204+
# asset_depr_schedules_links = get_comma_separated_links(
205+
# asset_depr_schedules_names, "Asset Depreciation Schedule"
206+
# )
207+
# frappe.msgprint(
208+
# _(
209+
# "Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
210+
# ).format(asset_depr_schedules_links)
211+
# )
188212
if (
189213
not frappe.db.exists(
190214
{
@@ -214,16 +238,6 @@ def validate_asset_and_reference(self):
214238
if self.is_existing_asset and self.purchase_invoice:
215239
frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
216240

217-
def prepare_depreciation_data(self):
218-
if self.calculate_depreciation:
219-
self.value_after_depreciation = 0
220-
self.set_depreciation_rate()
221-
else:
222-
self.finance_books = []
223-
self.value_after_depreciation = flt(self.gross_purchase_amount) - flt(
224-
self.opening_accumulated_depreciation
225-
)
226-
227241
def validate_item(self):
228242
item = frappe.get_cached_value(
229243
"Item", self.item_code, ["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1
@@ -308,6 +322,22 @@ def validate_finance_books(self):
308322
title=_("Missing Finance Book"),
309323
)
310324

325+
# def set_depreciation_start_date(self):
326+
# if not self.calculate_depreciation:
327+
# return
328+
329+
# for d in self.get("finance_books"):
330+
# if not d.depreciation_start_date:
331+
# if self.is_existing_asset and self.opening_number_of_booked_depreciations:
332+
333+
# months = d.frequency_of_depreciation * self.opening_number_of_booked_depreciations
334+
# else:
335+
# months = d.frequency_of_depreciation
336+
337+
# d.depreciation_start_date = get_last_day(
338+
# add_months(self.available_for_use_date, months)
339+
# )
340+
311341
def validate_precision(self):
312342
float_precision = cint(frappe.db.get_default("float_precision")) or 2
313343
if self.gross_purchase_amount:
@@ -415,58 +445,59 @@ def validate_asset_finance_books(self, row):
415445
frappe.throw(
416446
_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount").format(
417447
row.idx
418-
),
419-
title=_("Invalid Schedule"),
448+
)
420449
)
421450

422451
if not row.depreciation_start_date:
423-
if not self.available_for_use_date:
424-
frappe.throw(
425-
_("Row {0}: Depreciation Start Date is required").format(row.idx),
426-
title=_("Invalid Schedule"),
427-
)
428452
row.depreciation_start_date = get_last_day(self.available_for_use_date)
453+
self.validate_depreciation_start_date(row)
429454

430455
if not self.is_existing_asset:
431456
self.opening_accumulated_depreciation = 0
432457
self.opening_number_of_booked_depreciations = 0
433458
else:
434-
depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
435-
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
436-
frappe.throw(
437-
_("Opening Accumulated Depreciation must be less than or equal to {0}").format(
438-
depreciable_amount
439-
)
459+
self.validate_opening_depreciation_values(row)
460+
461+
def validate_opening_depreciation_values(self, row):
462+
depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
463+
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
464+
frappe.throw(
465+
_("Row #{0}: Opening Accumulated Depreciation must be less than or equal to {1}").format(
466+
row.idx, depreciable_amount
440467
)
468+
)
441469

442-
if self.opening_accumulated_depreciation:
443-
if not self.opening_number_of_booked_depreciations:
444-
frappe.throw(_("Please set Opening Number of Booked Depreciations"))
445-
else:
446-
self.opening_number_of_booked_depreciations = 0
470+
if self.opening_accumulated_depreciation:
471+
if not self.opening_number_of_booked_depreciations:
472+
frappe.throw(_("Please set opening number of booked depreciations"))
473+
else:
474+
self.opening_number_of_booked_depreciations = 0
447475

448-
if flt(row.total_number_of_depreciations) <= cint(self.opening_number_of_booked_depreciations):
476+
if flt(row.total_number_of_depreciations) <= cint(self.opening_number_of_booked_depreciations):
477+
frappe.throw(
478+
_(
479+
"Row #{0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations"
480+
).format(row.idx),
481+
title=_("Invalid Schedule"),
482+
)
483+
484+
def validate_depreciation_start_date(self, row):
485+
if row.depreciation_start_date:
486+
if getdate(row.depreciation_start_date) < getdate(self.purchase_date):
449487
frappe.throw(
450-
_(
451-
"Row {0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations"
452-
).format(row.idx),
453-
title=_("Invalid Schedule"),
488+
_("Row #{0}: Next Depreciation Date cannot be before Purchase Date").format(row.idx)
454489
)
455490

456-
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
457-
frappe.throw(
458-
_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date").format(
459-
row.idx
491+
if getdate(row.depreciation_start_date) < getdate(self.available_for_use_date):
492+
frappe.throw(
493+
_("Row #{0}: Next Depreciation Date cannot be before Available-for-use Date").format(
494+
row.idx
495+
)
460496
)
461-
)
462-
463-
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(
464-
self.available_for_use_date
465-
):
497+
else:
466498
frappe.throw(
467-
_(
468-
"Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date"
469-
).format(row.idx)
499+
_("Row #{0}: Depreciation Start Date is required").format(row.idx),
500+
title=_("Invalid Schedule"),
470501
)
471502

472503
def set_total_booked_depreciations(self):
@@ -490,15 +521,11 @@ def validate_expected_value_after_useful_life(self):
490521
if not depr_schedule:
491522
continue
492523

493-
accumulated_depreciation_after_full_schedule = [
494-
d.accumulated_depreciation_amount for d in depr_schedule
495-
]
524+
accumulated_depreciation_after_full_schedule = max(
525+
[d.accumulated_depreciation_amount for d in depr_schedule]
526+
)
496527

497528
if accumulated_depreciation_after_full_schedule:
498-
accumulated_depreciation_after_full_schedule = max(
499-
accumulated_depreciation_after_full_schedule
500-
)
501-
502529
asset_value_after_full_schedule = flt(
503530
flt(self.gross_purchase_amount) - flt(accumulated_depreciation_after_full_schedule),
504531
self.precision("gross_purchase_amount"),
@@ -780,50 +807,59 @@ def get_depreciation_rate(self, args, on_validate=False):
780807
if isinstance(args, str):
781808
args = json.loads(args)
782809

783-
float_precision = cint(frappe.db.get_default("float_precision")) or 2
810+
rate_field_precision = frappe.get_precision(args.doctype, "rate_of_depreciation") or 2
784811

785812
if args.get("depreciation_method") == "Double Declining Balance":
786-
return 200.0 / (
813+
return self.get_double_declining_balance_rate(args, rate_field_precision)
814+
elif args.get("depreciation_method") == "Written Down Value":
815+
return self.get_written_down_value_rate(args, rate_field_precision, on_validate)
816+
817+
def get_double_declining_balance_rate(self, args, rate_field_precision):
818+
return flt(
819+
200.0
820+
/ (
787821
(
788822
flt(args.get("total_number_of_depreciations"), 2)
789823
* flt(args.get("frequency_of_depreciation"))
790824
)
791825
/ 12
792-
)
826+
),
827+
rate_field_precision,
828+
)
793829

794-
if args.get("depreciation_method") == "Written Down Value":
795-
if (
796-
args.get("rate_of_depreciation")
797-
and on_validate
798-
and not self.flags.increase_in_asset_value_due_to_repair
799-
):
800-
return args.get("rate_of_depreciation")
830+
def get_written_down_value_rate(self, args, rate_field_precision, on_validate):
831+
if (
832+
args.get("rate_of_depreciation")
833+
and on_validate
834+
and not self.flags.increase_in_asset_value_due_to_repair
835+
):
836+
return args.get("rate_of_depreciation")
801837

802-
if self.flags.increase_in_asset_value_due_to_repair:
803-
value = flt(args.get("expected_value_after_useful_life")) / flt(
804-
args.get("value_after_depreciation")
805-
)
806-
else:
807-
value = flt(args.get("expected_value_after_useful_life")) / (
808-
flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation)
809-
)
838+
if self.flags.increase_in_asset_value_due_to_repair:
839+
value = flt(args.get("expected_value_after_useful_life")) / flt(
840+
args.get("value_after_depreciation")
841+
)
842+
else:
843+
value = flt(args.get("expected_value_after_useful_life")) / (
844+
flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation)
845+
)
810846

811-
depreciation_rate = math.pow(
812-
value,
813-
1.0
814-
/ (
847+
depreciation_rate = math.pow(
848+
value,
849+
1.0
850+
/ (
851+
(
815852
(
816-
(
817-
flt(args.get("total_number_of_depreciations"), 2)
818-
- flt(self.opening_number_of_booked_depreciations)
819-
)
820-
* flt(args.get("frequency_of_depreciation"))
853+
flt(args.get("total_number_of_depreciations"), 2)
854+
- flt(self.opening_number_of_booked_depreciations)
821855
)
822-
/ 12
823-
),
824-
)
856+
* flt(args.get("frequency_of_depreciation"))
857+
)
858+
/ 12
859+
),
860+
)
825861

826-
return flt((100 * (1 - depreciation_rate)), float_precision)
862+
return flt((100 * (1 - depreciation_rate)), rate_field_precision)
827863

828864

829865
def has_gl_entries(doctype, docname, target_account):

erpnext/assets/doctype/asset/test_asset.py

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
_get_pro_rata_amt,
3535
get_asset_depr_schedule_doc,
3636
get_depr_schedule,
37+
)
38+
from erpnext.assets.doctype.asset_depreciation_schedule.utils import (
3739
get_depreciation_amount,
3840
)
3941
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (

0 commit comments

Comments
 (0)