import frappe from frappe import _ def _cancel_and_delete(doctype: str, name: str) -> None: doc = frappe.get_doc(doctype, name) doc.flags.ignore_permissions = True doc.flags.ignore_links = True if doc.docstatus == 1: doc.cancel() frappe.db.commit() frappe.delete_doc(doctype, name, force=True, ignore_permissions=True, ignore_on_trash=True) frappe.db.commit() def _safe_collect(fn, *args) -> dict: results = {"deleted": [], "errors": []} try: results["deleted"] = fn(*args) except Exception as e: results["errors"].append(str(e)) return results def _del_asset_activities(asset_name: str) -> list: deleted = [] for name in frappe.get_all("Asset Activity", filters={"asset": asset_name}, pluck="name"): try: frappe.delete_doc("Asset Activity", name, force=True, ignore_permissions=True, ignore_on_trash=True) frappe.db.commit() deleted.append(name) except Exception as e: frappe.log_error(f"Asset Activity delete error [{name}]: {e}") return deleted def _del_asset_movements(asset_name: str) -> list: deleted = [] parent_names = list(set( frappe.get_all("Asset Movement Item", filters={"asset": asset_name}, pluck="parent") )) for name in parent_names: try: _cancel_and_delete("Asset Movement", name) deleted.append(name) except Exception as e: frappe.log_error(f"Asset Movement delete error [{name}]: {e}") return deleted def _del_asset_value_adjustments(asset_name: str) -> list: deleted = [] for name in frappe.get_all("Asset Value Adjustment", filters={"asset": asset_name}, pluck="name"): try: _cancel_and_delete("Asset Value Adjustment", name) deleted.append(name) except Exception as e: frappe.log_error(f"Asset Value Adjustment delete error [{name}]: {e}") return deleted def _del_asset_depreciation_schedules(asset_name: str) -> list: deleted = [] for name in frappe.get_all("Asset Depreciation Schedule", filters={"asset": asset_name}, pluck="name"): try: _cancel_and_delete("Asset Depreciation Schedule", name) deleted.append(name) except Exception as e: frappe.log_error(f"Asset Depreciation Schedule delete error [{name}]: {e}") return deleted def _del_asset_maintenance(asset_name: str) -> list: deleted = [] for name in frappe.get_all("Asset Maintenance", filters={"asset_name": asset_name}, pluck="name"): try: _cancel_and_delete("Asset Maintenance", name) deleted.append(name) except Exception as e: frappe.log_error(f"Asset Maintenance delete error [{name}]: {e}") return deleted def _del_asset_repair(asset_name: str) -> list: deleted = [] for name in frappe.get_all("Asset Repair", filters={"asset_name": asset_name}, pluck="name"): try: _cancel_and_delete("Asset Repair", name) deleted.append(name) except Exception as e: frappe.log_error(f"Asset Repair delete error [{name}]: {e}") return deleted @frappe.whitelist() def delete_asset(asset_name: str) -> dict: if not frappe.db.exists("Asset", asset_name): frappe.throw(_("Asset {0} does not exist.").format(asset_name), frappe.DoesNotExistError) if not frappe.has_permission("Asset", "delete", asset_name): frappe.throw(_("You do not have permission to delete Asset {0}.").format(asset_name), frappe.PermissionError) details = {} try: details["asset_activities"] = _safe_collect(_del_asset_activities, asset_name) details["asset_movements"] = _safe_collect(_del_asset_movements, asset_name) details["asset_value_adjustments"] = _safe_collect(_del_asset_value_adjustments, asset_name) details["asset_depreciation_schedules"] = _safe_collect(_del_asset_depreciation_schedules, asset_name) details["asset_maintenance"] = _safe_collect(_del_asset_maintenance, asset_name) # details["asset_repair"] = _safe_collect(_del_asset_repair, asset_name) asset_doc = frappe.get_doc("Asset", asset_name) asset_doc.flags.ignore_permissions = True asset_doc.flags.ignore_links = True if asset_doc.docstatus == 1: asset_doc.cancel() frappe.db.commit() frappe.delete_doc("Asset", asset_name, force=True, ignore_permissions=True, ignore_on_trash=True) frappe.db.commit() return {"success": True, "asset_name": asset_name, "details": details} except Exception as exc: frappe.db.rollback() frappe.log_error(title=f"Asset deletion failed: {asset_name}", message=frappe.get_traceback()) frappe.throw(_("Failed to delete asset {0}: {1}").format(asset_name, str(exc)))