def execute(): dataent.reload_doc("core", "doctype", "docperm") dataent.reload_doc("core", "doctype", "docshare") dataent.reload_doc('email', 'doctype', 'email_account') # default share to all writes dataent.db.sql("""update tabDocPerm set `share`=1 where ifnull(`write`,0)=1 and ifnull(`permlevel`,0)=0""") # every user must have access to his / her own detail users = dataent.get_all("User", filters={"user_type": "System User"}) usernames = [user.name for user in users] for user in usernames: dataent.share.add("User", user, user, write=1, share=1) # move event user to shared if dataent.db.exists("DocType", "Event User"): for event in dataent.get_all("Event User", fields=["parent", "person"]): if event.person in usernames: if not dataent.db.exists("Event", event.parent): dataent.db.sql("delete from `tabEvent User` where parent = %s",event.parent) else: dataent.share.add("Event", event.parent, event.person, write=1) dataent.delete_doc("DocType", "Event User") # move note user to shared if dataent.db.exists("DocType", "Note User"): for note in dataent.get_all("Note User", fields=["parent", "user", "permission"]): perm = {"read": 1} if note.permission=="Read" else {"write": 1} if note.user in usernames: dataent.share.add("Note", note.parent, note.user, **perm) dataent.delete_doc("DocType", "Note User")
def validate(self): if not self.global_unsubscribe and not (self.reference_doctype and self.reference_name): dataent.throw( _("Reference DocType and Reference Name are required"), dataent.MandatoryError) if not self.global_unsubscribe and dataent.db.get_value( self.doctype, self.name, "global_unsubscribe"): dataent.throw( _("Delete this record to allow sending to this email address")) if self.global_unsubscribe: if dataent.get_all("Email Unsubscribe", filters={ "email": self.email, "global_unsubscribe": 1, "name": ["!=", self.name] }): dataent.throw( _("{0} already unsubscribed").format(self.email), dataent.DuplicateEntryError) else: if dataent.get_all("Email Unsubscribe", filters={ "email": self.email, "reference_doctype": self.reference_doctype, "reference_name": self.reference_name, "name": ["!=", self.name] }): dataent.throw( _("{0} already unsubscribed for {1} {2}").format( self.email, self.reference_doctype, self.reference_name), dataent.DuplicateEntryError)
def migrate_item_variants(): for item in dataent.get_all("Item", filters={"has_variants": 1}): all_variants = dataent.get_all("Item", filters={"variant_of": item.name}, fields=["name", "description"]) item_attributes = dataent.db.sql("""select distinct item_attribute, item_attribute_value from `tabItem Variant` where parent=%s""", item.name) if not item_attributes and not all_variants: item = dataent.get_doc("Item", item.name) item.has_variants = 0 item.save() continue attribute_value_options = {} for attribute, value in item_attributes: attribute_value_options.setdefault(attribute, []).append(value) possible_combinations = get_possible_combinations(attribute_value_options) for variant in all_variants: for combination in possible_combinations: match = True for attribute, value in combination.items(): if "{0}: {1}".format(attribute, value) not in variant.description: match = False break if match: # found the right variant save_attributes_in_variant(variant, combination) break save_attributes_in_template(item, attribute_value_options) dataent.delete_doc("DocType", "Item Variant")
def get_site_info(): from dataent.utils.user import get_system_managers from dataent.core.doctype.user.user import STANDARD_USERS from dataent.email.queue import get_emails_sent_this_month # only get system users users = dataent.get_all('User', filters={ 'user_type': 'System User', 'name': ('not in', STANDARD_USERS) }, fields=[ 'name', 'enabled', 'last_login', 'last_active', 'language', 'time_zone' ]) system_managers = get_system_managers(only_name=True) for u in users: # tag system managers u.is_system_manager = 1 if u.name in system_managers else 0 u.full_name = get_fullname(u.name) u.email = u.name del u['name'] system_settings = dataent.db.get_singles_dict('System Settings') space_usage = dataent._dict((dataent.local.conf.limits or {}).get('space_usage', {})) kwargs = { "fields": ["user", "creation", "full_name"], "filters": { "Operation": "Login", "Status": "Success" }, "limit": "10" } site_info = { 'installed_apps': get_installed_apps_info(), 'users': users, 'country': system_settings.country, 'language': system_settings.language or 'english', 'time_zone': system_settings.time_zone, 'setup_complete': cint(system_settings.setup_complete), 'scheduler_enabled': system_settings.enable_scheduler, # usage 'emails_sent': get_emails_sent_this_month(), 'space_used': flt((space_usage.total or 0) / 1024.0, 2), 'database_size': space_usage.database_size, 'backup_size': space_usage.backup_size, 'files_size': space_usage.files_size, 'last_logins': dataent.get_all("Activity Log", **kwargs) } # from other apps for method_name in dataent.get_hooks('get_site_info'): site_info.update(dataent.get_attr(method_name)(site_info) or {}) # dumps -> loads to prevent datatype conflicts return json.loads(dataent.as_json(site_info))
def _get_linked_doctypes(doctype, without_ignore_user_permissions_enabled=False): ret = {} # find fields where this doctype is linked ret.update( get_linked_fields(doctype, without_ignore_user_permissions_enabled)) ret.update( get_dynamic_linked_fields(doctype, without_ignore_user_permissions_enabled)) filters = [['fieldtype', '=', 'Table'], ['options', '=', doctype]] if without_ignore_user_permissions_enabled: filters.append(['ignore_user_permissions', '!=', 1]) # find links of parents links = dataent.get_all("DocField", fields=["parent as dt"], filters=filters) links += dataent.get_all("Custom Field", fields=["dt"], filters=filters) for dt, in links: if dt in ret: continue ret[dt] = {"get_parent": True} for dt in list(ret): try: doctype_module = load_doctype_module(dt) except (ImportError, KeyError): # in case of Custom DocType # or in case of module rename eg. (Schools -> Education) continue if getattr(doctype_module, "exclude_from_linked_with", False): del ret[dt] return ret
def test_production_plan(self): pln = create_production_plan(item_code='Test Production Item 1') self.assertTrue(len(pln.mr_items), 2) pln.make_material_request() pln = dataent.get_doc('Production Plan', pln.name) self.assertTrue(pln.status, 'Material Requested') material_requests = dataent.get_all( 'Material Request Item', fields=['distinct parent'], filters={'production_plan': pln.name}, as_list=1) self.assertTrue(len(material_requests), 2) pln.make_work_order() work_orders = dataent.get_all('Work Order', fields=['name'], filters={'production_plan': pln.name}, as_list=1) self.assertTrue(len(work_orders), len(pln.po_items)) for name in material_requests: mr = dataent.get_doc('Material Request', name[0]) mr.cancel() for name in work_orders: mr = dataent.delete_doc('Work Order', name[0]) pln = dataent.get_doc('Production Plan', pln.name) pln.cancel()
def execute(): """ Structure History: 1. Item and Item Variant 2. Item, Variant Attribute, Manage Variants and Manage Variant Items 3. Item, Item Variant Attribute, Item Attribute and Item Attribute Type (latest) """ rename_and_reload_doctypes() variant_templates = dataent.get_all("Item", filters={"has_variants": 1}, limit_page_length=1) if not variant_templates: # database does not have items that have variants # so no point in running the patch return variant_attributes = dataent.get_all("Item Variant Attribute", fields=["*"], limit_page_length=1) if variant_attributes: # manage variant patch is already applied migrate_manage_variants() else: # old structure based on "Item Variant" table try: migrate_item_variants() except SQLError: print("`tabItem Variant` not found")
def check_applicable_doc_perm(user, doctype, docname): dataent.only_for('System Manager') applicable = [] doc_exists = dataent.get_all('User Permission', fields=['name'], filters={ "user": user, "allow": doctype, "for_value": docname, "apply_to_all_doctypes": 1, }, limit=1) if doc_exists: applicable = get_linked_doctypes(doctype).keys() else: data = dataent.get_all('User Permission', fields=['applicable_for'], filters={ "user": user, "allow": doctype, "for_value": docname, }) for d in data: applicable.append(d.applicable_for) return applicable
def load_address_and_contact(doc, key=None): """Loads address list and contact list in `__onload`""" from dataent.contacts.doctype.address.address import get_address_display filters = [ ["Dynamic Link", "link_doctype", "=", doc.doctype], ["Dynamic Link", "link_name", "=", doc.name], ["Dynamic Link", "parenttype", "=", "Address"], ] address_list = dataent.get_all("Address", filters=filters, fields=["*"]) address_list = [a.update({"display": get_address_display(a)}) for a in address_list] address_list = sorted(address_list, key = functools.cmp_to_key(lambda a, b: (int(a.is_primary_address - b.is_primary_address)) or (1 if a.modified - b.modified else 0)), reverse=True) doc.set_onload('addr_list', address_list) contact_list = [] filters = [ ["Dynamic Link", "link_doctype", "=", doc.doctype], ["Dynamic Link", "link_name", "=", doc.name], ["Dynamic Link", "parenttype", "=", "Contact"], ] contact_list = dataent.get_all("Contact", filters=filters, fields=["*"]) contact_list = sorted(contact_list, key = functools.cmp_to_key(lambda a, b: (int(a.is_primary_contact - b.is_primary_contact)) or (1 if a.modified - b.modified else 0)), reverse=True) doc.set_onload('contact_list', contact_list)
def execute(): """Fix relative urls for image src="files/" to src="/files/" in DocTypes with text editor fields""" doctypes_with_text_fields = dataent.get_all( "DocField", fields=["parent", "fieldname"], filters={"fieldtype": "Text Editor"}) done = [] for opts in doctypes_with_text_fields: if opts in done: continue try: result = dataent.get_all(opts.parent, fields=["name", opts.fieldname]) except dataent.SQLError as e: # bypass single tables continue for data in result: old_value = data[opts.fieldname] if not old_value: continue html = scrub_relative_urls(old_value) if html != old_value: # print_diff(html, old_value) dataent.db.set_value(opts.parent, data.name, opts.fieldname, html, update_modified=False) done.append(opts)
def monthly_auto_repeat(self, doctype, docname, start_date, end_date): def get_months(start, end): diff = (12 * end.year + end.month) - (12 * start.year + start.month) return diff + 1 doc = make_auto_repeat(reference_doctype=doctype, frequency='Monthly', reference_document=docname, start_date=start_date, end_date=end_date) disable_auto_repeat(doc) for data in get_auto_repeat_entries(today()): create_repeated_entries(data) docnames = dataent.get_all(doc.reference_doctype, {'auto_repeat': doc.name}) self.assertEqual(len(docnames), 1) doc = dataent.get_doc('Auto Repeat', doc.name) doc.db_set('disabled', 0) months = get_months(getdate(start_date), getdate(today())) for data in get_auto_repeat_entries(today()): create_repeated_entries(data) docnames = dataent.get_all(doc.reference_doctype, {'auto_repeat': doc.name}) self.assertEqual(len(docnames), months)
def notify_unreplied(): """Sends email notifications if there are unreplied Communications and `notify_if_unreplied` is set as true.""" for email_account in dataent.get_all("Email Account", "name", filters={"enable_incoming": 1, "notify_if_unreplied": 1}): email_account = dataent.get_doc("Email Account", email_account.name) if email_account.append_to: # get open communications younger than x mins, for given doctype for comm in dataent.get_all("Communication", "name", filters=[ {"sent_or_received": "Received"}, {"reference_doctype": email_account.append_to}, {"unread_notification_sent": 0}, {"email_account":email_account.name}, {"creation": ("<", datetime.now() - timedelta(seconds = (email_account.unreplied_for_mins or 30) * 60))}, {"creation": (">", datetime.now() - timedelta(seconds = (email_account.unreplied_for_mins or 30) * 60 * 3))} ]): comm = dataent.get_doc("Communication", comm.name) if dataent.db.get_value(comm.reference_doctype, comm.reference_name, "status")=="Open": # if status is still open dataent.sendmail(recipients=email_account.get_unreplied_notification_emails(), content=comm.content, subject=comm.subject, doctype= comm.reference_doctype, name=comm.reference_name) # update flag comm.db_set("unread_notification_sent", 1)
def execute(): dataent.reload_doctype('Issue') dataent.reload_doctype('Opportunity') for doctype in ('Issue', 'Opportunity'): dataent.db.sql( 'update tab{0} set mins_to_first_response=0'.format(doctype)) for parent in dataent.get_all(doctype, order_by='creation desc', limit=500): parent_doc = dataent.get_doc(doctype, parent.name) for communication in dataent.get_all('Communication', filters={ 'reference_doctype': doctype, 'reference_name': parent.name, 'communication_medium': 'Email' }, order_by='creation asc', limit=2): communication_doc = dataent.get_doc('Communication', communication.name) update_mins_to_first_communication(parent_doc, communication_doc) if parent_doc.mins_to_first_response: continue
def get_timesheets(project, start=0, search=None): filters = {"project": project} if search: filters["activity_type"] = ("like", "%{0}%".format(search)) timesheets = dataent.get_all( 'Timesheet Detail', filters=filters, fields=['project', 'activity_type', 'from_time', 'to_time', 'parent'], limit_start=start, limit_page_length=10) for timesheet in timesheets: timesheet.infos = dataent.get_all('Timesheet', filters={"name": timesheet.parent}, fields=[ 'name', '_comments', '_seen', 'status', 'modified', 'modified_by' ], limit_start=start, limit_page_length=10) for timesheet.info in timesheet.infos: timesheet.info.user_image = dataent.db.get_value( 'User', timesheet.info.modified_by, 'user_image') timesheet.info.comment_count = len( json.loads(timesheet.info._comments or "[]")) timesheet.info.css_seen = '' if timesheet.info._seen: if dataent.session.user in json.loads(timesheet.info._seen): timesheet.info.css_seen = 'seen' return timesheets
def get_link_options(web_form_name, doctype, allow_read_on_all_link_options=False): web_form_doc = dataent.get_doc("Web Form", web_form_name) doctype_validated = False limited_to_user = False if web_form_doc.login_required: # check if dataent session user is not guest or admin if dataent.session.user != 'Guest': doctype_validated = True if not allow_read_on_all_link_options: limited_to_user = True else: for field in web_form_doc.web_form_fields: if field.options == doctype: doctype_validated = True break if doctype_validated: link_options = [] if limited_to_user: link_options = "\n".join([ doc.name for doc in dataent.get_all( doctype, filters={"owner": dataent.session.user}) ]) else: link_options = "\n".join( [doc.name for doc in dataent.get_all(doctype)]) return link_options else: raise dataent.PermissionError('Not Allowed, {0}'.format(doctype))
def execute(): dataent.reload_doc('buying', 'doctype', 'supplier_scorecard_criteria') dataent.reload_doc('buying', 'doctype', 'supplier_scorecard_scoring_criteria') dataent.reload_doc('buying', 'doctype', 'supplier_scorecard') for criteria in dataent.get_all('Supplier Scorecard Criteria', fields=['name', 'formula'], limit_page_length=None): dataent.db.set_value( 'Supplier Scorecard Criteria', criteria.name, 'formula', criteria.formula.replace('<', '<').replace('>', '>')) for criteria in dataent.get_all('Supplier Scorecard Scoring Criteria', fields=['name', 'formula'], limit_page_length=None): if criteria.formula: # not mandatory dataent.db.set_value( 'Supplier Scorecard Scoring Criteria', criteria.name, 'formula', criteria.formula.replace('<', '<').replace('>', '>')) for sc in dataent.get_all('Supplier Scorecard', fields=['name', 'weighting_function'], limit_page_length=None): dataent.db.set_value( 'Supplier Scorecard', sc.name, 'weighting_function', sc.weighting_function.replace('<', '<').replace('>', '>'))
def delete_feedback_request_and_feedback(reference_doctype, reference_name): """ delete all the feedback request and feedback communication """ if not all([reference_doctype, reference_name]): return feedback_requests = dataent.get_all("Feedback Request", filters={ "is_feedback_submitted": 0, "reference_doctype": reference_doctype, "reference_name": reference_name }) communications = dataent.get_all( "Communication", { "communication_type": "Feedback", "reference_doctype": reference_doctype, "reference_name": reference_name }) for request in feedback_requests: dataent.delete_doc("Feedback Request", request.get("name"), ignore_permissions=True) for communication in communications: dataent.delete_doc("Communication", communication.get("name"), ignore_permissions=True)
def get_roles_and_doctypes(): dataent.only_for("System Manager") send_translations(dataent.get_lang_dict("doctype", "DocPerm")) active_domains = dataent.get_active_domains() doctypes = dataent.get_all("DocType", filters={ "istable": 0, "name": ("not in", ",".join(not_allowed_in_permission_manager)), }, or_filters={ "ifnull(restrict_to_domain, '')": "", "restrict_to_domain": ("in", active_domains) }, fields=["name"]) roles = dataent.get_all("Role", filters={ "name": ("not in", "Administrator"), "disabled": 0, }, or_filters={ "ifnull(restrict_to_domain, '')": "", "restrict_to_domain": ("in", active_domains) }, fields=["name"]) doctypes_list = [ {"label":_(d.get("name")), "value":d.get("name")} for d in doctypes] roles_list = [ {"label":_(d.get("name")), "value":d.get("name")} for d in roles] return { "doctypes": sorted(doctypes_list, key=lambda d: d['label']), "roles": sorted(roles_list, key=lambda d: d['label']) }
def submit_job_cards(): work_orders = dataent.get_all("Work Order", ["name", "creation"], { "docstatus": 1, "status": "Not Started" }) work_order = random.choice(work_orders) # for work_order in work_orders: start_date = work_order.creation work_order = dataent.get_doc("Work Order", work_order.name) job = dataent.get_all("Job Card", ["name", "operation", "work_order"], { "docstatus": 0, "work_order": work_order.name }) if not job: return job_map = {} for d in job: job_map[d.operation] = dataent.get_doc("Job Card", d.name) for operation in work_order.operations: job = job_map[operation.operation] job.actual_start_date = start_date minutes = operation.get("time_in_mins") random_minutes = random.randint(int(minutes / 2), minutes) job.actual_end_date = job.actual_start_date + timedelta( minutes=random_minutes) start_date = job.actual_end_date job.save() job.submit()
def execute(): for ps in dataent.get_all('Property Setter', filters={'property': '_idx'}, fields=['doc_type', 'value']): custom_fields = dataent.get_all('Custom Field', filters={'dt': ps.doc_type}, fields=['name', 'fieldname']) if custom_fields: _idx = json.loads(ps.value) for custom_field in custom_fields: if custom_field.fieldname in _idx: custom_field_idx = _idx.index(custom_field.fieldname) if custom_field_idx == 0: prev_fieldname = "" else: prev_fieldname = _idx[custom_field_idx - 1] else: prev_fieldname = _idx[-1] custom_field_idx = len(_idx) dataent.db.set_value('Custom Field', custom_field.name, 'insert_after', prev_fieldname) dataent.db.set_value('Custom Field', custom_field.name, 'idx', custom_field_idx)
def get_count(self, mapping): filters = mapping.get_filters() or {} or_filters = self.get_or_filters(mapping) to_insert = dataent.get_all(mapping.local_doctype, ['count(name) as total'], filters=filters, or_filters=or_filters)[0].total to_delete = dataent.get_all('Deleted Document', ['count(name) as total'], filters={'deleted_doctype': mapping.local_doctype}, or_filters=or_filters)[0].total return to_insert + to_delete
def setUpClass(self): create_records() pes = dataent.get_all("Payment Entry") jes = dataent.get_all("Journal Entry") sis = dataent.get_all("Sales Invoice") for pe in pes: dataent.db.set_value("Payment Entry", pe.name, "docstatus", 2) for je in jes: dataent.db.set_value("Journal Entry", je.name, "docstatus", 2) for si in sis: dataent.db.set_value("Sales Invoice", si.name, "docstatus", 2)
def copy_user_roles_to_has_roles(): if dataent.db.exists('DocType', 'UserRole'): for data in dataent.get_all('User', fields = ["name"]): doc = dataent.get_doc('User', data.name) doc.set('roles',[]) for args in dataent.get_all('UserRole', fields = ["role"], filters = {'parent': data.name, 'parenttype': 'User'}): doc.append('roles', { 'role': args.role }) for role in doc.roles: role.db_update()
def delete_events(self): participations = dataent.get_all("Event Participants", filters={"reference_doctype": self.doctype, "reference_docname": self.name, "parenttype": "Event"}, fields=["name", "parent"]) if participations: for participation in participations: total_participants = dataent.get_all("Event Participants", filters={"parenttype": "Event", "parent": participation.parent}) if len(total_participants) <= 1: dataent.db.sql("delete from `tabEvent` where name='%s'" % participation.parent) dataent.db.sql("delete from `tabEvent Participants` where name='%s'" % participation.name)
def get_opening_invoice_summary(self): def prepare_invoice_summary(doctype, invoices): # add company wise sales / purchase invoice summary paid_amount = [] outstanding_amount = [] for invoice in invoices: company = invoice.pop("company") _summary = invoices_summary.get(company, {}) _summary.update({ "currency": company_wise_currency.get(company), doctype: invoice }) invoices_summary.update({company: _summary}) paid_amount.append(invoice.paid_amount) outstanding_amount.append(invoice.outstanding_amount) if paid_amount or outstanding_amount: max_count.update({ doctype: { "max_paid": max(paid_amount) if paid_amount else 0.0, "max_due": max(outstanding_amount) if outstanding_amount else 0.0 } }) invoices_summary = {} max_count = {} fields = [ "company", "count(name) as total_invoices", "sum(outstanding_amount) as outstanding_amount" ] companies = dataent.get_all( "Company", fields=["name as company", "default_currency as currency"]) if not companies: return None, None company_wise_currency = { row.company: row.currency for row in companies } for doctype in ["Sales Invoice", "Purchase Invoice"]: invoices = dataent.get_all(doctype, filters=dict(is_opening="Yes", docstatus=1), fields=fields, group_by="company") prepare_invoice_summary(doctype, invoices) return invoices_summary, max_count
def get_all_perms(role): '''Returns valid permissions for a given role''' perms = dataent.get_all('DocPerm', fields='*', filters=dict(role=role)) custom_perms = dataent.get_all('Custom DocPerm', fields='*', filters=dict(role=role)) doctypes_with_custom_perms = dataent.db.sql_list("""select distinct parent from `tabCustom DocPerm`""") for p in perms: if p.parent not in doctypes_with_custom_perms: custom_perms.append(p) return custom_perms
def tearDown(self): for bt in dataent.get_all("Bank Transaction"): doc = dataent.get_doc("Bank Transaction", bt.name) doc.cancel() doc.delete() for ba in dataent.get_all("Bank Account"): dataent.get_doc("Bank Account", ba.name).delete() for at in dataent.get_all("Account Type"): dataent.get_doc("Account Type", at.name).delete() for ast in dataent.get_all("Account Subtype"): dataent.get_doc("Account Subtype", ast.name).delete()
def execute(): dataent.reload_doc("non_profit", "doctype", "member") old_named_members = dataent.get_all( "Member", filters={"name": ("not like", "MEM-%")}) correctly_named_members = dataent.get_all( "Member", filters={"name": ("like", "MEM-%")}) current_index = len(correctly_named_members) for member in old_named_members: current_index += 1 dataent.rename_doc("Member", member["name"], "MEM-" + str(current_index).zfill(5)) dataent.db.sql("""update `tabMember` set naming_series = 'MEM-'""")
def execute(): custom_doctypes = dataent.get_all('DocType', filters={'custom': 1}) for doctype in custom_doctypes: property_setters = dataent.get_all('Property Setter', filters={ 'doc_type': doctype.name, 'doctype_or_field': 'DocField' }, fields=[ 'name', 'property', 'value', 'property_type', 'field_name' ]) custom_fields = dataent.get_all('Custom Field', filters={'dt': doctype.name}, fields=['*']) property_setter_map = {} for prop in property_setters: property_setter_map[prop.field_name] = prop dataent.db.sql('DELETE FROM `tabProperty Setter` WHERE `name`=%s', prop.name) meta = dataent.get_meta(doctype.name) for df in meta.fields: ps = property_setter_map.get(df.fieldname, None) if ps: value = cint( ps.value) if ps.property_type == 'Int' else ps.value df.set(ps.property, value) for cf in custom_fields: cf.pop('parenttype') cf.pop('parentfield') cf.pop('parent') cf.pop('name') field = meta.get_field(cf.fieldname) if field: field.update(cf) else: df = dataent.new_doc('DocField', meta, 'fields') df.update(cf) meta.fields.append(df) dataent.db.sql('DELETE FROM `tabCustom Field` WHERE name=%s', cf.name) meta.save()
def get_linked_fields(doctype, without_ignore_user_permissions_enabled=False): filters = [['fieldtype', '=', 'Link'], ['options', '=', doctype]] if without_ignore_user_permissions_enabled: filters.append(['ignore_user_permissions', '!=', 1]) # find links of parents links = dataent.get_all("DocField", fields=["parent", "fieldname"], filters=filters, as_list=1) links += dataent.get_all("Custom Field", fields=["dt as parent", "fieldname"], filters=filters, as_list=1) ret = {} if not links: return ret links_dict = defaultdict(list) for doctype, fieldname in links: links_dict[doctype].append(fieldname) for doctype_name in links_dict: ret[doctype_name] = {"fieldname": links_dict.get(doctype_name)} table_doctypes = dataent.get_all( "DocType", filters=[["istable", "=", "1"], ["name", "in", tuple(links_dict)]]) child_filters = [['fieldtype', '=', 'Table'], [ 'options', 'in', tuple(doctype.name for doctype in table_doctypes) ]] if without_ignore_user_permissions_enabled: child_filters.append(['ignore_user_permissions', '!=', 1]) # find out if linked in a child table for parent, options in dataent.get_all("DocField", fields=["parent", "options"], filters=child_filters, as_list=1): ret[parent] = { "child_doctype": options, "fieldname": links_dict[options] } if options in ret: del ret[options] return ret