def get_series(): series_to_set = {} for doctype in doctype_series_map: if not dataent.db.exists('DocType', doctype): continue if not dataent.db.a_row_exists(doctype): continue if not dataent.db.has_column(doctype, 'naming_series'): continue if not dataent.get_meta(doctype).has_field('naming_series'): continue series_to_preserve = list(filter(None, get_series_to_preserve(doctype))) default_series = get_default_series(doctype) if not series_to_preserve: continue existing_series = ( dataent.get_meta(doctype).get_field("naming_series").options or "").split("\n") existing_series = list( filter(None, [d.strip() for d in existing_series])) # set naming series property setter series_to_preserve = list(set(series_to_preserve + existing_series)) if series_to_preserve: series_to_set[doctype] = { "options": "\n".join(series_to_preserve), "default": default_series } return series_to_set
def get_filter(doctype, f): """Returns a _dict like { "doctype": "fieldname": "operator": "value": } """ from dataent.model import default_fields, optional_fields if isinstance(f, dict): key, value = next(iter(f.items())) f = make_filter_tuple(doctype, key, value) if not isinstance(f, (list, tuple)): dataent.throw(dataent._("Filter must be a tuple or list (in a list)")) if len(f) == 3: f = (doctype, f[0], f[1], f[2]) elif len(f) > 4: f = f[0:4] elif len(f) != 4: dataent.throw( dataent. _("Filter must have 4 values (doctype, fieldname, operator, value): {0}" ).format(str(f))) f = dataent._dict(doctype=f[0], fieldname=f[1], operator=f[2], value=f[3]) sanitize_column(f.fieldname) if not f.operator: # if operator is missing f.operator = "=" valid_operators = ("=", "!=", ">", "<", ">=", "<=", "like", "not like", "in", "not in", "between", "descendants of", "ancestors of", "not descendants of", "not ancestors of", "is") if f.operator.lower() not in valid_operators: dataent.throw( dataent._("Operator must be one of {0}").format( ", ".join(valid_operators))) if f.doctype and (f.fieldname not in default_fields + optional_fields): # verify fieldname belongs to the doctype meta = dataent.get_meta(f.doctype) if not meta.has_field(f.fieldname): # try and match the doctype name from child tables for df in meta.get_table_fields(): if dataent.get_meta(df.options).has_field(f.fieldname): f.doctype = df.options break return f
def get_meta(): doctype_meta = { 'customer': dataent.get_meta('Customer'), 'invoice': dataent.get_meta('Sales Invoice') } for row in dataent.get_all('DocField', fields=['fieldname', 'options'], filters={'parent': 'Sales Invoice', 'fieldtype': 'Table'}): doctype_meta[row.fieldname] = dataent.get_meta(row.options) return doctype_meta
def get_series(): return { "sales_order_series": dataent.get_meta("Sales Order").get_options("naming_series") or "SO-Shopify-", "sales_invoice_series": dataent.get_meta("Sales Invoice").get_options("naming_series") or "SI-Shopify-", "delivery_note_series": dataent.get_meta("Delivery Note").get_options("naming_series") or "DN-Shopify-" }
def execute(): for dt in ("Sales Invoice Advance", "Purchase Invoice Advance"): dataent.reload_doctype(dt) dataent.db.sql( "update `tab{0}` set reference_type = 'Journal Entry'".format(dt)) if dataent.get_meta(dt).has_field('journal_entry'): rename_field(dt, "journal_entry", "reference_name") if dataent.get_meta(dt).has_field('jv_detail_no'): rename_field(dt, "jv_detail_no", "reference_row")
def update_student_name_in_linked_doctype(self): linked_doctypes = get_linked_doctypes("Student") for d in linked_doctypes: meta = dataent.get_meta(d) if not meta.issingle: if "student_name" in [f.fieldname for f in meta.fields]: dataent.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 dataent.get_meta(linked_doctypes[d]["child_doctype"]).fields]: dataent.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 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 = dataent.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 = dataent.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 dataent.get_meta(r.doctype).image_field: r.image = dataent.db.get_value( r.doctype, r.name, dataent.get_meta(r.doctype).image_field) except Exception: dataent.clear_messages() return results
def get_fields_label(doctype=None): meta = dataent.get_meta(doctype) if doctype in core_doctypes_list: return dataent.msgprint( _("Custom Fields cannot be added to core DocTypes.")) if meta.custom: return dataent.msgprint( _("Custom Fields can only be added to a standard DocType.")) return [{ "value": df.fieldname or "", "label": _(df.label or "") } for df in dataent.get_meta(doctype).get("fields")]
def update_values(dt, tax_table): rate_field_precision = get_field_precision( dataent.get_meta(dt + " Item").get_field("rate")) tax_amount_precision = get_field_precision( dataent.get_meta(tax_table).get_field("tax_amount")) # update net_total, discount_on dataent.db.sql(""" UPDATE `tab{0}` SET total_taxes_and_charges = round(base_total_taxes_and_charges / conversion_rate, {1}) WHERE docstatus < 2 and ifnull(base_total_taxes_and_charges, 0) != 0 and ifnull(total_taxes_and_charges, 0) = 0 """.format(dt, tax_amount_precision)) # update net_amount dataent.db.sql(""" UPDATE `tab{0}` par, `tab{1}` item SET item.net_amount = round(item.base_net_amount / par.conversion_rate, {2}), item.net_rate = round(item.base_net_rate / par.conversion_rate, {2}) WHERE par.name = item.parent and par.docstatus < 2 and ((ifnull(item.base_net_amount, 0) != 0 and ifnull(item.net_amount, 0) = 0) or (ifnull(item.base_net_rate, 0) != 0 and ifnull(item.net_rate, 0) = 0)) """.format(dt, dt + " Item", rate_field_precision)) # update tax in party currency dataent.db.sql(""" UPDATE `tab{0}` par, `tab{1}` tax SET tax.tax_amount = round(tax.base_tax_amount / par.conversion_rate, {2}), tax.total = round(tax.base_total / conversion_rate, {2}), tax.tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount / conversion_rate, {2}) WHERE par.name = tax.parent and par.docstatus < 2 and ((ifnull(tax.base_tax_amount, 0) != 0 and ifnull(tax.tax_amount, 0) = 0) or (ifnull(tax.base_total, 0) != 0 and ifnull(tax.total, 0) = 0) or (ifnull(tax.base_tax_amount_after_discount_amount, 0) != 0 and ifnull(tax.tax_amount_after_discount_amount, 0) = 0)) """.format(dt, tax_table, tax_amount_precision))
def get_accounts_data(self, account=None): accounts = [] self.validate_mandatory() company_currency = epaas.get_company_currency(self.company) precision = get_field_precision(dataent.get_meta("Exchange Rate Revaluation Account") .get_field("new_balance_in_base_currency"), company_currency) account_details = self.get_accounts_from_gle() for d in account_details: current_exchange_rate = d.balance / d.balance_in_account_currency \ if d.balance_in_account_currency else 0 new_exchange_rate = get_exchange_rate(d.account_currency, company_currency, self.posting_date) new_balance_in_base_currency = flt(d.balance_in_account_currency * new_exchange_rate) gain_loss = flt(new_balance_in_base_currency, precision) - flt(d.balance, precision) if gain_loss: accounts.append({ "account": d.account, "party_type": d.party_type, "party": d.party, "account_currency": d.account_currency, "balance_in_base_currency": d.balance, "balance_in_account_currency": d.balance_in_account_currency, "current_exchange_rate": current_exchange_rate, "new_exchange_rate": new_exchange_rate, "new_balance_in_base_currency": new_balance_in_base_currency }) if not accounts: self.throw_invalid_response_message(account_details) return accounts
def get_sorted_fields(doctype, custom_fields): """sort on basis of insert_after""" fields_dict = dataent.get_meta(doctype).get("fields") standard_fields_count = dataent.db.sql( """select count(name) from `tabDocField` where parent=%s""", doctype)[0][0] newlist = [] pending = [d.fieldname for d in fields_dict] maxloops = len(custom_fields) + 20 while (pending and maxloops > 0): maxloops -= 1 for fieldname in pending[:]: if fieldname in custom_fields and len( newlist) >= standard_fields_count: # field already added for n in newlist: if n == custom_fields.get(fieldname): newlist.insert(newlist.index(n) + 1, fieldname) pending.remove(fieldname) break else: newlist.append(fieldname) pending.remove(fieldname) # recurring at end if pending: newlist += pending return newlist
def update_in_custom_field(self, df, i): meta = dataent.get_meta(self.doc_type) meta_df = meta.get("fields", {"fieldname": df.fieldname}) if not (meta_df and meta_df[0].get("is_custom_field")): # not a custom field return custom_field = dataent.get_doc("Custom Field", meta_df[0].name) changed = False for property in docfield_properties: if df.get(property) != custom_field.get(property): if property == "fieldtype": self.validate_fieldtype_change(df, meta_df[0].get(property), df.get(property)) custom_field.set(property, df.get(property)) changed = True # check and update `insert_after` property if i != 0: insert_after = self.fields[i - 1].fieldname if custom_field.insert_after != insert_after: custom_field.insert_after = insert_after custom_field.idx = i changed = True if changed: custom_field.db_update() self.flags.update_db = True
def before_print(self): def toggle_print_hide(meta, fieldname): df = meta.get_field(fieldname) if self.get("print_without_amount"): df.set("__print_hide", 1) else: df.delete_key("__print_hide") item_meta = dataent.get_meta("Delivery Note Item") print_hide_fields = { "parent": [ "grand_total", "rounded_total", "in_words", "currency", "total", "taxes" ], "items": [ "rate", "amount", "discount_amount", "price_list_rate", "discount_percentage" ] } for key, fieldname in print_hide_fields.items(): for f in fieldname: toggle_print_hide(self.meta if key == "parent" else item_meta, f) super(DeliveryNote, self).before_print()
def apply_property_setters(self): property_setters = dataent.db.sql( """select * from `tabProperty Setter` where doc_type=%s""", (self.name, ), as_dict=1) if not property_setters: return integer_docfield_properties = [ d.fieldname for d in dataent.get_meta('DocField').fields if d.fieldtype in ('Int', 'Check') ] for ps in property_setters: if ps.doctype_or_field == 'DocType': if ps.property_type in ('Int', 'Check'): ps.value = cint(ps.value) self.set(ps.property, ps.value) else: docfield = self.get("fields", {"fieldname": ps.field_name}, limit=1) if docfield: docfield = docfield[0] else: continue if ps.property in integer_docfield_properties: ps.value = cint(ps.value) docfield.set(ps.property, ps.value)
def get_custom_docfield_properties(): fields_meta = dataent.get_meta('Custom Field').fields fields = {} for d in fields_meta: fields[d.fieldname] = d.fieldtype return fields
def create_custom_field_for_workflow_state(self): dataent.clear_cache(doctype=self.document_type) meta = dataent.get_meta(self.document_type) if not meta.get_field(self.workflow_state_field): # create custom field dataent.get_doc({ "doctype": "Custom Field", "dt": self.document_type, "__islocal": 1, "fieldname": self.workflow_state_field, "label": self.workflow_state_field.replace("_", " ").title(), "hidden": 1, "allow_on_submit": 1, "no_copy": 1, "fieldtype": "Link", "options": "Workflow State", "owner": "Administrator" }).save() dataent.msgprint( _("Created Custom Field {0} in {1}").format( self.workflow_state_field, self.document_type))
def get_app_settings(app_details): parameters = {} doctype = docname = app_details["doctype"] app_settings = get_parameters(app_details) if app_settings: settings = app_settings["settings"] dataent.reload_doc( "integrations", "doctype", "{0}_settings".format(app_details["service_name"].lower())) controller = dataent.get_meta("{0} Settings".format( app_details["service_name"])) for d in controller.fields: if settings.get(d.fieldname): if ''.join(set(cstr(settings.get(d.fieldname)))) == '*': setattr( settings, d.fieldname, get_decrypted_password(doctype, docname, d.fieldname, raise_exception=True)) parameters.update({d.fieldname: settings.get(d.fieldname)}) return parameters
def check_duplicate(self): parent = list( set( dataent.db.sql_list( """select dt.name from `tabDocField` df, `tabDocType` dt where dt.name = df.parent and df.fieldname='naming_series' and dt.name != %s""", self.select_doc_for_series) + dataent.db.sql_list( """select dt.name from `tabCustom Field` df, `tabDocType` dt where dt.name = df.dt and df.fieldname='naming_series' and dt.name != %s""", self.select_doc_for_series))) sr = [[dataent.get_meta(p).get_field("naming_series").options, p] for p in parent] dt = dataent.get_doc("DocType", self.select_doc_for_series) options = self.scrub_options_list(self.set_options.split("\n")) for series in options: dt.validate_series(series) for i in sr: if i[0]: existing_series = [ d.split('.')[0] for d in i[0].split("\n") ] if series.split(".")[0] in existing_series: dataent.throw( _("Series {0} already used in {1}").format( series, i[1]))
def quick_kanban_board(doctype, board_name, field_name, project=None): '''Create new KanbanBoard quickly with default options''' doc = dataent.new_doc('Kanban Board') meta = dataent.get_meta(doctype) options = '' for field in meta.fields: if field.fieldname == field_name: options = field.options columns = [] if options: columns = options.split('\n') for column in columns: if not column: continue doc.append("columns", dict( column_name=column )) doc.kanban_board_name = board_name doc.reference_doctype = doctype doc.field_name = field_name if project: doc.filters = '[["Task","project","=","{0}"]]'.format(project) if doctype in ['Note', 'ToDo']: doc.private = 1 doc.save() return doc
def fetch_to_customize(self): self.clear_existing_doc() if not self.doc_type: return meta = dataent.get_meta(self.doc_type) if self.doc_type in core_doctypes_list: return dataent.msgprint(_("Core DocTypes cannot be customized.")) if meta.issingle: return dataent.msgprint(_("Single DocTypes cannot be customized.")) if meta.custom: return dataent.msgprint( _("Only standard DocTypes are allowed to be customized from Customize Form." )) # doctype properties for property in doctype_properties: self.set(property, meta.get(property)) for d in meta.get("fields"): new_d = { "fieldname": d.fieldname, "is_custom_field": d.get("is_custom_field"), "name": d.name } for property in docfield_properties: new_d[property] = d.get(property) self.append("fields", new_d) # load custom translation translation = self.get_name_translation() self.label = translation.target_name if translation else ''
def get_price_list_rate(args, item_doc, out): meta = dataent.get_meta(args.parenttype or args.doctype) if meta.get_field("currency") or args.get('currency'): pl_details = get_price_list_currency_and_exchange_rate(args) args.update(pl_details) validate_price_list(args) if meta.get_field("currency"): validate_conversion_rate(args, meta) price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0 # variant if not price_list_rate and item_doc.variant_of: price_list_rate = get_price_list_rate_for(args, item_doc.variant_of) # insert in database if not price_list_rate: if args.price_list and args.rate: insert_item_price(args) return {} out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \ / flt(args.conversion_rate) if not out.price_list_rate and args.transaction_type=="buying": from epaas.stock.doctype.item.item import get_last_purchase_details out.update(get_last_purchase_details(item_doc.name, args.name, args.conversion_rate))
def get_dynamic_link_map(for_delete=False): '''Build a map of all dynamically linked tables. For example, if Note is dynamically linked to ToDo, the function will return `{"Note": ["ToDo"], "Sales Invoice": ["Journal Entry Detail"]}` Note: Will not map single doctypes ''' if getattr(dataent.local, 'dynamic_link_map', None) == None or dataent.flags.in_test: # Build from scratch dynamic_link_map = {} for df in get_dynamic_links(): meta = dataent.get_meta(df.parent) if meta.issingle: # always check in Single DocTypes dynamic_link_map.setdefault(meta.name, []).append(df) else: links = dataent.db.sql_list( """select distinct {options} from `tab{parent}`""".format( **df)) for doctype in links: dynamic_link_map.setdefault(doctype, []).append(df) dataent.local.dynamic_link_map = dynamic_link_map return dataent.local.dynamic_link_map
def get_linked_doctypes(doctype): from dataent.permissions import get_linked_doctypes linked_doctypes = get_linked_doctypes(doctype) child_doctypes = [d.options for d in dataent.get_meta(doctype).get_table_fields()] for child_dt in child_doctypes: linked_doctypes += get_linked_doctypes(child_dt) return linked_doctypes
def get_role_permissions(doctype_meta, user=None): """ Returns dict of evaluated role permissions like { "read": 1, "write": 0, // if "if_owner" is enabled "if_owner": { "read": 1, "write": 0 } } """ if isinstance(doctype_meta, string_types): doctype_meta = dataent.get_meta( doctype_meta) # assuming doctype name was passed if not user: user = dataent.session.user cache_key = (doctype_meta.name, user) if user == 'Administrator': return allow_everything() if not dataent.local.role_permissions.get(cache_key): perms = dataent._dict(if_owner={}) roles = dataent.get_roles(user) def is_perm_applicable(perm): return perm.role in roles and cint(perm.permlevel) == 0 def has_permission_without_if_owner_enabled(ptype): return any( p.get(ptype, 0) and not p.get('if_owner', 0) for p in applicable_permissions) applicable_permissions = list( filter(is_perm_applicable, getattr(doctype_meta, 'permissions', []))) has_if_owner_enabled = any( p.get('if_owner', 0) for p in applicable_permissions) for ptype in rights: pvalue = any(p.get(ptype, 0) for p in applicable_permissions) # check if any perm object allows perm type perms[ptype] = cint(pvalue) if (pvalue and has_if_owner_enabled and not has_permission_without_if_owner_enabled(ptype) and ptype != 'create'): perms['if_owner'][ptype] = 1 # has no access if not owner # only provide read access so that user is able to at-least access list # (and the documents will be filtered based on owner sin further checks) perms[ptype] = 1 if ptype == 'read' else 0 dataent.local.role_permissions[cache_key] = perms return dataent.local.role_permissions[cache_key]
def setup_perms_for(doctype): perms = dataent.get_all('DocPerm', fields='*', filters=dict(parent=doctype), order_by='idx asc') # get default perms try: standard_perms = get_standard_permissions(doctype) except (IOError, KeyError): # no json file, doctype no longer exists! return same = True if len(standard_perms) != len(perms): same = False else: for i, p in enumerate(perms): standard = standard_perms[i] for fieldname in dataent.get_meta( 'DocPerm').get_fieldnames_with_value(): if p.get(fieldname) != standard.get(fieldname): same = False break if not same: break if not same: setup_custom_perms(doctype)
def validate_applicable_charges_for_item(self): based_on = self.distribute_charges_based_on.lower() total = sum([flt(d.get(based_on)) for d in self.get("items")]) if not total: dataent.throw( _("Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'" ).format(based_on)) total_applicable_charges = sum( [flt(d.applicable_charges) for d in self.get("items")]) precision = get_field_precision(dataent.get_meta( "Landed Cost Item").get_field("applicable_charges"), currency=dataent.get_cached_value( 'Company', self.company, "default_currency")) diff = flt( self.total_taxes_and_charges) - flt(total_applicable_charges) diff = flt(diff, precision) if abs(diff) < (2.0 / (10**precision)): self.items[-1].applicable_charges += diff else: dataent.throw( _("Total Applicable Charges in Purchase Receipt Items table must be same as Total Taxes and Charges" ))
def trim_tables(doctype=None): """ Removes database fields that don't exist in the doctype (json or custom field). This may be needed as maintenance since removing a field in a DocType doesn't automatically delete the db field. """ ignore_fields = default_fields + optional_fields filters = {"issingle": 0} if doctype: filters["name"] = doctype for doctype in dataent.db.get_all("DocType", filters=filters): doctype = doctype.name columns = dataent.db.get_table_columns(doctype) fields = dataent.get_meta(doctype).get_fieldnames_with_value() columns_to_remove = [ f for f in list(set(columns) - set(fields)) if f not in ignore_fields and not f.startswith("_") ] if columns_to_remove: print(doctype, "columns removed:", columns_to_remove) columns_to_remove = ", ".join( ["drop `{0}`".format(c) for c in columns_to_remove]) query = """alter table `tab{doctype}` {columns}""".format( doctype=doctype, columns=columns_to_remove) dataent.db.sql_ddl(query)
def precision(self, fieldname, parentfield=None): """Returns float precision for a particular field (or get global default). :param fieldname: Fieldname for which precision is required. :param parentfield: If fieldname is in child table.""" from dataent.model.meta import get_field_precision if parentfield and not isinstance(parentfield, string_types): parentfield = parentfield.parentfield cache_key = parentfield or "main" if not hasattr(self, "_precision"): self._precision = dataent._dict() if cache_key not in self._precision: self._precision[cache_key] = dataent._dict() if fieldname not in self._precision[cache_key]: self._precision[cache_key][fieldname] = None doctype = self.meta.get_field( parentfield).options if parentfield else self.doctype df = dataent.get_meta(doctype).get_field(fieldname) if df.fieldtype in ("Currency", "Float", "Percent"): self._precision[cache_key][fieldname] = get_field_precision( df, self) return self._precision[cache_key][fieldname]
def get_html_and_style(doc, name=None, print_format=None, meta=None, no_letterhead=None, trigger_print=False, style=None): """Returns `html` and `style` of print format, used in PDF etc""" if isinstance(doc, string_types) and isinstance(name, string_types): doc = dataent.get_doc(doc, name) if isinstance(doc, string_types): doc = dataent.get_doc(json.loads(doc)) print_format = get_print_format_doc(print_format, meta=meta or dataent.get_meta(doc.doctype)) return { "html": get_html(doc, name=name, print_format=print_format, meta=meta, no_letterhead=no_letterhead, trigger_print=trigger_print), "style": get_print_style(style=style, print_format=print_format) }
def get_events(doctype, start, end, field_map, filters=None, fields=None): field_map = dataent._dict(json.loads(field_map)) doc_meta = dataent.get_meta(doctype) for d in doc_meta.fields: if d.fieldtype == "Color": field_map.update({"color": d.fieldname}) if filters: filters = json.loads(filters or '') if not fields: fields = [field_map.start, field_map.end, field_map.title, 'name'] if field_map.color: fields.append(field_map.color) start_date = "ifnull(%s, '0000-00-00 00:00:00')" % field_map.start end_date = "ifnull(%s, '2199-12-31 00:00:00')" % field_map.end filters += [ [doctype, start_date, '<=', end], [doctype, end_date, '>=', start], ] return dataent.get_list(doctype, fields=fields, filters=filters)