import frappe from frappe import _ from crm.fcrm.doctype.crm_notification.crm_notification import notify_user def validate(doc, method): """Require write access when directly assigning a CRM lead or deal.""" # assign_to and assignment rules insert with ignore_permissions after their # own permission check. if ( doc.is_new() and doc.reference_type in ["CRM Lead", "CRM Deal"] and doc.reference_name and not doc.flags.ignore_permissions ): frappe.get_doc(doc.reference_type, doc.reference_name).check_permission("write") def after_insert(doc, method): if doc.reference_type in ["CRM Lead", "CRM Deal"] and doc.reference_name and doc.allocated_to: fieldname = "lead_owner" if doc.reference_type == "CRM Lead" else "deal_owner" # Mirror assign_to: the latest assignment owns the record, overriding any prior owner. frappe.db.set_value( doc.reference_type, doc.reference_name, fieldname, doc.allocated_to, update_modified=False ) if doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"] and doc.reference_name and doc.allocated_to: notify_assigned_user(doc) def on_update(doc, method): if ( doc.has_value_changed("status") and doc.status == "Cancelled" and doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"] and doc.reference_name and doc.allocated_to ): notify_assigned_user(doc, is_cancelled=True) clear_owner_on_unassign(doc) def clear_owner_on_unassign(doc): # Owner concept only exists for Lead/Deal, not Task. if doc.reference_type not in ["CRM Lead", "CRM Deal"]: return fieldname = "lead_owner" if doc.reference_type == "CRM Lead" else "deal_owner" # Mirror assign_to: cancelling an assignment clears the owner. Wrinkle (accepted): # removing one of several manual co-assignees also clears, since owner is single-valued. frappe.db.set_value(doc.reference_type, doc.reference_name, fieldname, None, update_modified=False) def notify_assigned_user(doc, is_cancelled=False): _doc = frappe.get_doc(doc.reference_type, doc.reference_name) owner = frappe.get_cached_value("User", frappe.session.user, "full_name") notification_text = get_notification_text(owner, doc, _doc, is_cancelled) message = ( _("Your assignment on {0} {1} has been removed by {2}").format( doc.reference_type, doc.reference_name, owner ) if is_cancelled else _("{0} assigned a {1} {2} to you").format(owner, doc.reference_type, doc.reference_name) ) redirect_to_doctype, redirect_to_name = get_redirect_to_doc(doc) notify_user( { "owner": frappe.session.user, "assigned_to": doc.allocated_to, "notification_type": "Assignment", "message": message, "notification_text": notification_text, "reference_doctype": doc.reference_type, "reference_docname": doc.reference_name, "redirect_to_doctype": redirect_to_doctype, "redirect_to_docname": redirect_to_name, } ) def get_notification_text(owner, doc, reference_doc, is_cancelled=False): name = doc.reference_name doctype = doc.reference_type if doctype.startswith("CRM "): doctype = doctype[4:].lower() if doctype in ["lead", "deal"]: name = ( reference_doc.lead_name or name if doctype == "lead" else reference_doc.organization or reference_doc.lead_name or name ) if is_cancelled: return f"""