diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 41df6361fad..9ad41be1254 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -635,38 +635,44 @@ class Asset(AccountsController): return add_days(self.available_for_use_date, -1) # if it returns True, depreciation_amount will not be equal for the first and last rows - def check_is_pro_rata(self, row, wdv_or_dd_non_yearly=False): + def check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False): has_pro_rata = False # if not existing asset, from_date = available_for_use_date # otherwise, if number_of_depreciations_booked = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12 # from_date = 01/01/2022 - from_date = self.get_modified_available_for_use_date(row, wdv_or_dd_non_yearly) - days = date_diff(row.depreciation_start_date, from_date) + 1 - - if wdv_or_dd_non_yearly: - total_days = get_total_days(row.depreciation_start_date, 12) + if row.depreciation_method in ("Straight Line", "Manual"): + prev_depreciation_start_date = get_last_day( + add_months( + row.depreciation_start_date, + (row.frequency_of_depreciation * -1) * asset_doc.number_of_depreciations_booked, + ) + ) + from_date = asset_doc.available_for_use_date + days = date_diff(prev_depreciation_start_date, from_date) + 1 + total_days = get_total_days(prev_depreciation_start_date, row.frequency_of_depreciation) else: - # if frequency_of_depreciation is 12 months, total_days = 365 + from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False) + days = date_diff(row.depreciation_start_date, from_date) + 1 total_days = get_total_days(row.depreciation_start_date, row.frequency_of_depreciation) + if days <= 0: + frappe.throw( + _( + """Error: This asset already has {0} depreciation periods booked. + The `depreciation start` date must be at least {1} periods after the `available for use` date. + Please correct the dates accordingly.""" + ).format( + asset_doc.number_of_depreciations_booked, + asset_doc.number_of_depreciations_booked, + ) + ) + if days < total_days: has_pro_rata = True return has_pro_rata - def get_modified_available_for_use_date(self, row, wdv_or_dd_non_yearly=False): - if wdv_or_dd_non_yearly: - return add_months( - self.available_for_use_date, - (self.number_of_depreciations_booked * 12), - ) - else: - return add_months( - self.available_for_use_date, - (self.number_of_depreciations_booked * row.frequency_of_depreciation), - ) - def validate_asset_finance_books(self, row): if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount): frappe.throw( @@ -1290,6 +1296,28 @@ def get_item_details(item_code, asset_category, gross_purchase_amount): return books +def _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=False): + """ + if Asset has opening booked depreciations = 9, + available for use date = 17-07-2023, + depreciation start date = 30-04-2024 + then from date should be 01-04-2024 + """ + if asset_doc.number_of_depreciations_booked > 0: + from_date = add_months( + asset_doc.available_for_use_date, + (asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation) - 1, + ) + if is_last_day_of_the_month(row.depreciation_start_date): + return add_days(get_last_day(from_date), 1) + + # get from date when depreciation start date is not last day of the month + months_difference = month_diff(row.depreciation_start_date, from_date) - 1 + return add_days(add_months(row.depreciation_start_date, -1 * months_difference), 1) + else: + return asset_doc.available_for_use_date + + def get_asset_account(account_name, asset=None, asset_category=None, company=None): account = None if asset: diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 7007f212827..b89027578c5 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1451,7 +1451,7 @@ class TestDepreciationBasics(AssetSetup): affects `value_after_depreciation` """ - asset = create_asset(calculate_depreciation=1) + asset = create_asset(calculate_depreciation=1, depreciation_start_date="2021-12-31") asset.opening_accumulated_depreciation = 2000 asset.number_of_depreciations_booked = 1 diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 0fe2b56a944..87152cae42f 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -241,8 +241,6 @@ def install(country=None): {"doctype": "Issue Priority", "name": _("Low")}, {"doctype": "Issue Priority", "name": _("Medium")}, {"doctype": "Issue Priority", "name": _("High")}, - {"doctype": "Email Account", "email_id": "sales@example.com", "append_to": "Opportunity"}, - {"doctype": "Email Account", "email_id": "support@example.com", "append_to": "Issue"}, {"doctype": "Party Type", "party_type": "Customer", "account_type": "Receivable"}, {"doctype": "Party Type", "party_type": "Supplier", "account_type": "Payable"}, {"doctype": "Party Type", "party_type": "Employee", "account_type": "Payable"}, diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 3543e42e217..3728e030542 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -916,6 +916,11 @@ class Item(Document): changed_fields = [ field for field in restricted_fields if cstr(self.get(field)) != cstr(values.get(field)) ] + + # Allow to change valuation method from FIFO to Moving Average not vice versa + if self.valuation_method == "Moving Average" and "valuation_method" in changed_fields: + changed_fields.remove("valuation_method") + if not changed_fields: return diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 08a8262b246..1cacb0172c4 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1194,16 +1194,16 @@ class update_entries_after: ) in frappe.local.flags.currently_saving: msg = _("{0} units of {1} needed in {2} to complete this transaction.").format( abs(deficiency), - frappe.get_desk_link("Item", exceptions[0]["item_code"]), - frappe.get_desk_link("Warehouse", warehouse), + frappe.get_desk_link("Item", exceptions[0]["item_code"], show_title_with_name=True), + frappe.get_desk_link("Warehouse", warehouse, show_title_with_name=True), ) else: msg = _( "{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction." ).format( abs(deficiency), - frappe.get_desk_link("Item", exceptions[0]["item_code"]), - frappe.get_desk_link("Warehouse", warehouse), + frappe.get_desk_link("Item", exceptions[0]["item_code"], show_title_with_name=True), + frappe.get_desk_link("Warehouse", warehouse, show_title_with_name=True), exceptions[0]["posting_date"], exceptions[0]["posting_time"], frappe.get_desk_link(exceptions[0]["voucher_type"], exceptions[0]["voucher_no"]), @@ -1664,8 +1664,8 @@ def validate_negative_qty_in_future_sle(args, allow_negative_stock=False): if is_negative_with_precision(neg_sle): message = _("{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction.").format( abs(neg_sle[0]["qty_after_transaction"]), - frappe.get_desk_link("Item", args.item_code), - frappe.get_desk_link("Warehouse", args.warehouse), + frappe.get_desk_link("Item", args.item_code, show_title_with_name=True), + frappe.get_desk_link("Warehouse", args.warehouse, show_title_with_name=True), neg_sle[0]["posting_date"], neg_sle[0]["posting_time"], frappe.get_desk_link(neg_sle[0]["voucher_type"], neg_sle[0]["voucher_no"]),