def get_series(): series_to_set = {} for doctype in doctype_series_map: if not frappe.db.exists('DocType', doctype): continue if not frappe.db.a_row_exists(doctype): continue if not frappe.db.has_column(doctype, 'naming_series'): continue if not frappe.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 = (frappe.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_pos_data(): doc = frappe.new_doc('Sales Invoice') doc.update_stock = 1; doc.is_pos = 1; pos_profile = get_pos_profile(doc.company) or {} if pos_profile.get('name'): pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name')) else: frappe.msgprint(_("Warning Message: Create POS Profile")) update_pos_profile_data(doc, pos_profile) update_multi_mode_option(doc, pos_profile) print_template = frappe.db.get_value('Print Format', pos_profile.get('print_format'), 'html') or '' return { 'doc': doc, 'items': get_items(doc, pos_profile), 'customers': get_customers(pos_profile, doc), 'pricing_rules': get_pricing_rules(doc), 'mode_of_payment': get_mode_of_payment(doc), 'print_template': print_template, 'meta': { 'invoice': frappe.get_meta('Sales Invoice'), 'items': frappe.get_meta('Sales Invoice Item'), 'taxes': frappe.get_meta('Sales Taxes and Charges') } }
def get_pos_data(): doc = frappe.new_doc('Sales Invoice') doc.update_stock = 1; doc.is_pos = 1; pos_profile = get_pos_profile(doc.company) or {} if pos_profile.get('name'): pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name')) else: frappe.msgprint('<a href="#Form/POS Profile/New POS Profile">' + _("Welcome to POS: Create your POS Profile") + '</a>'); update_pos_profile_data(doc, pos_profile) update_multi_mode_option(doc, pos_profile) default_print_format = pos_profile.get('print_format') or "Point of Sale" print_template = frappe.db.get_value('Print Format', default_print_format, 'html') return { 'doc': doc, 'items': get_items(doc, pos_profile), 'customers': get_customers(pos_profile, doc), 'pricing_rules': get_pricing_rules(doc), 'print_template': print_template, 'write_off_account': pos_profile.get('write_off_account'), 'meta': { 'invoice': frappe.get_meta('Sales Invoice'), 'items': frappe.get_meta('Sales Invoice Item'), 'taxes': frappe.get_meta('Sales Taxes and Charges') } }
def test_save_customization_idx(self): d = self.get_customize_form("User") original_sequence = [df.fieldname for df in d.get("fields")] # move field to last location_field = d.get("fields", {"fieldname": "location"})[0] d.get("fields").remove(location_field) d.append("fields", location_field) d.run_method("save_customization") frappe.clear_cache(doctype=d.doc_type) property_setter_name, _idx = frappe.db.get_value( "Property Setter", {"doc_type": d.doc_type, "property": "_idx"}, ("name", "value") ) self.assertTrue(_idx) _idx = json.loads(_idx) for i, df in enumerate(frappe.get_meta(d.doc_type).get("fields")): self.assertEquals(_idx[i], df.fieldname) frappe.delete_doc("Property Setter", property_setter_name) frappe.clear_cache(doctype=d.doc_type) for i, df in enumerate(frappe.get_meta(d.doc_type).get("fields")): self.assertEquals(original_sequence[i], df.fieldname)
def get_pos_data(): doc = frappe.new_doc('Sales Invoice') doc.is_pos = 1; pos_profile = get_pos_profile(doc.company) or {} if not doc.company: doc.company = pos_profile.get('company') doc.update_stock = pos_profile.get('update_stock') if pos_profile.get('name'): pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name')) company_data = get_company_data(doc.company) update_pos_profile_data(doc, pos_profile, company_data) update_multi_mode_option(doc, pos_profile) default_print_format = pos_profile.get('print_format') or "Point of Sale" print_template = frappe.db.get_value('Print Format', default_print_format, 'html') return { 'doc': doc, 'default_customer': pos_profile.get('customer'), 'items': get_items_list(pos_profile), 'customers': get_customers_list(pos_profile), 'serial_no_data': get_serial_no_data(pos_profile, doc.company), 'batch_no_data': get_batch_no_data(), 'tax_data': get_item_tax_data(), 'price_list_data': get_price_list_data(doc.selling_price_list), 'bin_data': get_bin_data(pos_profile), 'pricing_rules': get_pricing_rule_data(doc), 'print_template': print_template, 'pos_profile': pos_profile, 'meta': { 'invoice': frappe.get_meta('Sales Invoice'), 'items': frappe.get_meta('Sales Invoice Item'), 'taxes': frappe.get_meta('Sales Taxes and Charges') } }
def get_series(): return { "sales_order_series" : frappe.get_meta("Sales Order").get_options("naming_series") or "SO-Shopify-", "sales_invoice_series" : frappe.get_meta("Sales Invoice").get_options("naming_series") or "SI-Shopify-", "delivery_note_series" : frappe.get_meta("Delivery Note").get_options("naming_series") or "DN-Shopify-" }
def setup_fields_to_fetch(self): '''Setup query to update values for newly set fetch values''' try: old_meta = frappe.get_meta(frappe.get_doc('DocType', self.name), cached=False) old_fields_to_fetch = [df.fieldname for df in old_meta.get_fields_to_fetch()] except frappe.DoesNotExistError: old_fields_to_fetch = [] new_meta = frappe.get_meta(self, cached=False) self.flags.update_fields_to_fetch_queries = [] if set(old_fields_to_fetch) != set([df.fieldname for df in new_meta.get_fields_to_fetch()]): for df in new_meta.get_fields_to_fetch(): if df.fieldname not in old_fields_to_fetch: link_fieldname, source_fieldname = df.options.split('.', 1) link_df = new_meta.get_field(link_fieldname) self.flags.update_fields_to_fetch_queries.append('''update `tab{link_doctype}` source, `tab{doctype}` target set target.`{fieldname}` = source.`{source_fieldname}` where target.`{link_fieldname}` = source.name and ifnull(target.`{fieldname}`, '')="" '''.format( link_doctype = link_df.options, source_fieldname = source_fieldname, doctype = self.name, fieldname = df.fieldname, link_fieldname = link_fieldname ))
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 get_fields_label(doctype=None): meta = frappe.get_meta(doctype) if doctype in core_doctypes_list: return frappe.msgprint(_("Custom Fields cannot be added to core DocTypes.")) if meta.custom: return frappe.msgprint(_("Custom Fields can only be added to a standard DocType.")) return [{"value": df.fieldname or "", "label": _(df.label or "")} for df in frappe.get_meta(doctype).get("fields")]
def get_meta(): doctype_meta = { 'customer': frappe.get_meta('Customer'), 'invoice': frappe.get_meta('Sales Invoice') } for row in frappe.get_all('DocField', fields = ['fieldname', 'options'], filters = {'parent': 'Sales Invoice', 'fieldtype': 'Table'}): doctype_meta[row.fieldname] = frappe.get_meta(row.options) return doctype_meta
def execute(): for dt in ("Sales Invoice Advance", "Purchase Invoice Advance"): frappe.reload_doctype(dt) frappe.db.sql("update `tab{0}` set reference_type = 'Journal Entry'".format(dt)) if frappe.get_meta(dt).has_field('journal_entry'): rename_field(dt, "journal_entry", "reference_name") if frappe.get_meta(dt).has_field('jv_detail_no'): rename_field(dt, "jv_detail_no", "reference_row")
def get_filter(doctype, f): """Returns a _dict like { "doctype": "fieldname": "operator": "value": } """ from frappe.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)): frappe.throw(frappe._("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: frappe.throw(frappe._("Filter must have 4 values (doctype, fieldname, operator, value): {0}").format(str(f))) f = frappe._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: frappe.throw(frappe._("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 = frappe.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 frappe.get_meta(df.options).has_field(f.fieldname): f.doctype = df.options break return f
def get_conditions(filters): conditions = [] for key in filters: if filters.get(key): if frappe.get_meta("Timesheet").has_field(key): dt = 'tabTimesheet' elif frappe.get_meta("Timesheet Detail").has_field(key): dt = 'tabTimesheet Detail' conditions.append("`%s`.%s = '%s'"%(dt, key, filters.get(key))) return " and {}".format(" and ".join(conditions)) if conditions else ""
def get_view_logs(doctype, docname): """ get and return the latest view logs if available """ logs = [] if hasattr(frappe.get_meta(doctype), 'track_views') and frappe.get_meta(doctype).track_views: view_logs = frappe.get_all("View Log", filters={ "reference_doctype": doctype, "reference_name": docname, }, fields=["name", "creation"], order_by="creation desc") if view_logs: logs = view_logs return logs
def set_new_name(doc): """Sets the `name`` property for the document based on various rules. 1. If amened doc, set suffix. 3. If `autoname` method is declared, then call it. 4. If `autoname` property is set in the DocType (`meta`), then build it using the `autoname` property. 2. If `name` is already defined, use that name 5. If no rule defined, use hash. #### Note: :param doc: Document to be named.""" doc.run_method("before_naming") autoname = frappe.get_meta(doc.doctype).autoname or "" if autoname.lower() != "prompt" and not frappe.flags.in_import: doc.name = None if getattr(doc, "amended_from", None): _set_amended_name(doc) return elif getattr(doc.meta, "issingle", False): doc.name = doc.doctype else: doc.run_method("autoname") if not doc.name and autoname: if autoname.startswith('field:'): fieldname = autoname[6:] doc.name = (doc.get(fieldname) or "").strip() if not doc.name: frappe.throw(_("{0} is required").format(doc.meta.get_label(fieldname))) raise Exception, 'Name is required' if autoname.startswith("naming_series:"): set_name_by_naming_series(doc) elif "#" in autoname: doc.name = make_autoname(autoname) elif autoname.lower()=='prompt': # set from __newname in save.py if not doc.name: frappe.throw(_("Name not set via prompt")) if not doc.name or autoname=='hash': doc.name = make_autoname('hash', doc.doctype) doc.name = validate_name(doc.doctype, doc.name, frappe.get_meta(doc.doctype).get_field("name_case"))
def get_list(doctype, txt, filters, limit_start, limit_page_length=20, ignore_permissions=False, fields=None, order_by=None): meta = frappe.get_meta(doctype) if not filters: filters = [] if not fields: fields = "distinct *" or_filters = [] if txt: if meta.search_fields: for f in meta.get_search_fields(): if f == 'name' or meta.get_field(f).fieldtype in ('Data', 'Text', 'Small Text', 'Text Editor'): or_filters.append([doctype, f, "like", "%" + txt + "%"]) else: if isinstance(filters, dict): filters["name"] = ("like", "%" + txt + "%") else: filters.append([doctype, "name", "like", "%" + txt + "%"]) return frappe.get_list(doctype, fields = fields, filters=filters, or_filters=or_filters, limit_start=limit_start, limit_page_length = limit_page_length, ignore_permissions=ignore_permissions, order_by=order_by)
def add_search_fields(self): """add search fields found in the doctypes indicated by link fields' options""" for df in self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}): if df.options: search_fields = frappe.get_meta(df.options).search_fields if search_fields: df.search_fields = map(lambda sf: sf.strip(), search_fields.split(","))
def get_company_default(company, fieldname): value = frappe.db.get_value("Company", company, fieldname) if not value: throw(_("Please set default value {0} in Company {1}").format(frappe.get_meta("Company").get_label(fieldname), company)) return value
def test_set_only_once(self): blog_post = frappe.get_meta("Blog Post") blog_post.get_field("title").set_only_once = 1 doc = frappe.get_doc("Blog Post", "_test-blog-post-1") doc.title = "New" self.assertRaises(frappe.CannotChangeConstantError, doc.save) blog_post.get_field("title").set_only_once = 0
def update_in_custom_field(self, df, i): meta = frappe.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 = frappe.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 validate_forbidden_types(self): forbidden_document_types = ("Bulk Email",) if (self.document_type in forbidden_document_types or frappe.get_meta(self.document_type).istable): # currently email alerts don't work on child tables as events are not fired for each record of child table frappe.throw(_("Cannot set Email Alert on Document Type {0}").format(self.document_type))
def get_price_list_rate(args, item_doc, out): meta = frappe.get_meta(args.parenttype or args.doctype) if meta.get_field("currency"): validate_price_list(args) validate_conversion_rate(args, meta) price_list_rate = get_price_list_rate_for(args.price_list, item_doc.name) # variant if not price_list_rate and item_doc.variant_of: price_list_rate = get_price_list_rate_for(args.price_list, 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 erpnext.stock.doctype.item.item import get_last_purchase_details out.update(get_last_purchase_details(item_doc.name, args.name, args.conversion_rate))
def check_if_doc_is_dynamically_linked(doc, method="Delete"): for query in dynamic_link_queries: for df in frappe.db.sql(query, as_dict=True): if frappe.get_meta(df.parent).issingle: # dynamic link in single doc refdoc = frappe.db.get_singles_dict(df.parent) if (refdoc.get(df.options)==doc.doctype and refdoc.get(df.fieldname)==doc.name and ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)) ): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype, doc.name, df.parent, ""), frappe.LinkExistsError) else: # dynamic link in table for refdoc in frappe.db.sql("""select name, docstatus from `tab{parent}` where {options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True): if ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)): # raise exception only if # linked to an non-cancelled doc when deleting # or linked to a submitted doc when cancelling frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}")\ .format(doc.doctype, doc.name, df.parent, refdoc.name), frappe.LinkExistsError)
def get_page_context_from_doctypes(): routes = frappe.cache().get_value("website_generator_routes") if not routes: routes = {} for app in frappe.get_installed_apps(): for doctype in frappe.get_hooks("website_generators", app_name = app): condition = "" route_column_name = "page_name" controller = get_controller(doctype) meta = frappe.get_meta(doctype) if meta.get_field("parent_website_route"): route_column_name = """concat(ifnull(parent_website_route, ""), if(ifnull(parent_website_route, "")="", "", "/"), page_name)""" if controller.website.condition_field: condition ="where {0}=1".format(controller.website.condition_field) for r in frappe.db.sql("""select {0} as route, name, modified from `tab{1}` {2}""".format(route_column_name, doctype, condition), as_dict=True): routes[r.route] = {"doctype": doctype, "name": r.name, "modified": r.modified} frappe.cache().set_value("website_generator_routes", routes) return routes
def validate_quantity(doc, args, ref, valid_items, already_returned_items): fields = ['stock_qty'] if doc.doctype in ['Purchase Receipt', 'Purchase Invoice']: fields.extend(['received_qty', 'rejected_qty']) already_returned_data = already_returned_items.get(args.item_code) or {} company_currency = erpnext.get_company_currency(doc.company) stock_qty_precision = get_field_precision(frappe.get_meta(doc.doctype + " Item") .get_field("stock_qty"), company_currency) for column in fields: returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0 if column == 'stock_qty': reference_qty = ref.get(column) current_stock_qty = args.get(column) else: reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0) current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0) max_returnable_qty = flt(reference_qty, stock_qty_precision) - returned_qty label = column.replace('_', ' ').title() if reference_qty: if flt(args.get(column)) > 0: frappe.throw(_("{0} must be negative in return document").format(label)) elif returned_qty >= reference_qty and args.get(column): frappe.throw(_("Item {0} has already been returned") .format(args.item_code), StockOverReturnError) elif abs(flt(current_stock_qty, stock_qty_precision)) > max_returnable_qty: frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}") .format(args.idx, max_returnable_qty, args.item_code), StockOverReturnError)
def get_context(context): """Build context for print""" if not ((frappe.form_dict.doctype and frappe.form_dict.name) or frappe.form_dict.doc): return { "body": """<h1>Error</h1> <p>Parameters doctype and name required</p> <pre>%s</pre>""" % repr(frappe.form_dict) } if frappe.form_dict.doc: doc = frappe.form_dict.doc else: doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name) meta = frappe.get_meta(doc.doctype) print_format = get_print_format_doc(None, meta = meta) return { "body": get_html(doc, print_format = print_format, meta=meta, trigger_print = frappe.form_dict.trigger_print, no_letterhead=frappe.form_dict.no_letterhead), "css": get_print_style(frappe.form_dict.style, print_format), "comment": frappe.session.user, "title": doc.get(meta.title_field) if meta.title_field else doc.name }
def get_series_to_set(): series_to_set = {} for doctype, new_series in doctype_series_map.items(): # you can't fix what does not exist :) if not frappe.db.a_row_exists(doctype): continue series_to_preserve = get_series_to_preserve(doctype, new_series) if not series_to_preserve: continue default_series = get_default_series(doctype, new_series) if not default_series: continue existing_series = (frappe.get_meta(doctype).get_field("naming_series").options or "").split("\n") existing_series = filter(None, [d.strip() for d in existing_series]) if (not (set(existing_series).difference(series_to_preserve) or set(series_to_preserve).difference(existing_series)) and len(series_to_preserve)==len(existing_series)): # print "No change for", doctype, ":", existing_series, "=", series_to_preserve continue # set naming series property setter series_to_preserve = list(set(series_to_preserve + existing_series)) if new_series in series_to_preserve: series_to_preserve.remove(new_series) if series_to_preserve: series_to_set[doctype] = {"options": "\n".join(series_to_preserve), "default": default_series} return series_to_set
def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1): from frappe.model.meta import get_field_precision self.exceptions = [] self.verbose = verbose self.allow_zero_rate = allow_zero_rate self.allow_negative_stock = allow_negative_stock self.via_landed_cost_voucher = via_landed_cost_voucher if not self.allow_negative_stock: self.allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock")) self.args = args for key, value in args.iteritems(): setattr(self, key, value) self.previous_sle = self.get_sle_before_datetime() self.previous_sle = self.previous_sle[0] if self.previous_sle else frappe._dict() for key in ("qty_after_transaction", "valuation_rate", "stock_value"): setattr(self, key, flt(self.previous_sle.get(key))) self.company = frappe.db.get_value("Warehouse", self.warehouse, "company") self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"), currency=frappe.db.get_value("Company", self.company, "default_currency", cache=True)) self.prev_stock_value = self.previous_sle.stock_value or 0.0 self.stock_queue = json.loads(self.previous_sle.stock_queue or "[]") self.valuation_method = get_valuation_method(self.item_code) self.stock_value_difference = 0.0 self.build()
def customer_query(doctype, txt, searchfield, start, page_len, filters): cust_master_name = frappe.defaults.get_user_default("cust_master_name") if cust_master_name == "Customer Name": fields = ["name", "customer_group", "territory"] else: fields = ["name", "customer_name", "customer_group", "territory"] meta = frappe.get_meta("Customer") fields = fields + [f for f in meta.get_search_fields() if not f in fields] fields = ", ".join(fields) return frappe.db.sql("""select {fields} from `tabCustomer` where docstatus < 2 and ({key} like %(txt)s or customer_name like %(txt)s) and disabled=0 {mcond} order by if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), if(locate(%(_txt)s, customer_name), locate(%(_txt)s, customer_name), 99999), idx desc, name, customer_name limit %(start)s, %(page_len)s""".format(**{ "fields": fields, "key": searchfield, "mcond": get_match_cond(doctype) }), { 'txt': "%%%s%%" % txt, '_txt': txt.replace("%", ""), 'start': start, 'page_len': page_len })
def build_match_conditions(self, as_condition=True): """add match conditions if applicable""" self.match_filters = [] self.match_conditions = [] if not self.tables: self.extract_tables() meta = frappe.get_meta(self.doctype) role_permissions = frappe.permissions.get_role_permissions(meta, user=self.user) if not meta.istable and not role_permissions.get("read") and not getattr(self, "ignore_permissions", False): frappe.throw(_("No permission to read {0}").format(self.doctype)) # apply user permissions? if role_permissions.get("apply_user_permissions", {}).get("read"): # get user permissions user_permissions = frappe.defaults.get_user_permissions(self.user) self.add_user_permissions(user_permissions, user_permission_doctypes=role_permissions.get("user_permission_doctypes")) if as_condition: conditions = "" if self.match_conditions: # will turn out like ((blog_post in (..) and blogger in (...)) or (blog_category in (...))) conditions = "((" + ") or (".join(self.match_conditions) + "))" doctype_conditions = self.get_permission_query_conditions() if doctype_conditions: conditions += (' and ' + doctype_conditions) if conditions else doctype_conditions return conditions else: return self.match_filters
def set_user_permission_if_allowed(doctype, name, user, with_message=False): if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions != 1: add_user_permission(doctype, name, user)
def create_qr_code(doc, method=None): region = get_region(doc.company) if region not in ["Saudi Arabia"]: return # if QR Code field not present, create it. Invoices without QR are invalid as per law. if not hasattr(doc, "ksa_einv_qr"): create_custom_fields({ doc.doctype: [ dict( fieldname="ksa_einv_qr", label="KSA E-Invoicing QR", fieldtype="Attach Image", read_only=1, no_copy=1, hidden=1, ) ] }) # Don't create QR Code if it already exists qr_code = doc.get("ksa_einv_qr") if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): return meta = frappe.get_meta(doc.doctype) if "ksa_einv_qr" in [d.fieldname for d in meta.get_image_fields()]: """TLV conversion for 1. Seller's Name 2. VAT Number 3. Time Stamp 4. Invoice Amount 5. VAT Amount """ tlv_array = [] # Sellers Name seller_name = frappe.db.get_value("Company", doc.company, "company_name_in_arabic") if not seller_name: frappe.throw( _("Arabic name missing for {} in the company document").format( doc.company)) tag = bytes([1]).hex() length = bytes([len(seller_name.encode("utf-8"))]).hex() value = seller_name.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # VAT Number tax_id = frappe.db.get_value("Company", doc.company, "tax_id") if not tax_id: frappe.throw( _("Tax ID missing for {} in the company document").format( doc.company)) tag = bytes([2]).hex() length = bytes([len(tax_id)]).hex() value = tax_id.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # Time Stamp posting_date = getdate(doc.posting_date) time = get_time(doc.posting_time) seconds = time.hour * 60 * 60 + time.minute * 60 + time.second time_stamp = add_to_date(posting_date, seconds=seconds) time_stamp = time_stamp.strftime("%Y-%m-%dT%H:%M:%SZ") tag = bytes([3]).hex() length = bytes([len(time_stamp)]).hex() value = time_stamp.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # Invoice Amount invoice_amount = str(doc.grand_total) tag = bytes([4]).hex() length = bytes([len(invoice_amount)]).hex() value = invoice_amount.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # VAT Amount vat_amount = str(get_vat_amount(doc)) tag = bytes([5]).hex() length = bytes([len(vat_amount)]).hex() value = vat_amount.encode("utf-8").hex() tlv_array.append("".join([tag, length, value])) # Joining bytes into one tlv_buff = "".join(tlv_array) # base64 conversion for QR Code base64_string = b64encode(bytes.fromhex(tlv_buff)).decode() qr_image = io.BytesIO() url = qr_create(base64_string, error="L") url.png(qr_image, scale=2, quiet_zone=1) name = frappe.generate_hash(doc.name, 5) # making file filename = f"QRCode-{name}.png".replace(os.path.sep, "__") _file = frappe.get_doc({ "doctype": "File", "file_name": filename, "is_private": 0, "content": qr_image.getvalue(), "attached_to_doctype": doc.get("doctype"), "attached_to_name": doc.get("name"), "attached_to_field": "ksa_einv_qr", }) _file.save() # assigning to document doc.db_set("ksa_einv_qr", _file.file_url) doc.notify_update()
def init_list(doctype): """Make boilerplate list views.""" doc = frappe.get_meta(doctype) make_boilerplate("controller_list.js", doc) make_boilerplate("controller_list.html", doc)
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): conditions = [] #Get searchfields from meta and use in Item Link field query meta = frappe.get_meta("Item", cached=True) searchfields = meta.get_search_fields() if "description" in searchfields: searchfields.remove("description") columns = '' extra_searchfields = [ field for field in searchfields if not field in ["name", "item_group", "description"] ] if extra_searchfields: columns = ", " + ", ".join(extra_searchfields) searchfields = searchfields + [ field for field in [searchfield or "name", "item_code", "item_group", "item_name"] if not field in searchfields ] searchfields = " or ".join( [field + " like %(txt)s" for field in searchfields]) description_cond = '' if frappe.db.count('Item', cache=True) < 50000: # scan description only if items are less than 50000 description_cond = 'or tabItem.description LIKE %(txt)s' return frappe.db.sql("""select tabItem.name, if(length(tabItem.item_name) > 40, concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, tabItem.item_group, if(length(tabItem.description) > 40, \ concat(substr(tabItem.description, 1, 40), "..."), description) as description {columns} from tabItem where tabItem.docstatus < 2 and tabItem.disabled=0 and tabItem.has_variants=0 and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00') and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s) {description_cond}) {fcond} {mcond} order by if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), if(locate(%(_txt)s, item_name), locate(%(_txt)s, item_name), 99999), idx desc, name, item_name limit %(start)s, %(page_len)s """.format( key=searchfield, columns=columns, scond=searchfields, fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'), mcond=get_match_cond(doctype).replace('%', '%%'), description_cond=description_cond), { "today": nowdate(), "txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len }, as_dict=as_dict)
def rebuild_for_doctype(doctype): """ Rebuild entries of doctype's documents in __global_search on change of searchable fields :param doctype: Doctype """ def _get_filters(): filters = frappe._dict({"docstatus": ["!=", 2]}) if meta.has_field("enabled"): filters.enabled = 1 if meta.has_field("disabled"): filters.disabled = 0 return filters meta = frappe.get_meta(doctype) if cint(meta.istable) == 1: parent_doctypes = frappe.get_all("DocField", fields="parent", filters={ "fieldtype": "Table", "options": doctype }) for p in parent_doctypes: rebuild_for_doctype(p.parent) return # Delete records delete_global_search_records_for_doctype(doctype) parent_search_fields = meta.get_global_search_fields() fieldnames = get_selected_fields(meta, parent_search_fields) # Get all records from parent doctype table all_records = frappe.get_all(doctype, fields=fieldnames, filters=_get_filters()) # Children data all_children, child_search_fields = get_children_data(doctype, meta) all_contents = [] for doc in all_records: content = [] for field in parent_search_fields: value = doc.get(field.fieldname) if value: content.append(get_formatted_value(value, field)) # get children data for child_doctype, records in all_children.get(doc.name, {}).items(): for field in child_search_fields.get(child_doctype): for r in records: if r.get(field.fieldname): content.append( get_formatted_value(r.get(field.fieldname), field)) if content: # if doctype published in website, push title, route etc. published = 0 title, route = "", "" try: if hasattr( get_controller(doctype), "is_website_published") and meta.allow_guest_to_view: d = frappe.get_doc(doctype, doc.name) published = 1 if d.is_website_published() else 0 title = d.get_title() route = d.get("route") except ImportError: # some doctypes has been deleted via future patch, hence controller does not exists pass all_contents.append({ "doctype": frappe.db.escape(doctype), "name": frappe.db.escape(doc.name), "content": frappe.db.escape(' ||| '.join(content or '')), "published": published, "title": frappe.db.escape(title or '')[:int(varchar_len)], "route": frappe.db.escape(route or '')[:int(varchar_len)] }) if all_contents: insert_values_for_multiple_docs(all_contents)
def get_graph_new(graph_list): months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] today = getdate(nowdate()) chartslist = [] if frappe.db.get_value('DocType', 'Catalog Settings'): default_currency = frappe.db.get_single_value('Catalog Settings', 'default_currency') currency_symbol = frappe.get_value('Currency', default_currency, 'symbol') elif frappe.db.get_value('DocType', 'Global Defaults'): default_currency = frappe.db.get_single_value('Global Defaults', 'default_currency') currency_symbol = frappe.get_value('Currency', default_currency, 'symbol') else: currency_symbol = None if graph_list: for item in graph_list: chart = frappe.get_doc('Dashboard Items', item.name) res = frappe.db.sql( '''select count(*) as count from `tab{doctype}`'''.format( doctype=chart.reference_doctype), as_dict=1) color = [] datasets = [] docfields = frappe.get_meta(chart.reference_doctype).get("fields") currency = False ignore_permissions = False if chart.check_user_permissions else True if chart.datasets: for it in chart.datasets: d_val = [] month = 0 while month < 12: month = month + 1 st_date = datetime(year=today.year, day=01, month=month) next_month = st_date.replace(day=28) + timedelta( days=4) ed_date = next_month - timedelta(days=next_month.day) filters_g = [] if chart.conditions: for c in chart.conditions: if c.condition_for == it.name: filters_g.append(get_conditions(c)) filt1 = ["creation", ">=", st_date] filt2 = ["creation", "<=", ed_date] filters_g.append(filt1) filters_g.append(filt2) result = frappe.get_list( chart.reference_doctype, fields=['*'], filters=filters_g, ignore_permissions=ignore_permissions, limit_page_length=res[0].count) if it.fieldname != 'Name': docs = next((x.fieldtype for x in docfields if x.fieldname == it.fieldname), None) else: docs = 'Link' if docs == 'Int' or docs == 'Float' or docs == 'Currency': total = sum(res[it.fieldname] for res in result) d_val.append(("%0.2f" % total)) else: d_val.append(len(result)) if docs == 'Currency': currency = True datasets.append({ 'values': d_val, 'name': it.label, 'chartType': it.chart_type.lower() }) color.append(it.color) ids = item.name.replace(' ', '').lower() chartslist.append({ 'label': months, 'dataset': datasets, 'title': chart.display_text, 'id': ids, 'color': color, 'type': chart.graph_type.lower(), 'size': item.display_type, 'dot_size': item.dot_size, 'space_ratio': item.space_ratio, 'hide_dots': item.hide_dots, 'hide_line': item.hide_line, 'heat_line': item.heat_line, 'values_over_points': item.values_over_points, 'navigate': item.navigate, 'height': item.chart_height, 'currency': currency, 'currency_symbol': currency_symbol }) else: filters = [] docs = next( (x.fieldname for x in docfields if x.label == chart.date_fields), None) query = '''select distinct {date_fields} from `tab{doctype}` '''.format( date_fields=docs, doctype=chart.reference_doctype) distinct_records = frappe.db.sql(query, as_dict=1) results = [] for dis in distinct_records: filters = [] if chart.conditions: for c in chart.conditions: if c.condition_for == it.name: filters.append(get_conditions(c)) fil = [docs, '=', dis.status] filters.append(fil) response = frappe.get_list( chart.reference_doctype, filters=filters, fields=[docs], ignore_permissions=ignore_permissions, limit_page_length=res[0].count) if chart.value_type == 'Count': results.append({ 'label': dis.status, 'value': len(response) }) else: total = sum(res[docs] for res in response) results.append({'label': dis, 'value': total}) label = [res['label'] for res in results] value = [res['value'] for res in results] ids = item.name.replace(' ', '').lower() datasets = [] datasets.append({ 'values': value, 'name': 'Test', 'chartType': chart.graph_type.lower() }) colors = [] if chart.color: colors.append(chart.color.split('\n')) chartslist.append({ 'label': label, 'dataset': datasets, 'title': chart.display_text, 'id': ids, 'color': colors, 'type': chart.graph_type.lower() }) return chartslist
def meta(self): if not hasattr(self, "_meta"): self._meta = frappe.get_meta(self.doctype) return self._meta
def get_invalid_links(self, is_submittable=False): """Returns list of invalid links and also updates fetch values if not set""" def get_msg(df, docname): if self.parentfield: return "{} #{}: {}: {}".format(_("Row"), self.idx, _(df.label), docname) else: return "{}: {}".format(_(df.label), docname) invalid_links = [] cancelled_links = [] for df in ( self.meta.get_link_fields() + self.meta.get("fields", {"fieldtype": ('=', "Dynamic Link")})): docname = self.get(df.fieldname) if docname: if df.fieldtype == "Link": doctype = df.options if not doctype: frappe.throw( _("Options not set for link field {0}").format( df.fieldname)) else: doctype = self.get(df.options) if not doctype: frappe.throw( _("{0} must be set first").format( self.meta.get_label(df.options))) # MySQL is case insensitive. Preserve case of the original docname in the Link Field. # get a map of values ot fetch along with this link query # that are mapped as link_fieldname.source_fieldname in Options of # Readonly or Data or Text type fields fields_to_fetch = [ _df for _df in self.meta.get_fields_to_fetch(df.fieldname) if not _df.get('fetch_if_empty') or (_df.get('fetch_if_empty') and not self.get(_df.fieldname)) ] if not fields_to_fetch: # cache a single value type values = frappe._dict(name=frappe.db.get_value( doctype, docname, 'name', cache=True)) else: values_to_fetch = ['name'] + [ _df.fetch_from.split('.')[-1] for _df in fields_to_fetch ] # don't cache if fetching other values too values = frappe.db.get_value(doctype, docname, values_to_fetch, as_dict=True) if frappe.get_meta(doctype).issingle: values.name = doctype if values: setattr(self, df.fieldname, values.name) for _df in fields_to_fetch: if self.is_new( ) or self.docstatus != 1 or _df.allow_on_submit: self.set_fetch_from_value(doctype, _df, values) notify_link_count(doctype, docname) if not values.name: invalid_links.append( (df.fieldname, docname, get_msg(df, docname))) elif (df.fieldname != "amended_from" and (is_submittable or self.meta.is_submittable) and frappe.get_meta(doctype).is_submittable and cint( frappe.db.get_value(doctype, docname, "docstatus")) == 2): cancelled_links.append( (df.fieldname, docname, get_msg(df, docname))) return invalid_links, cancelled_links
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
def get_options(self, arg=None): if frappe.get_meta( arg or self.select_doc_for_series).get_field("naming_series"): return frappe.get_meta( arg or self.select_doc_for_series).get_field("naming_series").options
def get_itemised_tax_breakup_header(item_doctype, tax_accounts): if frappe.get_meta(item_doctype).has_field('gst_hsn_code'): return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts else: return [_("Item"), _("Taxable Amount")] + tax_accounts
def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): """Returns True if user has permission `ptype` for given `doctype`. If `doc` is passed, it also checks user, share and owner permissions. Note: if Table DocType is passed, it always returns True. """ if not user: user = frappe.session.user if not doc and hasattr(doctype, 'doctype'): # first argument can be doc or doctype doc = doctype doctype = doc.doctype if frappe.is_table(doctype): return True if user == "Administrator": return True meta = frappe.get_meta(doctype) if doc: if isinstance(doc, string_types): doc = frappe.get_doc(meta.name, doc) perm = get_doc_permissions(doc, user=user, ptype=ptype).get(ptype) if not perm: push_perm_check_log('User do not have document access') else: if ptype == "submit" and not cint(meta.is_submittable): push_perm_check_log("Doctype is not submittable") return False if ptype == "import" and not cint(meta.allow_import): push_perm_check_log("Doctype is not importable") return False role_permissions = get_role_permissions(meta, user=user) perm = role_permissions.get(ptype) if not perm: push_perm_check_log( 'User do not have doctype access via role permission') def false_if_not_shared(): if ptype in ("read", "write", "share", "email", "print"): shared = frappe.share.get_shared( doctype, user, ["read" if ptype in ("email", "print") else ptype]) if doc: doc_name = get_doc_name(doc) if doc_name in shared: if ptype in ("read", "write", "share") or meta.permissions[0].get(ptype): return True elif shared: # if atleast one shared doc of that type, then return True # this is used in db_query to check if permission on DocType return True return False if not perm: perm = false_if_not_shared() return perm
def get_default_series(doctype): field = frappe.get_meta(doctype).get_field("naming_series") default_series = field.get("default", "") if field else "" return default_series
def get_filter(doctype, f, filters_config=None): """Returns a _dict like { "doctype": "fieldname": "operator": "value": "fieldtype": } """ from frappe.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)): frappe.throw(frappe._("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: frappe.throw(frappe._("Filter must have 4 values (doctype, fieldname, operator, value): {0}").format(str(f))) f = frappe._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", "is", "between", "descendants of", "ancestors of", "not descendants of", "not ancestors of", "timespan", "previous", "next") if filters_config: additional_operators = [] for key in filters_config: additional_operators.append(key.lower()) valid_operators = tuple(set(valid_operators + tuple(additional_operators))) if f.operator.lower() not in valid_operators: frappe.throw(frappe._("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 = frappe.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 frappe.get_meta(df.options).has_field(f.fieldname): f.doctype = df.options break try: df = frappe.get_meta(f.doctype).get_field(f.fieldname) except frappe.exceptions.DoesNotExistError: df = None f.fieldtype = df.fieldtype if df else None return f
def accept(web_form, data, docname=None, for_payment=False): '''Save the web form''' data = frappe._dict(json.loads(data)) for_payment = frappe.parse_json(for_payment) files = [] files_to_delete = [] web_form = frappe.get_doc("Web Form", web_form) if data.name and not web_form.allow_edit: frappe.throw(_("You are not allowed to update this Web Form Document")) frappe.flags.in_web_form = True meta = frappe.get_meta(data.doctype) if docname: # update doc = frappe.get_doc(data.doctype, docname) else: # insert doc = frappe.new_doc(data.doctype) # set values for field in web_form.web_form_fields: fieldname = field.fieldname df = meta.get_field(fieldname) value = data.get(fieldname, None) if df and df.fieldtype in ('Attach', 'Attach Image'): if value and 'data:' and 'base64' in value: files.append((fieldname, value)) if not doc.name: doc.set(fieldname, '') continue elif not value and doc.get(fieldname): files_to_delete.append(doc.get(fieldname)) doc.set(fieldname, value) if for_payment: web_form.validate_mandatory(doc) doc.run_method('validate_payment') if doc.name: if has_web_form_permission(doc.doctype, doc.name, "write"): doc.save(ignore_permissions=True) else: # only if permissions are present doc.save() else: # insert if web_form.login_required and frappe.session.user == "Guest": frappe.throw(_("You must login to submit this form")) ignore_mandatory = True if files else False doc.insert(ignore_permissions=True, ignore_mandatory=ignore_mandatory) # add files if files: for f in files: fieldname, filedata = f # remove earlier attached file (if exists) if doc.get(fieldname): remove_file_by_url(doc.get(fieldname), doctype=doc.doctype, name=doc.name) # save new file filename, dataurl = filedata.split(',', 1) _file = frappe.get_doc({ "doctype": "File", "file_name": filename, "attached_to_doctype": doc.doctype, "attached_to_name": doc.name, "content": dataurl, "decode": True }) _file.save() # update values doc.set(fieldname, _file.file_url) doc.save(ignore_permissions=True) if files_to_delete: for f in files_to_delete: if f: remove_file_by_url(doc.get(fieldname), doctype=doc.doctype, name=doc.name) frappe.flags.web_form_doc = doc if for_payment: return web_form.get_payment_gateway_url(doc) else: return doc
else: return None def validate_name(doctype, name, case=None, merge=False): if not name: return 'No Name Specified for %s' % doctype if name.startswith('New '+doctype): frappe.throw(_('There were some errors setting the name, please contact the administrator'), frappe.NameError) if case == 'Title Case': name = name.title() if case == 'UPPER CASE': name = name.upper() name = name.strip() if not frappe.get_meta(doctype).get("issingle") and (doctype == name) and (name != "DocType"): frappe.throw(_("Name of {0} cannot be {1}").format(doctype, name), frappe.NameError) special_characters = "<>" if re.findall("[{0}]+".format(special_characters), name): frappe.log_error("{0}-/{1}".format(name, re.findall("[{0}]+".format(special_characters), name))) message = ", ".join("'{0}'".format(c) for c in special_characters) frappe.throw(_("Name cannot contain special characters like {0} - {1}").format(message, name), frappe.NameError) return name def append_number_if_name_exists(doctype, value, fieldname='name', separator='-', filters=None): if not filters: filters = dict() filters.update({fieldname: value})
def get_monthly_goal_graph_data( title, doctype, docname, goal_value_field, goal_total_field, goal_history_field, goal_doctype, goal_doctype_link, goal_field, date_field, filter_str, aggregation="sum", ): """ Get month-wise graph data for a doctype based on aggregation values of a field in the goal doctype :param title: Graph title :param doctype: doctype of graph doc :param docname: of the doc to set the graph in :param goal_value_field: goal field of doctype :param goal_total_field: current month value field of doctype :param goal_history_field: cached history field :param goal_doctype: doctype the goal is based on :param goal_doctype_link: doctype link field in goal_doctype :param goal_field: field from which the goal is calculated :param filter_str: where clause condition :param aggregation: a value like 'count', 'sum', 'avg' :return: dict of graph data """ import json from frappe.utils.formatters import format_value # should have atleast read perm if not frappe.has_permission(goal_doctype): return None meta = frappe.get_meta(doctype) doc = frappe.get_doc(doctype, docname) goal = doc.get(goal_value_field) formatted_goal = format_value(goal, meta.get_field(goal_value_field), doc) current_month_value = doc.get(goal_total_field) formatted_value = format_value(current_month_value, meta.get_field(goal_total_field), doc) from frappe.utils import add_months, formatdate, getdate, today current_month_year = formatdate(today(), "MM-yyyy") history = doc.get(goal_history_field) try: month_to_value_dict = json.loads( history) if history and "{" in history else None except ValueError: month_to_value_dict = None if month_to_value_dict is None: doc_filter = ((goal_doctype_link + " = " + frappe.db.escape(docname)) if doctype != goal_doctype else "") if filter_str: doc_filter += " and " + filter_str if doc_filter else filter_str month_to_value_dict = get_monthly_results(goal_doctype, goal_field, date_field, doc_filter, aggregation) month_to_value_dict[current_month_year] = current_month_value months = [] months_formatted = [] values = [] values_formatted = [] for i in range(0, 12): date_value = add_months(today(), -i) month_value = formatdate(date_value, "MM-yyyy") month_word = getdate(date_value).strftime("%b %y") month_year = getdate(date_value).strftime("%B") + ", " + getdate( date_value).strftime("%Y") months.insert(0, month_word) months_formatted.insert(0, month_year) if month_value in month_to_value_dict: val = month_to_value_dict[month_value] else: val = 0 values.insert(0, val) values_formatted.insert( 0, format_value(val, meta.get_field(goal_total_field), doc)) y_markers = [] summary_values = [{ "title": _("This month"), "color": "#ffa00a", "value": formatted_value }] if float(goal) > 0: y_markers = [ { "label": _("Goal"), "lineType": "dashed", "value": goal }, ] summary_values += [ { "title": _("Goal"), "color": "#5e64ff", "value": formatted_goal }, { "title": _("Completed"), "color": "#28a745", "value": str(int(round(float(current_month_value) / float(goal) * 100))) + "%", }, ] data = { "title": title, # 'subtitle': "data": { "datasets": [{ "values": values, "formatted": values_formatted }], "labels": months, }, "summary": summary_values, } if y_markers: data["data"]["yMarkers"] = y_markers return data
def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data="No"): all_doctypes = all_doctypes=="Yes" if not parent_doctype: parent_doctype = doctype column_start_end = {} if all_doctypes: doctype_parentfield = {} child_doctypes = [] for df in frappe.get_meta(doctype).get_table_fields(): child_doctypes.append(df.options) doctype_parentfield[df.options] = df.fieldname def add_main_header(): w.writerow(['Data Import Template']) w.writerow([data_keys.main_table, doctype]) if parent_doctype != doctype: w.writerow([data_keys.parent_table, parent_doctype]) else: w.writerow(['']) w.writerow(['']) w.writerow(['Notes:']) w.writerow(['Please do not change the template headings.']) w.writerow(['First data column must be blank.']) w.writerow(['If you are uploading new records, leave the "name" (ID) column blank.']) w.writerow(['If you are uploading new records, "Naming Series" becomes mandatory, if present.']) w.writerow(['Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.']) w.writerow(['For updating, you can update only selective columns.']) w.writerow(['You can only upload upto 5000 records in one go. (may be less in some cases)']) if key == "parent": w.writerow(['"Parent" signifies the parent table in which this row must be added']) w.writerow(['If you are updating, please select "Overwrite" else existing rows will not be deleted.']) def build_field_columns(dt): meta = frappe.get_meta(dt) tablecolumns = filter(None, [(meta.get_field(f[0]) or None) for f in frappe.db.sql('desc `tab%s`' % dt)]) tablecolumns.sort(lambda a, b: a.idx - b.idx) if dt==doctype: column_start_end[dt] = frappe._dict({"start": 0}) else: column_start_end[dt] = frappe._dict({"start": len(columns)}) append_field_column(frappe._dict({ "fieldname": "name", "label": "ID", "fieldtype": "Data", "reqd": 1, "idx": 0, "info": "Leave blank for new records" }), True) for docfield in tablecolumns: append_field_column(docfield, True) # all non mandatory fields for docfield in tablecolumns: append_field_column(docfield, False) # append DocType name tablerow[column_start_end[dt].start + 1] = dt if dt!=doctype: tablerow[column_start_end[dt].start + 2] = doctype_parentfield[dt] column_start_end[dt].end = len(columns) + 1 def append_field_column(docfield, mandatory): if docfield and ((mandatory and docfield.reqd) or not (mandatory or docfield.reqd)) \ and (docfield.fieldname not in ('parenttype', 'trash_reason')) and not docfield.hidden: tablerow.append("") fieldrow.append(docfield.fieldname) labelrow.append(docfield.label) mandatoryrow.append(docfield.reqd and 'Yes' or 'No') typerow.append(docfield.fieldtype) inforow.append(getinforow(docfield)) columns.append(docfield.fieldname) def append_empty_field_column(): tablerow.append("~") fieldrow.append("~") labelrow.append("") mandatoryrow.append("") typerow.append("") inforow.append("") columns.append("") def getinforow(docfield): """make info comment for options, links etc.""" if docfield.fieldtype == 'Select': if not docfield.options: return '' elif docfield.options.startswith('link:'): return 'Valid %s' % docfield.options[5:] else: return 'One of: %s' % ', '.join(filter(None, docfield.options.split('\n'))) elif docfield.fieldtype == 'Link': return 'Valid %s' % docfield.options elif docfield.fieldtype == 'Int': return 'Integer' elif docfield.fieldtype == "Check": return "0 or 1" elif hasattr(docfield, "info"): return docfield.info else: return '' def add_field_headings(): w.writerow(tablerow) w.writerow(labelrow) w.writerow(fieldrow) w.writerow(mandatoryrow) w.writerow(typerow) w.writerow(inforow) w.writerow([data_keys.data_separator]) def add_data(): def add_data_row(row_group, dt, doc, rowidx): d = doc.copy() if all_doctypes: d.name = '"'+ d.name+'"' if len(row_group) < rowidx + 1: row_group.append([""] * (len(columns) + 1)) row = row_group[rowidx] for i, c in enumerate(columns[column_start_end[dt].start:column_start_end[dt].end]): row[column_start_end[dt].start + i + 1] = d.get(c, "") if with_data=='Yes': frappe.permissions.can_export(parent_doctype, raise_exception=True) # get permitted data only data = frappe.get_list(doctype, fields=["*"], limit_page_length=None) for doc in data: # add main table row_group = [] add_data_row(row_group, doctype, doc, 0) if all_doctypes: # add child tables for child_doctype in child_doctypes: for ci, child in enumerate(frappe.db.sql("""select * from `tab%s` where parent=%s order by idx""" % (child_doctype, "%s"), doc.name, as_dict=1)): add_data_row(row_group, child_doctype, child, ci) for row in row_group: w.writerow(row) w = UnicodeWriter() key = 'parent' if parent_doctype != doctype else 'name' add_main_header() w.writerow(['']) tablerow = [data_keys.doctype, ""] labelrow = ["Column Labels:", "ID"] fieldrow = [data_keys.columns, key] mandatoryrow = ['Mandatory:', 'Yes'] typerow = ['Type:', 'Data (text)'] inforow = ['Info:', ''] columns = [key] build_field_columns(doctype) if all_doctypes: for d in child_doctypes: append_empty_field_column() build_field_columns(d) add_field_headings() add_data() # write out response as a type csv frappe.response['result'] = cstr(w.getvalue()) frappe.response['type'] = 'csv' frappe.response['doctype'] = doctype
def migrate_doctype(self, doctype, filters=None, update=None, verbose=1, exclude=None, preprocess=None): """Migrate records from another doctype""" meta = frappe.get_meta(doctype) tables = {} for df in meta.get_table_fields(): if verbose: print("getting " + df.options) tables[df.fieldname] = self.get_list(df.options, limit_page_length=999999) # get links if verbose: print("getting " + doctype) docs = self.get_list(doctype, limit_page_length=999999, filters=filters) # build - attach children to parents if tables: docs = [frappe._dict(doc) for doc in docs] docs_map = dict((doc.name, doc) for doc in docs) for fieldname in tables: for child in tables[fieldname]: child = frappe._dict(child) if child.parent in docs_map: docs_map[child.parent].setdefault(fieldname, []).append(child) if verbose: print("inserting " + doctype) for doc in docs: if exclude and doc["name"] in exclude: continue if preprocess: preprocess(doc) if not doc.get("owner"): doc["owner"] = "Administrator" if doctype != "User" and not frappe.db.exists( "User", doc.get("owner")): frappe.get_doc({ "doctype": "User", "email": doc.get("owner"), "first_name": doc.get("owner").split("@")[0] }).insert() if update: doc.update(update) doc["doctype"] = doctype new_doc = frappe.get_doc(doc) new_doc.insert() if not meta.istable: if doctype != "Communication": self.migrate_doctype( "Communication", { "reference_doctype": doctype, "reference_name": doc["name"] }, update={"reference_name": new_doc.name}, verbose=0) if doctype != "File": self.migrate_doctype( "File", { "attached_to_doctype": doctype, "attached_to_name": doc["name"] }, update={"attached_to_name": new_doc.name}, verbose=0)
def get_basic_details(args, item): """ :param args: { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "price_list_uom_dependant": None, "plc_conversion_rate": 1.0, "doctype": "", "name": "", "supplier": None, "transaction_date": None, "conversion_rate": 1.0, "buying_price_list": None, "is_subcontracted": "Yes" / "No", "ignore_pricing_rule": 0/1 "project": "", barcode: "", serial_no: "", currency: "", update_stock: "", price_list: "", company: "", order_type: "", is_pos: "", project: "", qty: "", stock_qty: "", conversion_factor: "" } :param item: `item_code` of Item object :return: frappe._dict """ if not item: item = frappe.get_doc("Item", args.get("item_code")) if item.variant_of: item.update_template_tables() from frappe.defaults import get_user_default_as_list user_default_warehouse_list = get_user_default_as_list('Warehouse') user_default_warehouse = user_default_warehouse_list[0] \ if len(user_default_warehouse_list) == 1 else "" item_defaults = get_item_defaults(item.name, args.company) item_group_defaults = get_item_group_defaults(item.name, args.company) warehouse = args.get("set_warehouse") or user_default_warehouse or item_defaults.get("default_warehouse") or\ item_group_defaults.get("default_warehouse") or args.warehouse if args.get('doctype') == "Material Request" and not args.get( 'material_request_type'): args['material_request_type'] = frappe.db.get_value( 'Material Request', args.get('name'), 'material_request_type', cache=True) #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master if not args.uom: if args.get('doctype') in sales_doctypes: args.uom = item.sales_uom if item.sales_uom else item.stock_uom elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \ (args.get('doctype') == 'Material Request' and args.get('material_request_type') == 'Purchase'): args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom else: args.uom = item.stock_uom out = frappe._dict({ "item_code": item.name, "item_name": item.item_name, "description": cstr(item.description).strip(), "image": cstr(item.image).strip(), "warehouse": warehouse, "income_account": get_default_income_account(args, item_defaults, item_group_defaults), "expense_account": get_default_expense_account(args, item_defaults, item_group_defaults), "cost_center": get_default_cost_center(args, item_defaults, item_group_defaults), 'has_serial_no': item.has_serial_no, 'has_batch_no': item.has_batch_no, "batch_no": None, "item_tax_rate": json.dumps(dict( ([d.tax_type, d.tax_rate] for d in item.get("taxes")))), "uom": args.uom, "min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "", "qty": args.qty or 1.0, "stock_qty": args.qty or 1.0, "price_list_rate": 0.0, "base_price_list_rate": 0.0, "rate": 0.0, "base_rate": 0.0, "amount": 0.0, "base_amount": 0.0, "net_rate": 0.0, "net_amount": 0.0, "discount_percentage": 0.0, "supplier": get_default_supplier(args, item_defaults, item_group_defaults), "update_stock": args.get("update_stock") if args.get('doctype') in ['Sales Invoice', 'Purchase Invoice'] else 0, "delivered_by_supplier": item.delivered_by_supplier if args.get("doctype") in ["Sales Order", "Sales Invoice"] else 0, "is_fixed_asset": item.is_fixed_asset, "weight_per_unit": item.weight_per_unit, "weight_uom": item.weight_uom, "last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0, "transaction_date": args.get("transaction_date") }) if item.get("enable_deferred_revenue") or item.get( "enable_deferred_expense"): out.update(calculate_service_end_date(args, item)) # calculate conversion factor if item.stock_uom == args.uom: out.conversion_factor = 1.0 else: out.conversion_factor = args.conversion_factor or \ get_conversion_factor(item.name, args.uom).get("conversion_factor") args.conversion_factor = out.conversion_factor out.stock_qty = out.qty * out.conversion_factor # calculate last purchase rate if args.get('doctype') in purchase_doctypes: from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate out.last_purchase_rate = item_last_purchase_rate( args.name, args.conversion_rate, item.name, out.conversion_factor) # if default specified in item is for another company, fetch from company for d in [["Account", "income_account", "default_income_account"], ["Account", "expense_account", "default_expense_account"], ["Cost Center", "cost_center", "cost_center"], ["Warehouse", "warehouse", ""]]: if not out[d[1]]: out[d[1]] = frappe.get_cached_value('Company', args.company, d[2]) if d[2] else None for fieldname in ("item_name", "item_group", "barcodes", "brand", "stock_uom"): out[fieldname] = item.get(fieldname) child_doctype = args.doctype + ' Item' meta = frappe.get_meta(child_doctype) if meta.get_field("barcode"): update_barcode_value(out) return out
def get_asset_naming_series(): meta = frappe.get_meta("Asset") return meta.get_field("naming_series").options
def get_doctype_options(): doctype = frappe.form_dict['doctype'] return [doctype] + [d.options for d in frappe.get_meta(doctype).get_table_fields()]
def add(args=None): """add in someone's to do list args = { "assign_to": , "doctype": , "name": , "description": , "assignment_rule": } """ if not args: args = frappe.local.form_dict if frappe.db.sql( """SELECT `owner` FROM `tabToDo` WHERE `reference_type`=%(doctype)s AND `reference_name`=%(name)s AND `status`='Open' AND `owner`=%(assign_to)s""", args): frappe.throw(_("Already in user's To Do list"), DuplicateToDoError) else: from frappe.utils import nowdate if not args.get('description'): args['description'] = _('Assignment for {0} {1}'.format( args['doctype'], args['name'])) d = frappe.get_doc({ "doctype": "ToDo", "owner": args['assign_to'], "reference_type": args['doctype'], "reference_name": args['name'], "description": args.get('description'), "priority": args.get("priority", "Medium"), "status": "Open", "date": args.get('date', nowdate()), "assigned_by": args.get('assigned_by', frappe.session.user), 'assignment_rule': args.get('assignment_rule') }).insert(ignore_permissions=True) # set assigned_to if field exists if frappe.get_meta(args['doctype']).get_field("assigned_to"): frappe.db.set_value(args['doctype'], args['name'], "assigned_to", args['assign_to']) doc = frappe.get_doc(args['doctype'], args['name']) # if assignee does not have permissions, share if not frappe.has_permission(doc=doc, user=args['assign_to']): frappe.share.add(doc.doctype, doc.name, args['assign_to']) frappe.msgprint(_('Shared with user {0} with read access').format( args['assign_to']), alert=True) # make this document followed by assigned user follow_document(args['doctype'], args['name'], args['assign_to']) # notify notify_assignment(d.assigned_by, d.owner, d.reference_type, d.reference_name, action='ASSIGN',\ description=args.get("description")) return get(args)
def set_property_setters(self): meta = frappe.get_meta(self.doc_type) # doctype property setters for property in doctype_properties: if self.get(property) != meta.get(property): self.make_property_setter( property=property, value=self.get(property), property_type=doctype_properties[property]) for df in self.get("fields"): meta_df = meta.get("fields", {"fieldname": df.fieldname}) if not meta_df or meta_df[0].get("is_custom_field"): continue for property in docfield_properties: if property != "idx" and (df.get(property) or '') != ( meta_df[0].get(property) or ''): if property == "fieldtype": self.validate_fieldtype_change( df, meta_df[0].get(property), df.get(property)) elif property == "allow_on_submit" and df.get(property): frappe.msgprint(_("Row {0}: Not allowed to enable Allow on Submit for standard fields")\ .format(df.idx)) continue elif property == "reqd" and \ ((frappe.db.get_value("DocField", {"parent":self.doc_type,"fieldname":df.fieldname}, "reqd") == 1) \ and (df.get(property) == 0)): frappe.msgprint(_("Row {0}: Not allowed to disable Mandatory for standard fields")\ .format(df.idx)) continue elif property == "in_list_view" and df.get(property) \ and df.fieldtype!="Attach Image" and df.fieldtype in no_value_fields: frappe.msgprint( _("'In List View' not allowed for type {0} in row {1}" ).format(df.fieldtype, df.idx)) continue elif property == "precision" and cint(df.get("precision")) > 6 \ and cint(df.get("precision")) > cint(meta_df[0].get("precision")): self.flags.update_db = True elif property == "unique": self.flags.update_db = True elif (property == "read_only" and cint(df.get("read_only")) == 0 and frappe.db.get_value("DocField", { "parent": self.doc_type, "fieldname": df.fieldname }, "read_only") == 1): # if docfield has read_only checked and user is trying to make it editable, don't allow it frappe.msgprint( _("You cannot unset 'Read Only' for field {0}"). format(df.label)) continue elif property == "options" and df.get( "fieldtype" ) not in allowed_fieldtype_for_options_change: frappe.msgprint( _("You can't set 'Options' for field {0}").format( df.label)) continue elif property == 'translatable' and not supports_translation( df.get('fieldtype')): frappe.msgprint( _("You can't set 'Translatable' for field {0}"). format(df.label)) continue self.make_property_setter( property=property, value=df.get(property), property_type=docfield_properties[property], fieldname=df.fieldname)
def get_tax_accounts(item_list, columns, company_currency, doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"): import json item_row_map = {} tax_columns = [] invoice_item_row = {} itemised_tax = {} tax_amount_precision = get_field_precision( frappe.get_meta(tax_doctype).get_field("tax_amount"), currency=company_currency) or 2 for d in item_list: invoice_item_row.setdefault(d.parent, []).append(d) item_row_map.setdefault(d.parent, {}).setdefault(d.item_code or d.item_name, []).append(d) conditions = "" if doctype == "Purchase Invoice": conditions = " and category in ('Total', 'Valuation and Total') and base_tax_amount_after_discount_amount != 0" deducted_tax = get_deducted_taxes() tax_details = frappe.db.sql( """ select name, parent, description, item_wise_tax_detail, charge_type, base_tax_amount_after_discount_amount from `tab%s` where parenttype = %s and docstatus = 1 and (description is not null and description != '') and parent in (%s) %s order by description """ % (tax_doctype, '%s', ', '.join( ['%s'] * len(invoice_item_row)), conditions), tuple([doctype] + list(invoice_item_row))) for name, parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details: description = handle_html(description) if description not in tax_columns and tax_amount: # as description is text editor earlier and markup can break the column convention in reports tax_columns.append(description) if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item_code, tax_data in item_wise_tax_detail.items(): itemised_tax.setdefault(item_code, frappe._dict()) if isinstance(tax_data, list): tax_rate, tax_amount = tax_data else: tax_rate = tax_data tax_amount = 0 if charge_type == "Actual" and not tax_rate: tax_rate = "NA" item_net_amount = sum([ flt(d.base_net_amount) for d in item_row_map.get( parent, {}).get(item_code, []) ]) for d in item_row_map.get(parent, {}).get(item_code, []): item_tax_amount = flt((tax_amount * d.base_net_amount) / item_net_amount) \ if item_net_amount else 0 if item_tax_amount: tax_value = flt(item_tax_amount, tax_amount_precision) tax_value = (tax_value * -1 if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_value) itemised_tax.setdefault( d.name, {})[description] = frappe._dict({ "tax_rate": tax_rate, "tax_amount": tax_value }) except ValueError: continue elif charge_type == "Actual" and tax_amount: for d in invoice_item_row.get(parent, []): itemised_tax.setdefault( d.name, {})[description] = frappe._dict({ "tax_rate": "NA", "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total, tax_amount_precision) }) tax_columns.sort() for desc in tax_columns: columns.append({ 'label': _(desc + ' Rate'), 'fieldname': frappe.scrub(desc + ' Rate'), 'fieldtype': 'Float', 'width': 100 }) columns.append({ 'label': _(desc + ' Amount'), 'fieldname': frappe.scrub(desc + ' Amount'), 'fieldtype': 'Currency', 'options': 'currency', 'width': 100 }) return itemised_tax, tax_columns
def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_length=20, filters=None, filter_fields=None, as_dict=False, reference_doctype=None, ignore_user_permissions=False): start = cint(start) if isinstance(filters, string_types): filters = json.loads(filters) if searchfield: sanitize_searchfield(searchfield) if not searchfield: searchfield = "name" standard_queries = frappe.get_hooks().standard_queries or {} if query and query.split()[0].lower() != "select": # by method try: is_whitelisted(frappe.get_attr(query)) frappe.response["values"] = frappe.call(query, doctype, txt, searchfield, start, page_length, filters, as_dict=as_dict) except Exception as e: if frappe.local.conf.developer_mode: raise e else: frappe.respond_as_web_page(title='Invalid Method', html='Method not found', indicator_color='red', http_status_code=404) return elif not query and doctype in standard_queries: # from standard queries search_widget(doctype, txt, standard_queries[doctype][0], searchfield, start, page_length, filters) else: meta = frappe.get_meta(doctype) if query: frappe.throw(_("This query style is discontinued")) # custom query # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt)) else: if isinstance(filters, dict): filters_items = filters.items() filters = [] for f in filters_items: if isinstance(f[1], (list, tuple)): filters.append([doctype, f[0], f[1][0], f[1][1]]) else: filters.append([doctype, f[0], "=", f[1]]) if filters == None: filters = [] or_filters = [] # build from doctype if txt: search_fields = ["name"] if meta.title_field: search_fields.append(meta.title_field) if meta.search_fields: search_fields.extend(meta.get_search_fields()) for f in search_fields: fmeta = meta.get_field(f.strip()) if (doctype not in UNTRANSLATED_DOCTYPES) and ( f == "name" or (fmeta and fmeta.fieldtype in [ "Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor" ])): or_filters.append( [doctype, f.strip(), "like", "%{0}%".format(txt)]) if meta.get("fields", { "fieldname": "enabled", "fieldtype": "Check" }): filters.append([doctype, "enabled", "=", 1]) if meta.get("fields", { "fieldname": "disabled", "fieldtype": "Check" }): filters.append([doctype, "disabled", "!=", 1]) # format a list of fields combining search fields and filter fields fields = get_std_fields_list(meta, searchfield or "name") if filter_fields: fields = list(set(fields + json.loads(filter_fields))) formatted_fields = [ '`tab%s`.`%s`' % (meta.name, f.strip()) for f in fields ] # find relevance as location of search term from the beginning of string `name`. used for sorting results. formatted_fields.append( """locate({_txt}, `tab{doctype}`.`name`) as `_relevance`""". format(_txt=frappe.db.escape((txt or "").replace("%", "")), doctype=doctype)) # In order_by, `idx` gets second priority, because it stores link count from frappe.model.db_query import get_order_by order_by_based_on_meta = get_order_by(doctype, meta) # 2 is the index of _relevance column order_by = "_relevance, {0}, `tab{1}`.idx desc".format( order_by_based_on_meta, doctype) ignore_permissions = True if doctype == "DocType" else ( cint(ignore_user_permissions) and has_permission(doctype)) if doctype in UNTRANSLATED_DOCTYPES: page_length = None values = frappe.get_list(doctype, filters=filters, fields=formatted_fields, or_filters=or_filters, limit_start=start, limit_page_length=page_length, order_by=order_by, ignore_permissions=ignore_permissions, reference_doctype=reference_doctype, as_list=not as_dict, strict=False) if doctype in UNTRANSLATED_DOCTYPES: values = tuple([ v for v in list(values) if re.search( re.escape(txt) + ".*", ( _(v.name) if as_dict else _(v[0])), re.IGNORECASE) ]) # remove _relevance from results if as_dict: for r in values: r.pop("_relevance") frappe.response["values"] = values else: frappe.response["values"] = [r[:-1] for r in values]
def get_series(): return frappe.get_meta("Sales Invoice").get_field( "naming_series").options or ""
def validate_fields_for_doctype(doctype): doc = frappe.get_doc("DocType", doctype) doc.delete_duplicate_custom_fields() validate_fields(frappe.get_meta(doctype, cached=False))
def get_rendered_template(doc, name=None, print_format=None, meta=None, no_letterhead=None, trigger_print=False): print_settings = frappe.db.get_singles_dict("Print Settings") if isinstance(no_letterhead, string_types): no_letterhead = cint(no_letterhead) elif no_letterhead is None: no_letterhead = not cint(print_settings.with_letterhead) doc.flags.in_print = True if not frappe.flags.ignore_print_permissions: validate_print_permission(doc) if doc.meta.is_submittable: if doc.docstatus==0 and not cint(print_settings.allow_print_for_draft): frappe.throw(_("Not allowed to print draft documents"), frappe.PermissionError) if doc.docstatus==2 and not cint(print_settings.allow_print_for_cancelled): frappe.throw(_("Not allowed to print cancelled documents"), frappe.PermissionError) doc.run_method("before_print") if not hasattr(doc, "print_heading"): doc.print_heading = None if not hasattr(doc, "sub_heading"): doc.sub_heading = None if not meta: meta = frappe.get_meta(doc.doctype) jenv = frappe.get_jenv() format_data, format_data_map = [], {} # determine template if print_format: doc.print_section_headings = print_format.show_section_headings doc.print_line_breaks = print_format.line_breaks doc.align_labels_right = print_format.align_labels_right def get_template_from_string(): return jenv.from_string(get_print_format(doc.doctype, print_format)) if print_format.custom_format: template = get_template_from_string() elif print_format.format_data: # set format data format_data = json.loads(print_format.format_data) for df in format_data: format_data_map[df.get("fieldname")] = df if "visible_columns" in df: for _df in df.get("visible_columns"): format_data_map[_df.get("fieldname")] = _df doc.format_data_map = format_data_map template = "standard" elif print_format.standard=="Yes": template = get_template_from_string() else: # fallback template = "standard" else: template = "standard" if template == "standard": template = jenv.get_template(standard_format) letter_head = frappe._dict(get_letter_head(doc, no_letterhead) or {}) if letter_head.content: letter_head.content = frappe.utils.jinja.render_template(letter_head.content, {"doc": doc.as_dict()}) if letter_head.footer: letter_head.footer = frappe.utils.jinja.render_template(letter_head.footer, {"doc": doc.as_dict()}) convert_markdown(doc, meta) args = { "doc": doc, "meta": frappe.get_meta(doc.doctype), "layout": make_layout(doc, meta, format_data), "no_letterhead": no_letterhead, "trigger_print": cint(trigger_print), "letter_head": letter_head.content, "footer": letter_head.footer, "print_settings": frappe.get_doc("Print Settings") } html = template.render(args, filters={"len": len}) if cint(trigger_print): html += trigger_print_script return html
def add(args=None): """add in someone's to do list args = { "assign_to": , "doctype": , "name": , "description": } """ if not args: args = frappe.local.form_dict if frappe.db.sql( """select owner from `tabToDo` where reference_type=%(doctype)s and reference_name=%(name)s and status="Open" and owner=%(assign_to)s""", args): frappe.throw(_("Already in user's To Do list"), DuplicateToDoError) else: from frappe.utils import nowdate # if args.get("re_assign"): # remove_from_todo_if_already_assigned(args['doctype'], args['name']) if not args.get('description'): args['description'] = _('Assignment') d = frappe.get_doc({ "doctype": "ToDo", "owner": args['assign_to'], "reference_type": args['doctype'], "reference_name": args['name'], "description": args.get('description'), "priority": args.get("priority", "Medium"), "status": "Open", "date": args.get('date', nowdate()), "assigned_by": args.get('assigned_by', frappe.session.user), }).insert(ignore_permissions=True) # set assigned_to if field exists if frappe.get_meta(args['doctype']).get_field("assigned_to"): frappe.db.set_value(args['doctype'], args['name'], "assigned_to", args['assign_to']) doc = frappe.get_doc(args['doctype'], args['name']) # if assignee does not have permissions, share if not frappe.has_permission(doc=doc, user=args['assign_to']): frappe.share.add(doc.doctype, doc.name, args['assign_to']) frappe.msgprint(_('Shared with user {0} with read access').format( args['assign_to']), alert=True) # notify notify_assignment(d.assigned_by, d.owner, d.reference_type, d.reference_name, action='ASSIGN',\ description=args.get("description"), notify=args.get('notify')) return get(args)