You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

202 lines
6.2 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # License: MIT. See LICENSE
  3. """assign/unassign to ToDo"""
  4. import frappe
  5. from frappe import _
  6. from frappe.desk.form.document_follow import follow_document
  7. from frappe.desk.doctype.notification_log.notification_log import enqueue_create_notification,\
  8. get_title, get_title_html
  9. import frappe.utils
  10. import frappe.share
  11. import json
  12. class DuplicateToDoError(frappe.ValidationError): pass
  13. def get(args=None):
  14. """get assigned to"""
  15. if not args:
  16. args = frappe.local.form_dict
  17. return frappe.get_all("ToDo", fields=["allocated_to as owner", "name"], filters={
  18. "reference_type": args.get("doctype"),
  19. "reference_name": args.get("name"),
  20. "status": ("!=", "Cancelled")
  21. }, limit=5)
  22. @frappe.whitelist()
  23. def add(args=None):
  24. """add in someone's to do list
  25. args = {
  26. "assign_to": [],
  27. "doctype": ,
  28. "name": ,
  29. "description": ,
  30. "assignment_rule":
  31. }
  32. """
  33. if not args:
  34. args = frappe.local.form_dict
  35. users_with_duplicate_todo = []
  36. shared_with_users = []
  37. for assign_to in frappe.parse_json(args.get("assign_to")):
  38. filters = {
  39. "reference_type": args['doctype'],
  40. "reference_name": args['name'],
  41. "status": "Open",
  42. "allocated_to": assign_to
  43. }
  44. if frappe.get_all("ToDo", filters=filters):
  45. users_with_duplicate_todo.append(assign_to)
  46. else:
  47. from frappe.utils import nowdate
  48. if not args.get('description'):
  49. args['description'] = _('Assignment for {0} {1}').format(args['doctype'], args['name'])
  50. d = frappe.get_doc({
  51. "doctype": "ToDo",
  52. "allocated_to": assign_to,
  53. "reference_type": args['doctype'],
  54. "reference_name": args['name'],
  55. "description": args.get('description'),
  56. "priority": args.get("priority", "Medium"),
  57. "status": "Open",
  58. "date": args.get('date', nowdate()),
  59. "assigned_by": args.get('assigned_by', frappe.session.user),
  60. 'assignment_rule': args.get('assignment_rule')
  61. }).insert(ignore_permissions=True)
  62. # set assigned_to if field exists
  63. if frappe.get_meta(args['doctype']).get_field("assigned_to"):
  64. frappe.db.set_value(args['doctype'], args['name'], "assigned_to", assign_to)
  65. doc = frappe.get_doc(args['doctype'], args['name'])
  66. # if assignee does not have permissions, share
  67. if not frappe.has_permission(doc=doc, user=assign_to):
  68. frappe.share.add(doc.doctype, doc.name, assign_to)
  69. shared_with_users.append(assign_to)
  70. # make this document followed by assigned user
  71. if frappe.get_cached_value("User", assign_to, "follow_assigned_documents"):
  72. follow_document(args['doctype'], args['name'], assign_to)
  73. # notify
  74. notify_assignment(d.assigned_by, d.allocated_to, d.reference_type, d.reference_name, action='ASSIGN',
  75. description=args.get("description"))
  76. if shared_with_users:
  77. user_list = format_message_for_assign_to(shared_with_users)
  78. frappe.msgprint(_("Shared with the following Users with Read access:{0}").format(user_list, alert=True))
  79. if users_with_duplicate_todo:
  80. user_list = format_message_for_assign_to(users_with_duplicate_todo)
  81. frappe.msgprint(_("Already in the following Users ToDo list:{0}").format(user_list, alert=True))
  82. return get(args)
  83. @frappe.whitelist()
  84. def add_multiple(args=None):
  85. if not args:
  86. args = frappe.local.form_dict
  87. docname_list = json.loads(args['name'])
  88. for docname in docname_list:
  89. args.update({"name": docname})
  90. add(args)
  91. def close_all_assignments(doctype, name):
  92. assignments = frappe.db.get_all('ToDo', fields=['allocated_to'], filters =
  93. dict(reference_type = doctype, reference_name = name, status=('!=', 'Cancelled')))
  94. if not assignments:
  95. return False
  96. for assign_to in assignments:
  97. set_status(doctype, name, assign_to.allocated_to, status="Closed")
  98. return True
  99. @frappe.whitelist()
  100. def remove(doctype, name, assign_to):
  101. return set_status(doctype, name, assign_to, status="Cancelled")
  102. def set_status(doctype, name, assign_to, status="Cancelled"):
  103. """remove from todo"""
  104. try:
  105. todo = frappe.db.get_value("ToDo", {"reference_type":doctype,
  106. "reference_name":name, "allocated_to":assign_to, "status": ('!=', status)})
  107. if todo:
  108. todo = frappe.get_doc("ToDo", todo)
  109. todo.status = status
  110. todo.save(ignore_permissions=True)
  111. notify_assignment(todo.assigned_by, todo.allocated_to, todo.reference_type, todo.reference_name)
  112. except frappe.DoesNotExistError:
  113. pass
  114. # clear assigned_to if field exists
  115. if frappe.get_meta(doctype).get_field("assigned_to") and status=="Cancelled":
  116. frappe.db.set_value(doctype, name, "assigned_to", None)
  117. return get({"doctype": doctype, "name": name})
  118. def clear(doctype, name):
  119. '''
  120. Clears assignments, return False if not assigned.
  121. '''
  122. assignments = frappe.db.get_all('ToDo', fields=['allocated_to'], filters =
  123. dict(reference_type = doctype, reference_name = name))
  124. if not assignments:
  125. return False
  126. for assign_to in assignments:
  127. set_status(doctype, name, assign_to.allocated_to, "Cancelled")
  128. return True
  129. def notify_assignment(assigned_by, allocated_to, doc_type, doc_name, action='CLOSE',
  130. description=None):
  131. """
  132. Notify assignee that there is a change in assignment
  133. """
  134. if not (assigned_by and allocated_to and doc_type and doc_name):
  135. return
  136. # return if self assigned or user disabled
  137. if assigned_by == allocated_to or not frappe.db.get_value('User', allocated_to, 'enabled'):
  138. return
  139. # Search for email address in description -- i.e. assignee
  140. user_name = frappe.get_cached_value('User', frappe.session.user, 'full_name')
  141. title = get_title(doc_type, doc_name)
  142. description_html = "<div>{0}</div>".format(description) if description else None
  143. if action == 'CLOSE':
  144. subject = _('Your assignment on {0} {1} has been removed by {2}')\
  145. .format(frappe.bold(doc_type), get_title_html(title), frappe.bold(user_name))
  146. else:
  147. user_name = frappe.bold(user_name)
  148. document_type = frappe.bold(doc_type)
  149. title = get_title_html(title)
  150. subject = _('{0} assigned a new task {1} {2} to you').format(user_name, document_type, title)
  151. notification_doc = {
  152. 'type': 'Assignment',
  153. 'document_type': doc_type,
  154. 'subject': subject,
  155. 'document_name': doc_name,
  156. 'from_user': frappe.session.user,
  157. 'email_content': description_html
  158. }
  159. enqueue_create_notification(allocated_to, notification_doc)
  160. def format_message_for_assign_to(users):
  161. return "<br><br>" + "<br>".join(users)