From 5a274176d3faf6a114a80d34a842abd63ef0428b Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 1 Nov 2022 11:45:17 +0530 Subject: [PATCH 01/94] feat: add asset_depreciation_schedule --- .../asset_depreciation_schedule/__init__.py | 0 .../asset_depreciation_schedule.js | 8 + .../asset_depreciation_schedule.json | 165 ++++++++++++++++++ .../asset_depreciation_schedule.py | 8 + .../test_asset_depreciation_schedule.py | 9 + 5 files changed, 190 insertions(+) create mode 100644 erpnext/assets/doctype/asset_depreciation_schedule/__init__.py create mode 100644 erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js create mode 100644 erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json create mode 100644 erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py create mode 100644 erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/__init__.py b/erpnext/assets/doctype/asset_depreciation_schedule/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js new file mode 100644 index 0000000000..9d41de381e --- /dev/null +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js @@ -0,0 +1,8 @@ +// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Asset Depreciation Schedule', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json new file mode 100644 index 0000000000..06eced229f --- /dev/null +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -0,0 +1,165 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "naming_series:", + "creation": "2022-10-31 15:03:35.424877", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "asset", + "column_break_2", + "naming_series", + "depreciation_details_section", + "finance_book", + "depreciation_method", + "rate_of_depreciation", + "column_break_8", + "total_number_of_depreciations", + "frequency_of_depreciation_months", + "depreciation_schedule_section", + "depreciation_schedule", + "details_section", + "notes", + "column_break_15", + "status", + "amended_from" + ], + "fields": [ + { + "fieldname": "asset", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Asset", + "options": "Asset", + "reqd": 1 + }, + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Naming Series", + "options": "ACC-ADS-.YYYY.-" + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Asset Depreciation Schedule", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, + { + "collapsible": 1, + "fieldname": "depreciation_details_section", + "fieldtype": "Section Break", + "label": "Depreciation Details" + }, + { + "fieldname": "finance_book", + "fieldtype": "Link", + "label": "Finance Book", + "options": "Finance Book", + "read_only": 1 + }, + { + "fieldname": "depreciation_method", + "fieldtype": "Select", + "label": "Depreciation Method", + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", + "read_only": 1 + }, + { + "depends_on": "eval:doc.depreciation_method == 'Written Down Value'", + "description": "In Percentage", + "fieldname": "rate_of_depreciation", + "fieldtype": "Percent", + "label": "Rate of Depreciation", + "read_only": 1 + }, + { + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, + { + "depends_on": "total_number_of_depreciations", + "fieldname": "total_number_of_depreciations", + "fieldtype": "Int", + "label": "Total Number of Depreciations", + "read_only": 1 + }, + { + "depends_on": "frequency_of_depreciation_months", + "fieldname": "frequency_of_depreciation_months", + "fieldtype": "Int", + "label": "Frequency of Depreciation (Months)", + "read_only": 1 + }, + { + "fieldname": "depreciation_schedule_section", + "fieldtype": "Section Break", + "label": "Depreciation Schedule" + }, + { + "fieldname": "depreciation_schedule", + "fieldtype": "Table", + "label": "Depreciation Schedule", + "options": "Depreciation Schedule" + }, + { + "collapsible": 1, + "collapsible_depends_on": "notes", + "fieldname": "details_section", + "fieldtype": "Section Break", + "label": "Details" + }, + { + "fieldname": "notes", + "fieldtype": "Small Text", + "label": "Notes" + }, + { + "fieldname": "status", + "fieldtype": "Select", + "hidden": 1, + "label": "Status", + "options": "Draft\nActive\nCancelled", + "read_only": 1 + }, + { + "fieldname": "column_break_15", + "fieldtype": "Column Break" + } + ], + "in_create": 1, + "index_web_pages_for_search": 1, + "is_submittable": 1, + "links": [], + "modified": "2022-11-01 11:44:15.256470", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset Depreciation Schedule", + "naming_rule": "By \"Naming Series\" field", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py new file mode 100644 index 0000000000..625c3bdb1f --- /dev/null +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class AssetDepreciationSchedule(Document): + pass diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py new file mode 100644 index 0000000000..21de8cde51 --- /dev/null +++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py @@ -0,0 +1,9 @@ +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestAssetDepreciationSchedule(FrappeTestCase): + pass From 710d2452b7c32fbf50bc7b594e0f2388a81cc0be Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 11 Nov 2022 16:20:17 +0530 Subject: [PATCH 02/94] feat: moving, refactoring and adding functions to asset_depreciation_schedule --- erpnext/assets/doctype/asset/asset.json | 7 +- erpnext/assets/doctype/asset/asset.py | 38 +- erpnext/assets/doctype/asset/test_asset.py | 4 +- .../asset_depreciation_schedule.json | 26 +- .../asset_depreciation_schedule.py | 326 +++++++++++++++++- .../asset_value_adjustment.py | 4 +- 6 files changed, 360 insertions(+), 45 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index f0505ff983..9af03ca0e7 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -508,9 +508,14 @@ "group": "Value", "link_doctype": "Asset Value Adjustment", "link_fieldname": "asset" + }, + { + "group": "Depreciation", + "link_doctype": "Asset Depreciation Schedule", + "link_fieldname": "asset" } ], - "modified": "2022-07-20 10:15:12.887372", + "modified": "2022-11-01 15:25:27.669803", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index ca6be9b57b..449723b0aa 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -15,6 +15,7 @@ from frappe.utils import ( flt, get_datetime, get_last_day, + is_last_day_of_the_month, getdate, month_diff, nowdate, @@ -27,6 +28,10 @@ from erpnext.assets.doctype.asset.depreciation import ( get_depreciation_accounts, get_disposal_account_and_cost_center, ) +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + make_draft_asset_depreciation_schedules, + modify_draft_asset_depreciation_schedules, +) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.controllers.accounts_controller import AccountsController @@ -40,6 +45,7 @@ class Asset(AccountsController): self.set_missing_values() if not self.split_from: self.prepare_depreciation_data() + modify_draft_asset_depreciation_schedules(self) self.validate_gross_and_purchase_amount() if self.get("schedules"): self.validate_expected_value_after_useful_life() @@ -62,6 +68,10 @@ class Asset(AccountsController): make_reverse_gl_entries(voucher_type="Asset", voucher_no=self.name) self.db_set("booked_fixed_asset", 0) + def after_insert(self): + if not self.split_from: + make_draft_asset_depreciation_schedules(self) + def validate_asset_and_reference(self): if self.purchase_invoice or self.purchase_receipt: reference_doc = "Purchase Invoice" if self.purchase_invoice else "Purchase Receipt" @@ -83,8 +93,6 @@ class Asset(AccountsController): if self.calculate_depreciation: self.value_after_depreciation = 0 self.set_depreciation_rate() - self.make_depreciation_schedule(date_of_disposal) - self.set_accumulated_depreciation(date_of_disposal, date_of_return) else: self.finance_books = [] self.value_after_depreciation = flt(self.gross_purchase_amount) - flt( @@ -1072,32 +1080,6 @@ def get_total_days(date, frequency): return date_diff(date, period_start_date) -def is_last_day_of_the_month(date): - last_day_of_the_month = get_last_day(date) - - return getdate(last_day_of_the_month) == getdate(date) - - -@erpnext.allow_regional -def get_depreciation_amount(asset, depreciable_value, row): - if row.depreciation_method in ("Straight Line", "Manual"): - # if the Depreciation Schedule is being prepared for the first time - if not asset.flags.increase_in_asset_life: - depreciation_amount = ( - flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) - ) / flt(row.total_number_of_depreciations) - - # if the Depreciation Schedule is being modified after Asset Repair - else: - depreciation_amount = ( - flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life) - ) / (date_diff(asset.to_date, asset.available_for_use_date) / 365) - else: - depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100)) - - return depreciation_amount - - @frappe.whitelist() def split_asset(asset_name, split_qty): asset = frappe.get_doc("Asset", asset_name) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 370b13bb98..7084ea58f8 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -865,7 +865,9 @@ class TestDepreciationBasics(AssetSetup): def test_get_depreciation_amount(self): """Tests if get_depreciation_amount() returns the right value.""" - from erpnext.assets.doctype.asset.asset import get_depreciation_amount + from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depreciation_amount + ) asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31") diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index 06eced229f..49bd2e7faa 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -8,15 +8,15 @@ "engine": "InnoDB", "field_order": [ "asset", - "column_break_2", "naming_series", - "depreciation_details_section", + "column_break_2", "finance_book", + "depreciation_details_section", "depreciation_method", - "rate_of_depreciation", - "column_break_8", "total_number_of_depreciations", - "frequency_of_depreciation_months", + "column_break_8", + "frequency_of_depreciation", + "rate_of_depreciation", "depreciation_schedule_section", "depreciation_schedule", "details_section", @@ -92,13 +92,6 @@ "label": "Total Number of Depreciations", "read_only": 1 }, - { - "depends_on": "frequency_of_depreciation_months", - "fieldname": "frequency_of_depreciation_months", - "fieldtype": "Int", - "label": "Frequency of Depreciation (Months)", - "read_only": 1 - }, { "fieldname": "depreciation_schedule_section", "fieldtype": "Section Break", @@ -133,13 +126,20 @@ { "fieldname": "column_break_15", "fieldtype": "Column Break" + }, + { + "depends_on": "frequency_of_depreciation", + "fieldname": "frequency_of_depreciation", + "fieldtype": "Int", + "label": "Frequency of Depreciation (Months)", + "read_only": 1 } ], "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-11-01 11:44:15.256470", + "modified": "2022-11-01 17:23:33.873283", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 625c3bdb1f..1a545dd81a 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -1,8 +1,332 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -# import frappe +import frappe +from frappe.utils import ( + add_days, + add_months, + cint, + date_diff, + flt, + get_last_day, + is_last_day_of_the_month +) from frappe.model.document import Document +import erpnext + + class AssetDepreciationSchedule(Document): pass + + +def make_draft_asset_depreciation_schedules(asset): + for row in asset.get("finance_books"): + asset_depr_schedule = frappe.new_doc("Asset Depreciation Schedule") + + prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row) + + +def modify_draft_asset_depreciation_schedules(asset): + for row in asset.get("finance_books"): + asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name(asset.name, row) + + if not asset_depr_schedule_name: + return + + asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + + prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row) + + +def prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row): + set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset.name, row) + make_depreciation_schedule(asset_depr_schedule, asset, row) + set_accumulated_depreciation(asset_depr_schedule, asset, row) + + asset_depr_schedule.save() + + +def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_name, row): + asset_depr_schedule.asset = asset_name + asset_depr_schedule.finance_book = row.finance_book + asset_depr_schedule.depreciation_method = row.depreciation_method + asset_depr_schedule.total_number_of_depreciations = row.total_number_of_depreciations + asset_depr_schedule.frequency_of_depreciation = row.frequency_of_depreciation + asset_depr_schedule.rate_of_depreciation = row.rate_of_depreciation + asset_depr_schedule.status = "Draft" + + +def make_new_active_asset_depreciation_schedules_from_existing( + asset, date_of_disposal=None, date_of_return=None +): + for row in asset.get("finance_books"): + old_asset_depr_schedule_name = get_active_asset_depreciation_schedule(asset.name, row) + + if not old_asset_depr_schedule_name: + return + + old_asset_depr_schedule = frappe.get_doc( + "Asset Depreciation Schedule", + old_asset_depr_schedule_name + ) + + asset_depr_schedule = frappe.copy_doc(old_asset_depr_schedule, ignore_no_copy=False) + + make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal) + set_accumulated_depreciation(asset_depr_schedule, asset, row, date_of_disposal, date_of_return) + + asset_depr_schedule.save() + + +def make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal): + if row.depreciation_method != "Manual" and not asset_depr_schedule.get("depreciation_schedule"): + asset_depr_schedule.depreciation_schedule = [] + + if not asset.available_for_use_date: + return + + start = clear_depreciation_schedule(asset_depr_schedule) + + _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_disposal) + + +def get_draft_asset_depreciation_schedule_name(asset_name, finance_book): + return frappe.db.get_value( + "Asset Depreciation Schedule", + {"asset": asset_name, "finance_book": finance_book, "status": "Draft", "docstatus": 0}, + ) + + +def get_active_asset_depreciation_schedule(asset_name, finance_book): + return frappe.db.get_value( + "Asset Depreciation Schedule", + {"asset": asset_name, "finance_book": finance_book, "status": "Active", "docstatus": 1}, + ) + + +def clear_depreciation_schedule(asset_depr_schedule): + start = [] + num_of_depreciations_completed = 0 + depr_schedule = [] + + for schedule in asset_depr_schedule.get("depreciation_schedule"): + if len(start) != 0: + break + + if schedule.journal_entry: + num_of_depreciations_completed += 1 + depr_schedule.append(schedule) + else: + start.append(num_of_depreciations_completed) + num_of_depreciations_completed = 0 + + # to update start when all the schedule rows corresponding to the FB are linked with JEs + if len(start) == 0: + start.append(num_of_depreciations_completed) + + # when the Depreciation Schedule is being created for the first time + if start == []: + start = [0] + else: + asset_depr_schedule.depreciation_schedule = depr_schedule + + return start + + +def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_disposal): + asset.validate_asset_finance_books(row) + + value_after_depreciation = asset._get_value_after_depreciation(row) + row.value_after_depreciation = value_after_depreciation + + number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint( + asset.number_of_depreciations_booked + ) + + has_pro_rata = asset.check_is_pro_rata(row) + if has_pro_rata: + number_of_pending_depreciations += 1 + + skip_row = False + should_get_last_day = is_last_day_of_the_month(row.depreciation_start_date) + + for n in range(start[row.idx - 1], number_of_pending_depreciations): + # If depreciation is already completed (for double declining balance) + if skip_row: + continue + + depreciation_amount = get_depreciation_amount(asset, value_after_depreciation, row) + + if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1: + 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 will be a year later from start date + # so monthly schedule date is calculated by removing 11 months from it + monthly_schedule_date = add_months(schedule_date, -row.frequency_of_depreciation + 1) + + # if asset is being sold or scrapped + if date_of_disposal: + from_date = asset.get_from_date(row.finance_book) + depreciation_amount, days, months = asset.get_pro_rata_amt( + row, depreciation_amount, from_date, date_of_disposal + ) + + if depreciation_amount > 0: + add_depr_schedule_row( + asset_depr_schedule, + date_of_disposal, + depreciation_amount, + row.depreciation_method, + row.finance_book, + row.idx, + ) + + break + + # For first row + if has_pro_rata and not asset.opening_accumulated_depreciation and n == 0: + from_date = add_days( + asset.available_for_use_date, -1 + ) # needed to calc depr amount for available_for_use_date too + depreciation_amount, days, months = asset.get_pro_rata_amt( + row, depreciation_amount, from_date, row.depreciation_start_date + ) + + # For first depr schedule date will be the start date + # so monthly schedule date is calculated by removing + # month difference between use date and start date + monthly_schedule_date = add_months(row.depreciation_start_date, -months + 1) + + # For last row + elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1: + if not asset.flags.increase_in_asset_life: + # In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission + asset.to_date = add_months( + asset.available_for_use_date, + (n + asset.number_of_depreciations_booked) * cint(row.frequency_of_depreciation), + ) + + depreciation_amount_without_pro_rata = depreciation_amount + + depreciation_amount, days, months = asset.get_pro_rata_amt( + row, depreciation_amount, schedule_date, asset.to_date + ) + + depreciation_amount = asset.get_adjusted_depreciation_amount( + depreciation_amount_without_pro_rata, depreciation_amount, row.finance_book + ) + + monthly_schedule_date = add_months(schedule_date, 1) + schedule_date = add_days(schedule_date, days) + last_schedule_date = schedule_date + + if not depreciation_amount: + continue + value_after_depreciation -= flt(depreciation_amount, asset.precision("gross_purchase_amount")) + + # Adjust depreciation amount in the last period based on the expected value after useful life + if row.expected_value_after_useful_life and ( + ( + n == cint(number_of_pending_depreciations) - 1 + and value_after_depreciation != row.expected_value_after_useful_life + ) + or value_after_depreciation < row.expected_value_after_useful_life + ): + depreciation_amount += value_after_depreciation - row.expected_value_after_useful_life + skip_row = True + + if depreciation_amount > 0: + add_depr_schedule_row( + asset_depr_schedule, + schedule_date, + depreciation_amount, + row.depreciation_method, + row.finance_book, + row.idx, + ) + + +@erpnext.allow_regional +def get_depreciation_amount(asset, depreciable_value, row): + if row.depreciation_method in ("Straight Line", "Manual"): + # if the Depreciation Schedule is being prepared for the first time + if not asset.flags.increase_in_asset_life: + depreciation_amount = ( + flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) + ) / flt(row.total_number_of_depreciations) + + # if the Depreciation Schedule is being modified after Asset Repair + else: + depreciation_amount = ( + flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life) + ) / (date_diff(asset.to_date, asset.available_for_use_date) / 365) + else: + depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100)) + + return depreciation_amount + + +def add_depr_schedule_row( + asset_depr_schedule, + schedule_date, + depreciation_amount, + depreciation_method, + finance_book, + finance_book_id +): + asset_depr_schedule.append( + "depreciation_schedule", + { + "schedule_date": schedule_date, + "depreciation_amount": depreciation_amount, + "depreciation_method": depreciation_method, + "finance_book": finance_book, + "finance_book_id": finance_book_id, + }, + ) + + +def set_accumulated_depreciation( + asset_depr_schedule, asset, row, date_of_disposal, date_of_return, ignore_booked_entry=False +): + straight_line_idx = [ + d.idx for d in asset_depr_schedule.get("depreciation_schedule") + if d.depreciation_method == "Straight Line" + ] + finance_books = [] + + for i, d in enumerate(asset_depr_schedule.get("depreciation_schedule")): + if ignore_booked_entry and d.journal_entry: + continue + + if int(d.finance_book_id) not in finance_books: + accumulated_depreciation = flt(asset.opening_accumulated_depreciation) + value_after_depreciation = flt(asset.get_value_after_depreciation(d.finance_book_id)) + finance_books.append(int(d.finance_book_id)) + + depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) + value_after_depreciation -= flt(depreciation_amount) + + # for the last row, if depreciation method = Straight Line + if ( + straight_line_idx + and i == max(straight_line_idx) - 1 + and not date_of_disposal + and not date_of_return + ): + depreciation_amount += flt( + value_after_depreciation - flt(row.expected_value_after_useful_life), + d.precision("depreciation_amount"), + ) + + d.depreciation_amount = depreciation_amount + accumulated_depreciation += d.depreciation_amount + d.accumulated_depreciation_amount = flt( + accumulated_depreciation, d.precision("accumulated_depreciation_amount") + ) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 84aa8fa023..ae6e2b426e 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -10,7 +10,9 @@ from frappe.utils import cint, date_diff, flt, formatdate, getdate from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, ) -from erpnext.assets.doctype.asset.asset import get_depreciation_amount +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depreciation_amount +) from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts From 97ab7bd36bb9ffb1b488edcddf512164020710c7 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 11 Nov 2022 16:27:29 +0530 Subject: [PATCH 03/94] chore: remove some unwanted functions in asset --- erpnext/assets/doctype/asset/asset.py | 144 +------------------------- 1 file changed, 1 insertion(+), 143 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 449723b0aa..f55dceddf0 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -89,7 +89,7 @@ class Asset(AccountsController): _("Purchase Invoice cannot be made against an existing asset {0}").format(self.name) ) - def prepare_depreciation_data(self, date_of_disposal=None, date_of_return=None): + def prepare_depreciation_data(self): if self.calculate_depreciation: self.value_after_depreciation = 0 self.set_depreciation_rate() @@ -231,148 +231,6 @@ class Asset(AccountsController): self.get_depreciation_rate(d, on_validate=True), d.precision("rate_of_depreciation") ) - def make_depreciation_schedule(self, date_of_disposal): - if "Manual" not in [d.depreciation_method for d in self.finance_books] and not self.get( - "schedules" - ): - self.schedules = [] - - if not self.available_for_use_date: - return - - start = self.clear_depreciation_schedule() - - for finance_book in self.get("finance_books"): - self._make_depreciation_schedule(finance_book, start, date_of_disposal) - - def _make_depreciation_schedule(self, finance_book, start, date_of_disposal): - self.validate_asset_finance_books(finance_book) - - value_after_depreciation = self._get_value_after_depreciation(finance_book) - finance_book.value_after_depreciation = value_after_depreciation - - number_of_pending_depreciations = cint(finance_book.total_number_of_depreciations) - cint( - self.number_of_depreciations_booked - ) - - has_pro_rata = self.check_is_pro_rata(finance_book) - if has_pro_rata: - number_of_pending_depreciations += 1 - - skip_row = False - should_get_last_day = is_last_day_of_the_month(finance_book.depreciation_start_date) - - for n in range(start[finance_book.idx - 1], number_of_pending_depreciations): - # If depreciation is already completed (for double declining balance) - if skip_row: - continue - - depreciation_amount = get_depreciation_amount(self, value_after_depreciation, finance_book) - - if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1: - schedule_date = add_months( - finance_book.depreciation_start_date, n * cint(finance_book.frequency_of_depreciation) - ) - - if should_get_last_day: - schedule_date = get_last_day(schedule_date) - - # schedule date will be a year later from start date - # so monthly schedule date is calculated by removing 11 months from it - monthly_schedule_date = add_months(schedule_date, -finance_book.frequency_of_depreciation + 1) - - # if asset is being sold - if date_of_disposal: - from_date = self.get_from_date(finance_book.finance_book) - depreciation_amount, days, months = self.get_pro_rata_amt( - finance_book, depreciation_amount, from_date, date_of_disposal - ) - - if depreciation_amount > 0: - self._add_depreciation_row( - date_of_disposal, - depreciation_amount, - finance_book.depreciation_method, - finance_book.finance_book, - finance_book.idx, - ) - - break - - # For first row - if has_pro_rata and not self.opening_accumulated_depreciation and n == 0: - from_date = add_days( - self.available_for_use_date, -1 - ) # needed to calc depr amount for available_for_use_date too - depreciation_amount, days, months = self.get_pro_rata_amt( - finance_book, depreciation_amount, from_date, finance_book.depreciation_start_date - ) - - # For first depr schedule date will be the start date - # so monthly schedule date is calculated by removing month difference between use date and start date - monthly_schedule_date = add_months(finance_book.depreciation_start_date, -months + 1) - - # For last row - elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1: - if not self.flags.increase_in_asset_life: - # In case of increase_in_asset_life, the self.to_date is already set on asset_repair submission - self.to_date = add_months( - self.available_for_use_date, - (n + self.number_of_depreciations_booked) * cint(finance_book.frequency_of_depreciation), - ) - - depreciation_amount_without_pro_rata = depreciation_amount - - depreciation_amount, days, months = self.get_pro_rata_amt( - finance_book, depreciation_amount, schedule_date, self.to_date - ) - - depreciation_amount = self.get_adjusted_depreciation_amount( - depreciation_amount_without_pro_rata, depreciation_amount, finance_book.finance_book - ) - - monthly_schedule_date = add_months(schedule_date, 1) - schedule_date = add_days(schedule_date, days) - last_schedule_date = schedule_date - - if not depreciation_amount: - continue - value_after_depreciation -= flt(depreciation_amount, self.precision("gross_purchase_amount")) - - # Adjust depreciation amount in the last period based on the expected value after useful life - if finance_book.expected_value_after_useful_life and ( - ( - n == cint(number_of_pending_depreciations) - 1 - and value_after_depreciation != finance_book.expected_value_after_useful_life - ) - or value_after_depreciation < finance_book.expected_value_after_useful_life - ): - depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life - skip_row = True - - if depreciation_amount > 0: - self._add_depreciation_row( - schedule_date, - depreciation_amount, - finance_book.depreciation_method, - finance_book.finance_book, - finance_book.idx, - ) - - def _add_depreciation_row( - self, schedule_date, depreciation_amount, depreciation_method, finance_book, finance_book_id - ): - self.append( - "schedules", - { - "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount, - "depreciation_method": depreciation_method, - "finance_book": finance_book, - "finance_book_id": finance_book_id, - }, - ) - def _get_value_after_depreciation(self, finance_book): # value_after_depreciation - current Asset value if self.docstatus == 1 and finance_book.value_after_depreciation: From ed495dc846d6f1f0939103d18be850dd0285c9c6 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 14 Nov 2022 12:45:49 +0530 Subject: [PATCH 04/94] chore: add convert_draft_asset_depreciation_schedules_into_active and fix some bugs --- erpnext/assets/doctype/asset/asset.py | 41 +------------------ .../asset_depreciation_schedule.py | 33 +++++++++++++-- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index f55dceddf0..5fe756859f 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -31,6 +31,7 @@ from erpnext.assets.doctype.asset.depreciation import ( from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( make_draft_asset_depreciation_schedules, modify_draft_asset_depreciation_schedules, + convert_draft_asset_depreciation_schedules_into_active, ) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.controllers.accounts_controller import AccountsController @@ -58,6 +59,7 @@ class Asset(AccountsController): self.make_asset_movement() if not self.booked_fixed_asset and self.validate_make_gl_entry(): self.make_gl_entries() + convert_draft_asset_depreciation_schedules_into_active(self) def on_cancel(self): self.validate_cancellation() @@ -407,45 +409,6 @@ class Asset(AccountsController): if len(self.finance_books) == 1: return True - def set_accumulated_depreciation( - self, date_of_sale=None, date_of_return=None, ignore_booked_entry=False - ): - straight_line_idx = [ - d.idx for d in self.get("schedules") if d.depreciation_method == "Straight Line" - ] - finance_books = [] - - for i, d in enumerate(self.get("schedules")): - if ignore_booked_entry and d.journal_entry: - continue - - if int(d.finance_book_id) not in finance_books: - accumulated_depreciation = flt(self.opening_accumulated_depreciation) - value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id)) - finance_books.append(int(d.finance_book_id)) - - depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) - value_after_depreciation -= flt(depreciation_amount) - - # for the last row, if depreciation method = Straight Line - if ( - straight_line_idx - and i == max(straight_line_idx) - 1 - and not date_of_sale - and not date_of_return - ): - book = self.get("finance_books")[cint(d.finance_book_id) - 1] - depreciation_amount += flt( - value_after_depreciation - flt(book.expected_value_after_useful_life), - d.precision("depreciation_amount"), - ) - - d.depreciation_amount = depreciation_amount - accumulated_depreciation += d.depreciation_amount - d.accumulated_depreciation_amount = flt( - accumulated_depreciation, d.precision("accumulated_depreciation_amount") - ) - def get_value_after_depreciation(self, idx): return flt(self.get("finance_books")[cint(idx) - 1].value_after_depreciation) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 1a545dd81a..27920e3933 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -29,7 +29,9 @@ def make_draft_asset_depreciation_schedules(asset): def modify_draft_asset_depreciation_schedules(asset): for row in asset.get("finance_books"): - asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name(asset.name, row) + asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name( + asset.name, row.finance_book + ) if not asset_depr_schedule_name: return @@ -57,11 +59,29 @@ def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_nam asset_depr_schedule.status = "Draft" +def convert_draft_asset_depreciation_schedules_into_active(asset): + for row in asset.get("finance_books"): + asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name( + asset.name, row.finance_book + ) + + if not asset_depr_schedule_name: + return + + asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + + asset_depr_schedule.status = "Active" + + asset_depr_schedule.submit() + + def make_new_active_asset_depreciation_schedules_from_existing( asset, date_of_disposal=None, date_of_return=None ): for row in asset.get("finance_books"): - old_asset_depr_schedule_name = get_active_asset_depreciation_schedule(asset.name, row) + old_asset_depr_schedule_name = get_active_asset_depreciation_schedule( + asset.name, row.finance_book + ) if not old_asset_depr_schedule_name: return @@ -79,7 +99,7 @@ def make_new_active_asset_depreciation_schedules_from_existing( asset_depr_schedule.save() -def make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal): +def make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal=None): if row.depreciation_method != "Manual" and not asset_depr_schedule.get("depreciation_schedule"): asset_depr_schedule.depreciation_schedule = [] @@ -293,7 +313,12 @@ def add_depr_schedule_row( def set_accumulated_depreciation( - asset_depr_schedule, asset, row, date_of_disposal, date_of_return, ignore_booked_entry=False + asset_depr_schedule, + asset, + row, + date_of_disposal=None, + date_of_return=None, + ignore_booked_entry=False ): straight_line_idx = [ d.idx for d in asset_depr_schedule.get("depreciation_schedule") From ca3581d05531b2dba59db73a08a8076857b293d1 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 14 Nov 2022 12:47:48 +0530 Subject: [PATCH 05/94] chore: rename modify_draft_asset_depreciation_schedules --- erpnext/assets/doctype/asset/asset.py | 4 ++-- .../asset_depreciation_schedule.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 5fe756859f..85b309fad4 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -30,8 +30,8 @@ from erpnext.assets.doctype.asset.depreciation import ( ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( make_draft_asset_depreciation_schedules, - modify_draft_asset_depreciation_schedules, convert_draft_asset_depreciation_schedules_into_active, + update_draft_asset_depreciation_schedules, ) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.controllers.accounts_controller import AccountsController @@ -46,7 +46,7 @@ class Asset(AccountsController): self.set_missing_values() if not self.split_from: self.prepare_depreciation_data() - modify_draft_asset_depreciation_schedules(self) + update_draft_asset_depreciation_schedules(self) self.validate_gross_and_purchase_amount() if self.get("schedules"): self.validate_expected_value_after_useful_life() diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 27920e3933..7bb8b0e01d 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -27,7 +27,7 @@ def make_draft_asset_depreciation_schedules(asset): prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row) -def modify_draft_asset_depreciation_schedules(asset): +def update_draft_asset_depreciation_schedules(asset): for row in asset.get("finance_books"): asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name( asset.name, row.finance_book From ffd41703dee89032d065dad9e10e03ae2506480e Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 14 Nov 2022 14:36:10 +0530 Subject: [PATCH 06/94] chore: add expected_value_after_useful_life in depr schedule --- .../asset_depreciation_schedule.json | 13 +++++++++++-- .../asset_depreciation_schedule.py | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index 49bd2e7faa..83ed089de8 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -14,9 +14,10 @@ "depreciation_details_section", "depreciation_method", "total_number_of_depreciations", + "rate_of_depreciation", "column_break_8", "frequency_of_depreciation", - "rate_of_depreciation", + "expected_value_after_useful_life", "depreciation_schedule_section", "depreciation_schedule", "details_section", @@ -133,13 +134,21 @@ "fieldtype": "Int", "label": "Frequency of Depreciation (Months)", "read_only": 1 + }, + { + "default": "0", + "fieldname": "expected_value_after_useful_life", + "fieldtype": "Currency", + "label": "Expected Value After Useful Life", + "options": "Company:company:default_currency", + "read_only": 1 } ], "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-11-01 17:23:33.873283", + "modified": "2022-11-14 14:33:53.360643", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 7bb8b0e01d..f04a9fdd24 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -56,6 +56,7 @@ def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_nam asset_depr_schedule.total_number_of_depreciations = row.total_number_of_depreciations asset_depr_schedule.frequency_of_depreciation = row.frequency_of_depreciation asset_depr_schedule.rate_of_depreciation = row.rate_of_depreciation + asset_depr_schedule.expected_value_after_useful_life = row.expected_value_after_useful_life asset_depr_schedule.status = "Draft" From 417180e6ba7e9dd6ef6f35911c05f72b80063f1c Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 14 Nov 2022 17:51:11 +0530 Subject: [PATCH 07/94] chore: refactor some functions to use new depr schedule --- erpnext/assets/doctype/asset/asset.py | 101 +++++++----------- .../asset_depreciation_schedule.py | 23 ++-- 2 files changed, 47 insertions(+), 77 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 85b309fad4..b8f368a2e6 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -30,6 +30,7 @@ from erpnext.assets.doctype.asset.depreciation import ( ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( make_draft_asset_depreciation_schedules, + get_asset_depreciation_schedule_name, convert_draft_asset_depreciation_schedules_into_active, update_draft_asset_depreciation_schedules, ) @@ -48,8 +49,7 @@ class Asset(AccountsController): self.prepare_depreciation_data() update_draft_asset_depreciation_schedules(self) self.validate_gross_and_purchase_amount() - if self.get("schedules"): - self.validate_expected_value_after_useful_life() + self.validate_expected_value_after_useful_life() self.status = self.get_status() @@ -244,57 +244,17 @@ class Asset(AccountsController): return value_after_depreciation - # depreciation schedules need to be cleared before modification due to increase in asset life/asset sales - # JE: Journal Entry, FB: Finance Book - def clear_depreciation_schedule(self): - start = [] - num_of_depreciations_completed = 0 - depr_schedule = [] - - for schedule in self.get("schedules"): - # to update start when there are JEs linked with all the schedule rows corresponding to an FB - if len(start) == (int(schedule.finance_book_id) - 2): - start.append(num_of_depreciations_completed) - num_of_depreciations_completed = 0 - - # to ensure that start will only be updated once for each FB - if len(start) == (int(schedule.finance_book_id) - 1): - if schedule.journal_entry: - num_of_depreciations_completed += 1 - depr_schedule.append(schedule) - else: - start.append(num_of_depreciations_completed) - num_of_depreciations_completed = 0 - - # to update start when all the schedule rows corresponding to the last FB are linked with JEs - if len(start) == (len(self.finance_books) - 1): - start.append(num_of_depreciations_completed) - - # when the Depreciation Schedule is being created for the first time - if start == []: - start = [0] * len(self.finance_books) - else: - self.schedules = depr_schedule - - return start - def get_from_date(self, finance_book): - if not self.get("schedules"): + asset_depr_schedule_name = get_asset_depreciation_schedule_name( + self.name, finance_book + ) + + if not asset_depr_schedule_name: return self.available_for_use_date - if len(self.finance_books) == 1: - return self.schedules[-1].schedule_date + asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) - from_date = "" - for schedule in self.get("schedules"): - if schedule.finance_book == finance_book: - from_date = schedule.schedule_date - - if from_date: - return from_date - - # since depr for available_for_use_date is not yet booked - return add_days(self.available_for_use_date, -1) + return asset_depr_schedule.get("depreciation_schedule")[-1].schedule_date # if it returns True, depreciation_amount will not be equal for the first and last rows def check_is_pro_rata(self, row): @@ -398,26 +358,29 @@ class Asset(AccountsController): return depreciation_amount_for_last_row def get_depreciation_amount_for_first_row(self, finance_book): - if self.has_only_one_finance_book(): - return self.schedules[0].depreciation_amount - else: - for schedule in self.schedules: - if schedule.finance_book == finance_book: - return schedule.depreciation_amount + asset_depr_schedule_name = get_asset_depreciation_schedule_name(self.name, finance_book) - def has_only_one_finance_book(self): - if len(self.finance_books) == 1: - return True + asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + + return asset_depr_schedule.get("depreciation_schedule")[0].depreciation_amount def get_value_after_depreciation(self, idx): return flt(self.get("finance_books")[cint(idx) - 1].value_after_depreciation) def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): + asset_depr_schedule_name = get_asset_depreciation_schedule_name( + self.name, row.finance_book + ) + + if not asset_depr_schedule_name: + return + + asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + accumulated_depreciation_after_full_schedule = [ d.accumulated_depreciation_amount - for d in self.get("schedules") - if cint(d.finance_book_id) == row.idx + for d in asset_depr_schedule.get("depreciation_schedule") ] if accumulated_depreciation_after_full_schedule: @@ -466,10 +429,20 @@ class Asset(AccountsController): movement.cancel() def delete_depreciation_entries(self): - for d in self.get("schedules"): - if d.journal_entry: - frappe.get_doc("Journal Entry", d.journal_entry).cancel() - d.db_set("journal_entry", None) + for row in self.get("finance_books"): + asset_depr_schedule_name = get_asset_depreciation_schedule_name( + self.name, row.finance_book + ) + + if not asset_depr_schedule_name: + return + + asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + + for d in asset_depr_schedule.get("depreciation_schedule"): + if d.journal_entry: + frappe.get_doc("Journal Entry", d.journal_entry).cancel() + d.db_set("journal_entry", None) self.db_set( "value_after_depreciation", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index f04a9fdd24..ae3707b82f 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -29,7 +29,7 @@ def make_draft_asset_depreciation_schedules(asset): def update_draft_asset_depreciation_schedules(asset): for row in asset.get("finance_books"): - asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name( + asset_depr_schedule_name = get_asset_depreciation_schedule_name( asset.name, row.finance_book ) @@ -62,7 +62,7 @@ def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_nam def convert_draft_asset_depreciation_schedules_into_active(asset): for row in asset.get("finance_books"): - asset_depr_schedule_name = get_draft_asset_depreciation_schedule_name( + asset_depr_schedule_name = get_asset_depreciation_schedule_name( asset.name, row.finance_book ) @@ -80,7 +80,7 @@ def make_new_active_asset_depreciation_schedules_from_existing( asset, date_of_disposal=None, date_of_return=None ): for row in asset.get("finance_books"): - old_asset_depr_schedule_name = get_active_asset_depreciation_schedule( + old_asset_depr_schedule_name = get_asset_depreciation_schedule_name( asset.name, row.finance_book ) @@ -112,17 +112,14 @@ def make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_disposal) -def get_draft_asset_depreciation_schedule_name(asset_name, finance_book): +def get_asset_depreciation_schedule_name(asset_name, finance_book): return frappe.db.get_value( - "Asset Depreciation Schedule", - {"asset": asset_name, "finance_book": finance_book, "status": "Draft", "docstatus": 0}, - ) - - -def get_active_asset_depreciation_schedule(asset_name, finance_book): - return frappe.db.get_value( - "Asset Depreciation Schedule", - {"asset": asset_name, "finance_book": finance_book, "status": "Active", "docstatus": 1}, + doctype="Asset Depreciation Schedule", + filters=[ + ["asset", "=", asset_name], + ["finance_book", "=", finance_book], + ["docstatus", "<", 2], + ] ) From 76f28de7eb11652ca6006d1346dd51ad7a701936 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Wed, 23 Nov 2022 18:04:54 +0530 Subject: [PATCH 08/94] chore: refactor more functions to use new depr schedule --- erpnext/assets/doctype/asset/asset.py | 26 +-- erpnext/assets/doctype/asset/depreciation.py | 46 +++-- .../asset_depreciation_schedule.py | 184 ++++++++++-------- .../doctype/asset_repair/asset_repair.py | 13 +- 4 files changed, 149 insertions(+), 120 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index b8f368a2e6..6a248b0f8f 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -8,15 +8,14 @@ import math import frappe from frappe import _ from frappe.utils import ( - add_days, add_months, cint, date_diff, flt, get_datetime, get_last_day, - is_last_day_of_the_month, getdate, + is_last_day_of_the_month, month_diff, nowdate, today, @@ -28,13 +27,13 @@ from erpnext.assets.doctype.asset.depreciation import ( get_depreciation_accounts, get_disposal_account_and_cost_center, ) +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - make_draft_asset_depreciation_schedules, - get_asset_depreciation_schedule_name, convert_draft_asset_depreciation_schedules_into_active, + get_asset_depreciation_schedule, + make_draft_asset_depreciation_schedules, update_draft_asset_depreciation_schedules, ) -from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.controllers.accounts_controller import AccountsController @@ -245,9 +244,7 @@ class Asset(AccountsController): return value_after_depreciation def get_from_date(self, finance_book): - asset_depr_schedule_name = get_asset_depreciation_schedule_name( - self.name, finance_book - ) + asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, finance_book) if not asset_depr_schedule_name: return self.available_for_use_date @@ -358,7 +355,7 @@ class Asset(AccountsController): return depreciation_amount_for_last_row def get_depreciation_amount_for_first_row(self, finance_book): - asset_depr_schedule_name = get_asset_depreciation_schedule_name(self.name, finance_book) + asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, finance_book) asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) @@ -369,9 +366,7 @@ class Asset(AccountsController): def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule_name( - self.name, row.finance_book - ) + asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, row.finance_book) if not asset_depr_schedule_name: return @@ -379,8 +374,7 @@ class Asset(AccountsController): asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) accumulated_depreciation_after_full_schedule = [ - d.accumulated_depreciation_amount - for d in asset_depr_schedule.get("depreciation_schedule") + d.accumulated_depreciation_amount for d in asset_depr_schedule.get("depreciation_schedule") ] if accumulated_depreciation_after_full_schedule: @@ -430,9 +424,7 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule_name( - self.name, row.finance_book - ) + asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, row.finance_book) if not asset_depr_schedule_name: return diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 97941706aa..49f167ef1c 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -10,6 +10,9 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, ) from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + make_temp_asset_depreciation_schedule, +) def post_depreciation_entries(date=None, commit=True): @@ -499,24 +502,27 @@ def get_disposal_account_and_cost_center(company): def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_book=None): asset_doc = frappe.get_doc("Asset", asset) - if asset_doc.calculate_depreciation: - asset_doc.prepare_depreciation_data(getdate(disposal_date)) - - finance_book_id = 1 - if finance_book: - for fb in asset_doc.finance_books: - if fb.finance_book == finance_book: - finance_book_id = fb.idx - break - - asset_schedules = [ - sch for sch in asset_doc.schedules if cint(sch.finance_book_id) == finance_book_id - ] - accumulated_depr_amount = asset_schedules[-1].accumulated_depreciation_amount - - return flt( - flt(asset_doc.gross_purchase_amount) - accumulated_depr_amount, - asset_doc.precision("gross_purchase_amount"), - ) - else: + if not asset_doc.calculate_depreciation: return flt(asset_doc.value_after_depreciation) + + idx = 1 + if finance_book: + for d in asset.finance_books: + if d.finance_book == finance_book: + idx = d.idx + break + + row = asset_doc.finance_books[idx - 1] + + temp_asset_depreciation_schedule = make_temp_asset_depreciation_schedule( + asset_doc, row, getdate(disposal_date) + ) + + depr_schedule = temp_asset_depreciation_schedule.get("depreciation_schedule") + + accumulated_depr_amount = depr_schedule[-1].accumulated_depreciation_amount + + return flt( + flt(asset_doc.gross_purchase_amount) - accumulated_depr_amount, + asset_doc.precision("gross_purchase_amount"), + ) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index ae3707b82f..9df4241b57 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -2,6 +2,7 @@ # For license information, please see license.txt import frappe +from frappe.model.document import Document from frappe.utils import ( add_days, add_months, @@ -9,9 +10,8 @@ from frappe.utils import ( date_diff, flt, get_last_day, - is_last_day_of_the_month + is_last_day_of_the_month, ) -from frappe.model.document import Document import erpnext @@ -20,37 +20,47 @@ class AssetDepreciationSchedule(Document): pass -def make_draft_asset_depreciation_schedules(asset): - for row in asset.get("finance_books"): +def make_draft_asset_depreciation_schedules(asset_doc, date_of_disposal=None, date_of_return=None): + for row in asset_doc.get("finance_books"): asset_depr_schedule = frappe.new_doc("Asset Depreciation Schedule") - prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row) - - -def update_draft_asset_depreciation_schedules(asset): - for row in asset.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule_name( - asset.name, row.finance_book + prepare_draft_asset_depreciation_schedule_data( + asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return ) + asset_depr_schedule.insert() + + +def update_draft_asset_depreciation_schedules( + asset_doc, date_of_disposal=None, date_of_return=None +): + for row in asset_doc.get("finance_books"): + asset_depr_schedule_name = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + if not asset_depr_schedule_name: return asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) - prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row) + prepare_draft_asset_depreciation_schedule_data( + asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + ) + + asset_depr_schedule.save() -def prepare_draft_asset_depreciation_schedule_data(asset_depr_schedule, asset, row): - set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset.name, row) - make_depreciation_schedule(asset_depr_schedule, asset, row) - set_accumulated_depreciation(asset_depr_schedule, asset, row) - - asset_depr_schedule.save() +def prepare_draft_asset_depreciation_schedule_data( + asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return +): + set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_doc.name, row) + make_depreciation_schedule(asset_depr_schedule, asset_doc, row, date_of_disposal) + set_accumulated_depreciation( + asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + ) -def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_name, row): - asset_depr_schedule.asset = asset_name +def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset, row): + asset_depr_schedule.asset = asset asset_depr_schedule.finance_book = row.finance_book asset_depr_schedule.depreciation_method = row.depreciation_method asset_depr_schedule.total_number_of_depreciations = row.total_number_of_depreciations @@ -60,11 +70,9 @@ def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_nam asset_depr_schedule.status = "Draft" -def convert_draft_asset_depreciation_schedules_into_active(asset): - for row in asset.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule_name( - asset.name, row.finance_book - ) +def convert_draft_asset_depreciation_schedules_into_active(asset_doc): + for row in asset_doc.get("finance_books"): + asset_depr_schedule_name = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) if not asset_depr_schedule_name: return @@ -77,50 +85,63 @@ def convert_draft_asset_depreciation_schedules_into_active(asset): def make_new_active_asset_depreciation_schedules_from_existing( - asset, date_of_disposal=None, date_of_return=None + asset_doc, date_of_disposal=None, date_of_return=None, notes=None ): - for row in asset.get("finance_books"): - old_asset_depr_schedule_name = get_asset_depreciation_schedule_name( - asset.name, row.finance_book - ) + for row in asset_doc.get("finance_books"): + old_asset_depr_schedule_name = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) if not old_asset_depr_schedule_name: return old_asset_depr_schedule = frappe.get_doc( - "Asset Depreciation Schedule", - old_asset_depr_schedule_name + "Asset Depreciation Schedule", old_asset_depr_schedule_name ) asset_depr_schedule = frappe.copy_doc(old_asset_depr_schedule, ignore_no_copy=False) - make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal) - set_accumulated_depreciation(asset_depr_schedule, asset, row, date_of_disposal, date_of_return) + make_depreciation_schedule(asset_depr_schedule, asset_doc, row, date_of_disposal) + set_accumulated_depreciation( + asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + ) - asset_depr_schedule.save() + asset_depr_schedule.notes = notes + + asset_depr_schedule.submit() -def make_depreciation_schedule(asset_depr_schedule, asset, row, date_of_disposal=None): +def make_temp_asset_depreciation_schedule( + asset_doc, row, date_of_disposal=None, date_of_return=None +): + asset_depr_schedule = frappe.new_doc("Asset Depreciation Schedule") + + prepare_draft_asset_depreciation_schedule_data( + asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + ) + + return asset_depr_schedule + + +def get_asset_depreciation_schedule(asset, finance_book): + return frappe.db.get_value( + doctype="Asset Depreciation Schedule", + filters=[ + ["asset", "=", asset], + ["finance_book", "=", finance_book], + ["docstatus", "<", 2], + ], + ) + + +def make_depreciation_schedule(asset_depr_schedule, asset_doc, row, date_of_disposal): if row.depreciation_method != "Manual" and not asset_depr_schedule.get("depreciation_schedule"): asset_depr_schedule.depreciation_schedule = [] - if not asset.available_for_use_date: + if not asset_doc.available_for_use_date: return start = clear_depreciation_schedule(asset_depr_schedule) - _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_disposal) - - -def get_asset_depreciation_schedule_name(asset_name, finance_book): - return frappe.db.get_value( - doctype="Asset Depreciation Schedule", - filters=[ - ["asset", "=", asset_name], - ["finance_book", "=", finance_book], - ["docstatus", "<", 2], - ] - ) + _make_depreciation_schedule(asset_depr_schedule, asset_doc, row, start, date_of_disposal) def clear_depreciation_schedule(asset_depr_schedule): @@ -152,17 +173,17 @@ def clear_depreciation_schedule(asset_depr_schedule): return start -def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_disposal): - asset.validate_asset_finance_books(row) +def _make_depreciation_schedule(asset_depr_schedule, asset_doc, row, start, date_of_disposal): + asset_doc.validate_asset_finance_books(row) - value_after_depreciation = asset._get_value_after_depreciation(row) + value_after_depreciation = asset_doc._get_value_after_depreciation(row) row.value_after_depreciation = value_after_depreciation number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint( - asset.number_of_depreciations_booked + asset_doc.number_of_depreciations_booked ) - has_pro_rata = asset.check_is_pro_rata(row) + has_pro_rata = asset_doc.check_is_pro_rata(row) if has_pro_rata: number_of_pending_depreciations += 1 @@ -174,12 +195,10 @@ def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_ if skip_row: continue - depreciation_amount = get_depreciation_amount(asset, value_after_depreciation, row) + depreciation_amount = get_depreciation_amount(asset_doc, value_after_depreciation, row) if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1: - schedule_date = add_months( - row.depreciation_start_date, n * cint(row.frequency_of_depreciation) - ) + 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) @@ -190,8 +209,8 @@ def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_ # if asset is being sold or scrapped if date_of_disposal: - from_date = asset.get_from_date(row.finance_book) - depreciation_amount, days, months = asset.get_pro_rata_amt( + from_date = asset_doc.get_from_date(row.finance_book) + depreciation_amount, days, months = asset_doc.get_pro_rata_amt( row, depreciation_amount, from_date, date_of_disposal ) @@ -208,11 +227,11 @@ def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_ break # For first row - if has_pro_rata and not asset.opening_accumulated_depreciation and n == 0: + if has_pro_rata and not asset_doc.opening_accumulated_depreciation and n == 0: from_date = add_days( - asset.available_for_use_date, -1 + asset_doc.available_for_use_date, -1 ) # needed to calc depr amount for available_for_use_date too - depreciation_amount, days, months = asset.get_pro_rata_amt( + depreciation_amount, days, months = asset_doc.get_pro_rata_amt( row, depreciation_amount, from_date, row.depreciation_start_date ) @@ -223,20 +242,20 @@ def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_ # For last row elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1: - if not asset.flags.increase_in_asset_life: + 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.to_date = add_months( - asset.available_for_use_date, - (n + asset.number_of_depreciations_booked) * cint(row.frequency_of_depreciation), + asset_doc.to_date = add_months( + asset_doc.available_for_use_date, + (n + asset_doc.number_of_depreciations_booked) * cint(row.frequency_of_depreciation), ) depreciation_amount_without_pro_rata = depreciation_amount - depreciation_amount, days, months = asset.get_pro_rata_amt( - row, depreciation_amount, schedule_date, asset.to_date + depreciation_amount, days, months = asset_doc.get_pro_rata_amt( + row, depreciation_amount, schedule_date, asset_doc.to_date ) - depreciation_amount = asset.get_adjusted_depreciation_amount( + depreciation_amount = asset_doc.get_adjusted_depreciation_amount( depreciation_amount_without_pro_rata, depreciation_amount, row.finance_book ) @@ -246,7 +265,9 @@ def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_ if not depreciation_amount: continue - value_after_depreciation -= flt(depreciation_amount, asset.precision("gross_purchase_amount")) + value_after_depreciation -= flt( + depreciation_amount, asset_doc.precision("gross_purchase_amount") + ) # Adjust depreciation amount in the last period based on the expected value after useful life if row.expected_value_after_useful_life and ( @@ -271,19 +292,19 @@ def _make_depreciation_schedule(asset_depr_schedule, asset, row, start, date_of_ @erpnext.allow_regional -def get_depreciation_amount(asset, depreciable_value, row): +def get_depreciation_amount(asset_doc, depreciable_value, row): if row.depreciation_method in ("Straight Line", "Manual"): # if the Depreciation Schedule is being prepared for the first time - if not asset.flags.increase_in_asset_life: + if not asset_doc.flags.increase_in_asset_life: depreciation_amount = ( - flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) + flt(asset_doc.gross_purchase_amount) - flt(row.expected_value_after_useful_life) ) / flt(row.total_number_of_depreciations) # if the Depreciation Schedule is being modified after Asset Repair else: depreciation_amount = ( flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life) - ) / (date_diff(asset.to_date, asset.available_for_use_date) / 365) + ) / (date_diff(asset_doc.to_date, asset_doc.available_for_use_date) / 365) else: depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100)) @@ -296,7 +317,7 @@ def add_depr_schedule_row( depreciation_amount, depreciation_method, finance_book, - finance_book_id + finance_book_id, ): asset_depr_schedule.append( "depreciation_schedule", @@ -312,14 +333,15 @@ def add_depr_schedule_row( def set_accumulated_depreciation( asset_depr_schedule, - asset, + asset_doc, row, date_of_disposal=None, date_of_return=None, - ignore_booked_entry=False + ignore_booked_entry=False, ): straight_line_idx = [ - d.idx for d in asset_depr_schedule.get("depreciation_schedule") + d.idx + for d in asset_depr_schedule.get("depreciation_schedule") if d.depreciation_method == "Straight Line" ] finance_books = [] @@ -329,8 +351,8 @@ def set_accumulated_depreciation( continue if int(d.finance_book_id) not in finance_books: - accumulated_depreciation = flt(asset.opening_accumulated_depreciation) - value_after_depreciation = flt(asset.get_value_after_depreciation(d.finance_book_id)) + accumulated_depreciation = flt(asset_doc.opening_accumulated_depreciation) + value_after_depreciation = flt(asset_doc.get_value_after_depreciation(d.finance_book_id)) finance_books.append(int(d.finance_book_id)) depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index d5913c5946..ca6225f94e 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -8,6 +8,9 @@ from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours import erpnext from erpnext.accounts.general_ledger import make_gl_entries from erpnext.assets.doctype.asset.asset import get_asset_account +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_asset_depreciation_schedule, +) from erpnext.controllers.accounts_controller import AccountsController @@ -279,8 +282,11 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) + asset_depr_schedule = get_asset_depreciation_schedule(asset.name, row.finance_book) + depr_schedule = asset_depr_schedule.get("depreciation_schedule") + # the Schedule Date in the final row of the old Depreciation Schedule - last_schedule_date = asset.schedules[len(asset.schedules) - 1].schedule_date + last_schedule_date = asset_depr_schedule[len(asset_depr_schedule) - 1].schedule_date # the Schedule Date in the final row of the new Depreciation Schedule asset.to_date = add_months(last_schedule_date, extra_months) @@ -310,8 +316,11 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) + asset_depr_schedule = get_asset_depreciation_schedule(asset.name, row.finance_book) + depr_schedule = asset_depr_schedule.get("depreciation_schedule") + # the Schedule Date in the final row of the modified Depreciation Schedule - last_schedule_date = asset.schedules[len(asset.schedules) - 1].schedule_date + last_schedule_date = asset_depr_schedule[len(asset_depr_schedule) - 1].schedule_date # the Schedule Date in the final row of the original Depreciation Schedule asset.to_date = add_months(last_schedule_date, -extra_months) From 7db66b0916f5f37d110878adae462c060872bf3c Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 24 Nov 2022 13:02:48 +0530 Subject: [PATCH 09/94] chore: renaming some functions and variables, and partially refactoring AssetValueAdjustment --- erpnext/assets/doctype/asset/asset.py | 32 ++--- erpnext/assets/doctype/asset/depreciation.py | 4 +- .../asset_depreciation_schedule.py | 118 ++++++++++-------- .../asset_value_adjustment.py | 20 +-- 4 files changed, 96 insertions(+), 78 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 6a248b0f8f..e3e8a132c7 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -29,6 +29,7 @@ from erpnext.assets.doctype.asset.depreciation import ( ) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + cancel_asset_depreciation_schedules, convert_draft_asset_depreciation_schedules_into_active, get_asset_depreciation_schedule, make_draft_asset_depreciation_schedules, @@ -64,6 +65,7 @@ class Asset(AccountsController): self.validate_cancellation() self.cancel_movement_entries() self.delete_depreciation_entries() + cancel_asset_depreciation_schedules(self) self.set_status() self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry") make_reverse_gl_entries(voucher_type="Asset", voucher_no=self.name) @@ -244,14 +246,14 @@ class Asset(AccountsController): return value_after_depreciation def get_from_date(self, finance_book): - asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, finance_book) + asset_depr_schedule = get_asset_depreciation_schedule(self.name, finance_book) - if not asset_depr_schedule_name: + if not asset_depr_schedule: return self.available_for_use_date - asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) - return asset_depr_schedule.get("depreciation_schedule")[-1].schedule_date + return asset_depr_schedule_doc.get("depreciation_schedule")[-1].schedule_date # if it returns True, depreciation_amount will not be equal for the first and last rows def check_is_pro_rata(self, row): @@ -355,26 +357,26 @@ class Asset(AccountsController): return depreciation_amount_for_last_row def get_depreciation_amount_for_first_row(self, finance_book): - asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, finance_book) + asset_depr_schedule = get_asset_depreciation_schedule(self.name, finance_book) - asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) - return asset_depr_schedule.get("depreciation_schedule")[0].depreciation_amount + return asset_depr_schedule_doc.get("depreciation_schedule")[0].depreciation_amount def get_value_after_depreciation(self, idx): return flt(self.get("finance_books")[cint(idx) - 1].value_after_depreciation) def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, row.finance_book) + asset_depr_schedule = get_asset_depreciation_schedule(self.name, row.finance_book) - if not asset_depr_schedule_name: + if not asset_depr_schedule: return - asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) accumulated_depreciation_after_full_schedule = [ - d.accumulated_depreciation_amount for d in asset_depr_schedule.get("depreciation_schedule") + d.accumulated_depreciation_amount for d in asset_depr_schedule_doc.get("depreciation_schedule") ] if accumulated_depreciation_after_full_schedule: @@ -424,14 +426,14 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule(self.name, row.finance_book) + asset_depr_schedule = get_asset_depreciation_schedule(self.name, row.finance_book) - if not asset_depr_schedule_name: + if not asset_depr_schedule: return - asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) - for d in asset_depr_schedule.get("depreciation_schedule"): + for d in asset_depr_schedule_doc.get("depreciation_schedule"): if d.journal_entry: frappe.get_doc("Journal Entry", d.journal_entry).cancel() d.db_set("journal_entry", None) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 49f167ef1c..664838dee6 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -11,7 +11,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - make_temp_asset_depreciation_schedule, + get_temp_asset_depreciation_schedule_doc, ) @@ -514,7 +514,7 @@ def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_ row = asset_doc.finance_books[idx - 1] - temp_asset_depreciation_schedule = make_temp_asset_depreciation_schedule( + temp_asset_depreciation_schedule = get_temp_asset_depreciation_schedule_doc( asset_doc, row, getdate(disposal_date) ) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 9df4241b57..144b94dfbc 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -22,52 +22,52 @@ class AssetDepreciationSchedule(Document): def make_draft_asset_depreciation_schedules(asset_doc, date_of_disposal=None, date_of_return=None): for row in asset_doc.get("finance_books"): - asset_depr_schedule = frappe.new_doc("Asset Depreciation Schedule") + asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") prepare_draft_asset_depreciation_schedule_data( - asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) - asset_depr_schedule.insert() + asset_depr_schedule_doc.insert() def update_draft_asset_depreciation_schedules( asset_doc, date_of_disposal=None, date_of_return=None ): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) - if not asset_depr_schedule_name: + if not asset_depr_schedule: return - asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) prepare_draft_asset_depreciation_schedule_data( - asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) - asset_depr_schedule.save() + asset_depr_schedule_doc.save() def prepare_draft_asset_depreciation_schedule_data( - asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ): - set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset_doc.name, row) - make_depreciation_schedule(asset_depr_schedule, asset_doc, row, date_of_disposal) + set_draft_asset_depreciation_schedule_details(asset_depr_schedule_doc, asset_doc.name, row) + make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) set_accumulated_depreciation( - asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) -def set_draft_asset_depreciation_schedule_details(asset_depr_schedule, asset, row): - asset_depr_schedule.asset = asset - asset_depr_schedule.finance_book = row.finance_book - asset_depr_schedule.depreciation_method = row.depreciation_method - asset_depr_schedule.total_number_of_depreciations = row.total_number_of_depreciations - asset_depr_schedule.frequency_of_depreciation = row.frequency_of_depreciation - asset_depr_schedule.rate_of_depreciation = row.rate_of_depreciation - asset_depr_schedule.expected_value_after_useful_life = row.expected_value_after_useful_life - asset_depr_schedule.status = "Draft" +def set_draft_asset_depreciation_schedule_details(asset_depr_schedule_doc, asset, row): + asset_depr_schedule_doc.asset = asset + asset_depr_schedule_doc.finance_book = row.finance_book + asset_depr_schedule_doc.depreciation_method = row.depreciation_method + asset_depr_schedule_doc.total_number_of_depreciations = row.total_number_of_depreciations + asset_depr_schedule_doc.frequency_of_depreciation = row.frequency_of_depreciation + asset_depr_schedule_doc.rate_of_depreciation = row.rate_of_depreciation + asset_depr_schedule_doc.expected_value_after_useful_life = row.expected_value_after_useful_life + asset_depr_schedule_doc.status = "Draft" def convert_draft_asset_depreciation_schedules_into_active(asset_doc): @@ -84,41 +84,55 @@ def convert_draft_asset_depreciation_schedules_into_active(asset_doc): asset_depr_schedule.submit() -def make_new_active_asset_depreciation_schedules_from_existing( +def make_new_active_asset_depreciation_schedules_and_cancel_old_ones( asset_doc, date_of_disposal=None, date_of_return=None, notes=None ): for row in asset_doc.get("finance_books"): - old_asset_depr_schedule_name = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + old_asset_depr_schedule = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) - if not old_asset_depr_schedule_name: + if not old_asset_depr_schedule: return - old_asset_depr_schedule = frappe.get_doc( - "Asset Depreciation Schedule", old_asset_depr_schedule_name + old_asset_depr_schedule_doc = frappe.get_doc( + "Asset Depreciation Schedule", old_asset_depr_schedule ) - asset_depr_schedule = frappe.copy_doc(old_asset_depr_schedule, ignore_no_copy=False) + asset_depr_schedule_doc = frappe.copy_doc(old_asset_depr_schedule_doc, ignore_no_copy=False) - make_depreciation_schedule(asset_depr_schedule, asset_doc, row, date_of_disposal) + old_asset_depr_schedule.cancel() + + make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) set_accumulated_depreciation( - asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) - asset_depr_schedule.notes = notes + asset_depr_schedule_doc.notes = notes - asset_depr_schedule.submit() + asset_depr_schedule_doc.submit() -def make_temp_asset_depreciation_schedule( +def get_temp_asset_depreciation_schedule_doc( asset_doc, row, date_of_disposal=None, date_of_return=None ): - asset_depr_schedule = frappe.new_doc("Asset Depreciation Schedule") + asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") prepare_draft_asset_depreciation_schedule_data( - asset_depr_schedule, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) - return asset_depr_schedule + return asset_depr_schedule_doc + + +def cancel_asset_depreciation_schedules(asset_doc): + for row in asset_doc.get("finance_books"): + asset_depr_schedule = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + + if not asset_depr_schedule: + return + + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + + asset_depr_schedule_doc.cancel() def get_asset_depreciation_schedule(asset, finance_book): @@ -132,24 +146,26 @@ def get_asset_depreciation_schedule(asset, finance_book): ) -def make_depreciation_schedule(asset_depr_schedule, asset_doc, row, date_of_disposal): - if row.depreciation_method != "Manual" and not asset_depr_schedule.get("depreciation_schedule"): - asset_depr_schedule.depreciation_schedule = [] +def make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal): + if row.depreciation_method != "Manual" and not asset_depr_schedule_doc.get( + "depreciation_schedule" + ): + asset_depr_schedule_doc.depreciation_schedule = [] if not asset_doc.available_for_use_date: return - start = clear_depreciation_schedule(asset_depr_schedule) + start = clear_depreciation_schedule(asset_depr_schedule_doc) - _make_depreciation_schedule(asset_depr_schedule, asset_doc, row, start, date_of_disposal) + _make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal) -def clear_depreciation_schedule(asset_depr_schedule): +def clear_depreciation_schedule(asset_depr_schedule_doc): start = [] num_of_depreciations_completed = 0 depr_schedule = [] - for schedule in asset_depr_schedule.get("depreciation_schedule"): + for schedule in asset_depr_schedule_doc.get("depreciation_schedule"): if len(start) != 0: break @@ -168,12 +184,12 @@ def clear_depreciation_schedule(asset_depr_schedule): if start == []: start = [0] else: - asset_depr_schedule.depreciation_schedule = depr_schedule + asset_depr_schedule_doc.depreciation_schedule = depr_schedule return start -def _make_depreciation_schedule(asset_depr_schedule, asset_doc, row, start, date_of_disposal): +def _make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal): asset_doc.validate_asset_finance_books(row) value_after_depreciation = asset_doc._get_value_after_depreciation(row) @@ -216,7 +232,7 @@ def _make_depreciation_schedule(asset_depr_schedule, asset_doc, row, start, date if depreciation_amount > 0: add_depr_schedule_row( - asset_depr_schedule, + asset_depr_schedule_doc, date_of_disposal, depreciation_amount, row.depreciation_method, @@ -282,7 +298,7 @@ def _make_depreciation_schedule(asset_depr_schedule, asset_doc, row, start, date if depreciation_amount > 0: add_depr_schedule_row( - asset_depr_schedule, + asset_depr_schedule_doc, schedule_date, depreciation_amount, row.depreciation_method, @@ -312,14 +328,14 @@ def get_depreciation_amount(asset_doc, depreciable_value, row): def add_depr_schedule_row( - asset_depr_schedule, + asset_depr_schedule_doc, schedule_date, depreciation_amount, depreciation_method, finance_book, finance_book_id, ): - asset_depr_schedule.append( + asset_depr_schedule_doc.append( "depreciation_schedule", { "schedule_date": schedule_date, @@ -332,7 +348,7 @@ def add_depr_schedule_row( def set_accumulated_depreciation( - asset_depr_schedule, + asset_depr_schedule_doc, asset_doc, row, date_of_disposal=None, @@ -341,12 +357,12 @@ def set_accumulated_depreciation( ): straight_line_idx = [ d.idx - for d in asset_depr_schedule.get("depreciation_schedule") + for d in asset_depr_schedule_doc.get("depreciation_schedule") if d.depreciation_method == "Straight Line" ] finance_books = [] - for i, d in enumerate(asset_depr_schedule.get("depreciation_schedule")): + for i, d in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")): if ignore_booked_entry and d.journal_entry: continue diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index ae6e2b426e..e61c8f7e83 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -10,10 +10,11 @@ from frappe.utils import cint, date_diff, flt, formatdate, getdate from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, ) -from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depreciation_amount -) from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_asset_depreciation_schedule, + get_depreciation_amount, +) class AssetValueAdjustment(Document): @@ -114,20 +115,19 @@ class AssetValueAdjustment(Document): for d in asset.finance_books: d.value_after_depreciation = asset_value + asset_depr_schedule = get_asset_depreciation_schedule(asset.name, d.finance_book) + depr_schedule = asset_depr_schedule.get("depreciation_schedule") + if d.depreciation_method in ("Straight Line", "Manual"): - end_date = max(s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx) + end_date = max(s.schedule_date for s in depr_schedule) total_days = date_diff(end_date, self.date) rate_per_day = flt(d.value_after_depreciation) / flt(total_days) from_date = self.date else: - no_of_depreciations = len( - [ - s.name for s in asset.schedules if (cint(s.finance_book_id) == d.idx and not s.journal_entry) - ] - ) + no_of_depreciations = len([s.name for s in depr_schedule if not s.journal_entry]) value_after_depreciation = d.value_after_depreciation - for data in asset.schedules: + for data in depr_schedule: if cint(data.finance_book_id) == d.idx and not data.journal_entry: if d.depreciation_method in ("Straight Line", "Manual"): days = date_diff(data.schedule_date, from_date) From f35b19eac3db13bb7a29ea8d6b2cbb0f03de1001 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 24 Nov 2022 15:33:21 +0530 Subject: [PATCH 10/94] chore: renaming functions and variables again, and continuing refactoring AssetValueAdjustment --- erpnext/assets/doctype/asset/asset.py | 33 ++++---- erpnext/assets/doctype/asset/depreciation.py | 10 +-- erpnext/assets/doctype/asset/test_asset.py | 16 ++-- .../asset_depreciation_schedule.py | 76 ++++++++++--------- .../doctype/asset_repair/asset_repair.py | 12 ++- .../asset_value_adjustment.py | 34 ++++++--- 6 files changed, 99 insertions(+), 82 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index e3e8a132c7..39557849ec 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -29,11 +29,12 @@ from erpnext.assets.doctype.asset.depreciation import ( ) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - cancel_asset_depreciation_schedules, - convert_draft_asset_depreciation_schedules_into_active, - get_asset_depreciation_schedule, - make_draft_asset_depreciation_schedules, - update_draft_asset_depreciation_schedules, + cancel_asset_depr_schedules, + convert_draft_asset_depr_schedules_into_active, + get_asset_depr_schedule, + get_depr_schedule_from_asset_depr_schedule_of_asset, + make_draft_asset_depr_schedules, + update_draft_asset_depr_schedules, ) from erpnext.controllers.accounts_controller import AccountsController @@ -47,7 +48,7 @@ class Asset(AccountsController): self.set_missing_values() if not self.split_from: self.prepare_depreciation_data() - update_draft_asset_depreciation_schedules(self) + update_draft_asset_depr_schedules(self) self.validate_gross_and_purchase_amount() self.validate_expected_value_after_useful_life() @@ -59,13 +60,13 @@ class Asset(AccountsController): self.make_asset_movement() if not self.booked_fixed_asset and self.validate_make_gl_entry(): self.make_gl_entries() - convert_draft_asset_depreciation_schedules_into_active(self) + convert_draft_asset_depr_schedules_into_active(self) def on_cancel(self): self.validate_cancellation() self.cancel_movement_entries() self.delete_depreciation_entries() - cancel_asset_depreciation_schedules(self) + cancel_asset_depr_schedules(self) self.set_status() self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry") make_reverse_gl_entries(voucher_type="Asset", voucher_no=self.name) @@ -73,7 +74,7 @@ class Asset(AccountsController): def after_insert(self): if not self.split_from: - make_draft_asset_depreciation_schedules(self) + make_draft_asset_depr_schedules(self) def validate_asset_and_reference(self): if self.purchase_invoice or self.purchase_receipt: @@ -246,7 +247,7 @@ class Asset(AccountsController): return value_after_depreciation def get_from_date(self, finance_book): - asset_depr_schedule = get_asset_depreciation_schedule(self.name, finance_book) + asset_depr_schedule = get_asset_depr_schedule(self.name, finance_book) if not asset_depr_schedule: return self.available_for_use_date @@ -357,18 +358,16 @@ class Asset(AccountsController): return depreciation_amount_for_last_row def get_depreciation_amount_for_first_row(self, finance_book): - asset_depr_schedule = get_asset_depreciation_schedule(self.name, finance_book) - - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) - - return asset_depr_schedule_doc.get("depreciation_schedule")[0].depreciation_amount + return get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, finance_book)[ + 0 + ].depreciation_amount def get_value_after_depreciation(self, idx): return flt(self.get("finance_books")[cint(idx) - 1].value_after_depreciation) def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - asset_depr_schedule = get_asset_depreciation_schedule(self.name, row.finance_book) + asset_depr_schedule = get_asset_depr_schedule(self.name, row.finance_book) if not asset_depr_schedule: return @@ -426,7 +425,7 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - asset_depr_schedule = get_asset_depreciation_schedule(self.name, row.finance_book) + asset_depr_schedule = get_asset_depr_schedule(self.name, row.finance_book) if not asset_depr_schedule: return diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 664838dee6..39ebc8d664 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -11,7 +11,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_temp_asset_depreciation_schedule_doc, + get_temp_asset_depr_schedule_doc, ) @@ -514,13 +514,13 @@ def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_ row = asset_doc.finance_books[idx - 1] - temp_asset_depreciation_schedule = get_temp_asset_depreciation_schedule_doc( + temp_asset_depreciation_schedule = get_temp_asset_depr_schedule_doc( asset_doc, row, getdate(disposal_date) ) - depr_schedule = temp_asset_depreciation_schedule.get("depreciation_schedule") - - accumulated_depr_amount = depr_schedule[-1].accumulated_depreciation_amount + accumulated_depr_amount = temp_asset_depreciation_schedule.get("depreciation_schedule")[ + -1 + ].accumulated_depreciation_amount return flt( flt(asset_doc.gross_purchase_amount) - accumulated_depr_amount, diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index e25d890ad0..5ef81238af 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -882,7 +882,7 @@ class TestDepreciationBasics(AssetSetup): """Tests if get_depreciation_amount() returns the right value.""" from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depreciation_amount + get_depreciation_amount, ) asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31") @@ -902,8 +902,8 @@ class TestDepreciationBasics(AssetSetup): depreciation_amount = get_depreciation_amount(asset, 100000, asset.finance_books[0]) self.assertEqual(depreciation_amount, 30000) - def test_make_depreciation_schedule(self): - """Tests if make_depreciation_schedule() returns the right values.""" + def test_make_depr_schedule(self): + """Tests if make_depr_schedule() returns the right values.""" asset = create_asset( item_code="Macbook Pro", @@ -1194,8 +1194,8 @@ class TestDepreciationBasics(AssetSetup): depr_expense_account.parent_account = "Expenses - _TC" depr_expense_account.save() - def test_clear_depreciation_schedule(self): - """Tests if clear_depreciation_schedule() works as expected.""" + def test_clear_depr_schedule(self): + """Tests if clear_depr_schedule() works as expected.""" asset = create_asset( item_code="Macbook Pro", @@ -1211,11 +1211,11 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - asset.clear_depreciation_schedule() + asset.clear_depr_schedule() self.assertEqual(len(asset.schedules), 1) - def test_clear_depreciation_schedule_for_multiple_finance_books(self): + def test_clear_depr_schedule_for_multiple_finance_books(self): asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31", do_not_save=1) asset.calculate_depreciation = 1 @@ -1254,7 +1254,7 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2020-04-01") asset.load_from_db() - asset.clear_depreciation_schedule() + asset.clear_depr_schedule() self.assertEqual(len(asset.schedules), 6) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 144b94dfbc..43f7b4adf7 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -20,46 +20,44 @@ class AssetDepreciationSchedule(Document): pass -def make_draft_asset_depreciation_schedules(asset_doc, date_of_disposal=None, date_of_return=None): +def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): for row in asset_doc.get("finance_books"): asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") - prepare_draft_asset_depreciation_schedule_data( + prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) asset_depr_schedule_doc.insert() -def update_draft_asset_depreciation_schedules( - asset_doc, date_of_disposal=None, date_of_return=None -): +def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): for row in asset_doc.get("finance_books"): - asset_depr_schedule = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule = get_asset_depr_schedule(asset_doc.name, row.finance_book) if not asset_depr_schedule: return asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) - prepare_draft_asset_depreciation_schedule_data( + prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) asset_depr_schedule_doc.save() -def prepare_draft_asset_depreciation_schedule_data( +def prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ): - set_draft_asset_depreciation_schedule_details(asset_depr_schedule_doc, asset_doc.name, row) - make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) + set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc.name, row) + make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) set_accumulated_depreciation( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) -def set_draft_asset_depreciation_schedule_details(asset_depr_schedule_doc, asset, row): +def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset, row): asset_depr_schedule_doc.asset = asset asset_depr_schedule_doc.finance_book = row.finance_book asset_depr_schedule_doc.depreciation_method = row.depreciation_method @@ -70,9 +68,9 @@ def set_draft_asset_depreciation_schedule_details(asset_depr_schedule_doc, asset asset_depr_schedule_doc.status = "Draft" -def convert_draft_asset_depreciation_schedules_into_active(asset_doc): +def convert_draft_asset_depr_schedules_into_active(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule_name = get_asset_depr_schedule(asset_doc.name, row.finance_book) if not asset_depr_schedule_name: return @@ -84,48 +82,48 @@ def convert_draft_asset_depreciation_schedules_into_active(asset_doc): asset_depr_schedule.submit() -def make_new_active_asset_depreciation_schedules_and_cancel_old_ones( +def make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, date_of_disposal=None, date_of_return=None, notes=None ): for row in asset_doc.get("finance_books"): - old_asset_depr_schedule = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + current_asset_depr_schedule = get_asset_depr_schedule(asset_doc.name, row.finance_book) - if not old_asset_depr_schedule: + if not current_asset_depr_schedule: return - old_asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", old_asset_depr_schedule + current_asset_depr_schedule_doc = frappe.get_doc( + "Asset Depreciation Schedule", current_asset_depr_schedule ) - asset_depr_schedule_doc = frappe.copy_doc(old_asset_depr_schedule_doc, ignore_no_copy=False) + new_asset_depr_schedule_doc = frappe.copy_doc( + current_asset_depr_schedule_doc, ignore_no_copy=False + ) - old_asset_depr_schedule.cancel() + current_asset_depr_schedule_doc.cancel() - make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) + make_depr_schedule(new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal) set_accumulated_depreciation( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return + new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) - asset_depr_schedule_doc.notes = notes + new_asset_depr_schedule_doc.notes = notes - asset_depr_schedule_doc.submit() + new_asset_depr_schedule_doc.submit() -def get_temp_asset_depreciation_schedule_doc( - asset_doc, row, date_of_disposal=None, date_of_return=None -): +def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date_of_return=None): asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") - prepare_draft_asset_depreciation_schedule_data( + prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) return asset_depr_schedule_doc -def cancel_asset_depreciation_schedules(asset_doc): +def cancel_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule = get_asset_depreciation_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule = get_asset_depr_schedule(asset_doc.name, row.finance_book) if not asset_depr_schedule: return @@ -135,7 +133,7 @@ def cancel_asset_depreciation_schedules(asset_doc): asset_depr_schedule_doc.cancel() -def get_asset_depreciation_schedule(asset, finance_book): +def get_asset_depr_schedule(asset, finance_book): return frappe.db.get_value( doctype="Asset Depreciation Schedule", filters=[ @@ -146,7 +144,13 @@ def get_asset_depreciation_schedule(asset, finance_book): ) -def make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal): +def get_depr_schedule_from_asset_depr_schedule_of_asset(asset, finance_book): + asset_depr_schedule = get_asset_depr_schedule(asset, finance_book) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + return asset_depr_schedule_doc.get("depreciation_schedule") + + +def make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal): if row.depreciation_method != "Manual" and not asset_depr_schedule_doc.get( "depreciation_schedule" ): @@ -155,12 +159,12 @@ def make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_ if not asset_doc.available_for_use_date: return - start = clear_depreciation_schedule(asset_depr_schedule_doc) + start = clear_depr_schedule(asset_depr_schedule_doc) - _make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal) + _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal) -def clear_depreciation_schedule(asset_depr_schedule_doc): +def clear_depr_schedule(asset_depr_schedule_doc): start = [] num_of_depreciations_completed = 0 depr_schedule = [] @@ -189,7 +193,7 @@ def clear_depreciation_schedule(asset_depr_schedule_doc): return start -def _make_depreciation_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal): +def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal): asset_doc.validate_asset_finance_books(row) value_after_depreciation = asset_doc._get_value_after_depreciation(row) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index ca6225f94e..962e7fb58d 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -9,7 +9,7 @@ import erpnext from erpnext.accounts.general_ledger import make_gl_entries from erpnext.assets.doctype.asset.asset import get_asset_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_asset_depreciation_schedule, + get_depr_schedule_from_asset_depr_schedule_of_asset, ) from erpnext.controllers.accounts_controller import AccountsController @@ -282,11 +282,10 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) - asset_depr_schedule = get_asset_depreciation_schedule(asset.name, row.finance_book) - depr_schedule = asset_depr_schedule.get("depreciation_schedule") + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset.name, row.finance_book) # the Schedule Date in the final row of the old Depreciation Schedule - last_schedule_date = asset_depr_schedule[len(asset_depr_schedule) - 1].schedule_date + last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date # the Schedule Date in the final row of the new Depreciation Schedule asset.to_date = add_months(last_schedule_date, extra_months) @@ -316,11 +315,10 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) - asset_depr_schedule = get_asset_depreciation_schedule(asset.name, row.finance_book) - depr_schedule = asset_depr_schedule.get("depreciation_schedule") + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset.name, row.finance_book) # the Schedule Date in the final row of the modified Depreciation Schedule - last_schedule_date = asset_depr_schedule[len(asset_depr_schedule) - 1].schedule_date + last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date # the Schedule Date in the final row of the original Depreciation Schedule asset.to_date = add_months(last_schedule_date, -extra_months) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index e61c8f7e83..bba61e646e 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -5,15 +5,16 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import cint, date_diff, flt, formatdate, getdate +from frappe.utils import date_diff, flt, formatdate, getdate from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, ) from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_asset_depreciation_schedule, + get_asset_depr_schedule, get_depreciation_amount, + set_accumulated_depreciation, ) @@ -115,8 +116,17 @@ class AssetValueAdjustment(Document): for d in asset.finance_books: d.value_after_depreciation = asset_value - asset_depr_schedule = get_asset_depreciation_schedule(asset.name, d.finance_book) - depr_schedule = asset_depr_schedule.get("depreciation_schedule") + current_asset_depr_schedule = get_asset_depr_schedule(asset.name, d.finance_book) + + current_asset_depr_schedule_doc = frappe.get_doc( + "Asset Depreciation Schedule", current_asset_depr_schedule + ) + + new_asset_depr_schedule_doc = frappe.copy_doc( + current_asset_depr_schedule_doc, ignore_no_copy=False + ) + + depr_schedule = new_asset_depr_schedule_doc.get("depreciation_schedule") if d.depreciation_method in ("Straight Line", "Manual"): end_date = max(s.schedule_date for s in depr_schedule) @@ -128,7 +138,7 @@ class AssetValueAdjustment(Document): value_after_depreciation = d.value_after_depreciation for data in depr_schedule: - if cint(data.finance_book_id) == d.idx and not data.journal_entry: + if not data.journal_entry: if d.depreciation_method in ("Straight Line", "Manual"): days = date_diff(data.schedule_date, from_date) depreciation_amount = days * rate_per_day @@ -142,10 +152,16 @@ class AssetValueAdjustment(Document): d.db_update() - asset.set_accumulated_depreciation(ignore_booked_entry=True) - for asset_data in asset.schedules: - if not asset_data.journal_entry: - asset_data.db_update() + set_accumulated_depreciation(new_asset_depr_schedule_doc, asset, d, ignore_booked_entry=True) + for asset_data in depr_schedule: + if not asset_data.journal_entry: + asset_data.db_update() + + current_asset_depr_schedule_doc.cancel() + + new_asset_depr_schedule_doc.notes = "Asset value adjustment" + + new_asset_depr_schedule_doc.submit() @frappe.whitelist() From de17367a367681ebf124fccadaf184dbb523ee7d Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 24 Nov 2022 16:16:36 +0530 Subject: [PATCH 11/94] chore: finish refactoring asset_value_adjustment --- .../asset_value_adjustment/asset_value_adjustment.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index bba61e646e..b6c4a3d210 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -117,7 +117,6 @@ class AssetValueAdjustment(Document): d.value_after_depreciation = asset_value current_asset_depr_schedule = get_asset_depr_schedule(asset.name, d.finance_book) - current_asset_depr_schedule_doc = frappe.get_doc( "Asset Depreciation Schedule", current_asset_depr_schedule ) @@ -125,6 +124,10 @@ class AssetValueAdjustment(Document): new_asset_depr_schedule_doc = frappe.copy_doc( current_asset_depr_schedule_doc, ignore_no_copy=False ) + new_asset_depr_schedule_doc.notes = "Asset value adjustment" + + current_asset_depr_schedule_doc.cancel() + new_asset_depr_schedule_doc.insert() depr_schedule = new_asset_depr_schedule_doc.get("depreciation_schedule") @@ -157,10 +160,6 @@ class AssetValueAdjustment(Document): if not asset_data.journal_entry: asset_data.db_update() - current_asset_depr_schedule_doc.cancel() - - new_asset_depr_schedule_doc.notes = "Asset value adjustment" - new_asset_depr_schedule_doc.submit() From 4e63ba3ac6cfa30304a57de05c3bd733d07ec4ff Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 24 Nov 2022 17:39:11 +0530 Subject: [PATCH 12/94] chore: refactor schedules in journal_entry --- .../doctype/journal_entry/journal_entry.py | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index de012b28ec..90fbd55cff 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -6,7 +6,7 @@ import json import frappe from frappe import _, msgprint, scrub -from frappe.utils import cint, cstr, flt, fmt_money, formatdate, get_link_to_form, nowdate +from frappe.utils import cstr, flt, fmt_money, formatdate, get_link_to_form, nowdate import erpnext from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts @@ -23,6 +23,9 @@ from erpnext.accounts.utils import ( get_stock_accounts, get_stock_and_account_balance, ) +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depr_schedule_from_asset_depr_schedule_of_asset, +) from erpnext.controllers.accounts_controller import AccountsController @@ -286,16 +289,18 @@ class JournalEntry(AccountsController): for d in self.get("accounts"): if d.reference_type == "Asset" and d.reference_name: asset = frappe.get_doc("Asset", d.reference_name) - for s in asset.get("schedules"): - if s.journal_entry == self.name: - s.db_set("journal_entry", None) + for row in asset.get("finance_books"): + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( + asset.name, row.finance_book + ) + for s in depr_schedule: + if s.journal_entry == self.name: + s.db_set("journal_entry", None) - idx = cint(s.finance_book_id) or 1 - finance_books = asset.get("finance_books")[idx - 1] - finance_books.value_after_depreciation += s.depreciation_amount - finance_books.db_update() + row.value_after_depreciation += s.depreciation_amount + row.db_update() - asset.set_status() + asset.set_status() def unlink_inter_company_jv(self): if ( From 7d09440579da5865f8b6832829527b3aeab92f85 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 25 Nov 2022 16:49:44 +0530 Subject: [PATCH 13/94] chore: more refactoring --- .../doctype/sales_invoice/sales_invoice.py | 3 +- erpnext/assets/doctype/asset/asset.js | 25 --------- erpnext/assets/doctype/asset/asset.json | 17 +----- erpnext/assets/doctype/asset/asset.py | 24 +++++---- erpnext/assets/doctype/asset/depreciation.py | 53 +++++++++++-------- .../asset_capitalization.py | 3 +- .../asset_depreciation_schedule.js | 25 +++++++-- .../asset_depreciation_schedule.json | 11 +++- .../asset_depreciation_schedule.py | 47 ++++++++-------- .../asset_value_adjustment.py | 6 +-- 10 files changed, 108 insertions(+), 106 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 62cf0dcfeb..a99e92d9e0 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1189,8 +1189,7 @@ class SalesInvoice(SellingController): else: if asset.calculate_depreciation: - depreciate_asset(asset, self.posting_date) - asset.reload() + depreciate_asset(asset, self.posting_date, notes="Sell asset") fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name") diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 7e54219740..4c393f0d4b 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -76,7 +76,6 @@ frappe.ui.form.on('Asset', { refresh: function(frm) { frappe.ui.form.trigger("Asset", "is_existing_asset"); frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1); - frm.events.make_schedules_editable(frm); if (frm.doc.docstatus==1) { if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) { @@ -512,30 +511,6 @@ frappe.ui.form.on('Asset Finance Book', { } }); -frappe.ui.form.on('Depreciation Schedule', { - make_depreciation_entry: function(frm, cdt, cdn) { - var row = locals[cdt][cdn]; - if (!row.journal_entry) { - frappe.call({ - method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry", - args: { - "asset_name": frm.doc.name, - "date": row.schedule_date - }, - callback: function(r) { - frappe.model.sync(r.message); - frm.refresh(); - } - }) - } - }, - - depreciation_amount: function(frm, cdt, cdn) { - erpnext.asset.set_accumulated_depreciation(frm); - } - -}) - erpnext.asset.set_accumulated_depreciation = function(frm) { if(frm.doc.depreciation_method != "Manual") return; diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 9af03ca0e7..4bac3031e8 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -52,8 +52,6 @@ "column_break_24", "frequency_of_depreciation", "next_depreciation_date", - "section_break_14", - "schedules", "insurance_details", "policy_number", "insurer", @@ -307,19 +305,6 @@ "label": "Next Depreciation Date", "no_copy": 1 }, - { - "depends_on": "calculate_depreciation", - "fieldname": "section_break_14", - "fieldtype": "Section Break", - "label": "Depreciation Schedule" - }, - { - "fieldname": "schedules", - "fieldtype": "Table", - "label": "Depreciation Schedule", - "no_copy": 1, - "options": "Depreciation Schedule" - }, { "collapsible": 1, "fieldname": "insurance_details", @@ -515,7 +500,7 @@ "link_fieldname": "asset" } ], - "modified": "2022-11-01 15:25:27.669803", + "modified": "2022-11-25 12:47:19.689702", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 39557849ec..75c4809081 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -31,7 +31,7 @@ from erpnext.assets.doctype.asset_category.asset_category import get_asset_categ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( cancel_asset_depr_schedules, convert_draft_asset_depr_schedules_into_active, - get_asset_depr_schedule, + get_asset_depr_schedule_name, get_depr_schedule_from_asset_depr_schedule_of_asset, make_draft_asset_depr_schedules, update_draft_asset_depr_schedules, @@ -247,12 +247,12 @@ class Asset(AccountsController): return value_after_depreciation def get_from_date(self, finance_book): - asset_depr_schedule = get_asset_depr_schedule(self.name, finance_book) + asset_depr_schedule_name = get_asset_depr_schedule_name(self.name, finance_book) - if not asset_depr_schedule: + if not asset_depr_schedule_name: return self.available_for_use_date - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) return asset_depr_schedule_doc.get("depreciation_schedule")[-1].schedule_date @@ -367,12 +367,14 @@ class Asset(AccountsController): def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - asset_depr_schedule = get_asset_depr_schedule(self.name, row.finance_book) + asset_depr_schedule_name = get_asset_depr_schedule_name(self.name, row.finance_book) - if not asset_depr_schedule: + if not asset_depr_schedule_name: return - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + asset_depr_schedule_doc = frappe.get_doc( + "Asset Depreciation Schedule", asset_depr_schedule_name + ) accumulated_depreciation_after_full_schedule = [ d.accumulated_depreciation_amount for d in asset_depr_schedule_doc.get("depreciation_schedule") @@ -425,12 +427,14 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - asset_depr_schedule = get_asset_depr_schedule(self.name, row.finance_book) + asset_depr_schedule_name = get_asset_depr_schedule_name(self.name, row.finance_book) - if not asset_depr_schedule: + if not asset_depr_schedule_name: return - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + asset_depr_schedule_doc = frappe.get_doc( + "Asset Depreciation Schedule", asset_depr_schedule_name + ) for d in asset_depr_schedule_doc.get("depreciation_schedule"): if d.journal_entry: diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 39ebc8d664..a912a93ac5 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -11,7 +11,9 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_asset_depr_schedule_name, get_temp_asset_depr_schedule_doc, + make_new_active_asset_depr_schedules_and_cancel_current_ones, ) @@ -25,7 +27,7 @@ def post_depreciation_entries(date=None, commit=True): if not date: date = today() for asset in get_depreciable_assets(date): - make_depreciation_entry(asset, date) + make_depreciation_entry_for_all_asset_depr_schedules(asset, date) if commit: frappe.db.commit() @@ -41,13 +43,23 @@ def get_depreciable_assets(date): ) +def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): + for row in asset_doc.get("finance_books"): + asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) + make_depreciation_entry(asset_depr_schedule_name, date) + + @frappe.whitelist() -def make_depreciation_entry(asset_name, date=None): +def make_depreciation_entry(asset_depr_schedule_name, date=None): frappe.has_permission("Journal Entry", throw=True) if not date: date = today() + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + + asset_name = asset_depr_schedule_doc.asset + asset = frappe.get_doc("Asset", asset_name) ( fixed_asset_account, @@ -63,14 +75,14 @@ def make_depreciation_entry(asset_name, date=None): accounting_dimensions = get_checks_for_pl_and_bs_accounts() - for d in asset.get("schedules"): + for d in asset_depr_schedule_doc.get("depreciation_schedule"): if not d.journal_entry and getdate(d.schedule_date) <= getdate(date): je = frappe.new_doc("Journal Entry") je.voucher_type = "Depreciation Entry" je.naming_series = depreciation_series je.posting_date = d.schedule_date je.company = asset.company - je.finance_book = d.finance_book + je.finance_book = asset_depr_schedule_doc.finance_book je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount) credit_account, debit_account = get_credit_and_debit_accounts( @@ -121,14 +133,14 @@ def make_depreciation_entry(asset_name, date=None): d.db_set("journal_entry", je.name) - idx = cint(d.finance_book_id) - finance_books = asset.get("finance_books")[idx - 1] - finance_books.value_after_depreciation -= d.depreciation_amount - finance_books.db_update() + idx = cint(asset_depr_schedule_doc.finance_book_id) + row = asset.get("finance_books")[idx - 1] + row.value_after_depreciation -= d.depreciation_amount + row.db_update() asset.set_status() - return asset + return asset_depr_schedule_doc def get_depreciation_accounts(asset): @@ -202,8 +214,7 @@ def scrap_asset(asset_name): date = today() - depreciate_asset(asset, date) - asset.reload() + depreciate_asset(asset, date, notes="Scrap asset") depreciation_series = frappe.get_cached_value( "Company", asset.company, "series_for_depreciation_entry" @@ -247,22 +258,20 @@ def restore_asset(asset_name): asset.set_status() -def depreciate_asset(asset, date): - asset.flags.ignore_validate_update_after_submit = True - asset.prepare_depreciation_data(date_of_disposal=date) - asset.save() +def depreciate_asset(asset, date, notes): + make_new_active_asset_depr_schedules_and_cancel_current_ones( + asset, date_of_disposal=date, notes=notes + ) - make_depreciation_entry(asset.name, date) + make_depreciation_entry_for_all_asset_depr_schedules(asset, date) -def reset_depreciation_schedule(asset, date): - asset.flags.ignore_validate_update_after_submit = True - - # recreate original depreciation schedule of the asset - asset.prepare_depreciation_data(date_of_return=date) +def reset_depreciation_schedule(asset, date, notes): + make_new_active_asset_depr_schedules_and_cancel_current_ones( + asset, date_of_return=date, notes=notes + ) modify_depreciation_schedule_for_asset_repairs(asset) - asset.save() def modify_depreciation_schedule_for_asset_repairs(asset): diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 08355f047e..0787894dfd 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -427,8 +427,7 @@ class AssetCapitalization(StockController): asset = self.get_asset(item) if asset.calculate_depreciation: - depreciate_asset(asset, self.posting_date) - asset.reload() + depreciate_asset(asset, self.posting_date, notes="TODO") fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js index 9d41de381e..15e06e9a6f 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js @@ -1,8 +1,25 @@ // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.ui.form.on('Asset Depreciation Schedule', { - // refresh: function(frm) { +frappe.ui.form.on('Depreciation Schedule', { + make_depreciation_entry: function(frm, cdt, cdn) { + var row = locals[cdt][cdn]; + if (!row.journal_entry) { + frappe.call({ + method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry", + args: { + "asset_depr_schedule_name": frm.doc.name, + "date": row.schedule_date + }, + callback: function(r) { + frappe.model.sync(r.message); + frm.refresh(); + } + }) + } + }, - // } -}); + depreciation_amount: function(frm, cdt, cdn) { + erpnext.asset.set_accumulated_depreciation(frm); + } +}) \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index 83ed089de8..c5f7ca67b6 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -11,6 +11,7 @@ "naming_series", "column_break_2", "finance_book", + "finance_book_id", "depreciation_details_section", "depreciation_method", "total_number_of_depreciations", @@ -142,13 +143,21 @@ "label": "Expected Value After Useful Life", "options": "Company:company:default_currency", "read_only": 1 + }, + { + "fieldname": "finance_book_id", + "fieldtype": "Data", + "hidden": 1, + "label": "Finance Book Id", + "print_hide": 1, + "read_only": 1 } ], "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-11-14 14:33:53.360643", + "modified": "2022-11-25 14:31:52.668821", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 43f7b4adf7..6e78d7116b 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -33,12 +33,12 @@ def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_re def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): for row in asset_doc.get("finance_books"): - asset_depr_schedule = get_asset_depr_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - if not asset_depr_schedule: + if not asset_depr_schedule_name: return - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return @@ -57,9 +57,10 @@ def prepare_draft_asset_depr_schedule_data( ) -def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset, row): - asset_depr_schedule_doc.asset = asset +def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_name, row): + asset_depr_schedule_doc.asset = asset_name asset_depr_schedule_doc.finance_book = row.finance_book + asset_depr_schedule_doc.finance_book_id = row.idx asset_depr_schedule_doc.depreciation_method = row.depreciation_method asset_depr_schedule_doc.total_number_of_depreciations = row.total_number_of_depreciations asset_depr_schedule_doc.frequency_of_depreciation = row.frequency_of_depreciation @@ -70,29 +71,29 @@ def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset, row): def convert_draft_asset_depr_schedules_into_active(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) if not asset_depr_schedule_name: return - asset_depr_schedule = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) - asset_depr_schedule.status = "Active" + asset_depr_schedule_doc.status = "Active" - asset_depr_schedule.submit() + asset_depr_schedule_doc.submit() def make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, date_of_disposal=None, date_of_return=None, notes=None ): for row in asset_doc.get("finance_books"): - current_asset_depr_schedule = get_asset_depr_schedule(asset_doc.name, row.finance_book) + current_asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - if not current_asset_depr_schedule: + if not current_asset_depr_schedule_name: return current_asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", current_asset_depr_schedule + "Asset Depreciation Schedule", current_asset_depr_schedule_name ) new_asset_depr_schedule_doc = frappe.copy_doc( @@ -123,30 +124,34 @@ def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date def cancel_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule = get_asset_depr_schedule(asset_doc.name, row.finance_book) + asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - if not asset_depr_schedule: + if not asset_depr_schedule_name: return - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) asset_depr_schedule_doc.cancel() -def get_asset_depr_schedule(asset, finance_book): +def get_asset_depr_schedule_name(asset_name, finance_book): + finance_book_filter = ["finance_book", "is", "not set"] + if finance_book: + finance_book_filter = ["finance_book", "=", finance_book] + return frappe.db.get_value( doctype="Asset Depreciation Schedule", filters=[ - ["asset", "=", asset], - ["finance_book", "=", finance_book], + ["asset", "=", asset_name], + finance_book_filter, ["docstatus", "<", 2], ], ) -def get_depr_schedule_from_asset_depr_schedule_of_asset(asset, finance_book): - asset_depr_schedule = get_asset_depr_schedule(asset, finance_book) - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule) +def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book): + asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) return asset_depr_schedule_doc.get("depreciation_schedule") diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index b6c4a3d210..4783565323 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -12,7 +12,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_asset_depr_schedule, + get_asset_depr_schedule_name, get_depreciation_amount, set_accumulated_depreciation, ) @@ -116,9 +116,9 @@ class AssetValueAdjustment(Document): for d in asset.finance_books: d.value_after_depreciation = asset_value - current_asset_depr_schedule = get_asset_depr_schedule(asset.name, d.finance_book) + current_asset_depr_schedule_name = get_asset_depr_schedule_name(asset.name, d.finance_book) current_asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", current_asset_depr_schedule + "Asset Depreciation Schedule", current_asset_depr_schedule_name ) new_asset_depr_schedule_doc = frappe.copy_doc( From 96ede2fcf9f213cf1dd0877c8a5a1392d3dbce89 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 29 Nov 2022 21:30:23 +0530 Subject: [PATCH 14/94] fix: bug in new depr schedule --- erpnext/assets/doctype/asset/asset.py | 10 - .../asset_depreciation_schedule.py | 34 +- .../depreciation_schedule.json | 394 ++++-------------- 3 files changed, 101 insertions(+), 337 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 75c4809081..118bd02fe2 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -246,16 +246,6 @@ class Asset(AccountsController): return value_after_depreciation - def get_from_date(self, finance_book): - asset_depr_schedule_name = get_asset_depr_schedule_name(self.name, finance_book) - - if not asset_depr_schedule_name: - return self.available_for_use_date - - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) - - return asset_depr_schedule_doc.get("depreciation_schedule")[-1].schedule_date - # if it returns True, depreciation_amount will not be equal for the first and last rows def check_is_pro_rata(self, row): has_pro_rata = False diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 6e78d7116b..2480c0303f 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -96,11 +96,7 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( "Asset Depreciation Schedule", current_asset_depr_schedule_name ) - new_asset_depr_schedule_doc = frappe.copy_doc( - current_asset_depr_schedule_doc, ignore_no_copy=False - ) - - current_asset_depr_schedule_doc.cancel() + new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) make_depr_schedule(new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal) set_accumulated_depreciation( @@ -109,6 +105,8 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( new_asset_depr_schedule_doc.notes = notes + current_asset_depr_schedule_doc.cancel() + new_asset_depr_schedule_doc.submit() @@ -170,30 +168,19 @@ def make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal def clear_depr_schedule(asset_depr_schedule_doc): - start = [] + start = 0 num_of_depreciations_completed = 0 depr_schedule = [] for schedule in asset_depr_schedule_doc.get("depreciation_schedule"): - if len(start) != 0: - break - if schedule.journal_entry: num_of_depreciations_completed += 1 depr_schedule.append(schedule) else: - start.append(num_of_depreciations_completed) - num_of_depreciations_completed = 0 + start = num_of_depreciations_completed + break - # to update start when all the schedule rows corresponding to the FB are linked with JEs - if len(start) == 0: - start.append(num_of_depreciations_completed) - - # when the Depreciation Schedule is being created for the first time - if start == []: - start = [0] - else: - asset_depr_schedule_doc.depreciation_schedule = depr_schedule + asset_depr_schedule_doc.depreciation_schedule = depr_schedule return start @@ -215,7 +202,7 @@ def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_ skip_row = False should_get_last_day = is_last_day_of_the_month(row.depreciation_start_date) - for n in range(start[row.idx - 1], number_of_pending_depreciations): + for n in range(start, number_of_pending_depreciations): # If depreciation is already completed (for double declining balance) if skip_row: continue @@ -234,7 +221,10 @@ def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_ # if asset is being sold or scrapped if date_of_disposal: - from_date = asset_doc.get_from_date(row.finance_book) + from_date = asset_doc.available_for_use_date + if asset_depr_schedule_doc.depreciation_schedule: + from_date = asset_depr_schedule_doc.depreciation_schedule[-1].schedule_date + depreciation_amount, days, months = asset_doc.get_pro_rata_amt( row, depreciation_amount, from_date, date_of_disposal ) diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json index 35a2c9dd7f..1a669f9de1 100644 --- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json @@ -1,318 +1,102 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 1, - "autoname": "", - "beta": 0, - "creation": "2016-03-02 15:11:01.278862", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_rename": 1, + "creation": "2016-03-02 15:11:01.278862", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "finance_book", + "schedule_date", + "depreciation_amount", + "column_break_3", + "accumulated_depreciation_amount", + "journal_entry", + "make_depreciation_entry", + "finance_book_id", + "depreciation_method" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "finance_book", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Finance Book", - "length": 0, - "no_copy": 0, - "options": "Finance Book", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "finance_book", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Finance Book", + "options": "Finance Book", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Schedule Date", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "schedule_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Schedule Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "depreciation_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Depreciation Amount", - "length": 0, - "no_copy": 1, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "depreciation_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Depreciation Amount", + "options": "Company:company:default_currency", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "accumulated_depreciation_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Accumulated Depreciation Amount", - "length": 0, - "no_copy": 1, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "accumulated_depreciation_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Accumulated Depreciation Amount", + "options": "Company:company:default_currency", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.docstatus==1", - "fieldname": "journal_entry", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Journal Entry", - "length": 0, - "no_copy": 1, - "options": "Journal Entry", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "depends_on": "eval:doc.docstatus==1", + "fieldname": "journal_entry", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Journal Entry", + "options": "Journal Entry", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())", - "fieldname": "make_depreciation_entry", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Make Depreciation Entry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "allow_on_submit": 1, + "depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())", + "fieldname": "make_depreciation_entry", + "fieldtype": "Button", + "label": "Make Depreciation Entry" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "finance_book_id", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Finance Book Id", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "finance_book_id", + "fieldtype": "Data", + "hidden": 1, + "label": "Finance Book Id", + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "depreciation_method", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Depreciation Method", - "length": 0, - "no_copy": 1, - "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "depreciation_method", + "fieldtype": "Select", + "hidden": 1, + "label": "Depreciation Method", + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-05-10 15:12:41.679436", - "modified_by": "Administrator", - "module": "Assets", - "name": "Depreciation Schedule", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 + ], + "istable": 1, + "links": [], + "modified": "2022-11-29 18:27:05.748012", + "modified_by": "Administrator", + "module": "Assets", + "name": "Depreciation Schedule", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [] } \ No newline at end of file From f20238fa3e472cbb359f888fd1757b2732e0d042 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 1 Dec 2022 15:15:32 +0530 Subject: [PATCH 15/94] chore: use make_new_active_asset_depr_schedules_and_cancel_current_ones instead of prepare_depreciation_data --- .../doctype/sales_invoice/sales_invoice.py | 4 ++-- erpnext/assets/doctype/asset/depreciation.py | 18 +++++++++--------- .../asset_capitalization.py | 13 ++++++++----- .../asset_depreciation_schedule.py | 2 +- .../doctype/asset_repair/asset_repair.py | 15 +++++++-------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index a99e92d9e0..6e87415644 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1185,11 +1185,11 @@ class SalesInvoice(SellingController): if asset.calculate_depreciation: posting_date = frappe.db.get_value("Sales Invoice", self.return_against, "posting_date") reverse_depreciation_entry_made_after_disposal(asset, posting_date) - reset_depreciation_schedule(asset, self.posting_date) + reset_depreciation_schedule(asset, self.posting_date, "Return asset") else: if asset.calculate_depreciation: - depreciate_asset(asset, self.posting_date, notes="Sell asset") + depreciate_asset(asset, self.posting_date, "Sell asset") fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name") diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index a912a93ac5..ba4c7b01fb 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -214,7 +214,7 @@ def scrap_asset(asset_name): date = today() - depreciate_asset(asset, date, notes="Scrap asset") + depreciate_asset(asset, date, "Scrap asset") depreciation_series = frappe.get_cached_value( "Company", asset.company, "series_for_depreciation_entry" @@ -246,7 +246,7 @@ def restore_asset(asset_name): asset = frappe.get_doc("Asset", asset_name) reverse_depreciation_entry_made_after_disposal(asset, asset.disposal_date) - reset_depreciation_schedule(asset, asset.disposal_date) + reset_depreciation_schedule(asset, asset.disposal_date, "Restore asset") je = asset.journal_entry_for_scrap @@ -258,20 +258,20 @@ def restore_asset(asset_name): asset.set_status() -def depreciate_asset(asset, date, notes): +def depreciate_asset(asset_doc, date, notes): make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset, date_of_disposal=date, notes=notes + asset_doc, notes, date_of_disposal=date ) - make_depreciation_entry_for_all_asset_depr_schedules(asset, date) + make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) -def reset_depreciation_schedule(asset, date, notes): +def reset_depreciation_schedule(asset_doc, date, notes): make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset, date_of_return=date, notes=notes + asset_doc, notes, date_of_return=date ) - modify_depreciation_schedule_for_asset_repairs(asset) + modify_depreciation_schedule_for_asset_repairs(asset_doc) def modify_depreciation_schedule_for_asset_repairs(asset): @@ -283,7 +283,7 @@ def modify_depreciation_schedule_for_asset_repairs(asset): if repair.increase_in_asset_life: asset_repair = frappe.get_doc("Asset Repair", repair.name) asset_repair.modify_depreciation_schedule() - asset.prepare_depreciation_data() + make_new_active_asset_depr_schedules_and_cancel_current_ones(asset, "Asset Repair TODO") def reverse_depreciation_entry_made_after_disposal(asset, date): diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 0787894dfd..22459c44ef 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -19,6 +19,9 @@ from erpnext.assets.doctype.asset.depreciation import ( reverse_depreciation_entry_made_after_disposal, ) from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + make_new_active_asset_depr_schedules_and_cancel_current_ones, +) from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import ( get_current_asset_value, ) @@ -427,7 +430,7 @@ class AssetCapitalization(StockController): asset = self.get_asset(item) if asset.calculate_depreciation: - depreciate_asset(asset, self.posting_date, notes="TODO") + depreciate_asset(asset, self.posting_date, "Asset Capitalization TODO") fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, @@ -512,9 +515,9 @@ class AssetCapitalization(StockController): asset_doc.purchase_date = self.posting_date asset_doc.gross_purchase_amount = total_target_asset_value asset_doc.purchase_receipt_amount = total_target_asset_value - asset_doc.prepare_depreciation_data() - asset_doc.flags.ignore_validate_update_after_submit = True - asset_doc.save() + make_new_active_asset_depr_schedules_and_cancel_current_ones( + asset_doc, "Asset Capitalization TODO" + ) elif self.docstatus == 2: for item in self.asset_items: asset = self.get_asset(item) @@ -523,7 +526,7 @@ class AssetCapitalization(StockController): if asset.calculate_depreciation: reverse_depreciation_entry_made_after_disposal(asset, self.posting_date) - reset_depreciation_schedule(asset, self.posting_date) + reset_depreciation_schedule(asset, self.posting_date, "Asset Capitalization TODO") def get_asset(self, item): asset = frappe.get_doc("Asset", item.asset) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 2480c0303f..ed104c63de 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -84,7 +84,7 @@ def convert_draft_asset_depr_schedules_into_active(asset_doc): def make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset_doc, date_of_disposal=None, date_of_return=None, notes=None + asset_doc, notes, date_of_disposal=None, date_of_return=None ): for row in asset_doc.get("finance_books"): current_asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 962e7fb58d..33530bd89b 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -10,6 +10,7 @@ from erpnext.accounts.general_ledger import make_gl_entries from erpnext.assets.doctype.asset.asset import get_asset_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( get_depr_schedule_from_asset_depr_schedule_of_asset, + make_new_active_asset_depr_schedules_and_cancel_current_ones, ) from erpnext.controllers.accounts_controller import AccountsController @@ -54,10 +55,9 @@ class AssetRepair(AccountsController): and self.increase_in_asset_life ): self.modify_depreciation_schedule() - - self.asset_doc.flags.ignore_validate_update_after_submit = True - self.asset_doc.prepare_depreciation_data() - self.asset_doc.save() + make_new_active_asset_depr_schedules_and_cancel_current_ones( + self.asset_doc, "Asset Repair submit TODO" + ) def before_cancel(self): self.asset_doc = frappe.get_doc("Asset", self.asset) @@ -75,10 +75,9 @@ class AssetRepair(AccountsController): and self.increase_in_asset_life ): self.revert_depreciation_schedule_on_cancellation() - - self.asset_doc.flags.ignore_validate_update_after_submit = True - self.asset_doc.prepare_depreciation_data() - self.asset_doc.save() + make_new_active_asset_depr_schedules_and_cancel_current_ones( + self.asset_doc, "Asset Repair cancel TODO" + ) def check_repair_status(self): if self.repair_status == "Pending": From ca8c82749263c0229e9ffa74fcb2debbfc7d164a Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Sun, 4 Dec 2022 19:22:58 +0530 Subject: [PATCH 16/94] chore: refactor schedules in split_asset functions --- erpnext/assets/doctype/asset/asset.py | 80 +++++++++++-------- .../asset_depreciation_schedule.py | 11 ++- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 118bd02fe2..553e037916 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -34,6 +34,7 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_sched get_asset_depr_schedule_name, get_depr_schedule_from_asset_depr_schedule_of_asset, make_draft_asset_depr_schedules, + make_new_active_asset_depr_schedules_and_cancel_current_ones, update_draft_asset_depr_schedules, ) from erpnext.controllers.accounts_controller import AccountsController @@ -895,34 +896,35 @@ def update_existing_asset(asset, remaining_qty): }, ) - for finance_book in asset.get("finance_books"): + for row in asset.get("finance_books"): value_after_depreciation = flt( - (finance_book.value_after_depreciation * remaining_qty) / asset.asset_quantity + (row.value_after_depreciation * remaining_qty) / asset.asset_quantity ) expected_value_after_useful_life = flt( - (finance_book.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity + (row.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity ) frappe.db.set_value( - "Asset Finance Book", finance_book.name, "value_after_depreciation", value_after_depreciation + "Asset Finance Book", row.name, "value_after_depreciation", value_after_depreciation ) frappe.db.set_value( "Asset Finance Book", - finance_book.name, + row.name, "expected_value_after_useful_life", expected_value_after_useful_life, ) - accumulated_depreciation = 0 + accumulated_depreciation = 0 + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset.name, row.finance_book) - for term in asset.get("schedules"): - depreciation_amount = flt((term.depreciation_amount * remaining_qty) / asset.asset_quantity) - frappe.db.set_value( - "Depreciation Schedule", term.name, "depreciation_amount", depreciation_amount - ) - accumulated_depreciation += depreciation_amount - frappe.db.set_value( - "Depreciation Schedule", term.name, "accumulated_depreciation_amount", accumulated_depreciation - ) + for term in depr_schedule: + depreciation_amount = flt((term.depreciation_amount * remaining_qty) / asset.asset_quantity) + frappe.db.set_value( + "Depreciation Schedule", term.name, "depreciation_amount", depreciation_amount + ) + accumulated_depreciation += depreciation_amount + frappe.db.set_value( + "Depreciation Schedule", term.name, "accumulated_depreciation_amount", accumulated_depreciation + ) def create_new_asset_after_split(asset, split_qty): @@ -936,31 +938,41 @@ def create_new_asset_after_split(asset, split_qty): new_asset.opening_accumulated_depreciation = opening_accumulated_depreciation new_asset.asset_quantity = split_qty new_asset.split_from = asset.name - accumulated_depreciation = 0 - for finance_book in new_asset.get("finance_books"): - finance_book.value_after_depreciation = flt( - (finance_book.value_after_depreciation * split_qty) / asset.asset_quantity + for row in new_asset.get("finance_books"): + row.value_after_depreciation = flt( + (row.value_after_depreciation * split_qty) / asset.asset_quantity ) - finance_book.expected_value_after_useful_life = flt( - (finance_book.expected_value_after_useful_life * split_qty) / asset.asset_quantity + row.expected_value_after_useful_life = flt( + (row.expected_value_after_useful_life * split_qty) / asset.asset_quantity ) - for term in new_asset.get("schedules"): - depreciation_amount = flt((term.depreciation_amount * split_qty) / asset.asset_quantity) - term.depreciation_amount = depreciation_amount - accumulated_depreciation += depreciation_amount - term.accumulated_depreciation_amount = accumulated_depreciation - new_asset.submit() - new_asset.set_status() - for term in new_asset.get("schedules"): - # Update references in JV - if term.journal_entry: - add_reference_in_jv_on_split( - term.journal_entry, new_asset.name, asset.name, term.depreciation_amount - ) + make_new_active_asset_depr_schedules_and_cancel_current_ones( + new_asset, "create_new_asset_after_split TODO", submit=False + ) + + for row in new_asset.get("finance_books"): + accumulated_depreciation = 0 + + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( + new_asset.name, row.finance_book + ) + + for term in depr_schedule: + depreciation_amount = flt((term.depreciation_amount * split_qty) / asset.asset_quantity) + term.depreciation_amount = depreciation_amount + accumulated_depreciation += depreciation_amount + term.accumulated_depreciation_amount = accumulated_depreciation + + # Update references in JV + if term.journal_entry: + add_reference_in_jv_on_split( + term.journal_entry, new_asset.name, asset.name, term.depreciation_amount + ) + + new_asset.set_status() return new_asset diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index ed104c63de..89c9c1a84f 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -84,7 +84,7 @@ def convert_draft_asset_depr_schedules_into_active(asset_doc): def make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset_doc, notes, date_of_disposal=None, date_of_return=None + asset_doc, notes, submit=True, date_of_disposal=None, date_of_return=None ): for row in asset_doc.get("finance_books"): current_asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) @@ -107,7 +107,10 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( current_asset_depr_schedule_doc.cancel() - new_asset_depr_schedule_doc.submit() + new_asset_depr_schedule_doc.insert() + + if submit: + new_asset_depr_schedule_doc.submit() def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date_of_return=None): @@ -149,6 +152,10 @@ def get_asset_depr_schedule_name(asset_name, finance_book): def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) + + if not asset_depr_schedule_name: + return + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) return asset_depr_schedule_doc.get("depreciation_schedule") From 83ed93fbb61e9888cd2b6e7d5820b6bc284abb69 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Sun, 4 Dec 2022 22:45:48 +0530 Subject: [PATCH 17/94] chore: refactor chart and manual set_accumulated_depreciation logic --- erpnext/assets/doctype/asset/asset.js | 35 ++++++++++--------- .../asset_depreciation_schedule.js | 14 +++++++- .../asset_depreciation_schedule.json | 11 +++++- .../asset_depreciation_schedule.py | 1 + 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 4c393f0d4b..f937993f41 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -187,7 +187,11 @@ frappe.ui.form.on('Asset', { }) }, - setup_chart: function(frm) { + setup_chart: async function(frm) { + if(frm.doc.finance_books.length > 1) { + return + } + var x_intervals = [frm.doc.purchase_date]; var asset_values = [frm.doc.gross_purchase_amount]; var last_depreciation_date = frm.doc.purchase_date; @@ -201,7 +205,19 @@ frappe.ui.form.on('Asset', { flt(frm.doc.opening_accumulated_depreciation)); } - $.each(frm.doc.schedules || [], function(i, v) { + let depr_schedule = []; + + if (frm.doc.finance_books.length == 1) { + depr_schedule = (await frappe.call( + "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule_from_asset_depr_schedule_of_asset", + { + asset_name: frm.doc.name, + finance_book: frm.doc.finance_books[0].finance_book || null + } + )).message; + } + + $.each(depr_schedule || [], function(i, v) { x_intervals.push(v.schedule_date); var asset_value = flt(frm.doc.gross_purchase_amount) - flt(v.accumulated_depreciation_amount); if(v.journal_entry) { @@ -265,10 +281,6 @@ frappe.ui.form.on('Asset', { // frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation)); }, - opening_accumulated_depreciation: function(frm) { - erpnext.asset.set_accumulated_depreciation(frm); - }, - make_schedules_editable: function(frm) { if (frm.doc.finance_books) { var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0 @@ -511,17 +523,6 @@ frappe.ui.form.on('Asset Finance Book', { } }); -erpnext.asset.set_accumulated_depreciation = function(frm) { - if(frm.doc.depreciation_method != "Manual") return; - - var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation); - $.each(frm.doc.schedules || [], function(i, row) { - accumulated_depreciation += flt(row.depreciation_amount); - frappe.model.set_value(row.doctype, row.name, - "accumulated_depreciation_amount", accumulated_depreciation); - }) -}; - erpnext.asset.scrap_asset = function(frm) { frappe.confirm(__("Do you really want to scrap this asset?"), function () { frappe.call({ diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js index 15e06e9a6f..fdebbb17c3 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js @@ -1,5 +1,6 @@ // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt +frappe.provide("erpnext.asset"); frappe.ui.form.on('Depreciation Schedule', { make_depreciation_entry: function(frm, cdt, cdn) { @@ -22,4 +23,15 @@ frappe.ui.form.on('Depreciation Schedule', { depreciation_amount: function(frm, cdt, cdn) { erpnext.asset.set_accumulated_depreciation(frm); } -}) \ No newline at end of file +}); + +erpnext.asset.set_accumulated_depreciation = function(frm) { + if(frm.doc.depreciation_method != "Manual") return; + + var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation); + $.each(frm.doc.schedules || [], function(i, row) { + accumulated_depreciation += flt(row.depreciation_amount); + frappe.model.set_value(row.doctype, row.name, + "accumulated_depreciation_amount", accumulated_depreciation); + }) +}; diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index c5f7ca67b6..d39f30f943 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -10,6 +10,7 @@ "asset", "naming_series", "column_break_2", + "opening_accumulated_depreciation", "finance_book", "finance_book_id", "depreciation_details_section", @@ -151,7 +152,15 @@ "label": "Finance Book Id", "print_hide": 1, "read_only": 1 - } + }, + { + "depends_on": "opening_accumulated_depreciation", + "fieldname": "opening_accumulated_depreciation", + "fieldtype": "Currency", + "label": "Opening Accumulated Depreciation", + "read_only": 1, + "options": "Company:company:default_currency" + } ], "in_create": 1, "index_web_pages_for_search": 1, diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 89c9c1a84f..8d854dcad9 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -150,6 +150,7 @@ def get_asset_depr_schedule_name(asset_name, finance_book): ) +@frappe.whitelist() def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) From 8365d6bdb721db616b8a270f16957c4b2ab23bb7 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 6 Dec 2022 17:58:38 +0530 Subject: [PATCH 18/94] fix: refactor reverse_depreciation_entry_made_after_disposal and fix fb bug --- erpnext/assets/doctype/asset/asset.js | 12 ------ erpnext/assets/doctype/asset/depreciation.py | 40 +++++++++----------- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index f937993f41..aa73a224e2 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -281,17 +281,6 @@ frappe.ui.form.on('Asset', { // frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation)); }, - make_schedules_editable: function(frm) { - if (frm.doc.finance_books) { - var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0 - ? true : false; - - frm.toggle_enable("schedules", is_editable); - frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable); - frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable); - } - }, - make_sales_invoice: function(frm) { frappe.call({ args: { @@ -487,7 +476,6 @@ frappe.ui.form.on('Asset Finance Book', { depreciation_method: function(frm, cdt, cdn) { const row = locals[cdt][cdn]; frm.events.set_depreciation_rate(frm, row); - frm.events.make_schedules_editable(frm); }, expected_value_after_useful_life: function(frm, cdt, cdn) { diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index ba4c7b01fb..9bc3a488c8 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -12,6 +12,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( get_asset_depr_schedule_name, + get_depr_schedule_from_asset_depr_schedule_of_asset, get_temp_asset_depr_schedule_doc, make_new_active_asset_depr_schedules_and_cancel_current_ones, ) @@ -287,31 +288,26 @@ def modify_depreciation_schedule_for_asset_repairs(asset): def reverse_depreciation_entry_made_after_disposal(asset, date): - row = -1 - finance_book = asset.get("schedules")[0].get("finance_book") - for schedule in asset.get("schedules"): - if schedule.finance_book != finance_book: - row = 0 - finance_book = schedule.finance_book - else: - row += 1 + for row in asset.get("finance_books"): + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset, row.finance_book) - if schedule.schedule_date == date: - if not disposal_was_made_on_original_schedule_date( - asset, schedule, row, date - ) or disposal_happens_in_the_future(date): + for schedule_idx, schedule in enumerate(depr_schedule): + if schedule.schedule_date == date: + if not disposal_was_made_on_original_schedule_date( + asset, schedule, schedule_idx, date + ) or disposal_happens_in_the_future(date): - reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry) - reverse_journal_entry.posting_date = nowdate() - frappe.flags.is_reverse_depr_entry = True - reverse_journal_entry.submit() + reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry) + reverse_journal_entry.posting_date = nowdate() + frappe.flags.is_reverse_depr_entry = True + reverse_journal_entry.submit() - frappe.flags.is_reverse_depr_entry = False - asset.flags.ignore_validate_update_after_submit = True - schedule.journal_entry = None - depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry) - asset.finance_books[0].value_after_depreciation += depreciation_amount - asset.save() + frappe.flags.is_reverse_depr_entry = False + asset.flags.ignore_validate_update_after_submit = True + schedule.journal_entry = None + depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry) + row.value_after_depreciation += depreciation_amount + asset.save() def get_depreciation_amount_in_je(journal_entry): From e7d404a30ae56eb50699755cddf9365f7d8dffc6 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 6 Dec 2022 21:33:20 +0530 Subject: [PATCH 19/94] chore: remove finance_book and finance_book_id from depreciation_schedule and refactor some functions --- erpnext/assets/doctype/asset/depreciation.py | 17 +++++---- .../asset_depreciation_schedule.py | 35 ++++++------------- .../asset_value_adjustment.py | 2 +- .../depreciation_schedule.json | 20 +---------- 4 files changed, 21 insertions(+), 53 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 9bc3a488c8..3530fbd6de 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -294,7 +294,7 @@ def reverse_depreciation_entry_made_after_disposal(asset, date): for schedule_idx, schedule in enumerate(depr_schedule): if schedule.schedule_date == date: if not disposal_was_made_on_original_schedule_date( - asset, schedule, schedule_idx, date + schedule_idx, row, date ) or disposal_happens_in_the_future(date): reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry) @@ -318,15 +318,14 @@ def get_depreciation_amount_in_je(journal_entry): # if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone -def disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_disposal): - for finance_book in asset.get("finance_books"): - if schedule.finance_book == finance_book.finance_book: - orginal_schedule_date = add_months( - finance_book.depreciation_start_date, row * cint(finance_book.frequency_of_depreciation) - ) +def disposal_was_made_on_original_schedule_date(schedule_idx, row, posting_date_of_disposal): + orginal_schedule_date = add_months( + row.depreciation_start_date, schedule_idx * cint(row.frequency_of_depreciation) + ) + + if orginal_schedule_date == posting_date_of_disposal: + return True - if orginal_schedule_date == posting_date_of_disposal: - return True return False diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 8d854dcad9..35c461a972 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -50,17 +50,18 @@ def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_ def prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ): - set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc.name, row) + set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, row) make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) - set_accumulated_depreciation( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return - ) + set_accumulated_depreciation(asset_depr_schedule_doc, row, date_of_disposal, date_of_return) -def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_name, row): - asset_depr_schedule_doc.asset = asset_name +def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, row): + asset_depr_schedule_doc.asset = asset_doc.name asset_depr_schedule_doc.finance_book = row.finance_book asset_depr_schedule_doc.finance_book_id = row.idx + asset_depr_schedule_doc.opening_accumulated_depreciation = ( + asset_doc.opening_accumulated_depreciation + ) asset_depr_schedule_doc.depreciation_method = row.depreciation_method asset_depr_schedule_doc.total_number_of_depreciations = row.total_number_of_depreciations asset_depr_schedule_doc.frequency_of_depreciation = row.frequency_of_depreciation @@ -99,9 +100,7 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) make_depr_schedule(new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal) - set_accumulated_depreciation( - new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return - ) + set_accumulated_depreciation(new_asset_depr_schedule_doc, row, date_of_disposal, date_of_return) new_asset_depr_schedule_doc.notes = notes @@ -243,8 +242,6 @@ def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_ date_of_disposal, depreciation_amount, row.depreciation_method, - row.finance_book, - row.idx, ) break @@ -309,8 +306,6 @@ def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_ schedule_date, depreciation_amount, row.depreciation_method, - row.finance_book, - row.idx, ) @@ -339,8 +334,6 @@ def add_depr_schedule_row( schedule_date, depreciation_amount, depreciation_method, - finance_book, - finance_book_id, ): asset_depr_schedule_doc.append( "depreciation_schedule", @@ -348,15 +341,12 @@ def add_depr_schedule_row( "schedule_date": schedule_date, "depreciation_amount": depreciation_amount, "depreciation_method": depreciation_method, - "finance_book": finance_book, - "finance_book_id": finance_book_id, }, ) def set_accumulated_depreciation( asset_depr_schedule_doc, - asset_doc, row, date_of_disposal=None, date_of_return=None, @@ -367,17 +357,14 @@ def set_accumulated_depreciation( for d in asset_depr_schedule_doc.get("depreciation_schedule") if d.depreciation_method == "Straight Line" ] - finance_books = [] + + accumulated_depreciation = flt(asset_depr_schedule_doc.opening_accumulated_depreciation) + value_after_depreciation = flt(row.value_after_depreciation) for i, d in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")): if ignore_booked_entry and d.journal_entry: continue - if int(d.finance_book_id) not in finance_books: - accumulated_depreciation = flt(asset_doc.opening_accumulated_depreciation) - value_after_depreciation = flt(asset_doc.get_value_after_depreciation(d.finance_book_id)) - finance_books.append(int(d.finance_book_id)) - depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) value_after_depreciation -= flt(depreciation_amount) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 4783565323..d1538097b4 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -155,7 +155,7 @@ class AssetValueAdjustment(Document): d.db_update() - set_accumulated_depreciation(new_asset_depr_schedule_doc, asset, d, ignore_booked_entry=True) + set_accumulated_depreciation(new_asset_depr_schedule_doc, d, ignore_booked_entry=True) for asset_data in depr_schedule: if not asset_data.journal_entry: asset_data.db_update() diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json index 1a669f9de1..882c4bf00b 100644 --- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json @@ -7,25 +7,15 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "finance_book", "schedule_date", "depreciation_amount", "column_break_3", "accumulated_depreciation_amount", "journal_entry", "make_depreciation_entry", - "finance_book_id", "depreciation_method" ], "fields": [ - { - "fieldname": "finance_book", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Finance Book", - "options": "Finance Book", - "read_only": 1 - }, { "fieldname": "schedule_date", "fieldtype": "Date", @@ -69,14 +59,6 @@ "fieldtype": "Button", "label": "Make Depreciation Entry" }, - { - "fieldname": "finance_book_id", - "fieldtype": "Data", - "hidden": 1, - "label": "Finance Book Id", - "print_hide": 1, - "read_only": 1 - }, { "fieldname": "depreciation_method", "fieldtype": "Select", @@ -89,7 +71,7 @@ ], "istable": 1, "links": [], - "modified": "2022-11-29 18:27:05.748012", + "modified": "2022-12-06 20:35:50.264281", "modified_by": "Administrator", "module": "Assets", "name": "Depreciation Schedule", From 2cd42dbb1001cd17363eb3aa5598c25d5e2ef98b Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 6 Dec 2022 23:16:02 +0530 Subject: [PATCH 20/94] chore: refactor get_finance_book_value_map --- .../fixed_asset_register.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index 6b14dce084..f45b40bded 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -176,15 +176,17 @@ def get_finance_book_value_map(filters): return frappe._dict( frappe.db.sql( """ Select - parent, SUM(depreciation_amount) - FROM `tabDepreciation Schedule` + ads.name, SUM(depreciation_amount) + FROM `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds WHERE - parentfield='schedules' - AND schedule_date<=%s - AND journal_entry IS NOT NULL - AND ifnull(finance_book, '')=%s - GROUP BY parent""", - (date, cstr(filters.finance_book or "")), + ds.parent = ads.name + AND ifnull(ads.finance_book, '')=%s + AND ads.docstatus=1 + AND ds.parentfield='depreciation_schedule' + AND ds.schedule_date<=%s + AND ds.journal_entry IS NOT NULL + GROUP BY ads.name""", + (cstr(filters.finance_book or ""), date), ) ) From 18fc2b5695cb8b350e3541bb4587f1ec095b984b Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 6 Dec 2022 23:34:56 +0530 Subject: [PATCH 21/94] chore: fix bug in unlink_asset_reference --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 90fbd55cff..ac7b026580 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -293,6 +293,10 @@ class JournalEntry(AccountsController): depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( asset.name, row.finance_book ) + + if not depr_schedule: + return + for s in depr_schedule: if s.journal_entry == self.name: s.db_set("journal_entry", None) From 1fd73af744b33617517cb39a297eeca97e4250f4 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 9 Dec 2022 00:28:34 +0530 Subject: [PATCH 22/94] chore: refactor some reports --- .../asset_depreciations_and_balances.py | 4 ++-- .../report/fixed_asset_register/fixed_asset_register.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py index ad9b1ba58e..43b95dca80 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py @@ -131,8 +131,8 @@ def get_assets(filters): else 0 end), 0) as depreciation_amount_during_the_period - from `tabAsset` a, `tabDepreciation Schedule` ds - where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent and ifnull(ds.journal_entry, '') != '' + from `tabAsset` a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds + where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and ads.asset = a.name and ads.docstatus=1 and ads.name = ds.parent and ifnull(ds.journal_entry, '') != '' group by a.asset_category union SELECT a.asset_category, diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index f45b40bded..bb50df0ba2 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -176,7 +176,7 @@ def get_finance_book_value_map(filters): return frappe._dict( frappe.db.sql( """ Select - ads.name, SUM(depreciation_amount) + ads.asset, SUM(depreciation_amount) FROM `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds WHERE ds.parent = ads.name @@ -185,7 +185,7 @@ def get_finance_book_value_map(filters): AND ds.parentfield='depreciation_schedule' AND ds.schedule_date<=%s AND ds.journal_entry IS NOT NULL - GROUP BY ads.name""", + GROUP BY ads.asset""", (cstr(filters.finance_book or ""), date), ) ) From 187e1a324a5a24f4b3927e1a223344fc9ce8963b Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 9 Dec 2022 00:46:56 +0530 Subject: [PATCH 23/94] chore: refactor get_depreciable_assets --- erpnext/assets/doctype/asset/depreciation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 3530fbd6de..a7b5b60647 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -36,9 +36,11 @@ def post_depreciation_entries(date=None, commit=True): def get_depreciable_assets(date): return frappe.db.sql_list( """select distinct a.name - from tabAsset a, `tabDepreciation Schedule` ds - where a.name = ds.parent and a.docstatus=1 and ds.schedule_date<=%s and a.calculate_depreciation = 1 + from tabAsset a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds + where a.name = ads.asset and ads.name = ds.parent and a.docstatus=1 and ads.docstatus=1 and a.status in ('Submitted', 'Partially Depreciated') + and a.calculate_depreciation = 1 + and ds.schedule_date<=%s and ifnull(ds.journal_entry, '')=''""", date, ) From 77dc8e7966f772e5e09512a32e7c7cccf2c7c849 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 9 Dec 2022 00:58:19 +0530 Subject: [PATCH 24/94] fix: bug in posting depr entries --- erpnext/assets/doctype/asset/depreciation.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index a7b5b60647..bc5b8a990e 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -27,8 +27,8 @@ def post_depreciation_entries(date=None, commit=True): if not date: date = today() - for asset in get_depreciable_assets(date): - make_depreciation_entry_for_all_asset_depr_schedules(asset, date) + for asset_name in get_depreciable_assets(date): + make_depreciation_entry_for_all_asset_depr_schedules(asset_name, date) if commit: frappe.db.commit() @@ -46,7 +46,9 @@ def get_depreciable_assets(date): ) -def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): +def make_depreciation_entry_for_all_asset_depr_schedules(asset_name, date=None): + asset_doc = frappe.get_doc("Asset", asset_name) + for row in asset_doc.get("finance_books"): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) make_depreciation_entry(asset_depr_schedule_name, date) From 16365bfca3716b535a60eedf0ff07291c6c54d00 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 9 Dec 2022 14:04:00 +0530 Subject: [PATCH 25/94] chore: more refactoring --- .../doctype/journal_entry/journal_entry.py | 3 --- erpnext/assets/doctype/asset/asset.py | 23 ++++--------------- .../asset_depreciation_schedule.py | 1 + 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index ac7b026580..7d5ac258a5 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -294,9 +294,6 @@ class JournalEntry(AccountsController): asset.name, row.finance_book ) - if not depr_schedule: - return - for s in depr_schedule: if s.journal_entry == self.name: s.db_set("journal_entry", None) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 553e037916..d01b179f61 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -31,7 +31,6 @@ from erpnext.assets.doctype.asset_category.asset_category import get_asset_categ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( cancel_asset_depr_schedules, convert_draft_asset_depr_schedules_into_active, - get_asset_depr_schedule_name, get_depr_schedule_from_asset_depr_schedule_of_asset, make_draft_asset_depr_schedules, make_new_active_asset_depr_schedules_and_cancel_current_ones, @@ -358,17 +357,10 @@ class Asset(AccountsController): def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(self.name, row.finance_book) - - if not asset_depr_schedule_name: - return - - asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", asset_depr_schedule_name - ) + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, row.finance_book) accumulated_depreciation_after_full_schedule = [ - d.accumulated_depreciation_amount for d in asset_depr_schedule_doc.get("depreciation_schedule") + d.accumulated_depreciation_amount for d in depr_schedule ] if accumulated_depreciation_after_full_schedule: @@ -418,16 +410,9 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(self.name, row.finance_book) + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, row.finance_book) - if not asset_depr_schedule_name: - return - - asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", asset_depr_schedule_name - ) - - for d in asset_depr_schedule_doc.get("depreciation_schedule"): + for d in depr_schedule.get("depreciation_schedule"): if d.journal_entry: frappe.get_doc("Journal Entry", d.journal_entry).cancel() d.db_set("journal_entry", None) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 35c461a972..9f4047dcf7 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -157,6 +157,7 @@ def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book return asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + return asset_depr_schedule_doc.get("depreciation_schedule") From 90e1b9cb3d0da3f66baf366a9890d919ba21b363 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 9 Dec 2022 16:18:40 +0530 Subject: [PATCH 26/94] chore: fix asset depr schedule notes --- .../doctype/sales_invoice/sales_invoice.py | 5 ++++- erpnext/assets/doctype/asset/asset.py | 6 +++--- erpnext/assets/doctype/asset/depreciation.py | 12 ++++++++--- .../asset_capitalization.py | 16 ++++++++++---- .../asset_depreciation_schedule.json | 21 +++++++------------ .../doctype/asset_repair/asset_repair.py | 10 +++++---- .../asset_value_adjustment.py | 5 ++--- 7 files changed, 44 insertions(+), 31 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 6e87415644..85ed78407b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1189,7 +1189,10 @@ class SalesInvoice(SellingController): else: if asset.calculate_depreciation: - depreciate_asset(asset, self.posting_date, "Sell asset") + notes = _( + "This schedule was created when the Asset {0} was sold through Sales Invoice {1}." + ).format(asset.name, self.get("name")) + depreciate_asset(asset, self.posting_date, notes) fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name") diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index d01b179f61..0b37b8941b 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -352,13 +352,13 @@ class Asset(AccountsController): 0 ].depreciation_amount - def get_value_after_depreciation(self, idx): - return flt(self.get("finance_books")[cint(idx) - 1].value_after_depreciation) - def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, row.finance_book) + if not depr_schedule: + continue + accumulated_depreciation_after_full_schedule = [ d.accumulated_depreciation_amount for d in depr_schedule ] diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index bc5b8a990e..22c65fd400 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -219,8 +219,6 @@ def scrap_asset(asset_name): date = today() - depreciate_asset(asset, date, "Scrap asset") - depreciation_series = frappe.get_cached_value( "Company", asset.company, "series_for_depreciation_entry" ) @@ -239,6 +237,11 @@ def scrap_asset(asset_name): je.flags.ignore_permissions = True je.submit() + notes = _( + "This schedule was created when the Asset {0} was scrapped through Journal Entry {1}." + ).format(asset.name, je.name) + depreciate_asset(asset, date, notes) + frappe.db.set_value("Asset", asset_name, "disposal_date", date) frappe.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name) asset.set_status("Scrapped") @@ -288,7 +291,10 @@ def modify_depreciation_schedule_for_asset_repairs(asset): if repair.increase_in_asset_life: asset_repair = frappe.get_doc("Asset Repair", repair.name) asset_repair.modify_depreciation_schedule() - make_new_active_asset_depr_schedules_and_cancel_current_ones(asset, "Asset Repair TODO") + notes = _( + "This schedule was created when the Asset {0} went through the Asset Repair {1}." + ).format(asset.name, repair.name) + make_new_active_asset_depr_schedules_and_cancel_current_ones(asset, notes) def reverse_depreciation_entry_made_after_disposal(asset, date): diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 22459c44ef..96c01a5d8a 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -430,7 +430,11 @@ class AssetCapitalization(StockController): asset = self.get_asset(item) if asset.calculate_depreciation: - depreciate_asset(asset, self.posting_date, "Asset Capitalization TODO") + notes = _( + "This schedule was created when the Asset {0} was consumed through Asset Capitalization {1}." + ).format(asset.name, self.get("name")) + depreciate_asset(asset, self.posting_date, notes) + asset.reload() fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, @@ -515,9 +519,10 @@ class AssetCapitalization(StockController): asset_doc.purchase_date = self.posting_date asset_doc.gross_purchase_amount = total_target_asset_value asset_doc.purchase_receipt_amount = total_target_asset_value - make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset_doc, "Asset Capitalization TODO" + notes = _("This schedule was created when the Asset Capitalization {0} was submitted.").format( + self.name ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes) elif self.docstatus == 2: for item in self.asset_items: asset = self.get_asset(item) @@ -526,7 +531,10 @@ class AssetCapitalization(StockController): if asset.calculate_depreciation: reverse_depreciation_entry_made_after_disposal(asset, self.posting_date) - reset_depreciation_schedule(asset, self.posting_date, "Asset Capitalization TODO") + notes = _( + "This schedule was created when the Asset Capitalization {0} was cancelled." + ).format(self.name) + reset_depreciation_schedule(asset, self.posting_date, notes) def get_asset(self, item): asset = frappe.get_doc("Asset", item.asset) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index d39f30f943..0fea6a5b19 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -24,7 +24,6 @@ "depreciation_schedule", "details_section", "notes", - "column_break_15", "status", "amended_from" ], @@ -126,10 +125,6 @@ "options": "Draft\nActive\nCancelled", "read_only": 1 }, - { - "fieldname": "column_break_15", - "fieldtype": "Column Break" - }, { "depends_on": "frequency_of_depreciation", "fieldname": "frequency_of_depreciation", @@ -154,19 +149,19 @@ "read_only": 1 }, { - "depends_on": "opening_accumulated_depreciation", - "fieldname": "opening_accumulated_depreciation", - "fieldtype": "Currency", - "label": "Opening Accumulated Depreciation", - "read_only": 1, - "options": "Company:company:default_currency" - } + "depends_on": "opening_accumulated_depreciation", + "fieldname": "opening_accumulated_depreciation", + "fieldtype": "Currency", + "label": "Opening Accumulated Depreciation", + "options": "Company:company:default_currency", + "read_only": 1 + } ], "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-11-25 14:31:52.668821", + "modified": "2022-12-09 15:14:20.562294", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 33530bd89b..d3f74b08b2 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -55,9 +55,10 @@ class AssetRepair(AccountsController): and self.increase_in_asset_life ): self.modify_depreciation_schedule() - make_new_active_asset_depr_schedules_and_cancel_current_ones( - self.asset_doc, "Asset Repair submit TODO" + notes = _("This schedule was created when the Asset Repair {0} was submitted.").format( + self.name ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) def before_cancel(self): self.asset_doc = frappe.get_doc("Asset", self.asset) @@ -75,9 +76,10 @@ class AssetRepair(AccountsController): and self.increase_in_asset_life ): self.revert_depreciation_schedule_on_cancellation() - make_new_active_asset_depr_schedules_and_cancel_current_ones( - self.asset_doc, "Asset Repair cancel TODO" + notes = _("This schedule was created when the Asset Repair {0} was cancelled.").format( + self.name ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) def check_repair_status(self): if self.repair_status == "Pending": diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index d1538097b4..9caca33c30 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -121,9 +121,8 @@ class AssetValueAdjustment(Document): "Asset Depreciation Schedule", current_asset_depr_schedule_name ) - new_asset_depr_schedule_doc = frappe.copy_doc( - current_asset_depr_schedule_doc, ignore_no_copy=False - ) + new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) + new_asset_depr_schedule_doc.notes = "Asset value adjustment" current_asset_depr_schedule_doc.cancel() From ec6505d747bcbb2af63bcccd7559328fc9a97bb7 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 12 Dec 2022 16:35:30 +0530 Subject: [PATCH 27/94] chore: fix some bugs, refactor some functions, add proper notes --- .../doctype/sales_invoice/sales_invoice.py | 7 +- erpnext/assets/doctype/asset/asset.py | 74 ++++++++++++------- erpnext/assets/doctype/asset/depreciation.py | 13 ++-- .../asset_capitalization.py | 20 +++-- .../asset_depreciation_schedule.py | 45 ++++------- .../doctype/asset_repair/asset_repair.py | 20 ++--- 6 files changed, 100 insertions(+), 79 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 85ed78407b..f470fe6496 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1190,8 +1190,11 @@ class SalesInvoice(SellingController): else: if asset.calculate_depreciation: notes = _( - "This schedule was created when the Asset {0} was sold through Sales Invoice {1}." - ).format(asset.name, self.get("name")) + "This schedule was created when Asset {0} was sold through Sales Invoice {1}." + ).format( + get_link_to_form(asset.doctype, asset.name), + get_link_to_form(self.doctype, self.get("name")), + ) depreciate_asset(asset, self.posting_date, notes) fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 0b37b8941b..a9fed1c254 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -14,6 +14,7 @@ from frappe.utils import ( flt, get_datetime, get_last_day, + get_link_to_form, getdate, is_last_day_of_the_month, month_diff, @@ -31,9 +32,10 @@ from erpnext.assets.doctype.asset_category.asset_category import get_asset_categ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( cancel_asset_depr_schedules, convert_draft_asset_depr_schedules_into_active, + get_asset_depr_schedule_doc_of_asset, get_depr_schedule_from_asset_depr_schedule_of_asset, make_draft_asset_depr_schedules, - make_new_active_asset_depr_schedules_and_cancel_current_ones, + set_draft_asset_depr_schedule_details, update_draft_asset_depr_schedules, ) from erpnext.controllers.accounts_controller import AccountsController @@ -48,7 +50,6 @@ class Asset(AccountsController): self.set_missing_values() if not self.split_from: self.prepare_depreciation_data() - update_draft_asset_depr_schedules(self) self.validate_gross_and_purchase_amount() self.validate_expected_value_after_useful_life() @@ -97,6 +98,7 @@ class Asset(AccountsController): if self.calculate_depreciation: self.value_after_depreciation = 0 self.set_depreciation_rate() + update_draft_asset_depr_schedules(self) else: self.finance_books = [] self.value_after_depreciation = flt(self.gross_purchase_amount) - flt( @@ -858,12 +860,12 @@ def split_asset(asset_name, split_qty): remaining_qty = asset.asset_quantity - split_qty new_asset = create_new_asset_after_split(asset, split_qty) - update_existing_asset(asset, remaining_qty) + update_existing_asset(asset, remaining_qty, new_asset.name) return new_asset -def update_existing_asset(asset, remaining_qty): +def update_existing_asset(asset, remaining_qty, new_asset_name): remaining_gross_purchase_amount = flt( (asset.gross_purchase_amount * remaining_qty) / asset.asset_quantity ) @@ -898,18 +900,31 @@ def update_existing_asset(asset, remaining_qty): expected_value_after_useful_life, ) - accumulated_depreciation = 0 - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset.name, row.finance_book) + current_asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset( + asset.name, row.finance_book + ) + new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) - for term in depr_schedule: + set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, asset, row) + + accumulated_depreciation = 0 + + for term in new_asset_depr_schedule_doc.get("depreciation_schedule"): depreciation_amount = flt((term.depreciation_amount * remaining_qty) / asset.asset_quantity) - frappe.db.set_value( - "Depreciation Schedule", term.name, "depreciation_amount", depreciation_amount - ) + term.depreciation_amount = depreciation_amount accumulated_depreciation += depreciation_amount - frappe.db.set_value( - "Depreciation Schedule", term.name, "accumulated_depreciation_amount", accumulated_depreciation - ) + term.accumulated_depreciation_amount = accumulated_depreciation + + notes = _( + "This schedule was created when Asset {0} was updated after being split into new Asset {1}." + ).format( + get_link_to_form(asset.doctype, asset.name), get_link_to_form(asset.doctype, new_asset_name) + ) + new_asset_depr_schedule_doc.notes = notes + + current_asset_depr_schedule_doc.cancel() + + new_asset_depr_schedule_doc.submit() def create_new_asset_after_split(asset, split_qty): @@ -932,33 +947,42 @@ def create_new_asset_after_split(asset, split_qty): (row.expected_value_after_useful_life * split_qty) / asset.asset_quantity ) - new_asset.submit() + current_asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset( + asset.name, row.finance_book + ) + new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) - make_new_active_asset_depr_schedules_and_cancel_current_ones( - new_asset, "create_new_asset_after_split TODO", submit=False - ) + set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, new_asset, row) - for row in new_asset.get("finance_books"): accumulated_depreciation = 0 - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( - new_asset.name, row.finance_book - ) - - for term in depr_schedule: + for term in new_asset_depr_schedule_doc.get("depreciation_schedule"): depreciation_amount = flt((term.depreciation_amount * split_qty) / asset.asset_quantity) term.depreciation_amount = depreciation_amount accumulated_depreciation += depreciation_amount term.accumulated_depreciation_amount = accumulated_depreciation + notes = _("This schedule was created when new Asset {0} was split from Asset {1}.").format( + get_link_to_form(new_asset.doctype, new_asset.name), get_link_to_form(asset.doctype, asset.name) + ) + new_asset_depr_schedule_doc.notes = notes + + new_asset_depr_schedule_doc.insert() + + new_asset.submit() + new_asset.set_status() + + for row in new_asset.get("finance_books"): + depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( + new_asset.name, row.finance_book + ) + for term in depr_schedule: # Update references in JV if term.journal_entry: add_reference_in_jv_on_split( term.journal_entry, new_asset.name, asset.name, term.depreciation_amount ) - new_asset.set_status() - return new_asset diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 22c65fd400..b7d5511640 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -4,7 +4,7 @@ import frappe from frappe import _ -from frappe.utils import add_months, cint, flt, getdate, nowdate, today +from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, nowdate, today from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, @@ -238,8 +238,8 @@ def scrap_asset(asset_name): je.submit() notes = _( - "This schedule was created when the Asset {0} was scrapped through Journal Entry {1}." - ).format(asset.name, je.name) + "This schedule was created when Asset {0} was scrapped through Journal Entry {1}." + ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(je.doctype, je.name)) depreciate_asset(asset, date, notes) frappe.db.set_value("Asset", asset_name, "disposal_date", date) @@ -291,9 +291,10 @@ def modify_depreciation_schedule_for_asset_repairs(asset): if repair.increase_in_asset_life: asset_repair = frappe.get_doc("Asset Repair", repair.name) asset_repair.modify_depreciation_schedule() - notes = _( - "This schedule was created when the Asset {0} went through the Asset Repair {1}." - ).format(asset.name, repair.name) + notes = _("This schedule was created when Asset {0} went through Asset Repair {1}.").format( + get_link_to_form(asset.doctype, asset.name), + get_link_to_form(asset_repair.doctype, asset_repair.name), + ) make_new_active_asset_depr_schedules_and_cancel_current_ones(asset, notes) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 96c01a5d8a..26bac86094 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -7,7 +7,7 @@ import frappe # import erpnext from frappe import _ -from frappe.utils import cint, flt +from frappe.utils import cint, flt, get_link_to_form from six import string_types import erpnext @@ -431,8 +431,10 @@ class AssetCapitalization(StockController): if asset.calculate_depreciation: notes = _( - "This schedule was created when the Asset {0} was consumed through Asset Capitalization {1}." - ).format(asset.name, self.get("name")) + "This schedule was created when Asset {0} was consumed when Asset Capitalization {1} was submitted." + ).format( + get_link_to_form(asset.doctype, asset.name), get_link_to_form(self.doctype, self.get("name")) + ) depreciate_asset(asset, self.posting_date, notes) asset.reload() @@ -519,8 +521,10 @@ class AssetCapitalization(StockController): asset_doc.purchase_date = self.posting_date asset_doc.gross_purchase_amount = total_target_asset_value asset_doc.purchase_receipt_amount = total_target_asset_value - notes = _("This schedule was created when the Asset Capitalization {0} was submitted.").format( - self.name + notes = _( + "This schedule was created when target Asset {0} was updated when Asset Capitalization {1} was submitted." + ).format( + get_link_to_form(asset_doc.doctype, asset_doc.name), get_link_to_form(self.doctype, self.name) ) make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes) elif self.docstatus == 2: @@ -532,8 +536,10 @@ class AssetCapitalization(StockController): if asset.calculate_depreciation: reverse_depreciation_entry_made_after_disposal(asset, self.posting_date) notes = _( - "This schedule was created when the Asset Capitalization {0} was cancelled." - ).format(self.name) + "This schedule was created when Asset {0} was restored when Asset Capitalization {1} was cancelled." + ).format( + get_link_to_form(asset.doctype, asset.name), get_link_to_form(self.doctype, self.name) + ) reset_depreciation_schedule(asset, self.posting_date, notes) def get_asset(self, item): diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 9f4047dcf7..61e8ba2941 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -33,12 +33,7 @@ def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_re def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - - if not asset_depr_schedule_name: - return - - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_doc.name, row.finance_book) prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return @@ -72,12 +67,7 @@ def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, ro def convert_draft_asset_depr_schedules_into_active(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - - if not asset_depr_schedule_name: - return - - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_doc.name, row.finance_book) asset_depr_schedule_doc.status = "Active" @@ -85,16 +75,11 @@ def convert_draft_asset_depr_schedules_into_active(asset_doc): def make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset_doc, notes, submit=True, date_of_disposal=None, date_of_return=None + asset_doc, notes, date_of_disposal=None, date_of_return=None ): for row in asset_doc.get("finance_books"): - current_asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - - if not current_asset_depr_schedule_name: - return - - current_asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", current_asset_depr_schedule_name + current_asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset( + asset_doc.name, row.finance_book ) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) @@ -106,10 +91,7 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( current_asset_depr_schedule_doc.cancel() - new_asset_depr_schedule_doc.insert() - - if submit: - new_asset_depr_schedule_doc.submit() + new_asset_depr_schedule_doc.submit() def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date_of_return=None): @@ -124,12 +106,9 @@ def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date def cancel_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_doc.name, row.finance_book) - if not asset_depr_schedule_name: - return - - asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + asset_depr_schedule_doc.status = "Cancelled" asset_depr_schedule_doc.cancel() @@ -151,6 +130,12 @@ def get_asset_depr_schedule_name(asset_name, finance_book): @frappe.whitelist() def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book): + asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_name, finance_book) + + return asset_depr_schedule_doc.get("depreciation_schedule") + + +def get_asset_depr_schedule_doc_of_asset(asset_name, finance_book): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) if not asset_depr_schedule_name: @@ -158,7 +143,7 @@ def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) - return asset_depr_schedule_doc.get("depreciation_schedule") + return asset_depr_schedule_doc def make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal): diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index d3f74b08b2..31fd0f64e8 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -3,7 +3,7 @@ import frappe from frappe import _ -from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours +from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, time_diff_in_hours import erpnext from erpnext.accounts.general_ledger import make_gl_entries @@ -55,10 +55,11 @@ class AssetRepair(AccountsController): and self.increase_in_asset_life ): self.modify_depreciation_schedule() - notes = _("This schedule was created when the Asset Repair {0} was submitted.").format( - self.name - ) - make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) + + notes = _("This schedule was created when Asset Repair {0} was submitted.").format( + get_link_to_form(self.doctype, self.name) + ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) def before_cancel(self): self.asset_doc = frappe.get_doc("Asset", self.asset) @@ -76,10 +77,11 @@ class AssetRepair(AccountsController): and self.increase_in_asset_life ): self.revert_depreciation_schedule_on_cancellation() - notes = _("This schedule was created when the Asset Repair {0} was cancelled.").format( - self.name - ) - make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) + + notes = _("This schedule was created when Asset Repair {0} was cancelled.").format( + get_link_to_form(self.doctype, self.name) + ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) def check_repair_status(self): if self.repair_status == "Pending": From b997d1eb8773cd9bd5b5f45c3db1c2be3bff4409 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 12 Dec 2022 17:25:38 +0530 Subject: [PATCH 28/94] chore: add some validation, shorten some function names --- .../doctype/journal_entry/journal_entry.py | 6 ++-- erpnext/assets/doctype/asset/asset.js | 2 +- erpnext/assets/doctype/asset/asset.py | 26 ++++++---------- erpnext/assets/doctype/asset/depreciation.py | 4 +-- .../asset_depreciation_schedule.py | 30 ++++++++++++------- .../doctype/asset_repair/asset_repair.py | 6 ++-- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index e661d0b69c..2bbfe34bea 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -24,7 +24,7 @@ from erpnext.accounts.utils import ( get_stock_and_account_balance, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule_from_asset_depr_schedule_of_asset, + get_depr_schedule, ) from erpnext.controllers.accounts_controller import AccountsController @@ -287,9 +287,7 @@ class JournalEntry(AccountsController): if d.reference_type == "Asset" and d.reference_name: asset = frappe.get_doc("Asset", d.reference_name) for row in asset.get("finance_books"): - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( - asset.name, row.finance_book - ) + depr_schedule = get_depr_schedule(asset.name, row.finance_book) for s in depr_schedule: if s.journal_entry == self.name: diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index aa73a224e2..aa3af3beaf 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -209,7 +209,7 @@ frappe.ui.form.on('Asset', { if (frm.doc.finance_books.length == 1) { depr_schedule = (await frappe.call( - "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule_from_asset_depr_schedule_of_asset", + "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule", { asset_name: frm.doc.name, finance_book: frm.doc.finance_books[0].finance_book || null diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index a9fed1c254..47f88b0ae3 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -32,8 +32,8 @@ from erpnext.assets.doctype.asset_category.asset_category import get_asset_categ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( cancel_asset_depr_schedules, convert_draft_asset_depr_schedules_into_active, - get_asset_depr_schedule_doc_of_asset, - get_depr_schedule_from_asset_depr_schedule_of_asset, + get_asset_depr_schedule_doc, + get_depr_schedule, make_draft_asset_depr_schedules, set_draft_asset_depr_schedule_details, update_draft_asset_depr_schedules, @@ -50,6 +50,7 @@ class Asset(AccountsController): self.set_missing_values() if not self.split_from: self.prepare_depreciation_data() + update_draft_asset_depr_schedules(self) self.validate_gross_and_purchase_amount() self.validate_expected_value_after_useful_life() @@ -98,7 +99,6 @@ class Asset(AccountsController): if self.calculate_depreciation: self.value_after_depreciation = 0 self.set_depreciation_rate() - update_draft_asset_depr_schedules(self) else: self.finance_books = [] self.value_after_depreciation = flt(self.gross_purchase_amount) - flt( @@ -350,13 +350,11 @@ class Asset(AccountsController): return depreciation_amount_for_last_row def get_depreciation_amount_for_first_row(self, finance_book): - return get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, finance_book)[ - 0 - ].depreciation_amount + return get_depr_schedule(self.name, finance_book)[0].depreciation_amount def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, row.finance_book) + depr_schedule = get_depr_schedule(self.name, row.finance_book) if not depr_schedule: continue @@ -412,7 +410,7 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(self.name, row.finance_book) + depr_schedule = get_depr_schedule(self.name, row.finance_book) for d in depr_schedule.get("depreciation_schedule"): if d.journal_entry: @@ -900,9 +898,7 @@ def update_existing_asset(asset, remaining_qty, new_asset_name): expected_value_after_useful_life, ) - current_asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset( - asset.name, row.finance_book - ) + current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, asset, row) @@ -947,9 +943,7 @@ def create_new_asset_after_split(asset, split_qty): (row.expected_value_after_useful_life * split_qty) / asset.asset_quantity ) - current_asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset( - asset.name, row.finance_book - ) + current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, new_asset, row) @@ -973,9 +967,7 @@ def create_new_asset_after_split(asset, split_qty): new_asset.set_status() for row in new_asset.get("finance_books"): - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset( - new_asset.name, row.finance_book - ) + depr_schedule = get_depr_schedule(new_asset.name, row.finance_book) for term in depr_schedule: # Update references in JV if term.journal_entry: diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index b7d5511640..514fd86d68 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -12,7 +12,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( get_asset_depr_schedule_name, - get_depr_schedule_from_asset_depr_schedule_of_asset, + get_depr_schedule, get_temp_asset_depr_schedule_doc, make_new_active_asset_depr_schedules_and_cancel_current_ones, ) @@ -300,7 +300,7 @@ def modify_depreciation_schedule_for_asset_repairs(asset): def reverse_depreciation_entry_made_after_disposal(asset, date): for row in asset.get("finance_books"): - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset, row.finance_book) + depr_schedule = get_depr_schedule(asset, row.finance_book) for schedule_idx, schedule in enumerate(depr_schedule): if schedule.schedule_date == date: diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 61e8ba2941..71ce99237d 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -2,6 +2,7 @@ # For license information, please see license.txt import frappe +from frappe import _ from frappe.model.document import Document from frappe.utils import ( add_days, @@ -17,7 +18,18 @@ import erpnext class AssetDepreciationSchedule(Document): - pass + def validate(self): + self.validate_another_asset_depr_schedule_does_not_exist() + + def validate_another_asset_depr_schedule_does_not_exist(self): + asset_depr_schedule_name = get_asset_depr_schedule_name(self.asset, self.finance_book) + + if asset_depr_schedule_name: + frappe.throw( + _("Asset Depreciation Schedule for Asset {0} and Finance Book {1} already exists.").format( + self.asset, self.finance_book + ) + ) def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): @@ -33,7 +45,7 @@ def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_re def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return @@ -67,7 +79,7 @@ def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, ro def convert_draft_asset_depr_schedules_into_active(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) asset_depr_schedule_doc.status = "Active" @@ -78,9 +90,7 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, notes, date_of_disposal=None, date_of_return=None ): for row in asset_doc.get("finance_books"): - current_asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset( - asset_doc.name, row.finance_book - ) + current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) @@ -106,7 +116,7 @@ def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date def cancel_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) asset_depr_schedule_doc.status = "Cancelled" @@ -129,13 +139,13 @@ def get_asset_depr_schedule_name(asset_name, finance_book): @frappe.whitelist() -def get_depr_schedule_from_asset_depr_schedule_of_asset(asset_name, finance_book): - asset_depr_schedule_doc = get_asset_depr_schedule_doc_of_asset(asset_name, finance_book) +def get_depr_schedule(asset_name, finance_book): + asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_name, finance_book) return asset_depr_schedule_doc.get("depreciation_schedule") -def get_asset_depr_schedule_doc_of_asset(asset_name, finance_book): +def get_asset_depr_schedule_doc(asset_name, finance_book): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) if not asset_depr_schedule_name: diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 31fd0f64e8..2396df93a3 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -9,7 +9,7 @@ import erpnext from erpnext.accounts.general_ledger import make_gl_entries from erpnext.assets.doctype.asset.asset import get_asset_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule_from_asset_depr_schedule_of_asset, + get_depr_schedule, make_new_active_asset_depr_schedules_and_cancel_current_ones, ) from erpnext.controllers.accounts_controller import AccountsController @@ -285,7 +285,7 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset.name, row.finance_book) + depr_schedule = get_depr_schedule(asset.name, row.finance_book) # the Schedule Date in the final row of the old Depreciation Schedule last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date @@ -318,7 +318,7 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) - depr_schedule = get_depr_schedule_from_asset_depr_schedule_of_asset(asset.name, row.finance_book) + depr_schedule = get_depr_schedule(asset.name, row.finance_book) # the Schedule Date in the final row of the modified Depreciation Schedule last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date From 1ea2ba0dea352110cc495c630de36876bd165d68 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 12 Dec 2022 17:31:57 +0530 Subject: [PATCH 29/94] chore: handle some cases where asset_depr_schedule doesn't exist --- .../asset_depreciation_schedule.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 71ce99237d..b01f23929a 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -47,6 +47,9 @@ def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_ for row in asset_doc.get("finance_books"): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + if not asset_depr_schedule_doc: + continue + prepare_draft_asset_depr_schedule_data( asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return ) @@ -142,6 +145,9 @@ def get_asset_depr_schedule_name(asset_name, finance_book): def get_depr_schedule(asset_name, finance_book): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_name, finance_book) + if not asset_depr_schedule_doc: + return + return asset_depr_schedule_doc.get("depreciation_schedule") From 28d4942d6cda0db750421230c647b672b4848a0c Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 12 Dec 2022 18:19:34 +0530 Subject: [PATCH 30/94] chore: fix validation and add make_schedules_editable --- .../asset_depreciation_schedule.js | 14 ++++++++++ .../asset_depreciation_schedule.py | 26 ++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js index fdebbb17c3..c28b2b3b6a 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js @@ -2,6 +2,20 @@ // For license information, please see license.txt frappe.provide("erpnext.asset"); +frappe.ui.form.on('Asset Depreciation Schedule', { + onload: function(frm) { + frm.events.make_schedules_editable(frm); + }, + + make_schedules_editable: function(frm) { + var is_editable = frm.doc.depreciation_method == "Manual" ? true : false; + + frm.toggle_enable("depreciation_schedule", is_editable); + frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", is_editable); + frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", is_editable); + } +}); + frappe.ui.form.on('Depreciation Schedule', { make_depreciation_entry: function(frm, cdt, cdn) { var row = locals[cdt][cdn]; diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index b01f23929a..2cdea574dd 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -22,14 +22,28 @@ class AssetDepreciationSchedule(Document): self.validate_another_asset_depr_schedule_does_not_exist() def validate_another_asset_depr_schedule_does_not_exist(self): - asset_depr_schedule_name = get_asset_depr_schedule_name(self.asset, self.finance_book) + finance_book_filter = ["finance_book", "is", "not set"] + if self.finance_book: + finance_book_filter = ["finance_book", "=", self.finance_book] - if asset_depr_schedule_name: - frappe.throw( - _("Asset Depreciation Schedule for Asset {0} and Finance Book {1} already exists.").format( - self.asset, self.finance_book + num_asset_depr_schedules = frappe.db.count( + "Asset Depreciation Schedule", + [ + ["asset", "=", self.asset], + finance_book_filter, + ["docstatus", "<", 2], + ], + ) + + if num_asset_depr_schedules == 1: + asset_depr_schedule_name = get_asset_depr_schedule_name(self.asset, self.finance_book) + + if self.name != asset_depr_schedule_name: + frappe.throw( + _("Asset Depreciation Schedule for Asset {0} and Finance Book {1} already exists.").format( + self.asset, self.finance_book + ) ) - ) def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): From df134c7c5b73178cf4f771a5d35d463a8fa23fa5 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 13 Dec 2022 16:26:33 +0530 Subject: [PATCH 31/94] chore: fixing some tests --- .../doctype/sales_invoice/sales_invoice.py | 8 +- erpnext/assets/doctype/asset/asset.py | 36 ++---- erpnext/assets/doctype/asset/depreciation.py | 19 ++- erpnext/assets/doctype/asset/test_asset.py | 108 +++++++++++------- .../asset_depreciation_schedule.py | 66 ++++++++--- 5 files changed, 145 insertions(+), 92 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 9430f6a294..4168f01859 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1185,7 +1185,13 @@ class SalesInvoice(SellingController): if asset.calculate_depreciation: posting_date = frappe.db.get_value("Sales Invoice", self.return_against, "posting_date") reverse_depreciation_entry_made_after_disposal(asset, posting_date) - reset_depreciation_schedule(asset, self.posting_date, "Return asset") + notes = _( + "This schedule was created when Asset {0} was returned after being sold through Sales Invoice {1}." + ).format( + get_link_to_form(asset.doctype, asset.name), + get_link_to_form(self.doctype, self.get("name")), + ) + reset_depreciation_schedule(asset, self.posting_date, notes) else: if asset.calculate_depreciation: diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 47f88b0ae3..cb97ccce01 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -35,6 +35,7 @@ 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, set_draft_asset_depr_schedule_details, update_draft_asset_depr_schedules, ) @@ -62,7 +63,9 @@ class Asset(AccountsController): self.make_asset_movement() if not self.booked_fixed_asset and self.validate_make_gl_entry(): self.make_gl_entries() - convert_draft_asset_depr_schedules_into_active(self) + if not self.split_from: + make_draft_asset_depr_schedules_if_not_present(self) + convert_draft_asset_depr_schedules_into_active(self) def on_cancel(self): self.validate_cancellation() @@ -332,26 +335,6 @@ class Asset(AccountsController): ).format(row.idx) ) - # to ensure that final accumulated depreciation amount is accurate - def get_adjusted_depreciation_amount( - self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row, finance_book - ): - if not self.opening_accumulated_depreciation: - depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row(finance_book) - - if ( - depreciation_amount_for_first_row + depreciation_amount_for_last_row - != depreciation_amount_without_pro_rata - ): - depreciation_amount_for_last_row = ( - depreciation_amount_without_pro_rata - depreciation_amount_for_first_row - ) - - return depreciation_amount_for_last_row - - def get_depreciation_amount_for_first_row(self, finance_book): - return get_depr_schedule(self.name, finance_book)[0].depreciation_amount - def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): depr_schedule = get_depr_schedule(self.name, row.finance_book) @@ -412,7 +395,7 @@ class Asset(AccountsController): for row in self.get("finance_books"): depr_schedule = get_depr_schedule(self.name, row.finance_book) - for d in depr_schedule.get("depreciation_schedule"): + for d in depr_schedule: if d.journal_entry: frappe.get_doc("Journal Entry", d.journal_entry).cancel() d.db_set("journal_entry", None) @@ -943,6 +926,10 @@ def create_new_asset_after_split(asset, split_qty): (row.expected_value_after_useful_life * split_qty) / asset.asset_quantity ) + new_asset.submit() + new_asset.set_status() + + for row in new_asset.get("finance_books"): current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) @@ -961,10 +948,7 @@ def create_new_asset_after_split(asset, split_qty): ) new_asset_depr_schedule_doc.notes = notes - new_asset_depr_schedule_doc.insert() - - new_asset.submit() - new_asset.set_status() + new_asset_depr_schedule_doc.submit() for row in new_asset.get("finance_books"): depr_schedule = get_depr_schedule(new_asset.name, row.finance_book) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 514fd86d68..d7d248089a 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -28,7 +28,10 @@ def post_depreciation_entries(date=None, commit=True): if not date: date = today() for asset_name in get_depreciable_assets(date): - make_depreciation_entry_for_all_asset_depr_schedules(asset_name, date) + asset_doc = frappe.get_doc("Asset", asset_name) + + make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) + if commit: frappe.db.commit() @@ -46,9 +49,7 @@ def get_depreciable_assets(date): ) -def make_depreciation_entry_for_all_asset_depr_schedules(asset_name, date=None): - asset_doc = frappe.get_doc("Asset", asset_name) - +def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): for row in asset_doc.get("finance_books"): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) make_depreciation_entry(asset_depr_schedule_name, date) @@ -240,6 +241,7 @@ def scrap_asset(asset_name): notes = _( "This schedule was created when Asset {0} was scrapped through Journal Entry {1}." ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(je.doctype, je.name)) + depreciate_asset(asset, date, notes) frappe.db.set_value("Asset", asset_name, "disposal_date", date) @@ -254,10 +256,15 @@ def restore_asset(asset_name): asset = frappe.get_doc("Asset", asset_name) reverse_depreciation_entry_made_after_disposal(asset, asset.disposal_date) - reset_depreciation_schedule(asset, asset.disposal_date, "Restore asset") je = asset.journal_entry_for_scrap + notes = _( + "This schedule was created when Asset {0} was restored after being scrapped by Journal Entry {1}." + ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(je.doctype, je.name)) + + reset_depreciation_schedule(asset, asset.disposal_date, notes) + asset.db_set("disposal_date", None) asset.db_set("journal_entry_for_scrap", None) @@ -300,7 +307,7 @@ def modify_depreciation_schedule_for_asset_repairs(asset): def reverse_depreciation_entry_made_after_disposal(asset, date): for row in asset.get("finance_books"): - depr_schedule = get_depr_schedule(asset, row.finance_book) + depr_schedule = get_depr_schedule(asset.name, row.finance_book) for schedule_idx, schedule in enumerate(depr_schedule): if schedule.schedule_date == date: diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 60324ea73d..8835b32bcc 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -27,6 +27,11 @@ from erpnext.assets.doctype.asset.depreciation import ( restore_asset, scrap_asset, ) +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + clear_depr_schedule, + get_asset_depr_schedule_doc, + get_depr_schedule, +) from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( make_purchase_invoice as make_invoice, ) @@ -379,20 +384,23 @@ class TestAsset(AssetSetup): new_asset = split_asset(asset.name, 2) asset.load_from_db() + depr_schedule_of_asset = get_depr_schedule(asset.name) + depr_schedule_of_new_asset = get_depr_schedule(new_asset.name) + self.assertEqual(new_asset.asset_quantity, 2) self.assertEqual(new_asset.gross_purchase_amount, 24000) self.assertEqual(new_asset.opening_accumulated_depreciation, 4000) self.assertEqual(new_asset.split_from, asset.name) - self.assertEqual(new_asset.schedules[0].depreciation_amount, 4000) - self.assertEqual(new_asset.schedules[1].depreciation_amount, 4000) + self.assertEqual(depr_schedule_of_new_asset[0].depreciation_amount, 4000) + self.assertEqual(depr_schedule_of_new_asset[1].depreciation_amount, 4000) self.assertEqual(asset.asset_quantity, 8) self.assertEqual(asset.gross_purchase_amount, 96000) self.assertEqual(asset.opening_accumulated_depreciation, 16000) - self.assertEqual(asset.schedules[0].depreciation_amount, 16000) - self.assertEqual(asset.schedules[1].depreciation_amount, 16000) + self.assertEqual(depr_schedule_of_asset[0].depreciation_amount, 16000) + self.assertEqual(depr_schedule_of_asset[1].depreciation_amount, 16000) - journal_entry = asset.schedules[0].journal_entry + journal_entry = depr_schedule_of_asset[0].journal_entry jv = frappe.get_doc("Journal Entry", journal_entry) self.assertEqual(jv.accounts[0].credit_in_account_currency, 16000) @@ -629,7 +637,7 @@ class TestDepreciationMethods(AssetSetup): schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -651,7 +659,7 @@ class TestDepreciationMethods(AssetSetup): expected_schedules = [["2032-12-31", 30000.0, 77095.89], ["2033-06-06", 12904.11, 90000.0]] schedules = [ [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -678,7 +686,7 @@ class TestDepreciationMethods(AssetSetup): schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -703,7 +711,7 @@ class TestDepreciationMethods(AssetSetup): schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -733,7 +741,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -765,7 +773,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -798,7 +806,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -831,7 +839,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in asset.get("schedules") + for d in get_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -854,7 +862,7 @@ class TestDepreciationBasics(AssetSetup): ["2022-12-31", 30000, 90000], ] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -877,7 +885,7 @@ class TestDepreciationBasics(AssetSetup): ["2023-01-01", 15000, 90000], ] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -922,7 +930,7 @@ class TestDepreciationBasics(AssetSetup): expected_values = [["2020-12-31", 30000.0], ["2021-12-31", 30000.0], ["2022-12-31", 30000.0]] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) @@ -942,7 +950,7 @@ class TestDepreciationBasics(AssetSetup): expected_values = [30000.0, 60000.0, 90000.0] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(expected_values[i], schedule.accumulated_depreciation_amount) def test_check_is_pro_rata(self): @@ -1122,9 +1130,9 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - self.assertTrue(asset.schedules[0].journal_entry) - self.assertFalse(asset.schedules[1].journal_entry) - self.assertFalse(asset.schedules[2].journal_entry) + self.assertTrue(get_depr_schedule(asset.name)[0].journal_entry) + self.assertFalse(get_depr_schedule(asset.name)[1].journal_entry) + self.assertFalse(get_depr_schedule(asset.name)[2].journal_entry) def test_depr_entry_posting_when_depr_expense_account_is_an_expense_account(self): """Tests if the Depreciation Expense Account gets debited and the Accumulated Depreciation Account gets credited when the former's an Expense Account.""" @@ -1143,7 +1151,7 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - je = frappe.get_doc("Journal Entry", asset.schedules[0].journal_entry) + je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name)[0].journal_entry) accounting_entries = [ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts @@ -1179,7 +1187,7 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - je = frappe.get_doc("Journal Entry", asset.schedules[0].journal_entry) + je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name)[0].journal_entry) accounting_entries = [ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts @@ -1215,9 +1223,11 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - asset.clear_depr_schedule() + asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name) - self.assertEqual(len(asset.schedules), 1) + clear_depr_schedule(asset_depr_schedule_doc) + + self.assertEqual(len(asset_depr_schedule_doc.get("depreciation_schedule")), 1) def test_clear_depr_schedule_for_multiple_finance_books(self): asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31", do_not_save=1) @@ -1226,6 +1236,7 @@ class TestDepreciationBasics(AssetSetup): asset.append( "finance_books", { + "finance_book": "Test Finance Book 1", "depreciation_method": "Straight Line", "frequency_of_depreciation": 1, "total_number_of_depreciations": 3, @@ -1236,6 +1247,7 @@ class TestDepreciationBasics(AssetSetup): asset.append( "finance_books", { + "finance_book": "Test Finance Book 2", "depreciation_method": "Straight Line", "frequency_of_depreciation": 1, "total_number_of_depreciations": 6, @@ -1246,6 +1258,7 @@ class TestDepreciationBasics(AssetSetup): asset.append( "finance_books", { + "finance_book": "Test Finance Book 3", "depreciation_method": "Straight Line", "frequency_of_depreciation": 12, "total_number_of_depreciations": 3, @@ -1258,15 +1271,17 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2020-04-01") asset.load_from_db() - asset.clear_depr_schedule() + asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 1") + clear_depr_schedule(asset_depr_schedule_doc_1) + self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3) - self.assertEqual(len(asset.schedules), 6) + asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 2") + clear_depr_schedule(asset_depr_schedule_doc_2) + self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 3) - for schedule in asset.schedules: - if schedule.idx <= 3: - self.assertEqual(schedule.finance_book_id, "1") - else: - self.assertEqual(schedule.finance_book_id, "2") + asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 3") + clear_depr_schedule(asset_depr_schedule_doc_3) + self.assertEqual(len(asset_depr_schedule_doc_3.get("depreciation_schedule")), 0) def test_depreciation_schedules_are_set_up_for_multiple_finance_books(self): asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31", do_not_save=1) @@ -1275,6 +1290,7 @@ class TestDepreciationBasics(AssetSetup): asset.append( "finance_books", { + "finance_book": "Test Finance Book 1", "depreciation_method": "Straight Line", "frequency_of_depreciation": 12, "total_number_of_depreciations": 3, @@ -1285,6 +1301,7 @@ class TestDepreciationBasics(AssetSetup): asset.append( "finance_books", { + "finance_book": "Test Finance Book 2", "depreciation_method": "Straight Line", "frequency_of_depreciation": 12, "total_number_of_depreciations": 6, @@ -1294,13 +1311,11 @@ class TestDepreciationBasics(AssetSetup): ) asset.save() - self.assertEqual(len(asset.schedules), 9) + asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 1") + self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3) - for schedule in asset.schedules: - if schedule.idx <= 3: - self.assertEqual(schedule.finance_book_id, 1) - else: - self.assertEqual(schedule.finance_book_id, 2) + asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 2") + self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 6) def test_depreciation_entry_cancellation(self): asset = create_asset( @@ -1320,12 +1335,12 @@ class TestDepreciationBasics(AssetSetup): asset.load_from_db() # cancel depreciation entry - depr_entry = asset.get("schedules")[0].journal_entry + depr_entry = get_depr_schedule(asset.name)[0].journal_entry self.assertTrue(depr_entry) frappe.get_doc("Journal Entry", depr_entry).cancel() asset.load_from_db() - depr_entry = asset.get("schedules")[0].journal_entry + depr_entry = get_depr_schedule(asset.name)[0].journal_entry self.assertFalse(depr_entry) def test_asset_expected_value_after_useful_life(self): @@ -1340,7 +1355,7 @@ class TestDepreciationBasics(AssetSetup): ) accumulated_depreciation_after_full_schedule = max( - d.accumulated_depreciation_amount for d in asset.get("schedules") + d.accumulated_depreciation_amount for d in get_depr_schedule(asset.name) ) asset_value_after_full_schedule = flt(asset.gross_purchase_amount) - flt( @@ -1371,7 +1386,7 @@ class TestDepreciationBasics(AssetSetup): asset.load_from_db() # check depreciation entry series - self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR") + self.assertEqual(get_depr_schedule(asset.name)[0].journal_entry[:4], "DEPR") expected_gle = ( ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0), @@ -1441,7 +1456,7 @@ class TestDepreciationBasics(AssetSetup): "2020-07-15", ] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_dates[i]), getdate(schedule.schedule_date)) @@ -1455,6 +1470,15 @@ def create_asset_data(): if not frappe.db.exists("Location", "Test Location"): frappe.get_doc({"doctype": "Location", "location_name": "Test Location"}).insert() + if not frappe.db.exists("Finance Book", "Test Finance Book 1"): + frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 1"}).insert() + + if not frappe.db.exists("Finance Book", "Test Finance Book 2"): + frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 2"}).insert() + + if not frappe.db.exists("Finance Book", "Test Finance Book 3"): + frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 3"}).insert() + def create_asset(**args): args = frappe._dict(args) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 2cdea574dd..42b7b4b9ee 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -46,33 +46,41 @@ class AssetDepreciationSchedule(Document): ) -def make_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): +def make_draft_asset_depr_schedules_if_not_present(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") + asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) - prepare_draft_asset_depr_schedule_data( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return - ) - - asset_depr_schedule_doc.insert() + if not asset_depr_schedule_name: + make_draft_asset_depr_schedule(asset_doc, row) -def update_draft_asset_depr_schedules(asset_doc, date_of_disposal=None, date_of_return=None): +def make_draft_asset_depr_schedules(asset_doc): + for row in asset_doc.get("finance_books"): + make_draft_asset_depr_schedule(asset_doc, row) + + +def make_draft_asset_depr_schedule(asset_doc, row): + asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") + + prepare_draft_asset_depr_schedule_data(asset_depr_schedule_doc, asset_doc, row) + + asset_depr_schedule_doc.insert() + + +def update_draft_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) if not asset_depr_schedule_doc: continue - prepare_draft_asset_depr_schedule_data( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return - ) + prepare_draft_asset_depr_schedule_data(asset_depr_schedule_doc, asset_doc, row) asset_depr_schedule_doc.save() def prepare_draft_asset_depr_schedule_data( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, asset_doc, row, date_of_disposal=None, date_of_return=None ): set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, row) make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) @@ -140,7 +148,7 @@ def cancel_asset_depr_schedules(asset_doc): asset_depr_schedule_doc.cancel() -def get_asset_depr_schedule_name(asset_name, finance_book): +def get_asset_depr_schedule_name(asset_name, finance_book=None): finance_book_filter = ["finance_book", "is", "not set"] if finance_book: finance_book_filter = ["finance_book", "=", finance_book] @@ -156,7 +164,7 @@ def get_asset_depr_schedule_name(asset_name, finance_book): @frappe.whitelist() -def get_depr_schedule(asset_name, finance_book): +def get_depr_schedule(asset_name, finance_book=None): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_name, finance_book) if not asset_depr_schedule_doc: @@ -165,7 +173,7 @@ def get_depr_schedule(asset_name, finance_book): return asset_depr_schedule_doc.get("depreciation_schedule") -def get_asset_depr_schedule_doc(asset_name, finance_book): +def get_asset_depr_schedule_doc(asset_name, finance_book=None): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) if not asset_depr_schedule_name: @@ -291,8 +299,8 @@ def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_ row, depreciation_amount, schedule_date, asset_doc.to_date ) - depreciation_amount = asset_doc.get_adjusted_depreciation_amount( - depreciation_amount_without_pro_rata, depreciation_amount, row.finance_book + depreciation_amount = get_adjusted_depreciation_amount( + asset_depr_schedule_doc, depreciation_amount_without_pro_rata, depreciation_amount ) monthly_schedule_date = add_months(schedule_date, 1) @@ -325,6 +333,30 @@ def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_ ) +# to ensure that final accumulated depreciation amount is accurate +def get_adjusted_depreciation_amount( + asset_depr_schedule_doc, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row +): + if not asset_depr_schedule_doc.opening_accumulated_depreciation: + depreciation_amount_for_first_row = get_depreciation_amount_for_first_row( + asset_depr_schedule_doc + ) + + if ( + depreciation_amount_for_first_row + depreciation_amount_for_last_row + != depreciation_amount_without_pro_rata + ): + depreciation_amount_for_last_row = ( + depreciation_amount_without_pro_rata - depreciation_amount_for_first_row + ) + + return depreciation_amount_for_last_row + + +def get_depreciation_amount_for_first_row(asset_depr_schedule_doc): + return asset_depr_schedule_doc.get("depreciation_schedule")[0].depreciation_amount + + @erpnext.allow_regional def get_depreciation_amount(asset_doc, depreciable_value, row): if row.depreciation_method in ("Straight Line", "Manual"): From 22ef342ac7f87cc94da7ca8d0739a5ce7c3ebef2 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 13 Dec 2022 20:48:34 +0530 Subject: [PATCH 32/94] chore: fixing all tests --- .../doctype/sales_invoice/sales_invoice.py | 2 + .../sales_invoice/test_sales_invoice.py | 9 +++-- erpnext/assets/doctype/asset/depreciation.py | 35 ++++++++++++------ .../asset_capitalization.py | 2 + .../test_asset_capitalization.py | 7 +++- .../asset_depreciation_schedule.py | 37 +++++++++++++++---- .../doctype/asset_repair/asset_repair.py | 4 ++ .../doctype/asset_repair/test_asset_repair.py | 5 ++- .../asset_value_adjustment.py | 13 +++++-- 9 files changed, 87 insertions(+), 27 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 4168f01859..31cf1206ce 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1192,6 +1192,7 @@ class SalesInvoice(SellingController): get_link_to_form(self.doctype, self.get("name")), ) reset_depreciation_schedule(asset, self.posting_date, notes) + asset.reload() else: if asset.calculate_depreciation: @@ -1202,6 +1203,7 @@ class SalesInvoice(SellingController): get_link_to_form(self.doctype, self.get("name")), ) depreciate_asset(asset, self.posting_date, notes) + asset.reload() fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name") diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 855380ef25..363ca16e99 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -21,6 +21,9 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_comp from erpnext.accounts.utils import PaymentEntryUnlinkError from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depr_schedule, +) from erpnext.controllers.accounts_controller import update_invoice_status from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency @@ -2774,7 +2777,7 @@ class TestSalesInvoice(unittest.TestCase): ["2021-09-30", 5041.1, 26407.22], ] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -2805,7 +2808,7 @@ class TestSalesInvoice(unittest.TestCase): expected_values = [["2020-12-31", 30000, 30000], ["2021-12-31", 30000, 60000]] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -2834,7 +2837,7 @@ class TestSalesInvoice(unittest.TestCase): ["2025-06-06", 18633.88, 100000.0, False], ] - for i, schedule in enumerate(asset.schedules): + for i, schedule in enumerate(get_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index d7d248089a..4278658fd2 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -11,8 +11,8 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_asset_depr_schedule_doc, get_asset_depr_schedule_name, - get_depr_schedule, get_temp_asset_depr_schedule_doc, make_new_active_asset_depr_schedules_and_cancel_current_ones, ) @@ -220,6 +220,13 @@ def scrap_asset(asset_name): date = today() + notes = _("This schedule was created when Asset {0} was scrapped.").format( + get_link_to_form(asset.doctype, asset.name) + ) + + depreciate_asset(asset, date, notes) + asset.reload() + depreciation_series = frappe.get_cached_value( "Company", asset.company, "series_for_depreciation_entry" ) @@ -238,12 +245,6 @@ def scrap_asset(asset_name): je.flags.ignore_permissions = True je.submit() - notes = _( - "This schedule was created when Asset {0} was scrapped through Journal Entry {1}." - ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(je.doctype, je.name)) - - depreciate_asset(asset, date, notes) - frappe.db.set_value("Asset", asset_name, "disposal_date", date) frappe.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name) asset.set_status("Scrapped") @@ -259,9 +260,9 @@ def restore_asset(asset_name): je = asset.journal_entry_for_scrap - notes = _( - "This schedule was created when Asset {0} was restored after being scrapped by Journal Entry {1}." - ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(je.doctype, je.name)) + notes = _("This schedule was created when Asset {0} was restored.").format( + get_link_to_form(asset.doctype, asset.name) + ) reset_depreciation_schedule(asset, asset.disposal_date, notes) @@ -274,20 +275,28 @@ def restore_asset(asset_name): def depreciate_asset(asset_doc, date, notes): + asset_doc.flags.ignore_validate_update_after_submit = True + make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, notes, date_of_disposal=date ) + asset_doc.save() + make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) def reset_depreciation_schedule(asset_doc, date, notes): + asset_doc.flags.ignore_validate_update_after_submit = True + make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, notes, date_of_return=date ) modify_depreciation_schedule_for_asset_repairs(asset_doc) + asset_doc.save() + def modify_depreciation_schedule_for_asset_repairs(asset): asset_repairs = frappe.get_all( @@ -307,9 +316,9 @@ def modify_depreciation_schedule_for_asset_repairs(asset): def reverse_depreciation_entry_made_after_disposal(asset, date): for row in asset.get("finance_books"): - depr_schedule = get_depr_schedule(asset.name, row.finance_book) + asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) - for schedule_idx, schedule in enumerate(depr_schedule): + for schedule_idx, schedule in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")): if schedule.schedule_date == date: if not disposal_was_made_on_original_schedule_date( schedule_idx, row, date @@ -321,10 +330,12 @@ def reverse_depreciation_entry_made_after_disposal(asset, date): reverse_journal_entry.submit() frappe.flags.is_reverse_depr_entry = False + asset_depr_schedule_doc.flags.ignore_validate_update_after_submit = True asset.flags.ignore_validate_update_after_submit = True schedule.journal_entry = None depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry) row.value_after_depreciation += depreciation_amount + asset_depr_schedule_doc.save() asset.save() diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 26bac86094..7d3b645be7 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -527,6 +527,8 @@ class AssetCapitalization(StockController): get_link_to_form(asset_doc.doctype, asset_doc.name), get_link_to_form(self.doctype, self.name) ) make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes) + asset_doc.flags.ignore_validate_update_after_submit = True + asset_doc.save() elif self.docstatus == 2: for item in self.asset_items: asset = self.get_asset(item) diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index 86861f0b16..e99e71b0ac 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -12,6 +12,9 @@ from erpnext.assets.doctype.asset.test_asset import ( create_asset_data, set_depreciation_settings_in_company, ) +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depr_schedule, +) from erpnext.stock.doctype.item.test_item import create_item @@ -283,7 +286,9 @@ class TestAssetCapitalization(unittest.TestCase): self.assertEqual(consumed_asset.status, "Decapitalized") consumed_depreciation_schedule = [ - d for d in consumed_asset.schedules if getdate(d.schedule_date) == getdate(capitalization_date) + d + for d in get_depr_schedule(consumed_asset.name) + if getdate(d.schedule_date) == getdate(capitalization_date) ] self.assertTrue( consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 42b7b4b9ee..0d3241b760 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -80,10 +80,17 @@ def update_draft_asset_depr_schedules(asset_doc): def prepare_draft_asset_depr_schedule_data( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal=None, date_of_return=None + asset_depr_schedule_doc, + asset_doc, + row, + date_of_disposal=None, + date_of_return=None, + update_asset_finance_book_row=True, ): set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, row) - make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal) + make_depr_schedule( + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, update_asset_finance_book_row + ) set_accumulated_depreciation(asset_depr_schedule_doc, row, date_of_disposal, date_of_return) @@ -129,11 +136,18 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( new_asset_depr_schedule_doc.submit() -def get_temp_asset_depr_schedule_doc(asset_doc, row, date_of_disposal=None, date_of_return=None): +def get_temp_asset_depr_schedule_doc( + asset_doc, row, date_of_disposal=None, date_of_return=None, update_asset_finance_book_row=False +): asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") prepare_draft_asset_depr_schedule_data( - asset_depr_schedule_doc, asset_doc, row, date_of_disposal, date_of_return + asset_depr_schedule_doc, + asset_doc, + row, + date_of_disposal, + date_of_return, + update_asset_finance_book_row, ) return asset_depr_schedule_doc @@ -184,7 +198,9 @@ def get_asset_depr_schedule_doc(asset_name, finance_book=None): return asset_depr_schedule_doc -def make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal): +def make_depr_schedule( + asset_depr_schedule_doc, asset_doc, row, date_of_disposal, update_asset_finance_book_row=True +): if row.depreciation_method != "Manual" and not asset_depr_schedule_doc.get( "depreciation_schedule" ): @@ -195,7 +211,9 @@ def make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, date_of_disposal start = clear_depr_schedule(asset_depr_schedule_doc) - _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal) + _make_depr_schedule( + asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal, update_asset_finance_book_row + ) def clear_depr_schedule(asset_depr_schedule_doc): @@ -216,12 +234,17 @@ def clear_depr_schedule(asset_depr_schedule_doc): return start -def _make_depr_schedule(asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal): +def _make_depr_schedule( + asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal, update_asset_finance_book_row +): asset_doc.validate_asset_finance_books(row) value_after_depreciation = asset_doc._get_value_after_depreciation(row) row.value_after_depreciation = value_after_depreciation + if update_asset_finance_book_row: + row.db_update() + number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint( asset_doc.number_of_depreciations_booked ) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 2396df93a3..6239915232 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -59,7 +59,9 @@ class AssetRepair(AccountsController): notes = _("This schedule was created when Asset Repair {0} was submitted.").format( get_link_to_form(self.doctype, self.name) ) + self.asset_doc.flags.ignore_validate_update_after_submit = True make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) + self.asset_doc.save() def before_cancel(self): self.asset_doc = frappe.get_doc("Asset", self.asset) @@ -81,7 +83,9 @@ class AssetRepair(AccountsController): notes = _("This schedule was created when Asset Repair {0} was cancelled.").format( get_link_to_form(self.doctype, self.name) ) + self.asset_doc.flags.ignore_validate_update_after_submit = True make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes) + self.asset_doc.save() def check_repair_status(self): if self.repair_status == "Pending": diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py index 6e06f52ac6..4579b4d56a 100644 --- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py @@ -12,6 +12,9 @@ from erpnext.assets.doctype.asset.test_asset import ( create_asset_data, set_depreciation_settings_in_company, ) +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depr_schedule, +) from erpnext.stock.doctype.item.test_item import create_item @@ -238,7 +241,7 @@ class TestAssetRepair(unittest.TestCase): self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset)) self.assertEqual( - asset.schedules[-1].accumulated_depreciation_amount, + get_depr_schedule(asset.name)[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation, ) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 9caca33c30..0248a37030 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -5,7 +5,7 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import date_diff, flt, formatdate, getdate +from frappe.utils import date_diff, flt, formatdate, get_link_to_form, getdate from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, @@ -123,9 +123,16 @@ class AssetValueAdjustment(Document): new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) - new_asset_depr_schedule_doc.notes = "Asset value adjustment" - current_asset_depr_schedule_doc.cancel() + + notes = _( + "This schedule was created when Asset {0} was adjusted through Asset Value Adjustment {1}." + ).format( + get_link_to_form(asset.doctype, asset.name), + get_link_to_form(self.get("doctype"), self.get("name")), + ) + new_asset_depr_schedule_doc.notes = notes + new_asset_depr_schedule_doc.insert() depr_schedule = new_asset_depr_schedule_doc.get("depreciation_schedule") From c99cd74a15e3a126b68719c26def4be6f209b435 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Wed, 14 Dec 2022 13:20:37 +0530 Subject: [PATCH 33/94] chore: handle some error cases and add empty patch file --- .../asset_depreciation_schedule.py | 16 +++++++++++++--- erpnext/patches.txt | 1 + ...e_asset_depreciation_schedules_from_assets.py | 5 +++++ 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 0d3241b760..986acc09d4 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -113,9 +113,9 @@ def convert_draft_asset_depr_schedules_into_active(asset_doc): for row in asset_doc.get("finance_books"): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) - asset_depr_schedule_doc.status = "Active" - - asset_depr_schedule_doc.submit() + if asset_depr_schedule_doc.status == "Draft": + asset_depr_schedule_doc.status = "Active" + asset_depr_schedule_doc.submit() def make_new_active_asset_depr_schedules_and_cancel_current_ones( @@ -124,6 +124,13 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( for row in asset_doc.get("finance_books"): current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + if not current_asset_depr_schedule_doc: + frappe.throw( + _("Asset Depreciation Schedule not found for Asset {0} and Finance Book {1}").format( + asset_doc.name, row.finance_book + ) + ) + new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) make_depr_schedule(new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal) @@ -157,6 +164,9 @@ def cancel_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + if not asset_depr_schedule_doc: + continue + asset_depr_schedule_doc.status = "Cancelled" asset_depr_schedule_doc.cancel() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 0aad1d34e5..622fda42d8 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -268,6 +268,7 @@ erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v15_0.delete_taxjar_doctypes +erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets [post_model_sync] execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py new file mode 100644 index 0000000000..3e646b487f --- /dev/null +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -0,0 +1,5 @@ +# import frappe + + +def execute(): + pass From 7f5e761c041310e7dd53ebc12e81b70d69042f7b Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 15 Dec 2022 13:13:04 +0530 Subject: [PATCH 34/94] chore: add patch --- .../asset_depreciation_schedule.json | 4 +- .../asset_depreciation_schedule.py | 4 +- ...sset_depreciation_schedules_from_assets.py | 89 ++++++++++++++++++- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index 0fea6a5b19..199f73f508 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -142,7 +142,7 @@ }, { "fieldname": "finance_book_id", - "fieldtype": "Data", + "fieldtype": "Int", "hidden": 1, "label": "Finance Book Id", "print_hide": 1, @@ -161,7 +161,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-12-09 15:14:20.562294", + "modified": "2022-12-15 13:01:02.984906", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 986acc09d4..5639d3db97 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -167,7 +167,9 @@ def cancel_asset_depr_schedules(asset_doc): if not asset_depr_schedule_doc: continue - asset_depr_schedule_doc.status = "Cancelled" + frappe.db.set_value( + "Asset Depreciation Schedule", asset_depr_schedule_doc.name, "status", "Cancelled" + ) asset_depr_schedule_doc.cancel() diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py index 3e646b487f..11064a9c84 100644 --- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -1,5 +1,90 @@ -# import frappe +import frappe def execute(): - pass + assets = get_details_of_depreciable_assets() + + for asset in assets: + finance_book_rows = get_details_of_asset_finance_books_rows(asset.name) + + for fb_row in finance_book_rows: + asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule") + + asset_depr_schedule_doc.asset = asset.name + asset_depr_schedule_doc.finance_book = fb_row.finance_book + asset_depr_schedule_doc.finance_book_id = fb_row.idx + asset_depr_schedule_doc.opening_accumulated_depreciation = ( + asset.opening_accumulated_depreciation + ) + asset_depr_schedule_doc.depreciation_method = fb_row.depreciation_method + asset_depr_schedule_doc.total_number_of_depreciations = fb_row.total_number_of_depreciations + asset_depr_schedule_doc.frequency_of_depreciation = fb_row.frequency_of_depreciation + asset_depr_schedule_doc.rate_of_depreciation = fb_row.rate_of_depreciation + asset_depr_schedule_doc.expected_value_after_useful_life = ( + fb_row.expected_value_after_useful_life + ) + asset_depr_schedule_doc.status = "Draft" + + asset_depr_schedule_doc.insert() + + update_depreciation_schedules(asset.name, asset_depr_schedule_doc.name, fb_row.idx) + + if asset.docstatus == 1: + asset_depr_schedule_doc.status = "Active" + asset_depr_schedule_doc.submit() + elif asset.docstatus == 2: + asset_depr_schedule_doc.status = "Cancelled" + asset_depr_schedule_doc.submit() + asset_depr_schedule_doc.cancel() + + +def get_details_of_depreciable_assets(): + asset = frappe.qb.DocType("Asset") + + records = ( + frappe.qb.from_(asset) + .select(asset.name, asset.opening_accumulated_depreciation, asset.docstatus) + .where(asset.calculate_depreciation == 1) + ).run(as_dict=True) + + return records + + +def get_details_of_asset_finance_books_rows(asset_name): + afb = frappe.qb.DocType("Asset Finance Book") + + records = ( + frappe.qb.from_(afb) + .select( + afb.finance_book, + afb.idx, + afb.depreciation_method, + afb.total_number_of_depreciations, + afb.frequency_of_depreciation, + afb.rate_of_depreciation, + afb.expected_value_after_useful_life, + ) + .where((afb.parenttype == "Asset") & (afb.parent == asset_name)) + ).run(as_dict=True) + + return records + + +def update_depreciation_schedules(asset_name, asset_depr_schedule_name, fb_row_idx): + ds = frappe.qb.DocType("Depreciation Schedule") + + depr_schedules = ( + frappe.qb.from_(ds) + .select(ds.name) + .where((ds.parent == asset_name) & (int(ds.finance_book_id) == fb_row_idx)) + ).run(as_dict=True) + + for idx, depr_schedule in enumerate(depr_schedules, start=1): + ( + frappe.qb.update(ds) + .set(ds.idx, idx) + .set(ds.parent, asset_depr_schedule_name) + .set(ds.parentfield, "depreciation_schedule") + .set(ds.parenttype, "Asset Depreciation Schedule") + .where(ds.parent == depr_schedule.name) + ).run() From a358f777746c8acf83b40e6a53d1c3144ab7ae0f Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Thu, 15 Dec 2022 14:50:53 +0530 Subject: [PATCH 35/94] chore: move patch to post_model_sync and cancel asset depr schedule properly --- .../asset_depreciation_schedule.py | 1 + erpnext/patches.txt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 5639d3db97..05784e77e7 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -170,6 +170,7 @@ def cancel_asset_depr_schedules(asset_doc): frappe.db.set_value( "Asset Depreciation Schedule", asset_depr_schedule_doc.name, "status", "Cancelled" ) + asset_depr_schedule_doc.reload() asset_depr_schedule_doc.cancel() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 622fda42d8..59d76b115c 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -268,7 +268,6 @@ erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v15_0.delete_taxjar_doctypes -erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets [post_model_sync] execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') @@ -319,4 +318,5 @@ erpnext.patches.v13_0.update_schedule_type_in_loans erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization erpnext.patches.v14_0.update_partial_tds_fields erpnext.patches.v14_0.create_incoterms_and_migrate_shipment -erpnext.patches.v14_0.setup_clear_repost_logs \ No newline at end of file +erpnext.patches.v14_0.setup_clear_repost_logs +erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets \ No newline at end of file From 3e91a56c19c70a962e92e3f5360a2c0d31c4ad05 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Fri, 23 Dec 2022 11:01:18 +0530 Subject: [PATCH 36/94] chore: only consider draft and active assets in patch, and allow asset depr schedule to be manually createed --- .../asset_depreciation_schedule.json | 22 ++++++++++++++++--- ...sset_depreciation_schedules_from_assets.py | 11 ++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index 199f73f508..14e849b7dd 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -157,11 +157,10 @@ "read_only": 1 } ], - "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-12-15 13:01:02.984906", + "modified": "2022-12-15 16:28:44.585745", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", @@ -169,6 +168,8 @@ "owner": "Administrator", "permissions": [ { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -176,8 +177,23 @@ "print": 1, "read": 1, "report": 1, - "role": "System Manager", + "role": "Accounts User", "share": 1, + "submit": 1, + "write": 1 + }, + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Quality Manager", + "share": 1, + "submit": 1, "write": 1 } ], diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py index 11064a9c84..14d3689791 100644 --- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -2,7 +2,7 @@ import frappe def execute(): - assets = get_details_of_depreciable_assets() + assets = get_details_of_draft_or_submitted_depreciable_assets() for asset in assets: finance_book_rows = get_details_of_asset_finance_books_rows(asset.name) @@ -32,19 +32,16 @@ def execute(): if asset.docstatus == 1: asset_depr_schedule_doc.status = "Active" asset_depr_schedule_doc.submit() - elif asset.docstatus == 2: - asset_depr_schedule_doc.status = "Cancelled" - asset_depr_schedule_doc.submit() - asset_depr_schedule_doc.cancel() -def get_details_of_depreciable_assets(): +def get_details_of_draft_or_submitted_depreciable_assets(): asset = frappe.qb.DocType("Asset") records = ( frappe.qb.from_(asset) .select(asset.name, asset.opening_accumulated_depreciation, asset.docstatus) .where(asset.calculate_depreciation == 1) + .where(asset.docstatus < 2) ).run(as_dict=True) return records @@ -76,7 +73,7 @@ def update_depreciation_schedules(asset_name, asset_depr_schedule_name, fb_row_i depr_schedules = ( frappe.qb.from_(ds) .select(ds.name) - .where((ds.parent == asset_name) & (int(ds.finance_book_id) == fb_row_idx)) + .where((ds.parent == asset_name) & (ds.finance_book_id == str(fb_row_idx))) ).run(as_dict=True) for idx, depr_schedule in enumerate(depr_schedules, start=1): From bfa511cb6522b7e41f7e4dcd0286d6be729aeec4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 19 Dec 2022 21:25:04 +0530 Subject: [PATCH 37/94] refactor: hidden columns to help framework handle user permissions 'territory', 'supplier_group', 'customer_group' have been added as hidden columns to handle 'user permission' based access control. --- .../customer_ledger_summary.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 6b0d3c9764..4765e3b318 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -26,6 +26,7 @@ class PartyLedgerSummaryReport(object): ) self.get_gl_entries() + self.get_additional_columns() self.get_return_invoices() self.get_party_adjustment_amounts() @@ -33,6 +34,42 @@ class PartyLedgerSummaryReport(object): data = self.get_data() return columns, data + def get_additional_columns(self): + """ + Additional Columns for 'User Permission' based access control + """ + from frappe import qb + + if self.filters.party_type == "Customer": + self.territories = frappe._dict({}) + self.customer_group = frappe._dict({}) + + customer = qb.DocType("Customer") + result = ( + frappe.qb.from_(customer) + .select( + customer.name, customer.territory, customer.customer_group, customer.default_sales_partner + ) + .where((customer.disabled == 0)) + .run(as_dict=True) + ) + + for x in result: + self.territories[x.name] = x.territory + self.customer_group[x.name] = x.customer_group + else: + self.supplier_group = frappe._dict({}) + supplier = qb.DocType("Supplier") + result = ( + frappe.qb.from_(supplier) + .select(supplier.name, supplier.supplier_group) + .where((supplier.disabled == 0)) + .run(as_dict=True) + ) + + for x in result: + self.supplier_group[x.name] = x.supplier_group + def get_columns(self): columns = [ { @@ -116,6 +153,35 @@ class PartyLedgerSummaryReport(object): }, ] + # Hidden columns for handling 'User Permissions' + if self.filters.party_type == "Customer": + columns += [ + { + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Link", + "options": "Territory", + "hidden": 1, + }, + { + "label": _("Customer Group"), + "fieldname": "customer_group", + "fieldtype": "Link", + "options": "Customer Group", + "hidden": 1, + }, + ] + else: + columns += [ + { + "label": _("Supplier Group"), + "fieldname": "supplier_group", + "fieldtype": "Link", + "options": "Supplier Group", + "hidden": 1, + } + ] + return columns def get_data(self): @@ -143,6 +209,12 @@ class PartyLedgerSummaryReport(object): ), ) + if self.filters.party_type == "Customer": + self.party_data[gle.party].update({"territory": self.territories.get(gle.party)}) + self.party_data[gle.party].update({"customer_group": self.customer_group.get(gle.party)}) + else: + self.party_data[gle.party].update({"supplier_group": self.supplier_group.get(gle.party)}) + amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) self.party_data[gle.party].closing_balance += amount From 89229d9b586954991be6fda4c4fb12b5e70e6157 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 20 Dec 2022 14:02:56 +0530 Subject: [PATCH 38/94] refactor: additional doctype access for 'Accounts User' role --- .../doctype/customer_group/customer_group.json | 14 ++++++++++++-- .../doctype/supplier_group/supplier_group.json | 16 ++++++++++++++-- erpnext/setup/doctype/territory/territory.json | 14 ++++++++++++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json index 0e2ed9efcf..d6a431ea61 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.json +++ b/erpnext/setup/doctype/customer_group/customer_group.json @@ -139,10 +139,11 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2021-02-08 17:01:52.162202", + "modified": "2022-12-24 11:15:17.142746", "modified_by": "Administrator", "module": "Setup", "name": "Customer Group", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_customer_group", "owner": "Administrator", "permissions": [ @@ -198,10 +199,19 @@ "role": "Customer", "select": 1, "share": 1 + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } ], "search_fields": "parent_customer_group", "show_name_in_global_search": 1, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.json b/erpnext/setup/doctype/supplier_group/supplier_group.json index 9119bb947c..b3ed608cd0 100644 --- a/erpnext/setup/doctype/supplier_group/supplier_group.json +++ b/erpnext/setup/doctype/supplier_group/supplier_group.json @@ -6,6 +6,7 @@ "creation": "2013-01-10 16:34:24", "doctype": "DocType", "document_type": "Setup", + "engine": "InnoDB", "field_order": [ "supplier_group_name", "parent_supplier_group", @@ -106,10 +107,11 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2020-03-18 18:10:49.228407", + "modified": "2022-12-24 11:16:12.486719", "modified_by": "Administrator", "module": "Setup", "name": "Supplier Group", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_supplier_group", "owner": "Administrator", "permissions": [ @@ -156,8 +158,18 @@ "permlevel": 1, "read": 1, "role": "Purchase User" + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } ], "show_name_in_global_search": 1, - "sort_order": "ASC" + "sort_field": "modified", + "sort_order": "ASC", + "states": [] } \ No newline at end of file diff --git a/erpnext/setup/doctype/territory/territory.json b/erpnext/setup/doctype/territory/territory.json index a25bda054b..c3a4993374 100644 --- a/erpnext/setup/doctype/territory/territory.json +++ b/erpnext/setup/doctype/territory/territory.json @@ -123,11 +123,12 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2021-02-08 17:10:03.767426", + "modified": "2022-12-24 11:16:39.964956", "modified_by": "Administrator", "module": "Setup", "name": "Territory", "name_case": "Title Case", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_territory", "owner": "Administrator", "permissions": [ @@ -175,10 +176,19 @@ "role": "Customer", "select": 1, "share": 1 + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } ], "search_fields": "parent_territory,territory_manager", "show_name_in_global_search": 1, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file From a0484793c3c80e73687613e45d3489e4399a48ba Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 20 Dec 2022 14:38:50 +0530 Subject: [PATCH 39/94] refactor: remove unrelated filters from Supplier Ledger Summary Territory, Sales Partner and Sales Person doesn't belong in Supplier Ledger --- .../supplier_ledger_summary.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js index f81297760e..5dc4c3d1c1 100644 --- a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js @@ -63,24 +63,6 @@ frappe.query_reports["Supplier Ledger Summary"] = { "fieldtype": "Link", "options": "Payment Terms Template" }, - { - "fieldname":"territory", - "label": __("Territory"), - "fieldtype": "Link", - "options": "Territory" - }, - { - "fieldname":"sales_partner", - "label": __("Sales Partner"), - "fieldtype": "Link", - "options": "Sales Partner" - }, - { - "fieldname":"sales_person", - "label": __("Sales Person"), - "fieldtype": "Link", - "options": "Sales Person" - }, { "fieldname":"tax_id", "label": __("Tax Id"), From 03662be150e4756e03e3a3ffc2453ccd36d911f1 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Sun, 25 Dec 2022 18:05:19 +0530 Subject: [PATCH 40/94] chore: have different functions for draft. active and cancelled depr schedules --- .../doctype/journal_entry/journal_entry.py | 4 +- .../sales_invoice/test_sales_invoice.py | 8 +- erpnext/assets/doctype/asset/asset.js | 2 +- erpnext/assets/doctype/asset/asset.py | 18 ++-- erpnext/assets/doctype/asset/depreciation.py | 12 ++- erpnext/assets/doctype/asset/test_asset.py | 78 ++++++++++------- .../test_asset_capitalization.py | 4 +- .../asset_depreciation_schedule.py | 85 +++++++++++++------ .../doctype/asset_repair/asset_repair.py | 6 +- .../doctype/asset_repair/test_asset_repair.py | 4 +- .../asset_value_adjustment.py | 10 ++- 11 files changed, 146 insertions(+), 85 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 2bbfe34bea..b9463bc210 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -24,7 +24,7 @@ from erpnext.accounts.utils import ( get_stock_and_account_balance, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule, + get_cancelled_depr_schedule, ) from erpnext.controllers.accounts_controller import AccountsController @@ -287,7 +287,7 @@ class JournalEntry(AccountsController): if d.reference_type == "Asset" and d.reference_name: asset = frappe.get_doc("Asset", d.reference_name) for row in asset.get("finance_books"): - depr_schedule = get_depr_schedule(asset.name, row.finance_book) + depr_schedule = get_cancelled_depr_schedule(asset.name, row.finance_book) for s in depr_schedule: if s.journal_entry == self.name: diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 363ca16e99..22a317c1be 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -22,7 +22,7 @@ from erpnext.accounts.utils import PaymentEntryUnlinkError from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule, + get_draft_or_active_depr_schedule, ) from erpnext.controllers.accounts_controller import update_invoice_status from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data @@ -2777,7 +2777,7 @@ class TestSalesInvoice(unittest.TestCase): ["2021-09-30", 5041.1, 26407.22], ] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -2808,7 +2808,7 @@ class TestSalesInvoice(unittest.TestCase): expected_values = [["2020-12-31", 30000, 30000], ["2021-12-31", 30000, 60000]] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -2837,7 +2837,7 @@ class TestSalesInvoice(unittest.TestCase): ["2025-06-06", 18633.88, 100000.0, False], ] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index aa3af3beaf..9754ab3e79 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -209,7 +209,7 @@ frappe.ui.form.on('Asset', { if (frm.doc.finance_books.length == 1) { depr_schedule = (await frappe.call( - "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule", + "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_draft_or_active_depr_schedule", { asset_name: frm.doc.name, finance_book: frm.doc.finance_books[0].finance_book || null diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index cb97ccce01..b9274b14d4 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -32,8 +32,8 @@ from erpnext.assets.doctype.asset_category.asset_category import get_asset_categ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( cancel_asset_depr_schedules, convert_draft_asset_depr_schedules_into_active, - get_asset_depr_schedule_doc, - get_depr_schedule, + get_draft_or_active_asset_depr_schedule_doc, + get_draft_or_active_depr_schedule, make_draft_asset_depr_schedules, make_draft_asset_depr_schedules_if_not_present, set_draft_asset_depr_schedule_details, @@ -337,7 +337,7 @@ class Asset(AccountsController): def validate_expected_value_after_useful_life(self): for row in self.get("finance_books"): - depr_schedule = get_depr_schedule(self.name, row.finance_book) + depr_schedule = get_draft_or_active_depr_schedule(self.name, row.finance_book) if not depr_schedule: continue @@ -393,7 +393,7 @@ class Asset(AccountsController): def delete_depreciation_entries(self): for row in self.get("finance_books"): - depr_schedule = get_depr_schedule(self.name, row.finance_book) + depr_schedule = get_draft_or_active_depr_schedule(self.name, row.finance_book) for d in depr_schedule: if d.journal_entry: @@ -881,7 +881,9 @@ def update_existing_asset(asset, remaining_qty, new_asset_name): expected_value_after_useful_life, ) - current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) + current_asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset.name, row.finance_book + ) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, asset, row) @@ -930,7 +932,9 @@ def create_new_asset_after_split(asset, split_qty): new_asset.set_status() for row in new_asset.get("finance_books"): - current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) + current_asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset.name, row.finance_book + ) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, new_asset, row) @@ -951,7 +955,7 @@ def create_new_asset_after_split(asset, split_qty): new_asset_depr_schedule_doc.submit() for row in new_asset.get("finance_books"): - depr_schedule = get_depr_schedule(new_asset.name, row.finance_book) + depr_schedule = get_draft_or_active_depr_schedule(new_asset.name, row.finance_book) for term in depr_schedule: # Update references in JV if term.journal_entry: diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 4278658fd2..3a3123fb16 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -11,8 +11,8 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_asset_depr_schedule_doc, - get_asset_depr_schedule_name, + get_draft_or_active_asset_depr_schedule_doc, + get_draft_or_active_asset_depr_schedule_name, get_temp_asset_depr_schedule_doc, make_new_active_asset_depr_schedules_and_cancel_current_ones, ) @@ -51,7 +51,9 @@ def get_depreciable_assets(date): def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) + asset_depr_schedule_name = get_draft_or_active_asset_depr_schedule_name( + asset_doc.name, row.finance_book + ) make_depreciation_entry(asset_depr_schedule_name, date) @@ -316,7 +318,9 @@ def modify_depreciation_schedule_for_asset_repairs(asset): def reverse_depreciation_entry_made_after_disposal(asset, date): for row in asset.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, row.finance_book) + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset.name, row.finance_book + ) for schedule_idx, schedule in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")): if schedule.schedule_date == date: diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 8835b32bcc..f6da9d3902 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -29,8 +29,8 @@ from erpnext.assets.doctype.asset.depreciation import ( ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( clear_depr_schedule, - get_asset_depr_schedule_doc, - get_depr_schedule, + get_draft_or_active_asset_depr_schedule_doc, + get_draft_or_active_depr_schedule, ) from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( make_purchase_invoice as make_invoice, @@ -384,8 +384,8 @@ class TestAsset(AssetSetup): new_asset = split_asset(asset.name, 2) asset.load_from_db() - depr_schedule_of_asset = get_depr_schedule(asset.name) - depr_schedule_of_new_asset = get_depr_schedule(new_asset.name) + depr_schedule_of_asset = get_draft_or_active_depr_schedule(asset.name) + depr_schedule_of_new_asset = get_draft_or_active_depr_schedule(new_asset.name) self.assertEqual(new_asset.asset_quantity, 2) self.assertEqual(new_asset.gross_purchase_amount, 24000) @@ -637,7 +637,7 @@ class TestDepreciationMethods(AssetSetup): schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -659,7 +659,7 @@ class TestDepreciationMethods(AssetSetup): expected_schedules = [["2032-12-31", 30000.0, 77095.89], ["2033-06-06", 12904.11, 90000.0]] schedules = [ [cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -686,7 +686,7 @@ class TestDepreciationMethods(AssetSetup): schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -711,7 +711,7 @@ class TestDepreciationMethods(AssetSetup): schedules = [ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -741,7 +741,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -773,7 +773,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -806,7 +806,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -839,7 +839,7 @@ class TestDepreciationMethods(AssetSetup): flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2), ] - for d in get_depr_schedule(asset.name) + for d in get_draft_or_active_depr_schedule(asset.name) ] self.assertEqual(schedules, expected_schedules) @@ -862,7 +862,7 @@ class TestDepreciationBasics(AssetSetup): ["2022-12-31", 30000, 90000], ] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -885,7 +885,7 @@ class TestDepreciationBasics(AssetSetup): ["2023-01-01", 15000, 90000], ] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) @@ -930,7 +930,7 @@ class TestDepreciationBasics(AssetSetup): expected_values = [["2020-12-31", 30000.0], ["2021-12-31", 30000.0], ["2022-12-31", 30000.0]] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) @@ -950,7 +950,7 @@ class TestDepreciationBasics(AssetSetup): expected_values = [30000.0, 60000.0, 90000.0] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(expected_values[i], schedule.accumulated_depreciation_amount) def test_check_is_pro_rata(self): @@ -1130,9 +1130,9 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - self.assertTrue(get_depr_schedule(asset.name)[0].journal_entry) - self.assertFalse(get_depr_schedule(asset.name)[1].journal_entry) - self.assertFalse(get_depr_schedule(asset.name)[2].journal_entry) + self.assertTrue(get_draft_or_active_depr_schedule(asset.name)[0].journal_entry) + self.assertFalse(get_draft_or_active_depr_schedule(asset.name)[1].journal_entry) + self.assertFalse(get_draft_or_active_depr_schedule(asset.name)[2].journal_entry) def test_depr_entry_posting_when_depr_expense_account_is_an_expense_account(self): """Tests if the Depreciation Expense Account gets debited and the Accumulated Depreciation Account gets credited when the former's an Expense Account.""" @@ -1151,7 +1151,9 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name)[0].journal_entry) + je = frappe.get_doc( + "Journal Entry", get_draft_or_active_depr_schedule(asset.name)[0].journal_entry + ) accounting_entries = [ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts @@ -1187,7 +1189,9 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name)[0].journal_entry) + je = frappe.get_doc( + "Journal Entry", get_draft_or_active_depr_schedule(asset.name)[0].journal_entry + ) accounting_entries = [ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts @@ -1223,7 +1227,7 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2021-06-01") asset.load_from_db() - asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name) + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc(asset.name) clear_depr_schedule(asset_depr_schedule_doc) @@ -1271,15 +1275,21 @@ class TestDepreciationBasics(AssetSetup): post_depreciation_entries(date="2020-04-01") asset.load_from_db() - asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 1") + asset_depr_schedule_doc_1 = get_draft_or_active_asset_depr_schedule_doc( + asset.name, "Test Finance Book 1" + ) clear_depr_schedule(asset_depr_schedule_doc_1) self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3) - asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 2") + asset_depr_schedule_doc_2 = get_draft_or_active_asset_depr_schedule_doc( + asset.name, "Test Finance Book 2" + ) clear_depr_schedule(asset_depr_schedule_doc_2) self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 3) - asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 3") + asset_depr_schedule_doc_3 = get_draft_or_active_asset_depr_schedule_doc( + asset.name, "Test Finance Book 3" + ) clear_depr_schedule(asset_depr_schedule_doc_3) self.assertEqual(len(asset_depr_schedule_doc_3.get("depreciation_schedule")), 0) @@ -1311,10 +1321,14 @@ class TestDepreciationBasics(AssetSetup): ) asset.save() - asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 1") + asset_depr_schedule_doc_1 = get_draft_or_active_asset_depr_schedule_doc( + asset.name, "Test Finance Book 1" + ) self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3) - asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Test Finance Book 2") + asset_depr_schedule_doc_2 = get_draft_or_active_asset_depr_schedule_doc( + asset.name, "Test Finance Book 2" + ) self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 6) def test_depreciation_entry_cancellation(self): @@ -1335,12 +1349,12 @@ class TestDepreciationBasics(AssetSetup): asset.load_from_db() # cancel depreciation entry - depr_entry = get_depr_schedule(asset.name)[0].journal_entry + depr_entry = get_draft_or_active_depr_schedule(asset.name)[0].journal_entry self.assertTrue(depr_entry) frappe.get_doc("Journal Entry", depr_entry).cancel() asset.load_from_db() - depr_entry = get_depr_schedule(asset.name)[0].journal_entry + depr_entry = get_draft_or_active_depr_schedule(asset.name)[0].journal_entry self.assertFalse(depr_entry) def test_asset_expected_value_after_useful_life(self): @@ -1355,7 +1369,7 @@ class TestDepreciationBasics(AssetSetup): ) accumulated_depreciation_after_full_schedule = max( - d.accumulated_depreciation_amount for d in get_depr_schedule(asset.name) + d.accumulated_depreciation_amount for d in get_draft_or_active_depr_schedule(asset.name) ) asset_value_after_full_schedule = flt(asset.gross_purchase_amount) - flt( @@ -1386,7 +1400,7 @@ class TestDepreciationBasics(AssetSetup): asset.load_from_db() # check depreciation entry series - self.assertEqual(get_depr_schedule(asset.name)[0].journal_entry[:4], "DEPR") + self.assertEqual(get_draft_or_active_depr_schedule(asset.name)[0].journal_entry[:4], "DEPR") expected_gle = ( ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0), @@ -1456,7 +1470,7 @@ class TestDepreciationBasics(AssetSetup): "2020-07-15", ] - for i, schedule in enumerate(get_depr_schedule(asset.name)): + for i, schedule in enumerate(get_draft_or_active_depr_schedule(asset.name)): self.assertEqual(getdate(expected_dates[i]), getdate(schedule.schedule_date)) diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index e99e71b0ac..abbbd209a7 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -13,7 +13,7 @@ from erpnext.assets.doctype.asset.test_asset import ( set_depreciation_settings_in_company, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule, + get_draft_or_active_depr_schedule, ) from erpnext.stock.doctype.item.test_item import create_item @@ -287,7 +287,7 @@ class TestAssetCapitalization(unittest.TestCase): consumed_depreciation_schedule = [ d - for d in get_depr_schedule(consumed_asset.name) + for d in get_draft_or_active_depr_schedule(consumed_asset.name) if getdate(d.schedule_date) == getdate(capitalization_date) ] self.assertTrue( diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 05784e77e7..47965cf6aa 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -35,20 +35,19 @@ class AssetDepreciationSchedule(Document): ], ) - if num_asset_depr_schedules == 1: - asset_depr_schedule_name = get_asset_depr_schedule_name(self.asset, self.finance_book) - - if self.name != asset_depr_schedule_name: - frappe.throw( - _("Asset Depreciation Schedule for Asset {0} and Finance Book {1} already exists.").format( - self.asset, self.finance_book - ) + if num_asset_depr_schedules > 1: + frappe.throw( + _("Asset Depreciation Schedule for Asset {0} and Finance Book {1} already exists.").format( + self.asset, self.finance_book ) + ) def make_draft_asset_depr_schedules_if_not_present(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, row.finance_book) + asset_depr_schedule_name = get_draft_or_active_asset_depr_schedule_name( + asset_doc.name, row.finance_book + ) if not asset_depr_schedule_name: make_draft_asset_depr_schedule(asset_doc, row) @@ -69,7 +68,9 @@ def make_draft_asset_depr_schedule(asset_doc, row): def update_draft_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset_doc.name, row.finance_book + ) if not asset_depr_schedule_doc: continue @@ -111,7 +112,9 @@ def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, ro def convert_draft_asset_depr_schedules_into_active(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset_doc.name, row.finance_book + ) if asset_depr_schedule_doc.status == "Draft": asset_depr_schedule_doc.status = "Active" @@ -122,7 +125,9 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, notes, date_of_disposal=None, date_of_return=None ): for row in asset_doc.get("finance_books"): - current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + current_asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset_doc.name, row.finance_book + ) if not current_asset_depr_schedule_doc: frappe.throw( @@ -162,20 +167,17 @@ def get_temp_asset_depr_schedule_doc( def cancel_asset_depr_schedules(asset_doc): for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, row.finance_book) + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset_doc.name, row.finance_book + ) if not asset_depr_schedule_doc: continue - frappe.db.set_value( - "Asset Depreciation Schedule", asset_depr_schedule_doc.name, "status", "Cancelled" - ) - asset_depr_schedule_doc.reload() - asset_depr_schedule_doc.cancel() -def get_asset_depr_schedule_name(asset_name, finance_book=None): +def get_draft_or_active_asset_depr_schedule_name(asset_name, finance_book=None): finance_book_filter = ["finance_book", "is", "not set"] if finance_book: finance_book_filter = ["finance_book", "=", finance_book] @@ -185,14 +187,29 @@ def get_asset_depr_schedule_name(asset_name, finance_book=None): filters=[ ["asset", "=", asset_name], finance_book_filter, - ["docstatus", "<", 2], + ["status", "in", ["Draft", "Active"]], + ], + ) + + +def get_cancelled_asset_depr_schedule_name(asset_name, finance_book=None): + finance_book_filter = ["finance_book", "is", "not set"] + if finance_book: + finance_book_filter = ["finance_book", "=", finance_book] + + return frappe.db.get_value( + doctype="Asset Depreciation Schedule", + filters=[ + ["asset", "=", asset_name], + finance_book_filter, + ["docstatus", "=", "2"], ], ) @frappe.whitelist() -def get_depr_schedule(asset_name, finance_book=None): - asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_name, finance_book) +def get_draft_or_active_depr_schedule(asset_name, finance_book=None): + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc(asset_name, finance_book) if not asset_depr_schedule_doc: return @@ -200,8 +217,28 @@ def get_depr_schedule(asset_name, finance_book=None): return asset_depr_schedule_doc.get("depreciation_schedule") -def get_asset_depr_schedule_doc(asset_name, finance_book=None): - asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, finance_book) +def get_cancelled_depr_schedule(asset_name, finance_book=None): + asset_depr_schedule_doc = get_cancelled_asset_depr_schedule_doc(asset_name, finance_book) + + if not asset_depr_schedule_doc: + return + + return asset_depr_schedule_doc.get("depreciation_schedule") + + +def get_draft_or_active_asset_depr_schedule_doc(asset_name, finance_book=None): + asset_depr_schedule_name = get_draft_or_active_asset_depr_schedule_name(asset_name, finance_book) + + if not asset_depr_schedule_name: + return + + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + + return asset_depr_schedule_doc + + +def get_cancelled_asset_depr_schedule_doc(asset_name, finance_book=None): + asset_depr_schedule_name = get_cancelled_asset_depr_schedule_name(asset_name, finance_book) if not asset_depr_schedule_name: return diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 6239915232..c5036fa9e2 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -9,7 +9,7 @@ import erpnext from erpnext.accounts.general_ledger import make_gl_entries from erpnext.assets.doctype.asset.asset import get_asset_account from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule, + get_draft_or_active_depr_schedule, make_new_active_asset_depr_schedules_and_cancel_current_ones, ) from erpnext.controllers.accounts_controller import AccountsController @@ -289,7 +289,7 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) - depr_schedule = get_depr_schedule(asset.name, row.finance_book) + depr_schedule = get_draft_or_active_depr_schedule(asset.name, row.finance_book) # the Schedule Date in the final row of the old Depreciation Schedule last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date @@ -322,7 +322,7 @@ class AssetRepair(AccountsController): asset.number_of_depreciations_booked ) - depr_schedule = get_depr_schedule(asset.name, row.finance_book) + depr_schedule = get_draft_or_active_depr_schedule(asset.name, row.finance_book) # the Schedule Date in the final row of the modified Depreciation Schedule last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py index 4579b4d56a..8ba3c0eda0 100644 --- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py @@ -13,7 +13,7 @@ from erpnext.assets.doctype.asset.test_asset import ( set_depreciation_settings_in_company, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_depr_schedule, + get_draft_or_active_depr_schedule, ) from erpnext.stock.doctype.item.test_item import create_item @@ -241,7 +241,7 @@ class TestAssetRepair(unittest.TestCase): self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset)) self.assertEqual( - get_depr_schedule(asset.name)[-1].accumulated_depreciation_amount, + get_draft_or_active_depr_schedule(asset.name)[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation, ) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 0248a37030..3ead832ee2 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -12,8 +12,8 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( ) from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_asset_depr_schedule_name, get_depreciation_amount, + get_draft_or_active_asset_depr_schedule_doc, set_accumulated_depreciation, ) @@ -116,12 +116,13 @@ class AssetValueAdjustment(Document): for d in asset.finance_books: d.value_after_depreciation = asset_value - current_asset_depr_schedule_name = get_asset_depr_schedule_name(asset.name, d.finance_book) - current_asset_depr_schedule_doc = frappe.get_doc( - "Asset Depreciation Schedule", current_asset_depr_schedule_name + current_asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset.name, d.finance_book ) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) + new_asset_depr_schedule_doc.status = "Draft" + new_asset_depr_schedule_doc.docstatus = 0 current_asset_depr_schedule_doc.cancel() @@ -166,6 +167,7 @@ class AssetValueAdjustment(Document): if not asset_data.journal_entry: asset_data.db_update() + new_asset_depr_schedule_doc.status = "Active" new_asset_depr_schedule_doc.submit() From 7e1b6b3c2aa114331ad9085cfefee340b8ca2ad0 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Sat, 24 Dec 2022 18:11:04 +0530 Subject: [PATCH 41/94] fix: `shipping_address` in PO --- .../doctype/purchase_order/purchase_order.json | 16 ++++++++-------- .../selling/doctype/sales_order/sales_order.py | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index ce7de874c5..e1dd679781 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -108,7 +108,7 @@ "contact_display", "contact_mobile", "contact_email", - "company_shipping_address_section", + "shipping_address_section", "shipping_address", "column_break_99", "shipping_address_display", @@ -385,7 +385,7 @@ { "fieldname": "shipping_address", "fieldtype": "Link", - "label": "Company Shipping Address", + "label": "Shipping Address", "options": "Address", "print_hide": 1 }, @@ -1207,11 +1207,6 @@ "fieldtype": "Tab Break", "label": "Address & Contact" }, - { - "fieldname": "company_shipping_address_section", - "fieldtype": "Section Break", - "label": "Company Shipping Address" - }, { "fieldname": "company_billing_address_section", "fieldtype": "Section Break", @@ -1263,13 +1258,18 @@ "fieldname": "named_place", "fieldtype": "Data", "label": "Named Place" + }, + { + "fieldname": "shipping_address_section", + "fieldtype": "Section Break", + "label": "Shipping Address" } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], - "modified": "2022-12-12 18:36:37.455134", + "modified": "2022-12-25 18:08:59.074182", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 0013c95032..efe1f8eb17 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1031,8 +1031,6 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.discount_amount = 0.0 target.inter_company_order_reference = "" target.shipping_rule = "" - target.customer = "" - target.customer_name = "" target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") @@ -1059,9 +1057,11 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "contact_email", "contact_person", "taxes_and_charges", - "shipping_address", "terms", ], + "field_map": [ + ["shipping_address_name", "shipping_address"], + ], "validation": {"docstatus": ["=", 1]}, }, "Sales Order Item": { From 7d9f3f23dde6efd6fc3f218d48a3828dd9aa1133 Mon Sep 17 00:00:00 2001 From: Solufyin <34390782+Solufyin@users.noreply.github.com> Date: Mon, 26 Dec 2022 10:15:10 +0530 Subject: [PATCH 42/94] fix: Customer Primary Contact (#33424) Co-authored-by: Nihantra C. Patel --- erpnext/selling/doctype/customer/customer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 12ecb0112a..d9dab33501 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -737,7 +737,7 @@ def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, fil qb.from_(con) .join(dlink) .on(con.name == dlink.parent) - .select(con.name, con.full_name, con.email_id) + .select(con.name, con.email_id) .where((dlink.link_name == customer) & (con.name.like(f"%{txt}%"))) .run() ) From 8a79efab4b9a804a3c943edebf6e98c5f1985580 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 26 Dec 2022 10:17:55 +0530 Subject: [PATCH 43/94] feat: Accounting Dimension updation in Payment Request and Entry (#33411) --- .../doctype/payment_entry/payment_entry.py | 14 +++++++++ .../payment_request/payment_request.json | 28 ++++++++++++++++- .../payment_request/payment_request.py | 25 +++++++++++++++ erpnext/patches.txt | 3 +- ...counting_dimensions_for_payment_request.py | 31 +++++++++++++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 erpnext/patches/v14_0/create_accounting_dimensions_for_payment_request.py diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 79fab6480c..26192eca2e 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1758,6 +1758,8 @@ def get_payment_entry( pe.setup_party_account_field() pe.set_missing_values() + update_accounting_dimensions(pe, doc) + if party_account and bank: pe.set_exchange_rate(ref_doc=reference_doc) pe.set_amounts() @@ -1775,6 +1777,18 @@ def get_payment_entry( return pe +def update_accounting_dimensions(pe, doc): + """ + Updates accounting dimensions in Payment Entry based on the accounting dimensions in the reference document + """ + from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( + get_accounting_dimensions, + ) + + for dimension in get_accounting_dimensions(): + pe.set(dimension, doc.get(dimension)) + + def get_bank_cash_account(doc, bank_account): bank = get_default_bank_cash_account( doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"), account=bank_account diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index 2f3516e135..381f3fb531 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -32,6 +32,10 @@ "iban", "branch_code", "swift_number", + "accounting_dimensions_section", + "cost_center", + "dimension_col_break", + "project", "recipient_and_message", "print_format", "email_to", @@ -362,13 +366,35 @@ "label": "Payment Channel", "options": "\nEmail\nPhone", "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" } ], "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-09-30 16:19:43.680025", + "modified": "2022-12-21 16:56:40.115737", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Request", diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index fc938014b3..4fc12dbc16 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -10,6 +10,9 @@ from frappe.model.document import Document from frappe.utils import flt, get_url, nowdate from frappe.utils.background_jobs import enqueue +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( + get_accounting_dimensions, +) from erpnext.accounts.doctype.payment_entry.payment_entry import ( get_company_defaults, get_payment_entry, @@ -270,6 +273,17 @@ class PaymentRequest(Document): } ) + # Update dimensions + payment_entry.update( + { + "cost_center": self.get("cost_center"), + "project": self.get("project"), + } + ) + + for dimension in get_accounting_dimensions(): + payment_entry.update({dimension: self.get(dimension)}) + if payment_entry.difference_amount: company_details = get_company_defaults(ref_doc.company) @@ -449,6 +463,17 @@ def make_payment_request(**args): } ) + # Update dimensions + pr.update( + { + "cost_center": ref_doc.get("cost_center"), + "project": ref_doc.get("project"), + } + ) + + for dimension in get_accounting_dimensions(): + pr.update({dimension: ref_doc.get(dimension)}) + if args.order_type == "Shopping Cart" or args.mute_email: pr.flags.mute_email = True diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 0aad1d34e5..2420a23bb0 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -318,4 +318,5 @@ erpnext.patches.v13_0.update_schedule_type_in_loans erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization erpnext.patches.v14_0.update_partial_tds_fields erpnext.patches.v14_0.create_incoterms_and_migrate_shipment -erpnext.patches.v14_0.setup_clear_repost_logs \ No newline at end of file +erpnext.patches.v14_0.setup_clear_repost_logs +erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request \ No newline at end of file diff --git a/erpnext/patches/v14_0/create_accounting_dimensions_for_payment_request.py b/erpnext/patches/v14_0/create_accounting_dimensions_for_payment_request.py new file mode 100644 index 0000000000..bede419ad2 --- /dev/null +++ b/erpnext/patches/v14_0/create_accounting_dimensions_for_payment_request.py @@ -0,0 +1,31 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_field + + +def execute(): + accounting_dimensions = frappe.db.get_all( + "Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"] + ) + + if not accounting_dimensions: + return + + doctype = "Payment Request" + + for d in accounting_dimensions: + field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname}) + + if field: + continue + + df = { + "fieldname": d.fieldname, + "label": d.label, + "fieldtype": "Link", + "options": d.document_type, + "insert_after": "accounting_dimensions_section", + } + + create_custom_field(doctype, df, ignore_validate=True) + + frappe.clear_cache(doctype=doctype) From 67a7ccf3cead654e66a3d1b5ccb253d90b19c43b Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 26 Dec 2022 11:39:58 +0530 Subject: [PATCH 44/94] fix: `shipping_address` for non-drop shipping item --- .../doctype/sales_order/sales_order.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index efe1f8eb17..7c0601e3dd 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1024,6 +1024,15 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): ] items_to_map = list(set(items_to_map)) + def is_drop_ship_order(target): + drop_ship = True + for item in target.items: + if not item.delivered_by_supplier: + drop_ship = False + break + + return drop_ship + def set_missing_values(source, target): target.supplier = "" target.apply_discount_on = "" @@ -1031,6 +1040,14 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.discount_amount = 0.0 target.inter_company_order_reference = "" target.shipping_rule = "" + + if is_drop_ship_order(target): + target.customer = source.customer + target.customer_name = source.customer_name + target.shipping_address = source.shipping_address_name + else: + target.customer = target.customer_name = target.shipping_address = None + target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") @@ -1057,11 +1074,9 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "contact_email", "contact_person", "taxes_and_charges", + "shipping_address", "terms", ], - "field_map": [ - ["shipping_address_name", "shipping_address"], - ], "validation": {"docstatus": ["=", 1]}, }, "Sales Order Item": { From 6d791cabd15f9cd6737b220c7305c0ec5ea67646 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 26 Dec 2022 22:13:11 +0530 Subject: [PATCH 45/94] chore: more refactoring --- .../doctype/journal_entry/journal_entry.py | 4 +- .../asset_depreciation_schedule.json | 3 +- .../asset_depreciation_schedule.py | 42 ++++++++++++------- .../asset_value_adjustment.py | 1 - ...sset_depreciation_schedules_from_assets.py | 1 - 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index b9463bc210..d69777a21a 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -24,7 +24,7 @@ from erpnext.accounts.utils import ( get_stock_and_account_balance, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_cancelled_depr_schedule, + get_draft_or_active_depr_schedule, ) from erpnext.controllers.accounts_controller import AccountsController @@ -287,7 +287,7 @@ class JournalEntry(AccountsController): if d.reference_type == "Asset" and d.reference_name: asset = frappe.get_doc("Asset", d.reference_name) for row in asset.get("finance_books"): - depr_schedule = get_cancelled_depr_schedule(asset.name, row.finance_book) + depr_schedule = get_draft_or_active_depr_schedule(asset.name, row.finance_book) for s in depr_schedule: if s.journal_entry == self.name: diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index 14e849b7dd..f6f594c51e 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -157,10 +157,11 @@ "read_only": 1 } ], + "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-12-15 16:28:44.585745", + "modified": "2022-12-26 20:32:43.342271", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index 47965cf6aa..d004bdbf61 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -42,6 +42,12 @@ class AssetDepreciationSchedule(Document): ) ) + def on_submit(self): + self.db_set("status", "Active") + + def on_cancel(self): + self.db_set("status", "Cancelled") + def make_draft_asset_depr_schedules_if_not_present(asset_doc): for row in asset_doc.get("finance_books"): @@ -121,6 +127,18 @@ def convert_draft_asset_depr_schedules_into_active(asset_doc): asset_depr_schedule_doc.submit() +def cancel_asset_depr_schedules(asset_doc): + for row in asset_doc.get("finance_books"): + asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( + asset_doc.name, row.finance_book + ) + + if not asset_depr_schedule_doc: + continue + + asset_depr_schedule_doc.cancel() + + def make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, notes, date_of_disposal=None, date_of_return=None ): @@ -165,18 +183,6 @@ def get_temp_asset_depr_schedule_doc( return asset_depr_schedule_doc -def cancel_asset_depr_schedules(asset_doc): - for row in asset_doc.get("finance_books"): - asset_depr_schedule_doc = get_draft_or_active_asset_depr_schedule_doc( - asset_doc.name, row.finance_book - ) - - if not asset_depr_schedule_doc: - continue - - asset_depr_schedule_doc.cancel() - - def get_draft_or_active_asset_depr_schedule_name(asset_name, finance_book=None): finance_book_filter = ["finance_book", "is", "not set"] if finance_book: @@ -197,15 +203,23 @@ def get_cancelled_asset_depr_schedule_name(asset_name, finance_book=None): if finance_book: finance_book_filter = ["finance_book", "=", finance_book] - return frappe.db.get_value( + cancelled_asset_depr_schedule_names = frappe.db.get_all( doctype="Asset Depreciation Schedule", filters=[ ["asset", "=", asset_name], finance_book_filter, - ["docstatus", "=", "2"], + ["status", "=", "Cancelled"], ], + order_by="creation desc", + limit=1, + pluck="name", ) + if cancelled_asset_depr_schedule_names: + return cancelled_asset_depr_schedule_names[0] + + return + @frappe.whitelist() def get_draft_or_active_depr_schedule(asset_name, finance_book=None): diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 3ead832ee2..90ecfec5af 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -167,7 +167,6 @@ class AssetValueAdjustment(Document): if not asset_data.journal_entry: asset_data.db_update() - new_asset_depr_schedule_doc.status = "Active" new_asset_depr_schedule_doc.submit() diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py index 14d3689791..8dcbb2a1cc 100644 --- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -30,7 +30,6 @@ def execute(): update_depreciation_schedules(asset.name, asset_depr_schedule_doc.name, fb_row.idx) if asset.docstatus == 1: - asset_depr_schedule_doc.status = "Active" asset_depr_schedule_doc.submit() From 482116db9f926ff88d9a874302b96c8591d8e2e4 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 27 Dec 2022 10:03:32 +0530 Subject: [PATCH 46/94] chore: improve tests --- erpnext/assets/doctype/asset/test_asset.py | 40 +++++++++++++++++-- .../test_asset_capitalization.py | 15 ++++++- .../asset_depreciation_schedule.py | 4 +- .../doctype/asset_repair/test_asset_repair.py | 14 ++++++- .../test_asset_value_adjustment.py | 12 ++++++ 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index f6da9d3902..b0a8653eca 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -210,6 +210,9 @@ class TestAsset(AssetSetup): submit=1, ) + first_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(first_asset_depr_schedule.status, "Active") + post_depreciation_entries(date=add_months(purchase_date, 2)) asset.load_from_db() @@ -221,6 +224,11 @@ class TestAsset(AssetSetup): scrap_asset(asset.name) asset.load_from_db() + first_asset_depr_schedule.load_from_db() + + second_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(second_asset_depr_schedule.status, "Active") + self.assertEquals(first_asset_depr_schedule.status, "Cancelled") accumulated_depr_amount = flt( asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation, @@ -261,6 +269,11 @@ class TestAsset(AssetSetup): self.assertSequenceEqual(gle, expected_gle) restore_asset(asset.name) + second_asset_depr_schedule.load_from_db() + + third_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(third_asset_depr_schedule.status, "Active") + self.assertEquals(second_asset_depr_schedule.status, "Cancelled") asset.load_from_db() self.assertFalse(asset.journal_entry_for_scrap) @@ -288,6 +301,9 @@ class TestAsset(AssetSetup): submit=1, ) + first_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(first_asset_depr_schedule.status, "Active") + post_depreciation_entries(date=add_months(purchase_date, 2)) si = make_sales_invoice(asset=asset.name, item_code="Macbook Pro", company="_Test Company") @@ -299,6 +315,12 @@ class TestAsset(AssetSetup): self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold") + first_asset_depr_schedule.load_from_db() + + second_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(second_asset_depr_schedule.status, "Active") + self.assertEquals(first_asset_depr_schedule.status, "Cancelled") + pro_rata_amount, _, _ = asset.get_pro_rata_amt( asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date ) @@ -375,6 +397,9 @@ class TestAsset(AssetSetup): submit=1, ) + first_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(first_asset_depr_schedule.status, "Active") + post_depreciation_entries(date="2021-01-01") self.assertEqual(asset.asset_quantity, 10) @@ -383,9 +408,18 @@ class TestAsset(AssetSetup): new_asset = split_asset(asset.name, 2) asset.load_from_db() + first_asset_depr_schedule.load_from_db() - depr_schedule_of_asset = get_draft_or_active_depr_schedule(asset.name) - depr_schedule_of_new_asset = get_draft_or_active_depr_schedule(new_asset.name) + second_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + first_asset_depr_schedule_of_new_asset = get_draft_or_active_asset_depr_schedule_doc( + new_asset.name + ) + self.assertEquals(second_asset_depr_schedule.status, "Active") + self.assertEquals(first_asset_depr_schedule_of_new_asset.status, "Active") + self.assertEquals(first_asset_depr_schedule.status, "Cancelled") + + depr_schedule_of_asset = second_asset_depr_schedule.get("depreciation_schedule") + depr_schedule_of_new_asset = first_asset_depr_schedule_of_new_asset.get("depreciation_schedule") self.assertEqual(new_asset.asset_quantity, 2) self.assertEqual(new_asset.gross_purchase_amount, 24000) @@ -1351,9 +1385,9 @@ class TestDepreciationBasics(AssetSetup): # cancel depreciation entry depr_entry = get_draft_or_active_depr_schedule(asset.name)[0].journal_entry self.assertTrue(depr_entry) + frappe.get_doc("Journal Entry", depr_entry).cancel() - asset.load_from_db() depr_entry = get_draft_or_active_depr_schedule(asset.name)[0].journal_entry self.assertFalse(depr_entry) diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index abbbd209a7..897c678c08 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -13,7 +13,7 @@ from erpnext.assets.doctype.asset.test_asset import ( set_depreciation_settings_in_company, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_draft_or_active_depr_schedule, + get_draft_or_active_asset_depr_schedule_doc, ) from erpnext.stock.doctype.item.test_item import create_item @@ -256,6 +256,9 @@ class TestAssetCapitalization(unittest.TestCase): submit=1, ) + first_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(consumed_asset.name) + self.assertEquals(first_asset_depr_schedule.status, "Active") + # Create and submit Asset Captitalization asset_capitalization = create_asset_capitalization( entry_type="Decapitalization", @@ -285,9 +288,17 @@ class TestAssetCapitalization(unittest.TestCase): consumed_asset.reload() self.assertEqual(consumed_asset.status, "Decapitalized") + first_asset_depr_schedule.load_from_db() + + second_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(consumed_asset.name) + self.assertEquals(second_asset_depr_schedule.status, "Active") + self.assertEquals(first_asset_depr_schedule.status, "Cancelled") + + depr_schedule_of_consumed_asset = second_asset_depr_schedule.get("depreciation_schedule") + consumed_depreciation_schedule = [ d - for d in get_draft_or_active_depr_schedule(consumed_asset.name) + for d in depr_schedule_of_consumed_asset if getdate(d.schedule_date) == getdate(capitalization_date) ] self.assertTrue( diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index d004bdbf61..7a35013929 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -122,8 +122,10 @@ def convert_draft_asset_depr_schedules_into_active(asset_doc): asset_doc.name, row.finance_book ) + if not asset_depr_schedule_doc: + continue + if asset_depr_schedule_doc.status == "Draft": - asset_depr_schedule_doc.status = "Active" asset_depr_schedule_doc.submit() diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py index 8ba3c0eda0..8618392ea2 100644 --- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py @@ -13,7 +13,7 @@ from erpnext.assets.doctype.asset.test_asset import ( set_depreciation_settings_in_company, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( - get_draft_or_active_depr_schedule, + get_draft_or_active_asset_depr_schedule_doc, ) from erpnext.stock.doctype.item.test_item import create_item @@ -235,13 +235,23 @@ class TestAssetRepair(unittest.TestCase): def test_increase_in_asset_life(self): asset = create_asset(calculate_depreciation=1, submit=1) + + first_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(first_asset_depr_schedule.status, "Active") + initial_num_of_depreciations = num_of_depreciations(asset) create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1) + asset.reload() + first_asset_depr_schedule.load_from_db() + + second_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset.name) + self.assertEquals(second_asset_depr_schedule.status, "Active") + self.assertEquals(first_asset_depr_schedule.status, "Cancelled") self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset)) self.assertEqual( - get_draft_or_active_depr_schedule(asset.name)[-1].accumulated_depreciation_amount, + second_asset_depr_schedule.get("depreciation_schedule")[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation, ) diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py index 62c636624c..780c9db02b 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py @@ -7,6 +7,9 @@ import frappe from frappe.utils import add_days, get_last_day, nowdate from erpnext.assets.doctype.asset.test_asset import create_asset_data +from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_draft_or_active_asset_depr_schedule_doc, +) from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import ( get_current_asset_value, ) @@ -73,12 +76,21 @@ class TestAssetValueAdjustment(unittest.TestCase): ) asset_doc.submit() + first_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset_doc.name) + self.assertEquals(first_asset_depr_schedule.status, "Active") + current_value = get_current_asset_value(asset_doc.name) adj_doc = make_asset_value_adjustment( asset=asset_doc.name, current_asset_value=current_value, new_asset_value=50000.0 ) adj_doc.submit() + first_asset_depr_schedule.load_from_db() + + second_asset_depr_schedule = get_draft_or_active_asset_depr_schedule_doc(asset_doc.name) + self.assertEquals(second_asset_depr_schedule.status, "Active") + self.assertEquals(first_asset_depr_schedule.status, "Cancelled") + expected_gle = ( ("_Test Accumulated Depreciations - _TC", 0.0, 50000.0), ("_Test Depreciations - _TC", 50000.0, 0.0), From 8263bf9a9a716f7651386633fd6f26686f2008bd Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 27 Dec 2022 14:59:35 +0530 Subject: [PATCH 47/94] fix: Random behaviour while picking items using picklist (#33449) --- erpnext/stock/doctype/pick_list/pick_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index aff5e0539c..8704b6718b 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -441,7 +441,7 @@ def get_available_item_locations_for_batched_item( sle.`batch_no`, sle.`item_code` HAVING `qty` > 0 - ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation` + ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`, sle.`batch_no`, sle.`warehouse` """.format( warehouse_condition=warehouse_condition ), From 57adcc0b031eb9ceeff6eda050c7a7c90add1e93 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 27 Dec 2022 12:10:52 +0530 Subject: [PATCH 48/94] chore: move patch to pre_model_sync --- erpnext/patches.txt | 4 ++-- .../v15_0/create_asset_depreciation_schedules_from_assets.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ddceb3acfb..74f866e20e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -268,6 +268,7 @@ erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v15_0.delete_taxjar_doctypes +erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets [post_model_sync] execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') @@ -319,5 +320,4 @@ erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization erpnext.patches.v14_0.update_partial_tds_fields erpnext.patches.v14_0.create_incoterms_and_migrate_shipment erpnext.patches.v14_0.setup_clear_repost_logs -erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request -erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets \ No newline at end of file +erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request \ No newline at end of file diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py index 8dcbb2a1cc..e77e5262bb 100644 --- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -2,6 +2,8 @@ import frappe def execute(): + frappe.reload_doc("asset", "doctype", "Asset Depreciation Schedule") + assets = get_details_of_draft_or_submitted_depreciable_assets() for asset in assets: From c916fb0513e8da5b526ea4b4a6cae444c8a22039 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 27 Dec 2022 12:15:18 +0530 Subject: [PATCH 49/94] chore: fix module name in patch --- erpnext/patches.txt | 2 +- .../v15_0/create_asset_depreciation_schedules_from_assets.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 74f866e20e..ba92e9084f 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -268,7 +268,7 @@ erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v15_0.delete_taxjar_doctypes -erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets +erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets #03 [post_model_sync] execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py index e77e5262bb..02ffa70888 100644 --- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -2,7 +2,7 @@ import frappe def execute(): - frappe.reload_doc("asset", "doctype", "Asset Depreciation Schedule") + frappe.reload_doc("assets", "doctype", "Asset Depreciation Schedule") assets = get_details_of_draft_or_submitted_depreciable_assets() From 97f85882022a1e50b47900afcd3fd43aa6eece26 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 27 Dec 2022 12:15:37 +0530 Subject: [PATCH 50/94] chore: fix patch name --- erpnext/patches.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ba92e9084f..74f866e20e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -268,7 +268,7 @@ erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v15_0.delete_taxjar_doctypes -erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets #03 +erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets [post_model_sync] execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') From 21a09e74313d91a1abce6bd6dc9fb764ffd784af Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 27 Dec 2022 13:03:19 +0530 Subject: [PATCH 51/94] chore: fix patch --- .../v15_0/create_asset_depreciation_schedules_from_assets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py index 02ffa70888..749225c858 100644 --- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py +++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py @@ -84,5 +84,5 @@ def update_depreciation_schedules(asset_name, asset_depr_schedule_name, fb_row_i .set(ds.parent, asset_depr_schedule_name) .set(ds.parentfield, "depreciation_schedule") .set(ds.parenttype, "Asset Depreciation Schedule") - .where(ds.parent == depr_schedule.name) + .where(ds.name == depr_schedule.name) ).run() From d2686ce75bb39bffff4fd1b56ad4880444efb72e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 27 Dec 2022 17:42:03 +0530 Subject: [PATCH 52/94] fix: Multiple rows for same warehouse and batches in pick list (#33456) --- erpnext/stock/doctype/pick_list/pick_list.js | 10 ++++++++- erpnext/stock/doctype/pick_list/pick_list.py | 22 +++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js index 799406cd79..8213adb89b 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.js +++ b/erpnext/stock/doctype/pick_list/pick_list.js @@ -51,7 +51,15 @@ frappe.ui.form.on('Pick List', { if (!(frm.doc.locations && frm.doc.locations.length)) { frappe.msgprint(__('Add items in the Item Locations table')); } else { - frm.call('set_item_locations', {save: save}); + frappe.call({ + method: "set_item_locations", + doc: frm.doc, + args: { + "save": save, + }, + freeze: 1, + freeze_message: __("Setting Item Locations..."), + }); } }, get_item_locations: (frm) => { diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 8704b6718b..953fca7419 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -135,6 +135,7 @@ class PickList(Document): # reset self.delete_key("locations") + updated_locations = frappe._dict() for item_doc in items: item_code = item_doc.item_code @@ -155,7 +156,26 @@ class PickList(Document): for row in locations: location = item_doc.as_dict() location.update(row) - self.append("locations", location) + key = ( + location.item_code, + location.warehouse, + location.uom, + location.batch_no, + location.serial_no, + location.sales_order_item or location.material_request_item, + ) + + if key not in updated_locations: + updated_locations.setdefault(key, location) + else: + updated_locations[key].qty += location.qty + updated_locations[key].stock_qty += location.stock_qty + + for location in updated_locations.values(): + if location.picked_qty > location.stock_qty: + location.picked_qty = location.stock_qty + + self.append("locations", location) # If table is empty on update after submit, set stock_qty, picked_qty to 0 so that indicator is red # and give feedback to the user. This is to avoid empty Pick Lists. From 0b75aa53907e67d440884a2ea0084044265994a5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 27 Dec 2022 17:53:43 +0530 Subject: [PATCH 53/94] fix: Default dimensions on fetching items from BOM (#33439) --- erpnext/stock/doctype/stock_entry/stock_entry.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index b9102445e0..d4b4efa4cd 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -112,6 +112,10 @@ frappe.ui.form.on('Stock Entry', { } }); attach_bom_items(frm.doc.bom_no); + + if(!check_should_not_attach_bom_items(frm.doc.bom_no)) { + erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); + } }, setup_quality_inspection: function(frm) { @@ -326,7 +330,11 @@ frappe.ui.form.on('Stock Entry', { } frm.trigger("setup_quality_inspection"); - attach_bom_items(frm.doc.bom_no) + attach_bom_items(frm.doc.bom_no); + + if(!check_should_not_attach_bom_items(frm.doc.bom_no)) { + erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); + } }, before_save: function(frm) { @@ -939,7 +947,10 @@ erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockControlle method: "get_items", callback: function(r) { if(!r.exc) refresh_field("items"); - if(me.frm.doc.bom_no) attach_bom_items(me.frm.doc.bom_no) + if(me.frm.doc.bom_no) { + attach_bom_items(me.frm.doc.bom_no); + erpnext.accounts.dimensions.update_dimension(me.frm, me.frm.doctype); + } } }); } From 8e271fd7190447577fa15e1d180c33524576d529 Mon Sep 17 00:00:00 2001 From: Sabu Siyad Date: Wed, 28 Dec 2022 08:11:28 +0530 Subject: [PATCH 54/94] feat(exotel): make use of `CustomField` in API (#33338) * feat(exotel): pass kwargs for `make_a_call` https://developer.exotel.com/api/make-a-call-api#call-agent Signed-off-by: Sabu Siyad * feat(exotel): map custom field to doctype Signed-off-by: Sabu Siyad Signed-off-by: Sabu Siyad --- .../exotel_settings/exotel_settings.json | 34 +++++++++++++++++-- .../exotel_integration.py | 23 +++++++++++-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.json b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.json index 72f47b53ec..0d42ca8c85 100644 --- a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.json +++ b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2019-05-21 07:41:53.536536", "doctype": "DocType", "engine": "InnoDB", @@ -7,10 +8,14 @@ "section_break_2", "account_sid", "api_key", - "api_token" + "api_token", + "section_break_6", + "map_custom_field_to_doctype", + "target_doctype" ], "fields": [ { + "default": "0", "fieldname": "enabled", "fieldtype": "Check", "label": "Enabled" @@ -18,7 +23,8 @@ { "depends_on": "enabled", "fieldname": "section_break_2", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "label": "Credentials" }, { "fieldname": "account_sid", @@ -34,10 +40,31 @@ "fieldname": "api_key", "fieldtype": "Data", "label": "API Key" + }, + { + "depends_on": "enabled", + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "label": "Custom Field" + }, + { + "default": "0", + "fieldname": "map_custom_field_to_doctype", + "fieldtype": "Check", + "label": "Map Custom Field to DocType" + }, + { + "depends_on": "map_custom_field_to_doctype", + "fieldname": "target_doctype", + "fieldtype": "Link", + "label": "Target DocType", + "mandatory_depends_on": "map_custom_field_to_doctype", + "options": "DocType" } ], "issingle": 1, - "modified": "2019-05-22 06:25:18.026997", + "links": [], + "modified": "2022-12-14 17:24:50.176107", "modified_by": "Administrator", "module": "ERPNext Integrations", "name": "Exotel Settings", @@ -57,5 +84,6 @@ "quick_entry": 1, "sort_field": "modified", "sort_order": "ASC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/erpnext_integrations/exotel_integration.py b/erpnext/erpnext_integrations/exotel_integration.py index fd0f783575..0d40667e32 100644 --- a/erpnext/erpnext_integrations/exotel_integration.py +++ b/erpnext/erpnext_integrations/exotel_integration.py @@ -72,6 +72,24 @@ def get_call_log(call_payload): return frappe.get_doc("Call Log", call_log_id) +def map_custom_field(call_payload, call_log): + field_value = call_payload.get("CustomField") + + if not field_value: + return call_log + + settings = get_exotel_settings() + target_doctype = settings.target_doctype + mapping_enabled = settings.map_custom_field_to_doctype + + if not mapping_enabled or not target_doctype: + return call_log + + call_log.append("links", {"link_doctype": target_doctype, "link_name": field_value}) + + return call_log + + def create_call_log(call_payload): call_log = frappe.new_doc("Call Log") call_log.id = call_payload.get("CallSid") @@ -79,6 +97,7 @@ def create_call_log(call_payload): call_log.medium = call_payload.get("To") call_log.status = "Ringing" setattr(call_log, "from", call_payload.get("CallFrom")) + map_custom_field(call_payload, call_log) call_log.save(ignore_permissions=True) frappe.db.commit() return call_log @@ -93,10 +112,10 @@ def get_call_status(call_id): @frappe.whitelist() -def make_a_call(from_number, to_number, caller_id): +def make_a_call(from_number, to_number, caller_id, **kwargs): endpoint = get_exotel_endpoint("Calls/connect.json?details=true") response = requests.post( - endpoint, data={"From": from_number, "To": to_number, "CallerId": caller_id} + endpoint, data={"From": from_number, "To": to_number, "CallerId": caller_id, **kwargs} ) return response.json() From 6f5824cb213cdda10e225322dd417e0258e0a3ce Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 27 Dec 2022 14:54:23 +0530 Subject: [PATCH 55/94] fix: `fg_item_qty` in non-subcontracted PO --- .../doctype/purchase_order/purchase_order.py | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 4c10b4812e..5a4168a573 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -207,31 +207,36 @@ class PurchaseOrder(BuyingController): ) def validate_fg_item_for_subcontracting(self): - if self.is_subcontracted and not self.is_old_subcontracting_flow: + if self.is_subcontracted: + if not self.is_old_subcontracting_flow: + for item in self.items: + if not item.fg_item: + frappe.throw( + _("Row #{0}: Finished Good Item is not specified for service item {1}").format( + item.idx, item.item_code + ) + ) + else: + if not frappe.get_value("Item", item.fg_item, "is_sub_contracted_item"): + frappe.throw( + _( + "Row #{0}: Finished Good Item {1} must be a sub-contracted item for service item {2}" + ).format(item.idx, item.fg_item, item.item_code) + ) + elif not frappe.get_value("Item", item.fg_item, "default_bom"): + frappe.throw( + _("Row #{0}: Default BOM not found for FG Item {1}").format(item.idx, item.fg_item) + ) + if not item.fg_item_qty: + frappe.throw( + _("Row #{0}: Finished Good Item Qty is not specified for service item {0}").format( + item.idx, item.item_code + ) + ) + else: for item in self.items: - if not item.fg_item: - frappe.throw( - _("Row #{0}: Finished Good Item is not specified for service item {1}").format( - item.idx, item.item_code - ) - ) - else: - if not frappe.get_value("Item", item.fg_item, "is_sub_contracted_item"): - frappe.throw( - _( - "Row #{0}: Finished Good Item {1} must be a sub-contracted item for service item {2}" - ).format(item.idx, item.fg_item, item.item_code) - ) - elif not frappe.get_value("Item", item.fg_item, "default_bom"): - frappe.throw( - _("Row #{0}: Default BOM not found for FG Item {1}").format(item.idx, item.fg_item) - ) - if not item.fg_item_qty: - frappe.throw( - _("Row #{0}: Finished Good Item Qty is not specified for service item {0}").format( - item.idx, item.item_code - ) - ) + item.set("fg_item", None) + item.set("fg_item_qty", 0) def get_schedule_dates(self): for d in self.get("items"): From cabaed9ed2526e2649d173c806f6987d3377b0c3 Mon Sep 17 00:00:00 2001 From: Dany Robert Date: Wed, 28 Dec 2022 18:05:55 +0530 Subject: [PATCH 56/94] fix(pricing rule): consider child tables in condition (#33469) --- erpnext/accounts/doctype/pricing_rule/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 3989f8a8ac..1ce780eac8 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -252,10 +252,15 @@ def get_other_conditions(conditions, values, args): if args.get("doctype") in [ "Quotation", + "Quotation Item", "Sales Order", + "Sales Order Item", "Delivery Note", + "Delivery Note Item", "Sales Invoice", + "Sales Invoice Item", "POS Invoice", + "POS Invoice Item", ]: conditions += """ and ifnull(`tabPricing Rule`.selling, 0) = 1""" else: From e3a0ce5d6328d2ef68fb00419775ce113889c133 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 29 Dec 2022 09:34:51 +0530 Subject: [PATCH 57/94] fix: use base_net_amount in case of missing stock qty (#33457) --- .../item_wise_purchase_register.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index c04b9c7125..d34c21348c 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -53,9 +53,6 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum item_details = get_item_details() for d in item_list: - if not d.stock_qty: - continue - item_record = item_details.get(d.item_code) purchase_receipt = None @@ -94,7 +91,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum "expense_account": expense_account, "stock_qty": d.stock_qty, "stock_uom": d.stock_uom, - "rate": d.base_net_amount / d.stock_qty, + "rate": d.base_net_amount / d.stock_qty if d.stock_qty else d.base_net_amount, "amount": d.base_net_amount, } ) From 123920d0bc7b1d3c0e465d09d569ed2d08687a0b Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Thu, 29 Dec 2022 00:01:26 -0500 Subject: [PATCH 58/94] feat: add after_refresh hook to item dashboard (#33372) * fix: return promise * fix: use after_refresh hook instead of promise # Because there is already a before_refresh hook. I think it makes sense to do the same for after. --- erpnext/stock/dashboard/item_dashboard.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index 6e7622c067..1be528f1dd 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -102,6 +102,9 @@ erpnext.stock.ItemDashboard = class ItemDashboard { args: args, callback: function (r) { me.render(r.message); + if(me.after_refresh) { + me.after_refresh(); + } } }); } From 617518389ac0c6459197e27f94efbcb14d409dbf Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 29 Dec 2022 10:41:36 +0530 Subject: [PATCH 59/94] fix: Conversion factor error for invoices without item code (petty expenses) (#32714) * fix: Set default uom conversion factor to 1 for invoices * chore: set default conversion_factor as 1 * chore: remove print statements --- .../doctype/sales_invoice_item/sales_invoice_item.json | 2 +- erpnext/controllers/accounts_controller.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 62c3ced76a..35d19ed843 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -890,7 +890,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-11-02 12:53:12.693217", + "modified": "2022-12-28 16:17:33.484531", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 334a2d806d..788dc4982e 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -584,7 +584,12 @@ class AccountsController(TransactionBase): if bool(uom) != bool(stock_uom): # xor item.stock_uom = item.uom = uom or stock_uom - item.conversion_factor = get_uom_conv_factor(item.get("uom"), item.get("stock_uom")) + # UOM cannot be zero so substitute as 1 + item.conversion_factor = ( + get_uom_conv_factor(item.get("uom"), item.get("stock_uom")) + or item.get("conversion_factor") + or 1 + ) if self.doctype == "Purchase Invoice": self.set_expense_account(for_validate) From c716dcc01e1b29779dac28b4d531b3fa3ee27143 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 29 Dec 2022 12:34:18 +0530 Subject: [PATCH 60/94] fix: consider child nodes while getting bin details --- erpnext/controllers/selling_controller.py | 2 +- erpnext/public/js/controllers/buying.js | 3 +- erpnext/stock/get_item_details.py | 38 ++++++++++++++++------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 8b073a4320..cd1168d4ac 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -23,7 +23,7 @@ class SellingController(StockController): super(SellingController, self).onload() if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"): for item in self.get("items"): - item.update(get_bin_details(item.item_code, item.warehouse)) + item.update(get_bin_details(item.item_code, item.warehouse, include_child_warehouses=True)) def validate(self): super(SellingController, self).validate() diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 09779d89ec..b0e08cc6f2 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -225,7 +225,8 @@ erpnext.buying.BuyingController = class BuyingController extends erpnext.Transac args: { item_code: item.item_code, warehouse: item.warehouse, - company: doc.company + company: doc.company, + include_child_warehouses: true } }); } diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 1741d65460..dc00999b46 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -102,9 +102,11 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru elif out.get("warehouse"): if doc and doc.get("doctype") == "Purchase Order": # calculate company_total_stock only for po - bin_details = get_bin_details(args.item_code, out.warehouse, args.company) + bin_details = get_bin_details( + args.item_code, out.warehouse, args.company, include_child_warehouses=True + ) else: - bin_details = get_bin_details(args.item_code, out.warehouse) + bin_details = get_bin_details(args.item_code, out.warehouse, include_child_warehouses=True) out.update(bin_details) @@ -1060,7 +1062,9 @@ def get_pos_profile_item_details(company, args, pos_profile=None, update_data=Fa res[fieldname] = pos_profile.get(fieldname) if res.get("warehouse"): - res.actual_qty = get_bin_details(args.item_code, res.warehouse).get("actual_qty") + res.actual_qty = get_bin_details( + args.item_code, res.warehouse, include_child_warehouses=True + ).get("actual_qty") return res @@ -1171,14 +1175,26 @@ def get_projected_qty(item_code, warehouse): @frappe.whitelist() -def get_bin_details(item_code, warehouse, company=None): - bin_details = frappe.db.get_value( - "Bin", - {"item_code": item_code, "warehouse": warehouse}, - ["projected_qty", "actual_qty", "reserved_qty"], - as_dict=True, - cache=True, - ) or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} +def get_bin_details(item_code, warehouse, company=None, include_child_warehouses=False): + bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} + + if warehouse: + from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses + + warehouses = get_child_warehouses(warehouse) if include_child_warehouses else [warehouse] + bin_details = frappe.db.get_value( + "Bin", + filters={"item_code": item_code, "warehouse": ["in", warehouses]}, + fieldname=[ + "sum(projected_qty) as projected_qty", + "sum(actual_qty) as actual_qty", + "sum(reserved_qty) as reserved_qty", + ], + as_dict=True, + cache=True, + ) + bin_details = {k: 0 if not v else v for k, v in bin_details.items()} + if company: bin_details["company_total_stock"] = get_company_total_stock(item_code, company) return bin_details From c3911a592a51a390c0b426707f7ec777686cb621 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 29 Dec 2022 16:38:08 +0530 Subject: [PATCH 61/94] chore: use `frappe.qb` instead of `frappe.db.get_value` --- erpnext/stock/get_item_details.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index dc00999b46..6152880985 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1179,21 +1179,22 @@ def get_bin_details(item_code, warehouse, company=None, include_child_warehouses bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} if warehouse: + from frappe.query_builder.functions import Coalesce, Sum + from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses warehouses = get_child_warehouses(warehouse) if include_child_warehouses else [warehouse] - bin_details = frappe.db.get_value( - "Bin", - filters={"item_code": item_code, "warehouse": ["in", warehouses]}, - fieldname=[ - "sum(projected_qty) as projected_qty", - "sum(actual_qty) as actual_qty", - "sum(reserved_qty) as reserved_qty", - ], - as_dict=True, - cache=True, - ) - bin_details = {k: 0 if not v else v for k, v in bin_details.items()} + + bin = frappe.qb.DocType("Bin") + bin_details = ( + frappe.qb.from_(bin) + .select( + Coalesce(Sum(bin.projected_qty), 0).as_("projected_qty"), + Coalesce(Sum(bin.actual_qty), 0).as_("actual_qty"), + Coalesce(Sum(bin.reserved_qty), 0).as_("reserved_qty"), + ) + .where((bin.item_code == item_code) & (bin.warehouse.isin(warehouses))) + ).run(as_dict=True)[0] if company: bin_details["company_total_stock"] = get_company_total_stock(item_code, company) From 728dc1acf4db979e1dde7d950279d8335028e1a7 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Fri, 30 Dec 2022 11:08:31 +0530 Subject: [PATCH 62/94] Revert "fix: daily scheduler to identify and fix stock transfer entries having incorrect valuation" --- erpnext/hooks.py | 1 - .../stock/doctype/stock_entry/stock_entry.py | 73 +------------------ .../doctype/stock_entry/test_stock_entry.py | 42 +---------- 3 files changed, 2 insertions(+), 114 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 7d72c76b81..fd19d2585c 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -420,7 +420,6 @@ scheduler_events = { "erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall", "erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans", "erpnext.crm.utils.open_leads_opportunities_based_on_todays_event", - "erpnext.stock.doctype.stock_entry.stock_entry.audit_incorrect_valuation_entries", ], "monthly_long": [ "erpnext.accounts.deferred_revenue.process_deferred_accounting", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index a047a9b814..d401f818c6 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -4,24 +4,12 @@ import json from collections import defaultdict -from typing import Dict import frappe from frappe import _ from frappe.model.mapper import get_mapped_doc from frappe.query_builder.functions import Sum -from frappe.utils import ( - add_days, - cint, - comma_or, - cstr, - flt, - format_time, - formatdate, - getdate, - nowdate, - today, -) +from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate import erpnext from erpnext.accounts.general_ledger import process_gl_map @@ -2712,62 +2700,3 @@ def get_stock_entry_data(work_order): ) .orderby(stock_entry.creation, stock_entry_detail.item_code, stock_entry_detail.idx) ).run(as_dict=1) - - -def audit_incorrect_valuation_entries(): - # Audit of stock transfer entries having incorrect valuation - from erpnext.controllers.stock_controller import create_repost_item_valuation_entry - - stock_entries = get_incorrect_stock_entries() - - for stock_entry, values in stock_entries.items(): - reposting_data = frappe._dict( - { - "posting_date": values.posting_date, - "posting_time": values.posting_time, - "voucher_type": "Stock Entry", - "voucher_no": stock_entry, - "company": values.company, - } - ) - - create_repost_item_valuation_entry(reposting_data) - - -def get_incorrect_stock_entries() -> Dict: - stock_entry = frappe.qb.DocType("Stock Entry") - stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry") - transfer_purposes = [ - "Material Transfer", - "Material Transfer for Manufacture", - "Send to Subcontractor", - ] - - query = ( - frappe.qb.from_(stock_entry) - .inner_join(stock_ledger_entry) - .on(stock_entry.name == stock_ledger_entry.voucher_no) - .select( - stock_entry.name, - stock_entry.company, - stock_entry.posting_date, - stock_entry.posting_time, - Sum(stock_ledger_entry.stock_value_difference).as_("stock_value"), - ) - .where( - (stock_entry.docstatus == 1) - & (stock_entry.purpose.isin(transfer_purposes)) - & (stock_ledger_entry.modified > add_days(today(), -2)) - ) - .groupby(stock_ledger_entry.voucher_detail_no) - .having(Sum(stock_ledger_entry.stock_value_difference) != 0) - ) - - data = query.run(as_dict=True) - stock_entries = {} - - for row in data: - if abs(row.stock_value) > 0.1 and row.name not in stock_entries: - stock_entries.setdefault(row.name, row) - - return stock_entries diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 680d209735..b574b718fe 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -5,7 +5,7 @@ import frappe from frappe.permissions import add_user_permission, remove_user_permission from frappe.tests.utils import FrappeTestCase, change_settings -from frappe.utils import add_days, flt, now, nowdate, nowtime, today +from frappe.utils import add_days, flt, nowdate, nowtime, today from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.stock.doctype.item.test_item import ( @@ -17,8 +17,6 @@ from erpnext.stock.doctype.item.test_item import ( from erpnext.stock.doctype.serial_no.serial_no import * # noqa from erpnext.stock.doctype.stock_entry.stock_entry import ( FinishedGoodError, - audit_incorrect_valuation_entries, - get_incorrect_stock_entries, move_sample_to_retention_warehouse, ) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -1616,44 +1614,6 @@ class TestStockEntry(FrappeTestCase): self.assertRaises(BatchExpiredError, se.save) - def test_audit_incorrect_stock_entries(self): - item_code = "Test Incorrect Valuation Rate Item - 001" - create_item(item_code=item_code, is_stock_item=1) - - make_stock_entry( - item_code=item_code, - purpose="Material Receipt", - posting_date=add_days(nowdate(), -10), - qty=2, - rate=500, - to_warehouse="_Test Warehouse - _TC", - ) - - transfer_entry = make_stock_entry( - item_code=item_code, - purpose="Material Transfer", - qty=2, - rate=500, - from_warehouse="_Test Warehouse - _TC", - to_warehouse="_Test Warehouse 1 - _TC", - ) - - sle_name = frappe.db.get_value( - "Stock Ledger Entry", {"voucher_no": transfer_entry.name, "actual_qty": (">", 0)}, "name" - ) - - frappe.db.set_value( - "Stock Ledger Entry", sle_name, {"modified": add_days(now(), -1), "stock_value_difference": 10} - ) - - stock_entries = get_incorrect_stock_entries() - self.assertTrue(transfer_entry.name in stock_entries) - - audit_incorrect_valuation_entries() - - stock_entries = get_incorrect_stock_entries() - self.assertFalse(transfer_entry.name in stock_entries) - def make_serialized_item(**args): args = frappe._dict(args) From 48a9cd5ef38ddc0f10c178c13b9e891764255dbd Mon Sep 17 00:00:00 2001 From: Gughan Ravikumar Date: Fri, 30 Dec 2022 13:16:40 +0530 Subject: [PATCH 63/94] fix: allow arbitary items in Quotation ans Sales Order (#33430) fix: allow arbitary items in Quotation ans Sales Order --- erpnext/selling/doctype/quotation_item/quotation_item.json | 3 +-- erpnext/selling/doctype/sales_order_item/sales_order_item.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 31a95896bc..ca7dfd2337 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -90,7 +90,6 @@ "oldfieldtype": "Link", "options": "Item", "print_width": "150px", - "reqd": 1, "search_index": 1, "width": "150px" }, @@ -649,7 +648,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-07-15 12:40:51.074820", + "modified": "2022-12-25 02:49:53.926625", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index b801de314c..d0dabad5c9 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -114,7 +114,6 @@ "oldfieldtype": "Link", "options": "Item", "print_width": "150px", - "reqd": 1, "width": "150px" }, { @@ -865,7 +864,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-11-18 11:39:01.741665", + "modified": "2022-12-25 02:51:10.247569", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", From ad53ecf2b48a808dc98f2834dbbfb9c5ebf73c72 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 30 Dec 2022 13:37:41 +0530 Subject: [PATCH 64/94] fix: Multi-currency issues in Bank Recociliation Tool --- .../bank_reconciliation_tool.py | 2 +- .../doctype/bank_transaction/bank_transaction.py | 2 +- .../js/bank_reconciliation_tool/dialog_manager.js | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index d353270b45..f5f04aeea8 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -302,7 +302,7 @@ def reconcile_vouchers(bank_transaction_name, vouchers): dict( account=account, voucher_type=voucher["payment_doctype"], voucher_no=voucher["payment_name"] ), - ["credit", "debit"], + ["credit_in_account_currency as credit", "debit_in_account_currency as debit"], as_dict=1, ) gl_amount, transaction_amount = ( diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py index a788514335..9b36c93a0f 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py @@ -137,7 +137,7 @@ def get_paid_amount(payment_entry, currency, bank_account): ) elif doc.payment_type == "Pay": paid_amount_field = ( - "paid_amount" if doc.paid_to_account_currency == currency else "base_paid_amount" + "paid_amount" if doc.paid_from_account_currency == currency else "base_paid_amount" ) return frappe.db.get_value( diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index ca01f68140..b5e6ab871d 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -355,12 +355,14 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { fieldname: "deposit", fieldtype: "Currency", label: "Deposit", + options: "currency", read_only: 1, }, { fieldname: "withdrawal", fieldtype: "Currency", label: "Withdrawal", + options: "currency", read_only: 1, }, { @@ -378,6 +380,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { fieldname: "allocated_amount", fieldtype: "Currency", label: "Allocated Amount", + options: "Currency", read_only: 1, }, @@ -385,8 +388,17 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { fieldname: "unallocated_amount", fieldtype: "Currency", label: "Unallocated Amount", + options: "Currency", read_only: 1, }, + { + fieldname: "currency", + fieldtype: "Link", + label: "Currency", + options: "Currency", + read_only: 1, + hidden: 1, + } ]; } From 8d62cdfd5f683c20c8ac0bd06e2b40b86579fd56 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Sat, 31 Dec 2022 14:14:25 -0500 Subject: [PATCH 65/94] fix: add missing 'ordered_qty' to get_bin_details --- erpnext/stock/get_item_details.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 1741d65460..02456f3d29 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1175,10 +1175,10 @@ def get_bin_details(item_code, warehouse, company=None): bin_details = frappe.db.get_value( "Bin", {"item_code": item_code, "warehouse": warehouse}, - ["projected_qty", "actual_qty", "reserved_qty"], + ["projected_qty", "actual_qty", "reserved_qty", "ordered_qty"], as_dict=True, cache=True, - ) or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} + ) or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0, "ordered_qty": 0} if company: bin_details["company_total_stock"] = get_company_total_stock(item_code, company) return bin_details From 239a5f8bf4c6dda9a955dc6472d9387d80afe619 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Sat, 31 Dec 2022 15:41:07 -0500 Subject: [PATCH 66/94] test: get_item_details contains bin details --- erpnext/stock/doctype/item/test_item.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index e1ee9389de..7e426ae4af 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -83,6 +83,7 @@ class TestItem(FrappeTestCase): def test_get_item_details(self): # delete modified item price record and make as per test_records frappe.db.sql("""delete from `tabItem Price`""") + frappe.db.sql("""delete from `tabBin`""") to_check = { "item_code": "_Test Item", @@ -103,9 +104,26 @@ class TestItem(FrappeTestCase): "batch_no": None, "uom": "_Test UOM", "conversion_factor": 1.0, + "reserved_qty": 1, + "actual_qty": 5, + "ordered_qty": 10, + "projected_qty": 14, } make_test_objects("Item Price") + make_test_objects( + "Bin", + [ + { + "item_code": "_Test Item", + "warehouse": "_Test Warehouse - _TC", + "reserved_qty": 1, + "actual_qty": 5, + "ordered_qty": 10, + "projected_qty": 14, + } + ], + ) company = "_Test Company" currency = frappe.get_cached_value("Company", company, "default_currency") @@ -129,7 +147,7 @@ class TestItem(FrappeTestCase): ) for key, value in to_check.items(): - self.assertEqual(value, details.get(key)) + self.assertEqual(value, details.get(key), key) def test_item_tax_template(self): expected_item_tax_template = [ From 98c39c4f5f5824839ca6da0ceaa4f6868be27c1c Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Sun, 1 Jan 2023 22:25:12 -0500 Subject: [PATCH 67/94] fix: update payment entry references (#33274) * fix: set_amounts after deductions and losses are set * test: difference_amount changes after update_references_in_payment_entry * chore: linter * fix: use kwargs instad of destructing a dict [skip ci] * fix(test): test payment entry difference_amount after payment reconciliation. --- erpnext/accounts/test/test_utils.py | 44 +++++++++++++++++++ erpnext/accounts/utils.py | 10 ++--- erpnext/www/book-appointment/__init__.py | 0 .../www/book-appointment/verify/__init__.py | 0 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 erpnext/www/book-appointment/__init__.py create mode 100644 erpnext/www/book-appointment/verify/__init__.py diff --git a/erpnext/accounts/test/test_utils.py b/erpnext/accounts/test/test_utils.py index 882cd694a3..3aca60eae5 100644 --- a/erpnext/accounts/test/test_utils.py +++ b/erpnext/accounts/test/test_utils.py @@ -3,11 +3,14 @@ import unittest import frappe from frappe.test_runner import make_test_objects +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry +from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.party import get_party_shipping_address from erpnext.accounts.utils import ( get_future_stock_vouchers, get_voucherwise_gl_entries, sort_stock_vouchers_by_posting_date, + update_reference_in_payment_entry, ) from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt @@ -73,6 +76,47 @@ class TestUtils(unittest.TestCase): sorted_vouchers = sort_stock_vouchers_by_posting_date(list(reversed(vouchers))) self.assertEqual(sorted_vouchers, vouchers) + def test_update_reference_in_payment_entry(self): + item = make_item().name + + purchase_invoice = make_purchase_invoice( + item=item, supplier="_Test Supplier USD", currency="USD", conversion_rate=82.32 + ) + purchase_invoice.submit() + + payment_entry = get_payment_entry(purchase_invoice.doctype, purchase_invoice.name) + payment_entry.target_exchange_rate = 62.9 + payment_entry.paid_amount = 15725 + payment_entry.deductions = [] + payment_entry.insert() + + self.assertEqual(payment_entry.difference_amount, -4855.00) + payment_entry.references = [] + payment_entry.submit() + + payment_reconciliation = frappe.new_doc("Payment Reconciliation") + payment_reconciliation.company = payment_entry.company + payment_reconciliation.party_type = "Supplier" + payment_reconciliation.party = purchase_invoice.supplier + payment_reconciliation.receivable_payable_account = payment_entry.paid_to + payment_reconciliation.get_unreconciled_entries() + payment_reconciliation.allocate_entries( + { + "payments": [d.__dict__ for d in payment_reconciliation.payments], + "invoices": [d.__dict__ for d in payment_reconciliation.invoices], + } + ) + for d in payment_reconciliation.invoices: + # Reset invoice outstanding_amount because allocate_entries will zero this value out. + d.outstanding_amount = d.amount + for d in payment_reconciliation.allocation: + d.difference_account = "Exchange Gain/Loss - _TC" + payment_reconciliation.reconcile() + + payment_entry.load_from_db() + self.assertEqual(len(payment_entry.references), 1) + self.assertEqual(payment_entry.difference_amount, 0) + ADDRESS_RECORDS = [ { diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 1e573b01ba..445dcc53c6 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -611,11 +611,6 @@ def update_reference_in_payment_entry(d, payment_entry, do_not_save=False): new_row.docstatus = 1 new_row.update(reference_details) - payment_entry.flags.ignore_validate_update_after_submit = True - payment_entry.setup_party_account_field() - payment_entry.set_missing_values() - payment_entry.set_amounts() - if d.difference_amount and d.difference_account: account_details = { "account": d.difference_account, @@ -627,6 +622,11 @@ def update_reference_in_payment_entry(d, payment_entry, do_not_save=False): payment_entry.set_gain_or_loss(account_details=account_details) + payment_entry.flags.ignore_validate_update_after_submit = True + payment_entry.setup_party_account_field() + payment_entry.set_missing_values() + payment_entry.set_amounts() + if not do_not_save: payment_entry.save(ignore_permissions=True) diff --git a/erpnext/www/book-appointment/__init__.py b/erpnext/www/book-appointment/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/www/book-appointment/verify/__init__.py b/erpnext/www/book-appointment/verify/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 010718ffed09bef6c485045f9808e7163064130f Mon Sep 17 00:00:00 2001 From: Sabu Siyad Date: Mon, 2 Jan 2023 08:58:01 +0530 Subject: [PATCH 68/94] fix(ecommerce/cart): explicitly set `frappe.boot` (#33431) related: https://github.com/frappe/frappe/pull/18323 Signed-off-by: Sabu Siyad Signed-off-by: Sabu Siyad --- erpnext/templates/includes/cart/cart_address.html | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html index cf60017373..a8188ec825 100644 --- a/erpnext/templates/includes/cart/cart_address.html +++ b/erpnext/templates/includes/cart/cart_address.html @@ -55,6 +55,7 @@ {% endif %}