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.
 
 
 
 
 
 

121 line
4.1 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. # Search
  4. from __future__ import unicode_literals
  5. import frappe
  6. import frappe.desk.reportview
  7. from frappe.utils import cstr, unique
  8. # this is called by the Link Field
  9. @frappe.whitelist()
  10. def search_link(doctype, txt, query=None, filters=None, page_len=20, searchfield=None):
  11. search_widget(doctype, txt, query, searchfield=searchfield, page_len=page_len, filters=filters)
  12. frappe.response['results'] = build_for_autosuggest(frappe.response["values"])
  13. del frappe.response["values"]
  14. # this is called by the search box
  15. @frappe.whitelist()
  16. def search_widget(doctype, txt, query=None, searchfield=None, start=0,
  17. page_len=10, filters=None, as_dict=False):
  18. if isinstance(filters, basestring):
  19. import json
  20. filters = json.loads(filters)
  21. meta = frappe.get_meta(doctype)
  22. if not searchfield:
  23. searchfield = "name"
  24. standard_queries = frappe.get_hooks().standard_queries or {}
  25. if query and query.split()[0].lower()!="select":
  26. # by method
  27. frappe.response["values"] = frappe.call(query, doctype, txt,
  28. searchfield, start, page_len, filters, as_dict=as_dict)
  29. elif not query and doctype in standard_queries:
  30. # from standard queries
  31. search_widget(doctype, txt, standard_queries[doctype][0],
  32. searchfield, start, page_len, filters)
  33. else:
  34. if query:
  35. frappe.throw("This query style is discontinued")
  36. # custom query
  37. # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt))
  38. else:
  39. if isinstance(filters, dict):
  40. filters_items = filters.items()
  41. filters = []
  42. for f in filters_items:
  43. if isinstance(f[1], (list, tuple)):
  44. filters.append([doctype, f[0], f[1][0], f[1][1]])
  45. else:
  46. filters.append([doctype, f[0], "=", f[1]])
  47. if filters==None:
  48. filters = []
  49. or_filters = []
  50. # build from doctype
  51. if txt:
  52. search_fields = ["name"]
  53. if meta.title_field:
  54. search_fields.append(meta.title_field)
  55. if meta.search_fields:
  56. search_fields.extend(meta.get_search_fields())
  57. for f in search_fields:
  58. fmeta = meta.get_field(f.strip())
  59. if f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text",
  60. "Link", "Select", "Read Only", "Text Editor"]):
  61. or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)])
  62. if meta.get("fields", {"fieldname":"enabled", "fieldtype":"Check"}):
  63. filters.append([doctype, "enabled", "=", 1])
  64. if meta.get("fields", {"fieldname":"disabled", "fieldtype":"Check"}):
  65. filters.append([doctype, "disabled", "!=", 1])
  66. fields = get_std_fields_list(meta, searchfield or "name")
  67. # find relevance as location of search term from the beginning of string `name`. used for sorting results.
  68. fields.append("""locate("{_txt}", `tab{doctype}`.`name`) as `_relevance`""".format(
  69. _txt=frappe.db.escape((txt or "").replace("%", "")), doctype=frappe.db.escape(doctype)))
  70. values = frappe.desk.reportview.execute(doctype,
  71. filters=filters, fields=fields,
  72. or_filters = or_filters, limit_start = start,
  73. limit_page_length=page_len,
  74. order_by="if(_relevance, _relevance, 99999), idx desc, modified desc".format(doctype),
  75. ignore_permissions = True if doctype == "DocType" else False, # for dynamic links
  76. as_dict=as_dict,
  77. as_list=not as_dict)
  78. # remove _relevance from results
  79. frappe.response["values"] = [r[:-1] for r in values]
  80. def get_std_fields_list(meta, key):
  81. # get additional search fields
  82. sflist = meta.search_fields and meta.search_fields.split(",") or []
  83. title_field = [meta.title_field] if (meta.title_field and meta.title_field not in sflist) else []
  84. sflist = ['name'] + sflist + title_field
  85. if not key in sflist:
  86. sflist = sflist + [key]
  87. return ['`tab%s`.`%s`' % (meta.name, f.strip()) for f in sflist]
  88. def build_for_autosuggest(res):
  89. results = []
  90. for r in res:
  91. out = {"value": r[0], "description": ", ".join(unique(cstr(d) for d in r)[1:])}
  92. results.append(out)
  93. return results
  94. def scrub_custom_query(query, key, txt):
  95. if '%(key)s' in query:
  96. query = query.replace('%(key)s', key)
  97. if '%s' in query:
  98. query = query.replace('%s', ((txt or '') + '%'))
  99. return query