diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 7e542197407..7791b117444 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -136,6 +136,10 @@ frappe.ui.form.on('Asset', {
}, __("Manage"));
}
+ if (frm.doc.depr_entry_posting_status === "Failed") {
+ frm.trigger("set_depr_posting_failure_alert");
+ }
+
frm.trigger("setup_chart");
}
@@ -146,6 +150,19 @@ frappe.ui.form.on('Asset', {
}
},
+ set_depr_posting_failure_alert: function (frm) {
+ const alert = `
+
+
+
+ Failed to post depreciation entries
+
+
+
`;
+
+ frm.dashboard.set_headline_alert(alert);
+ },
+
toggle_reference_doc: function(frm) {
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
frm.set_df_property('purchase_invoice', 'read_only', 1);
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index f0505ff9835..8b6af47b049 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -70,6 +70,7 @@
"column_break_51",
"purchase_receipt_amount",
"default_finance_book",
+ "depr_entry_posting_status",
"amended_from"
],
"fields": [
@@ -488,6 +489,16 @@
"fieldtype": "Int",
"label": "Asset Quantity",
"read_only_depends_on": "eval:!doc.is_existing_asset"
+ },
+ {
+ "fieldname": "depr_entry_posting_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Depreciation Entry Posting Status",
+ "no_copy": 1,
+ "options": "\nSuccessful\nFailed",
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 72,
@@ -510,7 +521,7 @@
"link_fieldname": "asset"
}
],
- "modified": "2022-07-20 10:15:12.887372",
+ "modified": "2022-12-05 16:21:30.024060",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 97941706aa8..4da2b42a1a0 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -5,6 +5,9 @@
import frappe
from frappe import _
from frappe.utils import add_months, cint, flt, getdate, nowdate, today
+from frappe.utils.user import get_users_with_role
+from frappe.utils.data import get_link_to_form
+
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
@@ -12,7 +15,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
-def post_depreciation_entries(date=None, commit=True):
+def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled
if not cint(
frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")
@@ -21,10 +24,22 @@ 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)
- if commit:
+
+ failed_asset_names = []
+
+ for asset_name in get_depreciable_assets(date):
+ try:
+ make_depreciation_entry(asset_name, date)
frappe.db.commit()
+ except Exception as e:
+ frappe.db.rollback()
+ failed_asset_names.append(asset_name)
+
+ if failed_asset_names:
+ mark_asset_depr_entry_posting_status_as_failed(failed_asset_names)
+ notify_depr_entry_posting_error_to_account_managers(failed_asset_names)
+
+ frappe.db.commit()
def get_depreciable_assets(date):
@@ -123,6 +138,10 @@ def make_depreciation_entry(asset_name, date=None):
finance_books.value_after_depreciation -= d.depreciation_amount
finance_books.db_update()
+ asset.flags.ignore_validate_update_after_submit = True
+ asset.depr_entry_posting_status = "Successful"
+ asset.save()
+
asset.set_status()
return asset
@@ -186,6 +205,47 @@ def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation
return credit_account, debit_account
+def mark_asset_depr_entry_posting_status_as_failed(failed_asset_names):
+ for asset_name in failed_asset_names:
+ asset = frappe.get_doc("Asset", asset_name)
+ asset.flags.ignore_validate_update_after_submit = True
+ asset.depr_entry_posting_status = "Failed"
+ asset.save()
+
+
+def notify_depr_entry_posting_error_to_account_managers(failed_asset_names):
+ recipients = get_users_with_role("Accounts Manager")
+
+ if not recipients:
+ recipients = get_users_with_role("System Manager")
+
+ subject = _("Error while posting depreciation entries")
+
+ asset_links = get_comma_separated_asset_links(failed_asset_names)
+
+ message = (
+ _("Hi,")
+ + "
"
+ +_(
+ "The following assets have failed to post depreciation entries: {0}"
+ ).format(asset_links)
+ + "."
+ )
+
+ frappe.sendmail(recipients=recipients, subject=subject, message=message)
+
+
+def get_comma_separated_asset_links(asset_names):
+ asset_links = []
+
+ for asset_name in asset_names:
+ asset_links.append(get_link_to_form("Asset", asset_name))
+
+ asset_links = ", ".join(asset_links)
+
+ return asset_links
+
+
@frappe.whitelist()
def scrap_asset(asset_name):
asset = frappe.get_doc("Asset", asset_name)