diff --git a/frappe/__init__.py b/frappe/__init__.py
index 6979bcae14..2361500eab 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json
from .exceptions import *
from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template
-__version__ = '8.7.1'
+__version__ = '8.7.2'
__title__ = "Frappe Framework"
local = Local()
diff --git a/frappe/core/doctype/user/test_user.py b/frappe/core/doctype/user/test_user.py
index b2206a8d37..c9ed243841 100644
--- a/frappe/core/doctype/user/test_user.py
+++ b/frappe/core/doctype/user/test_user.py
@@ -200,6 +200,28 @@ class TestUser(unittest.TestCase):
clear_limit("expiry")
frappe.local.conf = _dict(frappe.get_site_config())
+ def test_delete_user(self):
+ new_user = frappe.get_doc(dict(doctype='User', email='test-for-delete@example.com',
+ first_name='Tester Delete User')).insert()
+ self.assertEquals(new_user.user_type, 'Website User')
+
+ # role with desk access
+ new_user.add_roles('_Test Role 2')
+ new_user.save()
+ self.assertEquals(new_user.user_type, 'System User')
+
+ comm = frappe.get_doc({
+ "doctype":"Communication",
+ "subject": "To check user able to delete even if linked with communication",
+ "content": "To check user able to delete even if linked with communication",
+ "sent_or_received": "Sent",
+ "user": new_user.name
+ })
+ comm.insert(ignore_permissions=True)
+
+ frappe.delete_doc('User', new_user.name)
+ self.assertFalse(frappe.db.exists('User', new_user.name))
+
def test_deactivate_additional_users(self):
update_limits({'users': get_total_users()+1})
diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py
index a94163ed20..12deec3427 100755
--- a/frappe/email/email_body.py
+++ b/frappe/email/email_body.py
@@ -324,7 +324,7 @@ def add_attachment(fname, fcontent, content_type=None,
# Set the filename parameter
if fname:
attachment_type = 'inline' if inline else 'attachment'
- part.add_header(b'Content-Disposition', attachment_type, filename=fname.encode('utf=8'))
+ part.add_header(b'Content-Disposition', attachment_type, filename=text_type(fname))
if content_id:
part.add_header(b'Content-ID', '<{0}>'.format(content_id))
diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py
index e242a48c88..3e4f60c7f6 100644
--- a/frappe/model/delete_doc.py
+++ b/frappe/model/delete_doc.py
@@ -183,13 +183,18 @@ def check_if_doc_is_linked(doc, method="Delete"):
if not issingle:
for item in frappe.db.get_values(link_dt, {link_field:doc.name},
["name", "parent", "parenttype", "docstatus"], as_dict=True):
+ linked_doctype = item.parenttype if item.parent else link_dt
+ if linked_doctype in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", 'File', 'Version'):
+ # don't check for communication and todo!
+ continue
+
if item and ((item.parent or item.name) != doc.name) \
and ((method=="Delete" and item.docstatus<2) or (method=="Cancel" and item.docstatus==1)):
# raise exception only if
# linked to an non-cancelled doc when deleting
# or linked to a submitted doc when cancelling
frappe.throw(_('Cannot delete or cancel because {0} {1} is linked with {2} {3}')
- .format(doc.doctype, doc.name, item.parenttype if item.parent else link_dt,
+ .format(doc.doctype, doc.name, linked_doctype,
item.parent or item.name), frappe.LinkExistsError)
def check_if_doc_is_dynamically_linked(doc, method="Delete"):