def check_applicable_doc_perm(user, doctype, docname): frappe.only_for('System Manager') applicable = [] doc_exists = frappe.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 = frappe.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 check_applicable_doc_perm(user, doctype, docname): frappe.only_for("System Manager") applicable = [] doc_exists = frappe.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 = frappe.get_all( "User Permission", fields=["applicable_for"], filters={ "user": user, "allow": doctype, "for_value": docname, }, ) for permission in data: applicable.append(permission.applicable_for) return applicable
def get_applicable_for_doctype_list(doctype, txt, searchfield, start, page_len, filters): linked_doctypes_map = get_linked_doctypes(doctype, True) linked_doctypes = [] for linked_doctype, linked_doctype_values in linked_doctypes_map.items(): linked_doctypes.append(linked_doctype) child_doctype = linked_doctype_values.get("child_doctype") if child_doctype: linked_doctypes.append(child_doctype) linked_doctypes += [doctype] if txt: linked_doctypes = [ d for d in linked_doctypes if txt.lower() in d.lower() ] linked_doctypes.sort() return_list = [] for doctype in linked_doctypes[start:page_len]: return_list.append([doctype]) return return_list
def get_document_completion_status(doctypes, frm_doctype, frm_docname): if isinstance(doctypes, basestring): doctypes = json.loads(doctypes) doc = frappe.get_doc(frm_doctype, frm_docname) linkinfo = get_linked_doctypes(frm_doctype) flow_completion = {} if hasattr(doc, "prev_link_mapper"): for doctype in doc.prev_link_mapper: fieldname = doc.prev_link_mapper[doctype]["fieldname"] lookup_doctype = doc.prev_link_mapper[doctype]["doctype"] limit = doc.prev_link_mapper[doctype].get("limit") or 1 condition = make_condition(doc.prev_link_mapper[doctype].get("filters")) if condition: condition = "where {condition}".format(condition=condition) else: condition = "" result = frappe.db.sql_list("select {fieldname} from `tab{doctype}` \ {condition} limit {limit}".format(fieldname=fieldname, doctype=lookup_doctype, condition=condition, limit=limit)) if result: flow_completion[doctype] = True for doctype in doctypes: if doctype not in flow_completion: links = get_linked_docs(frm_doctype, frm_docname, linkinfo, for_doctype=doctype) if links: flow_completion[doctype] = True return flow_completion
def execute(): doctypes_to_skip = [] for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip', 'Attendance', 'Training Feedback', 'Training Result Employee', 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee', 'Timesheet', 'Sales Person', 'Payroll Employee Detail']: if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue doctypes_to_skip.append(doctype) frappe.reload_doctype('User Permission') user_permissions = frappe.get_all("User Permission", filters=[['allow', '=', 'Department'], ['applicable_for', 'in', [None] + doctypes_to_skip]], fields=['name', 'applicable_for']) user_permissions_to_delete = [] new_user_permissions_list = [] for user_permission in user_permissions: if user_permission.applicable_for: # simply delete user permission record since it needs to be skipped. user_permissions_to_delete.append(user_permission.name) else: # if applicable_for is `None` it means that user permission is applicable for every doctype # to avoid this we need to create other user permission records and only skip the listed doctypes in this patch linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys() applicable_for_doctypes = list(set(linked_doctypes) - set(doctypes_to_skip)) user_permissions_to_delete.append(user_permission.name) for doctype in applicable_for_doctypes: if doctype: # Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes) new_user_permissions_list.append(( frappe.generate_hash("", 10), user_permission.user, user_permission.allow, user_permission.for_value, doctype, 0 )) if new_user_permissions_list: frappe.db.sql(''' INSERT INTO `tabUser Permission` (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`) VALUES {}'''.format(', '.join(['%s'] * len(new_user_permissions_list))), # nosec tuple(new_user_permissions_list) ) if user_permissions_to_delete: frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` IN ({})'.format( # nosec ','.join(['%s'] * len(user_permissions_to_delete)) ), tuple(user_permissions_to_delete))
def update_student_name_in_linked_doctype(self): linked_doctypes = get_linked_doctypes("Student") for d in linked_doctypes: if "student_name" in [f.fieldname for f in frappe.get_meta(d).fields]: frappe.db.sql("""UPDATE `tab{0}` set student_name = %s where {1} = %s""" .format(d, linked_doctypes[d]["fieldname"]),(self.title, self.name)) if "child_doctype" in linked_doctypes[d].keys() and "student_name" in \ [f.fieldname for f in frappe.get_meta(linked_doctypes[d]["child_doctype"]).fields]: frappe.db.sql("""UPDATE `tab{0}` set student_name = %s where {1} = %s""" .format(linked_doctypes[d]["child_doctype"], linked_doctypes[d]["fieldname"]),(self.title, self.name))
def update_student_name_in_linked_doctype(self): linked_doctypes = get_linked_doctypes("Student") for d in linked_doctypes: meta = frappe.get_meta(d) if not meta.issingle: if "student_name" in [f.fieldname for f in meta.fields]: frappe.db.sql("""UPDATE `tab{0}` set student_name = %s where {1} = %s""" .format(d, linked_doctypes[d]["fieldname"][0]),(self.title, self.name)) if "child_doctype" in linked_doctypes[d].keys() and "student_name" in \ [f.fieldname for f in frappe.get_meta(linked_doctypes[d]["child_doctype"]).fields]: frappe.db.sql("""UPDATE `tab{0}` set student_name = %s where {1} = %s""" .format(linked_doctypes[d]["child_doctype"], linked_doctypes[d]["fieldname"][0]),(self.title, self.name))
def get_applicable_for_doctype_list(doctype, txt, searchfield, start, page_len, filters): linked_doctypes = get_linked_doctypes(doctype, True).keys() linked_doctypes = list(linked_doctypes) linked_doctypes += [doctype] if txt: linked_doctypes = [d for d in linked_doctypes if txt in d.lower()] linked_doctypes.sort() return_list = [] for doctype in linked_doctypes[start:page_len]: return_list.append([doctype]) return return_list
def get_linked_docs_info(doctype,docname): linkinfo = get_linked_doctypes(doctype) linked_doc = get_linked_docs(doctype,docname,linkinfo) linked_doc_list =[] if linked_doc: for key, value in linked_doc.items() : if key != "Activity Log": for val in value: dco_info = { "doctype" : key, "docname" : val.name, "docstatus": val.docstatus, } linked_doc_list.append(dco_info) return linked_doc_list
def reasign_batch(item_code, batch, stock_entry): doc_batch = frappe.get_doc("Batch",batch) if "Nouveau" in stock_entry: frappe.throw("l'entrée de marchandise doit être enregistrée avant de pouvoir utiliser cette fonction.") return linked_doctypes = get_linked_doctypes("Batch") if print_debug: frappe.errprint("linked_doctypes : " + cstr(linked_doctypes)) if print_debug: frappe.errprint("stock_entry : " + cstr(stock_entry)) linked_doc = get_linked_docs("Batch",batch, linked_doctypes) if linked_doc: if print_debug: frappe.errprint("linked_doc : " + cstr(linked_doc)) for key, value in linked_doc.items(): if print_debug: frappe.errprint("key : " + cstr(key)) if print_debug: frappe.errprint("value : " + cstr(value)) if key != "Stock Entry" and key != "Purchase Receipt": frappe.throw(_("Le lot {0} est lié au document {1}. Veuillez supprimer tous les liens avec le lot {0} avant de continuer").format(batch,cstr(value))) if key == "Stock Entry": for link in value: stock_entry_split = stock_entry.split('-') if not stock_entry_split[1] in link.name: if print_debug: frappe.errprint("stock_entry : " + stock_entry) if print_debug: frappe.errprint("link.name : " + link.name) frappe.throw(_("Le lot {0} est lié au document {1}. Veuillez supprimer tous les liens avec le lot {0} avant de continuer").format(batch,link.name)) for stock_entry_detail_name in frappe.get_all("Stock Entry Detail", {"batch_no":batch,"parent":link.name}, "name"): frappe.db.set_value("Stock Entry Detail", stock_entry_detail_name, "batch_no","") if key == "Purchase Receipt": for link in value: stock_entry_split = stock_entry.split('-') if not stock_entry_split[1] in link.name: if print_debug: frappe.errprint("stock_entry : " + stock_entry) if print_debug: frappe.errprint("link.name : " + link.name) frappe.throw(_("Le lot {0} est lié au document {1}. Veuillez supprimer tous les liens avec le lot {0} avant de continuer").format(batch,link.name)) for doc_detail_name in frappe.get_all("Purchase Receipt Item", {"batch_no":batch,"parent":link.name}, "name"): frappe.db.set_value("Purchase Receipt Item", doc_detail_name, "batch_no","") frappe.db.set_value("Batch", batch, "item",item_code)
def validate(self): if self.applicable_for: # get_applicable_for_doctype_list(self.applicable_for, "", searchfield, start, page_len, filters) linked_doctypes_map = get_linked_doctypes(self.applicable_for, True) linked_doctypes = [] for linked_doctype, linked_doctype_values in linked_doctypes_map.items( ): linked_doctypes.append(linked_doctype) child_doctype = linked_doctype_values.get("child_doctype") if child_doctype: linked_doctypes.append(child_doctype) linked_doctypes += [self.applicable_for] linked_doctypes.sort() self.applicable_for_table = {} for dt in linked_doctypes: print(dt) self.append("applicable_for_table", {"name1": dt}) print(linked_doctypes)
def execute(): doctypes_to_skip = [] for doctype in [ 'Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip', 'Attendance', 'Training Feedback', 'Training Result Employee', 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee', 'Timesheet', 'Sales Person', 'Payroll Employee Detail' ]: if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department' }): continue doctypes_to_skip.append(doctype) frappe.reload_doctype('User Permission') user_permissions = frappe.get_all( "User Permission", filters=[['allow', '=', 'Department'], ['applicable_for', 'in', [None] + doctypes_to_skip]], fields=['name', 'applicable_for']) user_permissions_to_delete = [] new_user_permissions_list = [] for user_permission in user_permissions: if user_permission.applicable_for: # simply delete user permission record since it needs to be skipped. user_permissions_to_delete.append(user_permission.name) else: # if applicable_for is `None` it means that user permission is applicable for every doctype # to avoid this we need to create other user permission records and only skip the listed doctypes in this patch linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys() applicable_for_doctypes = list( set(linked_doctypes) - set(doctypes_to_skip)) user_permissions_to_delete.append(user_permission.name) for doctype in applicable_for_doctypes: if doctype: # Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes) new_user_permissions_list.append( (frappe.generate_hash("", 10), user_permission.user, user_permission.allow, user_permission.for_value, doctype, 0)) if new_user_permissions_list: frappe.db.sql( ''' INSERT INTO `tabUser Permission` (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`) VALUES {}'''.format(', '.join(['%s'] * len(new_user_permissions_list))), # nosec tuple(new_user_permissions_list)) if user_permissions_to_delete: frappe.db.sql( 'DELETE FROM `tabUser Permission` WHERE `name` IN ({})'. format( # nosec ','.join(['%s'] * len(user_permissions_to_delete))), tuple(user_permissions_to_delete))
def execute(): frappe.reload_doctype('User Permission') # to check if we need to migrate from skip_for_doctype has_skip_for_doctype = frappe.db.has_column("User Permission", "skip_for_doctype") skip_for_doctype_map = {} new_user_permissions_list = [] user_permissions_to_delete = [] for user_permission in frappe.get_all('User Permission', fields=['*']): skip_for_doctype = [] # while migrating from v11 -> v11 if has_skip_for_doctype: if not user_permission.skip_for_doctype: continue skip_for_doctype = user_permission.skip_for_doctype.split('\n') else: # while migrating from v10 -> v11 if skip_for_doctype_map.get( (user_permission.allow, user_permission.user)) == None: skip_for_doctype = get_doctypes_to_skip( user_permission.allow, user_permission.user) # cache skip for doctype for same user and doctype skip_for_doctype_map[(user_permission.allow, user_permission.user)] = skip_for_doctype else: skip_for_doctype = skip_for_doctype_map[(user_permission.allow, user_permission.user)] if skip_for_doctype: # only specific doctypes are selected # split this into multiple records and delete linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys() linked_doctypes = list(linked_doctypes) # append the doctype for which we have build the user permission linked_doctypes += [user_permission.allow] applicable_for_doctypes = list( set(linked_doctypes) - set(skip_for_doctype)) user_permissions_to_delete.append(user_permission.name) user_permission.name = None user_permission.skip_for_doctype = None for doctype in applicable_for_doctypes: if doctype: # Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes) new_user_permissions_list.append( (frappe.generate_hash("", 10), user_permission.user, user_permission.allow, user_permission.for_value, doctype, 0)) else: # No skip_for_doctype found! Just update apply_to_all_doctypes. frappe.db.set_value('User Permission', user_permission.name, 'apply_to_all_doctypes', 1) if new_user_permissions_list: frappe.db.sql( ''' INSERT INTO `tabUser Permission` (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`) VALUES {} '''.format( # nosec ', '.join(['%s'] * len(new_user_permissions_list))), tuple(new_user_permissions_list)) if user_permissions_to_delete: frappe.db.sql( 'DELETE FROM `tabUser Permission` WHERE `name` in ({})' # nosec .format(','.join(['%s'] * len(user_permissions_to_delete))), tuple(user_permissions_to_delete))
def test_linked_with(self): results = get_linked_docs("Role", "System Manager", linkinfo=get_linked_doctypes("Role")) self.assertTrue("User" in results) self.assertTrue("DocType" in results)
def get_related_documents(doctype, docname): document_details = defaultdict(list) si_list = [] linked_doc_info = get_linked_doctypes(doctype) document_details[doctype].append( frappe.get_doc(doctype, docname).as_dict()) # also consider the sales return for linked_doctype in [ "Sales Order", "Material Request", "Stock Entry", "Delivery Note", "Sales Invoice", "Payment Entry" ]: link = linked_doc_info.get(linked_doctype) filters = [[ link.get('child_doctype', linked_doctype), link.get("fieldname")[0], '=', docname ]] if link.get("doctype_fieldname"): filters.append([ link.get('child_doctype'), link.get("doctype_fieldname"), "=", doctype ]) if linked_doctype == "Payment Entry": filters.append(["Payment Entry", "docstatus", "=", 1]) names = frappe.get_all(linked_doctype, fields="name", filters=filters, distinct=1) for doc in names: doc_obj = frappe.get_doc(linked_doctype, doc.name) if linked_doctype == "Sales Invoice": si_list.append(doc_obj.name) if linked_doctype == "Sales Invoice" and doc_obj.is_return: document_details["Sales Return"].append(doc_obj.as_dict()) else: document_details[linked_doctype].append(doc_obj.as_dict()) for so in document_details["Sales Order"]: for d in so.get("items"): d.remaining_qty = flt( d.qty) - (flt(d.delivered_qty) + flt(d.returned_qty)) # include the Payment Entry against invoice pe_names = map(lambda d: d.name, document_details["Payment Entry"] or []) if si_list: payment_entry = frappe.db.sql( '''select distinct parent as name from `tabPayment Entry Reference` where docstatus=1 and reference_name in (%s)''' % ', '.join(['%s'] * len(si_list)), tuple(si_list), as_dict=1) for pe in payment_entry: if pe.name not in pe_names: pe_doc = frappe.get_doc("Payment Entry", pe.name).as_dict() document_details["Payment Entry"].append(pe_doc) # remove payment references to other documents and calculate total paid positive_payment_total = 0 negative_payment_total = 0 for pe in document_details["Payment Entry"]: new_list = [] for pref in pe.references: if (pref.reference_doctype == doctype and pref.reference_name == docname) \ or (pref.reference_doctype == "Sales Invoice" and pref.reference_name in si_list): new_list.append(pref) if flt(pref.allocated_amount) < 0: negative_payment_total -= flt(pref.allocated_amount) else: positive_payment_total += flt(pref.allocated_amount) pe.references = new_list sales_order_total = document_details["Sales Order"][0].rounded_total sales_return_total = -sum( map(lambda d: d.rounded_total, document_details["Sales Return"]) ) if "Sales Return" in document_details else 0.0 total_outstanding_amount = positive_payment_total - negative_payment_total - sales_order_total + sales_return_total document_details["Sales Order"][ 0].total_payment_amount = positive_payment_total document_details["Sales Order"][ 0].total_refund_amount = negative_payment_total document_details["Sales Order"][0].total_return_amount = sales_return_total document_details["Sales Order"][ 0].total_outstanding_amount = total_outstanding_amount return document_details
def execute(): frappe.reload_doctype('User Permission') # to check if we need to migrate from skip_for_doctype has_skip_for_doctype = frappe.db.has_column("User Permission", "skip_for_doctype") skip_for_doctype_map = {} new_user_permissions_list = [] user_permissions_to_delete = [] for user_permission in frappe.get_all('User Permission', fields=['*']): skip_for_doctype = [] # while migrating from v11 -> v11 if has_skip_for_doctype: if not user_permission.skip_for_doctype: continue skip_for_doctype = user_permission.skip_for_doctype.split('\n') else: # while migrating from v10 -> v11 if skip_for_doctype_map.get((user_permission.allow, user_permission.user)) == None: skip_for_doctype = get_doctypes_to_skip(user_permission.allow, user_permission.user) # cache skip for doctype for same user and doctype skip_for_doctype_map[(user_permission.allow, user_permission.user)] = skip_for_doctype else: skip_for_doctype = skip_for_doctype_map[(user_permission.allow, user_permission.user)] if skip_for_doctype: # only specific doctypes are selected # split this into multiple records and delete linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys() linked_doctypes = list(linked_doctypes) # append the doctype for which we have build the user permission linked_doctypes += [user_permission.allow] applicable_for_doctypes = list(set(linked_doctypes) - set(skip_for_doctype)) user_permissions_to_delete.append(user_permission.name) user_permission.name = None user_permission.skip_for_doctype = None for doctype in applicable_for_doctypes: if doctype: # Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes, creation, modified) new_user_permissions_list.append(( frappe.generate_hash("", 10), user_permission.user, user_permission.allow, user_permission.for_value, doctype, 0, user_permission.creation, user_permission.modified )) else: # No skip_for_doctype found! Just update apply_to_all_doctypes. frappe.db.set_value('User Permission', user_permission.name, 'apply_to_all_doctypes', 1) if new_user_permissions_list: frappe.db.sql(''' INSERT INTO `tabUser Permission` (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`, `creation`, `modified`) VALUES {} '''.format( # nosec ', '.join(['%s'] * len(new_user_permissions_list)) ), tuple(new_user_permissions_list)) if user_permissions_to_delete: frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` in ({})' # nosec .format(','.join(['%s'] * len(user_permissions_to_delete))), tuple(user_permissions_to_delete) )