def get_notifications_for_doctypes(config, notification_count): """Notifications for DocTypes""" can_read = frappe.get_user().get_can_read() open_count_doctype = {} for d in config.for_doctype: if d in can_read: condition = config.for_doctype[d] if d in notification_count: open_count_doctype[d] = notification_count[d] else: try: if isinstance(condition, dict): result = len(frappe.get_list(d, fields=["name"], filters=condition, limit_page_length = 100, as_list=True, ignore_ifnull=True)) else: result = frappe.get_attr(condition)() except frappe.PermissionError: frappe.clear_messages() pass # frappe.msgprint("Permission Error in notifications for {0}".format(d)) except Exception as e: # OperationalError: (1412, 'Table definition has changed, please retry transaction') # InternalError: (1684, 'Table definition is being modified by concurrent DDL statement') if e.args[0] not in (1412, 1684): raise else: open_count_doctype[d] = result frappe.cache().hset("notification_count:" + d, frappe.session.user, result) return open_count_doctype
def create_lead_for_item_inquiry(lead,mobile,email, subject, message,company=None): lead_doc = frappe.new_doc('Lead') lead_doc.lead_name = lead if company: lead_doc.company_name = company lead_doc.mobile_no = mobile lead_doc.email_id = email lead_doc.status = 'Lead' lead_doc.lead_owner = '' try: lead_doc.insert(ignore_permissions=True) lead_doc.save(ignore_permissions=True) except frappe.exceptions.DuplicateEntryError: frappe.clear_messages() lead_doc = frappe.get_doc('Lead', {'email_id': email}) lead_doc.add_comment('Comment', text=''' <div> <h5>{subject}</h5> <p>{message}</p> </div> '''.format(subject=subject, message=message)) return "okay"
def execute_gql_query(): query, variables, operation_name = get_query() validation_errors = validate( schema=get_schema(), document_ast=parse(query), rules=( depth_limit_validator( max_depth=cint(frappe.local.conf.get("frappe_graphql_depth_limit")) or 10 ), ) ) if validation_errors: output = frappe._dict(errors=validation_errors) else: output = execute( query=query, variables=variables, operation_name=operation_name ) frappe.clear_messages() frappe.local.response = output if len(output.get("errors", [])): frappe.db.rollback() log_error(query, variables, operation_name, output) frappe.local.response["http_status_code"] = get_max_http_status_code(output.get("errors")) errors = [] for err in output.errors: if isinstance(err, GraphQLError): err = err.formatted errors.append(err) output.errors = errors
def create_lead_for_item_inquiry(lead, subject, message): lead = frappe.parse_json(lead) lead_doc = frappe.new_doc('Lead') lead_doc.update(lead) lead_doc.set('lead_owner', '') if not frappe.db.exists('Lead Source', 'Product Inquiry'): frappe.get_doc({ 'doctype': 'Lead Source', 'source_name': 'Product Inquiry' }).insert(ignore_permissions=True) lead_doc.set('source', 'Product Inquiry') try: lead_doc.save(ignore_permissions=True) except frappe.exceptions.DuplicateEntryError: frappe.clear_messages() lead_doc = frappe.get_doc('Lead', {'email_id': lead['email_id']}) lead_doc.add_comment('Comment', text=''' <div> <h5>{subject}</h5> <p>{message}</p> </div> '''.format(subject=subject, message=message)) return lead_doc
def test_make_thumbnail(self): # test web image test_file = frappe.get_doc({ "doctype": "File", "file_name": 'logo', "file_url": frappe.utils.get_url('/_test/assets/image.jpg'), }).insert(ignore_permissions=True) test_file.make_thumbnail() self.assertEquals(test_file.thumbnail_url, '/files/image_small.jpg') # test local image test_file.db_set('thumbnail_url', None) test_file.reload() test_file.file_url = "/files/image_small.jpg" test_file.make_thumbnail(suffix="xs", crop=True) self.assertEquals(test_file.thumbnail_url, '/files/image_small_xs.jpg') frappe.clear_messages() test_file.db_set('thumbnail_url', None) test_file.reload() test_file.file_url = frappe.utils.get_url('unknown.jpg') test_file.make_thumbnail(suffix="xs") self.assertEqual(json.loads(frappe.message_log[0]), { "message": f"File '{frappe.utils.get_url('unknown.jpg')}' not found" }) self.assertEquals(test_file.thumbnail_url, None)
def create_lead_for_item_inquiry(lead, subject, message): lead = frappe.parse_json(lead) lead_doc = frappe.new_doc("Lead") for fieldname in ("lead_name", "company_name", "email_id", "phone"): lead_doc.set(fieldname, lead.get(fieldname)) lead_doc.set("lead_owner", "") if not frappe.db.exists("Lead Source", "Product Inquiry"): frappe.get_doc({ "doctype": "Lead Source", "source_name": "Product Inquiry" }).insert(ignore_permissions=True) lead_doc.set("source", "Product Inquiry") try: lead_doc.save(ignore_permissions=True) except frappe.exceptions.DuplicateEntryError: frappe.clear_messages() lead_doc = frappe.get_doc("Lead", {"email_id": lead["email_id"]}) lead_doc.add_comment( "Comment", text=""" <div> <h5>{subject}</h5> <p>{message}</p> </div> """.format(subject=subject, message=message), ) return lead_doc
def add_comment_in_reference_doc(self, comment_type, text): if self.attached_to_doctype and self.attached_to_name: try: doc = frappe.get_doc(self.attached_to_doctype, self.attached_to_name) doc.add_comment(comment_type, text) except frappe.DoesNotExistError: frappe.clear_messages()
def create_lead_for_landingpage(lead, mobile, email, subject, interestedin, address, job): lead_doc = frappe.new_doc('Lead') lead_doc.lead_name = lead lead_doc.mobile_no = mobile lead_doc.email_id = email lead_doc.custom_address = address lead_doc.custom_job = job lead_doc.custom_interested_in = interestedin lead_doc.status = 'Lead' lead_doc.lead_owner = '' try: lead_doc.insert(ignore_permissions=True) lead_doc.save(ignore_permissions=True) except frappe.exceptions.DuplicateEntryError: frappe.clear_messages() lead_doc = frappe.get_doc('Lead', {'email_id': email}) lead_doc.add_comment('Comment', text=''' {subject}: \n Interested in :{message} '''.format(subject=subject, message=interestedin)) return "okay"
def get_attr(attr): try: obj = frappe.get_attr(attr) return obj, inspect.ismodule(obj) except (AttributeError, frappe.AppNotInstalledError, frappe.ValidationError): frappe.clear_messages() obj = frappe.get_module(attr) return obj, inspect.ismodule(obj)
def set_list_settings(doctype, values): try: doc = frappe.get_doc("List View Settings", doctype) except frappe.DoesNotExistError: doc = frappe.new_doc("List View Settings") doc.name = doctype frappe.clear_messages() doc.update(frappe.parse_json(values)) doc.save()
def search(text, start=0, limit=20, doctype=""): """ Search for given text in __global_search :param text: phrase to be searched :param start: start results at, default 0 :param limit: number of results to return, default 20 :return: Array of result objects """ from frappe.desk.doctype.global_search_settings.global_search_settings import ( get_doctypes_for_global_search, ) from frappe.query_builder.functions import Match results = [] sorted_results = [] allowed_doctypes = get_doctypes_for_global_search() for text in set(text.split("&")): text = text.strip() if not text: continue global_search = frappe.qb.Table("__global_search") rank = Match(global_search.content).Against(text).as_("rank") query = (frappe.qb.from_(global_search).select( global_search.doctype, global_search.name, global_search.content, rank).orderby("rank", order=frappe.qb.desc).limit(limit)) if doctype: query = query.where(global_search.doctype == doctype) elif allowed_doctypes: query = query.where(global_search.doctype.isin(allowed_doctypes)) if cint(start) > 0: query = query.offset(start) result = query.run(as_dict=True) results.extend(result) # sort results based on allowed_doctype's priority for doctype in allowed_doctypes: for index, r in enumerate(results): if r.doctype == doctype and r.rank > 0.0: try: meta = frappe.get_meta(r.doctype) if meta.image_field: r.image = frappe.db.get_value(r.doctype, r.name, meta.image_field) except Exception: frappe.clear_messages() sorted_results.extend([r]) return sorted_results
def search(text, start=0, limit=20, doctype=""): """ Search for given text in __global_search :param text: phrase to be searched :param start: start results at, default 0 :param limit: number of results to return, default 20 :return: Array of result objects """ results = [] texts = text.split('&') for text in texts: mariadb_conditions = '' postgres_conditions = '' if doctype: mariadb_conditions = postgres_conditions = '`doctype` = {} AND '.format( doctype) mariadb_conditions += 'MATCH(`content`) AGAINST ({} IN BOOLEAN MODE)'.format( frappe.db.escape('+' + text + '*')) postgres_conditions += 'TO_TSVECTOR("content") @@ PLAINTO_TSQUERY({})'.format( frappe.db.escape(text)) common_query = '''SELECT `doctype`, `name`, `content` FROM `__global_search` WHERE {conditions} LIMIT {limit} OFFSET {start}''' result = frappe.db.multisql( { 'mariadb': common_query.format( conditions=mariadb_conditions, limit=limit, start=start), 'postgres': common_query.format( conditions=postgres_conditions, limit=limit, start=start) }, as_dict=True) tmp_result = [] for i in result: if i in results or not results: tmp_result.append(i) results += tmp_result for r in results: try: if frappe.get_meta(r.doctype).image_field: r.image = frappe.db.get_value( r.doctype, r.name, frappe.get_meta(r.doctype).image_field) except Exception: frappe.clear_messages() return results
def bulk_workflow_approval(docnames, doctype, action): from collections import defaultdict # dictionaries for logging errored_transactions = defaultdict(list) successful_transactions = defaultdict(list) # WARN: message log is cleared print("Clearing frappe.message_log...") frappe.clear_messages() docnames = json.loads(docnames) for (idx, docname) in enumerate(docnames, 1): message_dict = {} try: show_progress(docnames, _('Applying: {0}').format(action), idx, docname) apply_workflow(frappe.get_doc(doctype, docname), action) frappe.db.commit() except Exception as e: if not frappe.message_log: # Exception is raised manually and not from msgprint or throw message = "{0}".format(e.__class__.__name__) if e.args: message += " : {0}".format(e.args[0]) message_dict = {"docname": docname, "message": message} errored_transactions[docname].append(message_dict) frappe.db.rollback() frappe.log_error(frappe.get_traceback(), "Workflow {0} threw an error for {1} {2}".format(action, doctype, docname)) finally: if not message_dict: if frappe.message_log: messages = frappe.get_message_log() for message in messages: frappe.message_log.pop() message_dict = {"docname": docname, "message": message.get("message")} if message.get("raise_exception", False): errored_transactions[docname].append(message_dict) else: successful_transactions[docname].append(message_dict) else: successful_transactions[docname].append({"docname": docname, "message": None}) if errored_transactions and successful_transactions: indicator = "orange" elif errored_transactions: indicator = "red" else: indicator = "green" print_workflow_log(errored_transactions, _("Errored Transactions"), doctype, indicator) print_workflow_log(successful_transactions, _("Successful Transactions"), doctype, indicator)
def search(text, start=0, limit=20, doctype=""): """ Search for given text in __global_search :param text: phrase to be searched :param start: start results at, default 0 :param limit: number of results to return, default 20 :return: Array of result objects """ results = [] texts = text.split('&') for text in texts: text = "+" + text + "*" if not doctype: result = frappe.db.sql(''' select doctype, name, content from __global_search where match(content) against (%s IN BOOLEAN MODE) limit {start}, {limit}'''.format(start=start, limit=limit), text + "*", as_dict=True) else: result = frappe.db.sql(''' select doctype, name, content from __global_search where doctype = %s AND match(content) against (%s IN BOOLEAN MODE) limit {start}, {limit}'''.format(start=start, limit=limit), (doctype, text), as_dict=True) tmp_result = [] for i in result: if i in results or not results: tmp_result.append(i) results = tmp_result for r in results: try: if frappe.get_meta(r.doctype).image_field: r.image = frappe.db.get_value( r.doctype, r.name, frappe.get_meta(r.doctype).image_field) except Exception: frappe.clear_messages() return results
def reset_password(user): if user=="Administrator": return 'not allowed' try: user = frappe.get_doc("User", user) user.validate_reset_password() user.reset_password(send_email=True) return frappe.msgprint(_("Password reset instructions have been sent to your email")) except frappe.DoesNotExistError: frappe.clear_messages() return 'not found'
def configure_domain(): try: email_account = frappe.new_doc("Email Domain") email_account.email_server = "imap.gmail.com" email_account.email_id = "*****@*****.**" email_account.domain_name = "flexsofts.com" email_account.smtp_server = "smtp.mailgun.org" email_account.smtp_port = int("587") email_account.use_imap = int(1) email_account.use_ssl = int(1) email_account.tls = int(1) email_account.attachment_limit = int(1) email_account.save() except frappe.DuplicateEntryError: frappe.clear_messages()
def make_records(records, debug=False): from frappe import _dict from frappe.modules import scrub if debug: print("make_records: in DEBUG mode") # LOG every success and failure for record in records: doctype = record.get("doctype") condition = record.get("__condition") if condition and not condition(): continue doc = frappe.new_doc(doctype) doc.update(record) # ignore mandatory for root parent_link_field = "parent_" + scrub(doc.doctype) if doc.meta.get_field( parent_link_field) and not doc.get(parent_link_field): doc.flags.ignore_mandatory = True try: doc.insert(ignore_permissions=True) except frappe.DuplicateEntryError as e: # print("Failed to insert duplicate {0} {1}".format(doctype, doc.name)) # pass DuplicateEntryError and continue if e.args and e.args[0] == doc.doctype and e.args[1] == doc.name: # make sure DuplicateEntryError is for the exact same doc and not a related doc frappe.clear_messages() else: raise except Exception as e: exception = record.get("__exception") if exception: config = _dict(exception) if isinstance(e, config.exception): config.handler() else: show_document_insert_error() else: show_document_insert_error()
def reset_password(user): if user=="Administrator": return 'not allowed' try: user = frappe.get_doc("User", user) if not user.enabled: return 'disabled' user.validate_reset_password() user.reset_password(send_email=True) return frappe.msgprint(_("Password reset instructions have been sent to your email")) except frappe.DoesNotExistError: frappe.clear_messages() return 'not found'
def create_bank_entries(columns, data, bank_account, upload_type=None): if not upload_type: frappe.throw(_("Please upload a file first")) header_map = get_header_mapping(columns, bank_account, upload_type) if not header_map: return {"status": "Missing header map"} success = 0 errors = 0 duplicates = 0 for d in json.loads(data): if all(item is None for item in d) is True: continue fields = {} for key, dummy in iteritems(header_map): fields.update({header_map.get(key): d.get(key)}) try: bank_transaction = frappe.new_doc("Bank Transaction") bank_transaction.update(fields) bank_transaction.date = getdate(parse_date(bank_transaction.date)) bank_transaction.bank_account = bank_account bank_transaction.flags.import_statement = True bank_transaction.insert() bank_transaction.submit() success += 1 frappe.db.commit() except frappe.UniqueValidationError: duplicates += 1 frappe.clear_messages() except frappe.DuplicateEntryError: duplicates += 1 frappe.clear_messages() except Exception: errors += 1 frappe.log_error(frappe.get_traceback(), _("Bank transaction creation error")) return { "success": success, "errors": errors, "duplicates": duplicates, "status": "Complete" }
def get_notifications_for_targets(config, notification_percent): """Notifications for doc targets""" can_read = frappe.get_user().get_can_read() doc_target_percents = {} # doc_target_percents = { # "Company": { # "Acme": 87, # "RobotsRUs": 50, # }, {}... # } for doctype in config.targets: if doctype in can_read: if doctype in notification_percent: doc_target_percents[doctype] = notification_percent[doctype] else: doc_target_percents[doctype] = {} d = config.targets[doctype] condition = d["filters"] target_field = d["target_field"] value_field = d["value_field"] try: if isinstance(condition, dict): doc_list = frappe.get_list( doctype, fields=["name", target_field, value_field], filters=condition, limit_page_length=100, ignore_ifnull=True, ) except frappe.PermissionError: frappe.clear_messages() pass except Exception as e: if e.args[0] not in (1412, 1684): raise else: for doc in doc_list: value = doc[value_field] target = doc[target_field] doc_target_percents[doctype][doc.name] = ( value / target * 100) if value < target else 100 return doc_target_percents
def get_notifications_for(notification_type, config, notification_count): open_count = {} notification_map = config.get(notification_type) or {} for m in notification_map: try: if m in notification_count: open_count[m] = notification_count[m] else: open_count[m] = frappe.get_attr(notification_map[m])() frappe.cache().hset("notification_count:" + m, frappe.session.user, open_count[m]) except frappe.PermissionError: frappe.clear_messages() pass # frappe.msgprint("Permission Error in notifications for {0}".format(m)) return open_count
def create(user, exists_ok=False, fields=None): authenticate(user) exists_ok, fields = safe_json_loads(exists_ok, fields) try: dprof = frappe.new_doc('Chat Profile') dprof.user = user dprof.save(ignore_permissions=True) except frappe.DuplicateEntryError: frappe.clear_messages() if not exists_ok: frappe.throw(_('Chat Profile for User {0} exists.').format(user)) profile = get(user, fields=fields) return profile
def search(text, start=0, limit=20, doctype=""): """ Search for given text in __global_search :param text: phrase to be searched :param start: start results at, default 0 :param limit: number of results to return, default 20 :return: Array of result objects """ results = [] texts = text.split('&') for text in texts: text = "+" + text + "*" if not doctype: result = frappe.db.sql(''' select doctype, name, content from __global_search where match(content) against (%s IN BOOLEAN MODE) limit {start}, {limit}'''.format(start=start, limit=limit), text+"*", as_dict=True) else: result = frappe.db.sql(''' select doctype, name, content from __global_search where doctype = %s AND match(content) against (%s IN BOOLEAN MODE) limit {start}, {limit}'''.format(start=start, limit=limit), (doctype, text), as_dict=True) tmp_result=[] for i in result: if i in results or not results: tmp_result.append(i) results = tmp_result for r in results: try: if frappe.get_meta(r.doctype).image_field: r.image = frappe.db.get_value(r.doctype, r.name, frappe.get_meta(r.doctype).image_field) except Exception: frappe.clear_messages() return results
def execute_gql_query(): query, variables, operation_name = get_query() output = execute(query=query, variables=variables, operation_name=operation_name) frappe.clear_messages() frappe.local.response = output if len(output.get("errors", [])): frappe.db.rollback() log_error(query, variables, operation_name, output) frappe.local.response["http_status_code"] = get_max_http_status_code( output.get("errors")) errors = [] for err in output.errors: if isinstance(err, GraphQLError): err = err.formatted errors.append(err) output.errors = errors
def make_fixtures(company=None): docs = [] company = company.name if company else frappe.db.get_value("Global Defaults", None, "default_company") set_salary_components(docs) set_tds_account(docs, company) for d in docs: try: doc = frappe.get_doc(d) doc.flags.ignore_permissions = True doc.insert() except frappe.NameError: frappe.clear_messages() except frappe.DuplicateEntryError: frappe.clear_messages() # create records for Tax Withholding Category set_tax_withholding_category(company)
def test_make_thumbnail(self): # test web image test_file: File = frappe.get_doc( { "doctype": "File", "file_name": "logo", "file_url": frappe.utils.get_url("/_test/assets/image.jpg"), } ).insert(ignore_permissions=True) test_file.make_thumbnail() self.assertEquals(test_file.thumbnail_url, "/files/image_small.jpg") # test web image without extension test_file = frappe.get_doc( { "doctype": "File", "file_name": "logo", "file_url": frappe.utils.get_url("/_test/assets/image"), } ).insert(ignore_permissions=True) test_file.make_thumbnail() self.assertTrue(test_file.thumbnail_url.endswith("_small.jpeg")) # test local image test_file.db_set("thumbnail_url", None) test_file.reload() test_file.file_url = "/files/image_small.jpg" test_file.make_thumbnail(suffix="xs", crop=True) self.assertEquals(test_file.thumbnail_url, "/files/image_small_xs.jpg") frappe.clear_messages() test_file.db_set("thumbnail_url", None) test_file.reload() test_file.file_url = frappe.utils.get_url("unknown.jpg") test_file.make_thumbnail(suffix="xs") self.assertEqual( json.loads(frappe.message_log[0]).get("message"), f"File '{frappe.utils.get_url('unknown.jpg')}' not found", ) self.assertEquals(test_file.thumbnail_url, None)
def reset_password(user): if user == "Administrator": return "not allowed" try: user = frappe.get_doc("User", user) if not user.enabled: return "disabled" user.validate_reset_password() user.reset_password(send_email=True) return frappe.msgprint( msg=_("Password reset instructions have been sent to your email"), title=_("Password Email Sent"), ) except frappe.DoesNotExistError: frappe.local.response["http_status_code"] = 400 frappe.clear_messages() return "not found"
def get_notifications_for_targets(config, notification_percent): """Notifications for doc targets""" can_read = frappe.get_user().get_can_read() doc_target_percents = {} # doc_target_percents = { # "Company": { # "Acme": 87, # "RobotsRUs": 50, # }, {}... # } for doctype in config.targets: if doctype in can_read: if doctype in notification_percent: doc_target_percents[doctype] = notification_percent[doctype] else: doc_target_percents[doctype] = {} d = config.targets[doctype] condition = d["filters"] target_field = d["target_field"] value_field = d["value_field"] try: if isinstance(condition, dict): doc_list = frappe.get_list(doctype, fields=["name", target_field, value_field], filters=condition, limit_page_length = 100, ignore_ifnull=True) except frappe.PermissionError: frappe.clear_messages() pass except Exception as e: if e.args[0] not in (1412, 1684): raise else: for doc in doc_list: value = doc[value_field] target = doc[target_field] doc_target_percents[doctype][doc.name] = (value/target * 100) if value < target else 100 return doc_target_percents
def configure_account(): try: email_account = frappe.get_doc("Email Account", "Notifications") email_account.email_account_name = "Notifications" email_account.email_id = "*****@*****.**" email_account.email_server = "imap.gmail.com" email_account.enable_outgoing = 1 email_account.enable_incoming = 0 email_account.default_outgoing = 1 email_account.login_id_is_different = 1 email_account.login_id = "*****@*****.**" email_account.smtp_port = 587 email_account.password = "******" email_account.domain = "flexsofts.com" email_account.email_sync_option = "UNSEEN" email_account.smtp_server = "smtp.mailgun.org" email_account.use_imap = 1 email_account.use_tls = 1 email_account.use_ssl = 1 email_account.save() except frappe.DuplicateEntryError: frappe.clear_messages()
def handle_pwd_reset_request(*args, **kwargs): message = { "message": "If that email address is in our database, we will send you an email to reset your password.", "data": None } email = kwargs.get("email") try: user = frappe.get_cached_doc("User", {"name": email, "enabled": 1}) user.validate_reset_password() enqueue(user.reset_password, queue="short", is_async=True, send_email=True) return message except frappe.DoesNotExistError as e: frappe.clear_messages() return message except Exception as e: raise e
def get_template(): if not frappe.has_permission("Attendance", "create"): raise frappe.PermissionError args = frappe.local.form_dict if getdate(args.from_date) > getdate(args.to_date): frappe.throw(_("To Date should be greater than From Date")) w = UnicodeWriter() w = add_header(w) try: w = add_data(w, args) except Exception as e: frappe.clear_messages() frappe.respond_as_web_page("Holiday List Missing", html=e) return # write out response as a type csv frappe.response['result'] = cstr(w.getvalue()) frappe.response['type'] = 'csv' frappe.response['doctype'] = "Attendance"
def get_list_settings(doctype): try: return frappe.get_cached_doc("List View Settings", doctype) except frappe.DoesNotExistError: frappe.clear_messages()
def search(text, start=0, limit=20, doctype=""): """ Search for given text in __global_search :param text: phrase to be searched :param start: start results at, default 0 :param limit: number of results to return, default 20 :return: Array of result objects """ from frappe.desk.doctype.global_search_settings.global_search_settings import get_doctypes_for_global_search results = [] sorted_results = [] allowed_doctypes = get_doctypes_for_global_search() for text in set(text.split('&')): text = text.strip() if not text: continue conditions = '1=1' offset = '' mariadb_text = frappe.db.escape('+' + text + '*') mariadb_fields = '`doctype`, `name`, `content`, MATCH (`content`) AGAINST ({} IN BOOLEAN MODE) AS rank'.format( mariadb_text) postgres_fields = '`doctype`, `name`, `content`, TO_TSVECTOR("content") @@ PLAINTO_TSQUERY({}) AS rank'.format( frappe.db.escape(text)) values = {} if doctype: conditions = '`doctype` = %(doctype)s' values['doctype'] = doctype elif allowed_doctypes: conditions = '`doctype` IN %(allowed_doctypes)s' values['allowed_doctypes'] = tuple(allowed_doctypes) if int(start) > 0: offset = 'OFFSET {}'.format(start) common_query = """ SELECT {fields} FROM `__global_search` WHERE {conditions} ORDER BY rank DESC LIMIT {limit} {offset} """ result = frappe.db.multisql( { 'mariadb': common_query.format(fields=mariadb_fields, conditions=conditions, limit=limit, offset=offset), 'postgres': common_query.format(fields=postgres_fields, conditions=conditions, limit=limit, offset=offset) }, values=values, as_dict=True) results.extend(result) # sort results based on allowed_doctype's priority for doctype in allowed_doctypes: for index, r in enumerate(results): if r.doctype == doctype and r.rank > 0.0: try: meta = frappe.get_meta(r.doctype) if meta.image_field: r.image = frappe.db.get_value(r.doctype, r.name, meta.image_field) except Exception: frappe.clear_messages() sorted_results.extend([r]) return sorted_results