33
33
get_asset_depr_schedule_doc ,
34
34
get_depr_schedule ,
35
35
make_draft_asset_depr_schedules ,
36
- make_draft_asset_depr_schedules_if_not_present ,
37
36
update_draft_asset_depr_schedules ,
38
37
)
39
38
from erpnext .controllers .accounts_controller import AccountsController
@@ -127,30 +126,55 @@ def validate(self):
127
126
self .set_missing_values ()
128
127
self .validate_gross_and_purchase_amount ()
129
128
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
- )
149
129
self .validate_expected_value_after_useful_life ()
150
130
self .set_total_booked_depreciations ()
151
131
self .total_asset_cost = self .gross_purchase_amount
152
132
self .status = self .get_status ()
153
133
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
+
154
178
def on_submit (self ):
155
179
self .validate_in_use_date ()
156
180
self .make_asset_movement ()
@@ -174,17 +198,17 @@ def on_cancel(self):
174
198
self .db_set ("booked_fixed_asset" , 0 )
175
199
add_asset_activity (self .name , _ ("Asset cancelled" ))
176
200
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
+ # )
188
212
if (
189
213
not frappe .db .exists (
190
214
{
@@ -214,16 +238,6 @@ def validate_asset_and_reference(self):
214
238
if self .is_existing_asset and self .purchase_invoice :
215
239
frappe .throw (_ ("Purchase Invoice cannot be made against an existing asset {0}" ).format (self .name ))
216
240
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
-
227
241
def validate_item (self ):
228
242
item = frappe .get_cached_value (
229
243
"Item" , self .item_code , ["is_fixed_asset" , "is_stock_item" , "disabled" ], as_dict = 1
@@ -308,6 +322,22 @@ def validate_finance_books(self):
308
322
title = _ ("Missing Finance Book" ),
309
323
)
310
324
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
+
311
341
def validate_precision (self ):
312
342
float_precision = cint (frappe .db .get_default ("float_precision" )) or 2
313
343
if self .gross_purchase_amount :
@@ -415,58 +445,59 @@ def validate_asset_finance_books(self, row):
415
445
frappe .throw (
416
446
_ ("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount" ).format (
417
447
row .idx
418
- ),
419
- title = _ ("Invalid Schedule" ),
448
+ )
420
449
)
421
450
422
451
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
- )
428
452
row .depreciation_start_date = get_last_day (self .available_for_use_date )
453
+ self .validate_depreciation_start_date (row )
429
454
430
455
if not self .is_existing_asset :
431
456
self .opening_accumulated_depreciation = 0
432
457
self .opening_number_of_booked_depreciations = 0
433
458
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
440
467
)
468
+ )
441
469
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
447
475
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 ):
449
487
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 )
454
489
)
455
490
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
+ )
460
496
)
461
- )
462
-
463
- if row .depreciation_start_date and getdate (row .depreciation_start_date ) < getdate (
464
- self .available_for_use_date
465
- ):
497
+ else :
466
498
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" ),
470
501
)
471
502
472
503
def set_total_booked_depreciations (self ):
@@ -490,15 +521,11 @@ def validate_expected_value_after_useful_life(self):
490
521
if not depr_schedule :
491
522
continue
492
523
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
+ )
496
527
497
528
if accumulated_depreciation_after_full_schedule :
498
- accumulated_depreciation_after_full_schedule = max (
499
- accumulated_depreciation_after_full_schedule
500
- )
501
-
502
529
asset_value_after_full_schedule = flt (
503
530
flt (self .gross_purchase_amount ) - flt (accumulated_depreciation_after_full_schedule ),
504
531
self .precision ("gross_purchase_amount" ),
@@ -780,50 +807,59 @@ def get_depreciation_rate(self, args, on_validate=False):
780
807
if isinstance (args , str ):
781
808
args = json .loads (args )
782
809
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
784
811
785
812
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
+ / (
787
821
(
788
822
flt (args .get ("total_number_of_depreciations" ), 2 )
789
823
* flt (args .get ("frequency_of_depreciation" ))
790
824
)
791
825
/ 12
792
- )
826
+ ),
827
+ rate_field_precision ,
828
+ )
793
829
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" )
801
837
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
+ )
810
846
811
- depreciation_rate = math .pow (
812
- value ,
813
- 1.0
814
- / (
847
+ depreciation_rate = math .pow (
848
+ value ,
849
+ 1.0
850
+ / (
851
+ (
815
852
(
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 )
821
855
)
822
- / 12
823
- ),
824
- )
856
+ * flt (args .get ("frequency_of_depreciation" ))
857
+ )
858
+ / 12
859
+ ),
860
+ )
825
861
826
- return flt ((100 * (1 - depreciation_rate )), float_precision )
862
+ return flt ((100 * (1 - depreciation_rate )), rate_field_precision )
827
863
828
864
829
865
def has_gl_entries (doctype , docname , target_account ):
0 commit comments