Some doctypes like `Payment Entry`, `Bank Account`, `Pricing Rule` were present in 2 dashboards (customer and supplier dashboard), both of which were included in ERPNext communucation_doctype hooks Signed-off-by: Akhil Narang <me@akhilnarang.dev>
242 lines
7.3 KiB
Python
242 lines
7.3 KiB
Python
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
# License: MIT. See LICENSE
|
|
|
|
from typing import TYPE_CHECKING, Literal, Optional
|
|
|
|
import frappe
|
|
|
|
if TYPE_CHECKING:
|
|
from frappe.email.doctype.email_queue.email_queue import EmailQueue
|
|
|
|
|
|
def sendmail_to_system_managers(subject, content):
|
|
frappe.sendmail(recipients=get_system_managers(), subject=subject, content=content)
|
|
|
|
|
|
@frappe.whitelist()
|
|
def get_contact_list(txt, page_length=20, extra_filters: str | None = None) -> list[dict]:
|
|
"""Return email ids for a multiselect field."""
|
|
if extra_filters:
|
|
extra_filters = frappe.parse_json(extra_filters)
|
|
|
|
filters = [
|
|
["Contact Email", "email_id", "is", "set"],
|
|
]
|
|
if extra_filters:
|
|
filters.extend(extra_filters)
|
|
|
|
fields = ["first_name", "middle_name", "last_name", "company_name"]
|
|
contacts = frappe.get_list(
|
|
"Contact",
|
|
fields=["full_name", "`tabContact Email`.email_id"],
|
|
filters=filters,
|
|
or_filters=[[field, "like", f"%{txt}%"] for field in fields]
|
|
+ [["Contact Email", "email_id", "like", f"%{txt}%"]],
|
|
limit_page_length=page_length,
|
|
)
|
|
|
|
# The multiselect field will store the `label` as the selected value.
|
|
# The `value` is just used as a unique key to distinguish between the options.
|
|
# https://github.com/frappe/frappe/blob/6c6a89bcdd9454060a1333e23b855d0505c9ebc2/frappe/public/js/frappe/form/controls/autocomplete.js#L29-L35
|
|
return [
|
|
frappe._dict(
|
|
value=d.email_id,
|
|
label=d.email_id,
|
|
description=d.full_name,
|
|
)
|
|
for d in contacts
|
|
]
|
|
|
|
|
|
def get_system_managers():
|
|
return frappe.db.sql_list(
|
|
"""select parent FROM `tabHas Role`
|
|
WHERE role='System Manager'
|
|
AND parent!='Administrator'
|
|
AND parent IN (SELECT email FROM tabUser WHERE enabled=1)"""
|
|
)
|
|
|
|
|
|
@frappe.whitelist()
|
|
def relink(name, reference_doctype=None, reference_name=None):
|
|
frappe.db.sql(
|
|
"""update
|
|
`tabCommunication`
|
|
set
|
|
reference_doctype = %s,
|
|
reference_name = %s,
|
|
status = "Linked"
|
|
where
|
|
communication_type = "Communication" and
|
|
name = %s""",
|
|
(reference_doctype, reference_name, name),
|
|
)
|
|
|
|
|
|
@frappe.whitelist()
|
|
@frappe.validate_and_sanitize_search_inputs
|
|
def get_communication_doctype(doctype, txt, searchfield, start, page_len, filters):
|
|
user_perms = frappe.utils.user.UserPermissions(frappe.session.user)
|
|
user_perms.build_permissions()
|
|
can_read = user_perms.can_read
|
|
from frappe import _
|
|
from frappe.modules import load_doctype_module
|
|
|
|
com_doctypes = []
|
|
if len(txt) < 2:
|
|
for name in frappe.get_hooks("communication_doctypes"):
|
|
try:
|
|
module = load_doctype_module(name, suffix="_dashboard")
|
|
if hasattr(module, "get_data"):
|
|
for i in module.get_data()["transactions"]:
|
|
com_doctypes += i["items"]
|
|
except ImportError:
|
|
pass
|
|
else:
|
|
com_doctypes = [
|
|
d[0] for d in frappe.db.get_values("DocType", {"issingle": 0, "istable": 0, "hide_toolbar": 0})
|
|
]
|
|
|
|
results = []
|
|
txt_lower = txt.lower().replace("%", "")
|
|
|
|
for dt in list(set(com_doctypes)):
|
|
if dt in can_read:
|
|
if txt_lower in dt.lower() or txt_lower in _(dt).lower():
|
|
results.append([dt])
|
|
|
|
return results
|
|
|
|
|
|
def sendmail(
|
|
recipients=None,
|
|
sender="",
|
|
subject="No Subject",
|
|
message="No Message",
|
|
as_markdown=False,
|
|
delayed=True,
|
|
reference_doctype=None,
|
|
reference_name=None,
|
|
unsubscribe_method=None,
|
|
unsubscribe_params=None,
|
|
unsubscribe_message=None,
|
|
add_unsubscribe_link=1,
|
|
attachments=None,
|
|
content=None,
|
|
doctype=None,
|
|
name=None,
|
|
reply_to=None,
|
|
queue_separately=False,
|
|
cc=None,
|
|
bcc=None,
|
|
message_id=None,
|
|
in_reply_to=None,
|
|
send_after=None,
|
|
expose_recipients=None,
|
|
send_priority=1,
|
|
communication=None,
|
|
retry=1,
|
|
now=None,
|
|
read_receipt=None,
|
|
is_notification=False,
|
|
inline_images=None,
|
|
template=None,
|
|
args=None,
|
|
header=None,
|
|
print_letterhead=False,
|
|
with_container=False,
|
|
email_read_tracker_url=None,
|
|
x_priority: Literal[1, 3, 5] = 3,
|
|
email_headers=None,
|
|
) -> Optional["EmailQueue"]:
|
|
"""Send email using user's default **Email Account** or global default **Email Account**.
|
|
|
|
|
|
:param recipients: List of recipients.
|
|
:param sender: Email sender. Default is current user or default outgoing account.
|
|
:param subject: Email Subject.
|
|
:param message: (or `content`) Email Content.
|
|
:param as_markdown: Convert content markdown to HTML.
|
|
:param delayed: Send via scheduled email sender **Email Queue**. Don't send immediately. Default is true
|
|
:param send_priority: Priority for Email Queue, default 1.
|
|
:param reference_doctype: (or `doctype`) Append as communication to this DocType.
|
|
:param reference_name: (or `name`) Append as communication to this document name.
|
|
:param unsubscribe_method: Unsubscribe url with options email, doctype, name. e.g. `/api/method/unsubscribe`
|
|
:param unsubscribe_params: Unsubscribe paramaters to be loaded on the unsubscribe_method [optional] (dict).
|
|
:param attachments: List of attachments.
|
|
:param reply_to: Reply-To Email Address.
|
|
:param message_id: Used for threading. If a reply is received to this email, Message-Id is sent back as In-Reply-To in received email.
|
|
:param in_reply_to: Used to send the Message-Id of a received email back as In-Reply-To.
|
|
:param send_after: Send after the given datetime.
|
|
:param expose_recipients: Display all recipients in the footer message - "This email was sent to"
|
|
:param communication: Communication link to be set in Email Queue record
|
|
:param inline_images: List of inline images as {"filename", "filecontent"}. All src properties will be replaced with random Content-Id
|
|
:param template: Name of html template from templates/emails folder
|
|
:param args: Arguments for rendering the template
|
|
:param header: Append header in email
|
|
:param with_container: Wraps email inside a styled container
|
|
:param x_priority: 1 = HIGHEST, 3 = NORMAL, 5 = LOWEST
|
|
:param email_headers: Additional headers to be added in the email, e.g. {"X-Custom-Header": "value"} or {"Custom-Header": "value"}. Automatically prepends "X-" to the header name if not present.
|
|
"""
|
|
|
|
from frappe.utils.jinja import get_email_from_template
|
|
|
|
if recipients is None:
|
|
recipients = []
|
|
if cc is None:
|
|
cc = []
|
|
if bcc is None:
|
|
bcc = []
|
|
|
|
text_content = None
|
|
if template:
|
|
message, text_content = get_email_from_template(template, args)
|
|
|
|
message = content or message
|
|
|
|
if as_markdown:
|
|
from frappe.utils import md_to_html
|
|
|
|
message = md_to_html(message)
|
|
|
|
if not delayed:
|
|
now = True
|
|
|
|
from frappe.email.doctype.email_queue.email_queue import QueueBuilder
|
|
|
|
builder = QueueBuilder(
|
|
recipients=recipients,
|
|
sender=sender,
|
|
subject=subject,
|
|
message=message,
|
|
text_content=text_content,
|
|
reference_doctype=doctype or reference_doctype,
|
|
reference_name=name or reference_name,
|
|
add_unsubscribe_link=add_unsubscribe_link,
|
|
unsubscribe_method=unsubscribe_method,
|
|
unsubscribe_params=unsubscribe_params,
|
|
unsubscribe_message=unsubscribe_message,
|
|
attachments=attachments,
|
|
reply_to=reply_to,
|
|
cc=cc,
|
|
bcc=bcc,
|
|
message_id=message_id,
|
|
in_reply_to=in_reply_to,
|
|
send_after=send_after,
|
|
expose_recipients=expose_recipients,
|
|
send_priority=send_priority,
|
|
queue_separately=queue_separately,
|
|
communication=communication,
|
|
read_receipt=read_receipt,
|
|
is_notification=is_notification,
|
|
inline_images=inline_images,
|
|
header=header,
|
|
print_letterhead=print_letterhead,
|
|
with_container=with_container,
|
|
email_read_tracker_url=email_read_tracker_url,
|
|
x_priority=x_priority,
|
|
email_headers=email_headers,
|
|
)
|
|
|
|
# build email queue and send the email if send_now is True.
|
|
return builder.process(send_now=now)
|