From 61cd0f98fdfc7c6379d204e5a9b5d4a2ac075d71 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 16 Jan 2023 18:35:40 +0530 Subject: [PATCH 1/6] fix: asset repair link and improve notes --- erpnext/assets/doctype/asset/asset.json | 4 ++-- erpnext/assets/doctype/asset/depreciation.py | 8 ++------ .../asset_capitalization.py | 6 +++--- .../doctype/asset_repair/asset_repair.py | 8 ++++---- .../asset_value_adjustment.py | 20 +++++++++++++------ 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 4bac3031e8..8649a80c79 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -487,7 +487,7 @@ { "group": "Repair", "link_doctype": "Asset Repair", - "link_fieldname": "asset_name" + "link_fieldname": "asset" }, { "group": "Value", @@ -500,7 +500,7 @@ "link_fieldname": "asset" } ], - "modified": "2022-11-25 12:47:19.689702", + "modified": "2023-01-16 12:01:00.502301", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 7686c348a6..97deea6f33 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -295,12 +295,12 @@ def reset_depreciation_schedule(asset_doc, date, notes): asset_doc, notes, date_of_return=date ) - modify_depreciation_schedule_for_asset_repairs(asset_doc) + modify_depreciation_schedule_for_asset_repairs(asset_doc, notes) asset_doc.save() -def modify_depreciation_schedule_for_asset_repairs(asset): +def modify_depreciation_schedule_for_asset_repairs(asset, notes): asset_repairs = frappe.get_all( "Asset Repair", filters={"asset": asset.name}, fields=["name", "increase_in_asset_life"] ) @@ -309,10 +309,6 @@ 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 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 62a3483629..821accf96a 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -430,7 +430,7 @@ class AssetCapitalization(StockController): if asset.calculate_depreciation: notes = _( - "This schedule was created when Asset {0} was consumed when Asset Capitalization {1} was submitted." + "This schedule was created when Asset {0} was consumed through Asset Capitalization {1}." ).format( get_link_to_form(asset.doctype, asset.name), get_link_to_form(self.doctype, self.get("name")) ) @@ -521,7 +521,7 @@ class AssetCapitalization(StockController): asset_doc.gross_purchase_amount = total_target_asset_value asset_doc.purchase_receipt_amount = total_target_asset_value notes = _( - "This schedule was created when target Asset {0} was updated when Asset Capitalization {1} was submitted." + "This schedule was created when target Asset {0} was updated through Asset Capitalization {1}." ).format( get_link_to_form(asset_doc.doctype, asset_doc.name), get_link_to_form(self.doctype, self.name) ) @@ -537,7 +537,7 @@ class AssetCapitalization(StockController): if asset.calculate_depreciation: reverse_depreciation_entry_made_after_disposal(asset, self.posting_date) notes = _( - "This schedule was created when Asset {0} was restored when Asset Capitalization {1} was cancelled." + "This schedule was created when Asset {0} was restored on Asset Capitalization {1}'s cancellation." ).format( get_link_to_form(asset.doctype, asset.name), get_link_to_form(self.doctype, self.name) ) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index b8cd115872..ff87c83e23 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -56,8 +56,8 @@ class AssetRepair(AccountsController): ): self.modify_depreciation_schedule() - notes = _("This schedule was created when Asset Repair {0} was submitted.").format( - get_link_to_form(self.doctype, self.name) + notes = _("This schedule was created when Asset {0} was repaired through Asset Repair {1}.").format( + get_link_to_form(self.asset_doc.doctype, self.asset_doc.name), 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) @@ -80,8 +80,8 @@ class AssetRepair(AccountsController): ): self.revert_depreciation_schedule_on_cancellation() - notes = _("This schedule was created when Asset Repair {0} was cancelled.").format( - get_link_to_form(self.doctype, self.name) + notes = _("This schedule was created when Asset {0}'s Asset Repair {1} was cancelled.").format( + get_link_to_form(self.asset_doc.doctype, self.asset_doc.name), 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) 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 262d552997..6cfbe53cf6 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -127,12 +127,20 @@ class AssetValueAdjustment(Document): current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True 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")), - ) + if self.docstatus == 1: + 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")), + ) + elif self.docstatus == 2: + notes = _( + "This schedule was created when Asset {0}'s Asset Value Adjustment {1} was cancelled." + ).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() From cf7b43f7f0dfeeda3997e5bf8cfec150b710fbdb Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 16 Jan 2023 23:10:02 +0530 Subject: [PATCH 2/6] fix: handle_post_depr_entries_fail, show error alert and send email --- erpnext/assets/doctype/asset/asset.js | 17 ++++++ erpnext/assets/doctype/asset/asset.json | 13 ++++- erpnext/assets/doctype/asset/depreciation.py | 58 +++++++++++++++++-- .../asset_depreciation_schedule.json | 2 +- 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index b8185c929e..8f5b85d1b2 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -135,6 +135,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"); } @@ -145,6 +149,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 8649a80c79..2ea8a5667b 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -68,6 +68,7 @@ "column_break_51", "purchase_receipt_amount", "default_finance_book", + "depr_entry_posting_status", "amended_from" ], "fields": [ @@ -473,6 +474,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": "Successful\nFailed", + "print_hide": 1, + "read_only": 1 } ], "idx": 72, @@ -500,7 +511,7 @@ "link_fieldname": "asset" } ], - "modified": "2023-01-16 12:01:00.502301", + "modified": "2023-01-16 21:16:54.435493", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 97deea6f33..5337fd64ee 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -5,6 +5,7 @@ import frappe from frappe import _ from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, nowdate, today +from frappe.utils.user import get_users_with_role from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, @@ -18,7 +19,7 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_sched ) -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") @@ -27,13 +28,24 @@ def post_depreciation_entries(date=None, commit=True): if not date: date = today() + + failed_asset_names = [] + for asset_name in get_depreciable_assets(date): asset_doc = frappe.get_doc("Asset", asset_name) - make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) - - if commit: + try: + make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) frappe.db.commit() + except Exception as e: + frappe.db.rollback() + failed_asset_names.append(asset_name) + + if failed_asset_names: + set_depr_entry_posting_status_for_failed_assets(failed_asset_names) + notify_depr_entry_posting_error(failed_asset_names) + + frappe.db.commit() def get_depreciable_assets(date): @@ -146,6 +158,8 @@ def make_depreciation_entry(asset_depr_schedule_name, date=None): row.value_after_depreciation -= d.depreciation_amount row.db_update() + frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Successful") + asset.set_status() return asset_depr_schedule_doc @@ -209,6 +223,42 @@ def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation return credit_account, debit_account +def set_depr_entry_posting_status_for_failed_assets(failed_asset_names): + for asset_name in failed_asset_names: + frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Failed") + + +def notify_depr_entry_posting_error(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) 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 af09cda8fb..898c482079 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -159,7 +159,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-01-02 15:38:30.766779", + "modified": "2023-01-16 21:08:21.421260", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", From a144bb01fea88c48751b81c0ad1c9593db4ee984 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Mon, 16 Jan 2023 23:26:39 +0530 Subject: [PATCH 3/6] chore: stying --- erpnext/assets/doctype/asset_repair/asset_repair.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index ff87c83e23..9a05a74ef9 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -56,8 +56,11 @@ class AssetRepair(AccountsController): ): self.modify_depreciation_schedule() - notes = _("This schedule was created when Asset {0} was repaired through Asset Repair {1}.").format( - get_link_to_form(self.asset_doc.doctype, self.asset_doc.name), get_link_to_form(self.doctype, self.name) + notes = _( + "This schedule was created when Asset {0} was repaired through Asset Repair {1}." + ).format( + get_link_to_form(self.asset_doc.doctype, self.asset_doc.name), + 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) @@ -81,7 +84,8 @@ class AssetRepair(AccountsController): self.revert_depreciation_schedule_on_cancellation() notes = _("This schedule was created when Asset {0}'s Asset Repair {1} was cancelled.").format( - get_link_to_form(self.asset_doc.doctype, self.asset_doc.name), get_link_to_form(self.doctype, self.name) + get_link_to_form(self.asset_doc.doctype, self.asset_doc.name), + 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) From cebb5a42f40ae105209afc7403a2d28030ad20c7 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 17 Jan 2023 00:25:59 +0530 Subject: [PATCH 4/6] chore: add missing /n in options --- erpnext/assets/doctype/asset/asset.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 2ea8a5667b..8a64a95317 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -481,7 +481,7 @@ "hidden": 1, "label": "Depreciation Entry Posting Status", "no_copy": 1, - "options": "Successful\nFailed", + "options": "\nSuccessful\nFailed", "print_hide": 1, "read_only": 1 } @@ -511,7 +511,7 @@ "link_fieldname": "asset" } ], - "modified": "2023-01-16 21:16:54.435493", + "modified": "2023-01-17 00:25:30.387242", "modified_by": "Administrator", "module": "Assets", "name": "Asset", From 86cf5c89ab95778587c41fc708325cddabc6e348 Mon Sep 17 00:00:00 2001 From: anandbaburajan Date: Tue, 17 Jan 2023 00:31:21 +0530 Subject: [PATCH 5/6] chore: add depr_entry_posting_status in create_asset --- erpnext/assets/doctype/asset/test_asset.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index d61ef8ecf8..51a2b52897 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1549,6 +1549,7 @@ def create_asset(**args): "asset_owner": args.asset_owner or "Company", "is_existing_asset": args.is_existing_asset or 1, "asset_quantity": args.get("asset_quantity") or 1, + "depr_entry_posting_status": args.depr_entry_posting_status or "", } ) From db9beb3cddc78376ccd30b57efafa35381b482d6 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 17 Jan 2023 14:53:24 +0530 Subject: [PATCH 6/6] fix: Rate from LDC in TDS reports (#33699) --- .../tax_withholding_category/tax_withholding_category.py | 6 ++---- .../report/tds_payable_monthly/tds_payable_monthly.py | 7 +++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index b834d1404d..1bce43fd31 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -259,9 +259,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N if tax_deducted: net_total = inv.tax_withholding_net_total if ldc: - tax_amount = get_tds_amount_from_ldc( - ldc, parties, pan_no, tax_details, posting_date, net_total - ) + tax_amount = get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total) else: tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0 @@ -538,7 +536,7 @@ def get_invoice_total_without_tcs(inv, tax_details): return inv.grand_total - tcs_tax_row_amount -def get_tds_amount_from_ldc(ldc, parties, pan_no, tax_details, posting_date, net_total): +def get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total): tds_amount = 0 limit_consumed = frappe.db.get_value( "Purchase Invoice", diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index 98838907be..bfe2a0fd2b 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -4,6 +4,7 @@ import frappe from frappe import _ +from frappe.utils import flt def execute(filters=None): @@ -65,6 +66,12 @@ def get_result( else: total_amount_credited += entry.credit + ## Check if ldc is applied and show rate as per ldc + actual_rate = (tds_deducted / total_amount_credited) * 100 + + if flt(actual_rate) < flt(rate): + rate = actual_rate + if tds_deducted: row = { "pan"