diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 88d1e5c32f..dc242bcff6 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -447,7 +447,14 @@ class Communication(Document, CommunicationEmailMixin): self.add_link(doctype, name) def add_link(self, link_doctype, link_name, autosave=False): - self.append("timeline_links", {"link_doctype": link_doctype, "link_name": link_name}) + self.append( + "timeline_links", + { + "link_doctype": link_doctype, + "link_name": link_name, + "communication_date": self.communication_date, + }, + ) if autosave: self.save(ignore_permissions=True) @@ -466,9 +473,13 @@ class Communication(Document, CommunicationEmailMixin): def on_doctype_update(): """Add indexes in `tabCommunication`""" - frappe.db.add_index("Communication", ["reference_doctype", "reference_name"]) frappe.db.add_index("Communication", ["status", "communication_type"]) frappe.db.add_index("Communication", ["message_id(140)"]) + frappe.db.add_index( + "Communication", + ["reference_doctype", "reference_name", "communication_date", "communication_type"], + index_name="comm_ref_type_date_idx", + ) def has_permission(doc, ptype, user=None, debug=False): diff --git a/frappe/core/doctype/communication/patches/__init__.py b/frappe/core/doctype/communication/patches/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/core/doctype/communication/patches/drop_ref_dt_dn_index.py b/frappe/core/doctype/communication/patches/drop_ref_dt_dn_index.py new file mode 100644 index 0000000000..2afe5e9f7c --- /dev/null +++ b/frappe/core/doctype/communication/patches/drop_ref_dt_dn_index.py @@ -0,0 +1,8 @@ +import frappe +from frappe.database.utils import drop_index_if_exists + + +def execute(): + index_fields = ["reference_doctype", "reference_name"] + index_name = frappe.db.get_index_name(index_fields) + drop_index_if_exists("tabCommunication", index_name) diff --git a/frappe/core/doctype/communication_link/communication_link.json b/frappe/core/doctype/communication_link/communication_link.json index 9a6b5dcff3..c912910c29 100644 --- a/frappe/core/doctype/communication_link/communication_link.json +++ b/frappe/core/doctype/communication_link/communication_link.json @@ -7,7 +7,8 @@ "field_order": [ "link_doctype", "link_name", - "link_title" + "link_title", + "communication_date" ], "fields": [ { @@ -32,19 +33,26 @@ "in_list_view": 1, "label": "Link Title", "read_only": 1 + }, + { + "fieldname": "communication_date", + "fieldtype": "Datetime", + "label": "Communication Date", + "read_only": 1 } ], "istable": 1, "links": [], - "modified": "2024-03-23 16:01:30.438791", + "modified": "2025-11-08 11:07:13.960236", "modified_by": "Administrator", "module": "Core", "name": "Communication Link", "owner": "Administrator", "permissions": [], "quick_entry": 1, + "row_format": "Dynamic", "sort_field": "creation", "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/frappe/core/doctype/communication_link/communication_link.py b/frappe/core/doctype/communication_link/communication_link.py index f6e2a52659..38d8733b4d 100644 --- a/frappe/core/doctype/communication_link/communication_link.py +++ b/frappe/core/doctype/communication_link/communication_link.py @@ -14,6 +14,7 @@ class CommunicationLink(Document): if TYPE_CHECKING: from frappe.types import DF + communication_date: DF.Datetime | None link_doctype: DF.Link link_name: DF.DynamicLink link_title: DF.ReadOnly | None @@ -27,3 +28,4 @@ class CommunicationLink(Document): def on_doctype_update(): frappe.db.add_index("Communication Link", ["link_doctype", "link_name"]) + frappe.db.add_index("Communication Link", ["link_doctype", "link_name", "communication_date", "parent"]) diff --git a/frappe/core/doctype/communication_link/patches/__init__.py b/frappe/core/doctype/communication_link/patches/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/core/doctype/communication_link/patches/copy_communication_date_to_link.py b/frappe/core/doctype/communication_link/patches/copy_communication_date_to_link.py new file mode 100644 index 0000000000..29e20fd78c --- /dev/null +++ b/frappe/core/doctype/communication_link/patches/copy_communication_date_to_link.py @@ -0,0 +1,13 @@ +import frappe + + +# copy communication_date from Communication to Communication Link +def execute(): + frappe.db.sql( + """ + update `tabCommunication Link` cl + inner join `tabCommunication` c on cl.parent = c.name + set cl.communication_date = c.communication_date + where c.communication_date is not null + """ + ) diff --git a/frappe/database/utils.py b/frappe/database/utils.py index 0ceb9bd440..3165046faf 100644 --- a/frappe/database/utils.py +++ b/frappe/database/utils.py @@ -183,3 +183,20 @@ def commit_after_response(func): request.after_response.add(callback_manager.run) callback_manager.add(func) + + +def drop_index_if_exists(table: str, index: str): + import click + + if not frappe.db.has_index(table, index): + click.echo(f"- Skipped {index} index for {table} because it doesn't exist") + return + + try: + frappe.db.sql_ddl(f"ALTER TABLE `{table}` DROP INDEX `{index}`") + except Exception as e: + frappe.log_error("Failed to drop index") + click.secho(f"x Failed to drop index {index} from {table}\n {e!s}", fg="red") + return + + click.echo(f"✓ dropped {index} index from {table}") diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 430dac8818..49d05a6e73 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -292,6 +292,8 @@ def get_communication_data( WHERE C.communication_type IN ('Communication', 'Automated Message') AND (C.reference_doctype = %(doctype)s AND C.reference_name = %(name)s) {conditions} + ORDER BY C.communication_date DESC + LIMIT %(cte_limit)s """ # communications linked in Timeline Links @@ -302,6 +304,8 @@ def get_communication_data( WHERE C.communication_type IN ('Communication', 'Automated Message') AND `tabCommunication Link`.link_doctype = %(doctype)s AND `tabCommunication Link`.link_name = %(name)s {conditions} + ORDER BY `tabCommunication Link`.communication_date DESC + LIMIT %(cte_limit)s """ sqlite_query = f""" @@ -316,8 +320,13 @@ def get_communication_data( OFFSET %(start)s""" query = f""" + WITH part1 AS ({part1}), part2 AS ({part2}) SELECT * - FROM (({part1}) UNION ({part2})) AS combined + FROM ( + SELECT * FROM part1 + UNION + SELECT * FROM part2 + ) AS combined {group_by or ""} ORDER BY communication_date DESC LIMIT %(limit)s @@ -335,6 +344,7 @@ def get_communication_data( name=str(name), start=frappe.utils.cint(start), limit=limit, + cte_limit=limit + start, ), as_dict=as_dict, ) diff --git a/frappe/patches.txt b/frappe/patches.txt index 3a20616fb0..5b076fab59 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -249,4 +249,6 @@ execute:frappe.call("frappe.core.doctype.system_settings.system_settings.sync_sy frappe.patches.v15_0.migrate_to_utm frappe.patches.v16_0.add_module_deprecation_warning frappe.patches.v16_0.auto_generate_desktop_icon_and_sidebar -frappe.patches.v16_0.add_private_workspaces_to_sidebar \ No newline at end of file +frappe.patches.v16_0.add_private_workspaces_to_sidebar +frappe.core.doctype.communication_link.patches.copy_communication_date_to_link +frappe.core.doctype.communication.patches.drop_ref_dt_dn_index diff --git a/frappe/patches/v14_0/drop_unused_indexes.py b/frappe/patches/v14_0/drop_unused_indexes.py index a2b3f468c2..711ba39f15 100644 --- a/frappe/patches/v14_0/drop_unused_indexes.py +++ b/frappe/patches/v14_0/drop_unused_indexes.py @@ -2,9 +2,8 @@ This patch just drops some known indexes which aren't being used anymore or never were used. """ -import click - import frappe +from frappe.database.utils import drop_index_if_exists UNUSED_INDEXES = [ ("Comment", ["link_doctype", "link_name"]), @@ -39,18 +38,3 @@ def execute(): if table not in db_tables: continue drop_index_if_exists(table, index_name) - - -def drop_index_if_exists(table: str, index: str): - if not frappe.db.has_index(table, index): - click.echo(f"- Skipped {index} index for {table} because it doesn't exist") - return - - try: - frappe.db.sql_ddl(f"ALTER TABLE `{table}` DROP INDEX `{index}`") - except Exception as e: - frappe.log_error("Failed to drop index") - click.secho(f"x Failed to drop index {index} from {table}\n {e!s}", fg="red") - return - - click.echo(f"✓ dropped {index} index from {table}") diff --git a/frappe/patches/v15_0/drop_modified_index.py b/frappe/patches/v15_0/drop_modified_index.py index 8cdcf12ece..e8e3590896 100644 --- a/frappe/patches/v15_0/drop_modified_index.py +++ b/frappe/patches/v15_0/drop_modified_index.py @@ -1,5 +1,5 @@ import frappe -from frappe.patches.v14_0.drop_unused_indexes import drop_index_if_exists +from frappe.database.utils import drop_index_if_exists def execute():