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
Example #2
0
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')
		}
	}
Example #3
0
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')
		}
	}
Example #4
0
    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)
Example #5
0
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-"
		}
		
Example #7
0
	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
					))
Example #8
0
	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))
Example #9
0
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")]
Example #10
0
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")
Example #12
0
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
Example #13
0
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 ""
Example #14
0
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
Example #15
0
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"))
Example #16
0
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)
Example #17
0
	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(","))
Example #18
0
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
Example #19
0
	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
Example #20
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
Example #21
0
	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))
Example #23
0
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)
Example #24
0
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)
Example #26
0
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
Example #28
0
	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()
Example #29
0
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
		})
Example #30
0
	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
Example #31
0
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)
Example #32
0
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()
Example #33
0
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)
Example #34
0
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)
Example #35
0
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)
Example #36
0
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
Example #37
0
    def meta(self):
        if not hasattr(self, "_meta"):
            self._meta = frappe.get_meta(self.doctype)

        return self._meta
Example #38
0
    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
Example #39
0
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
Example #40
0
 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
Example #41
0
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
Example #42
0
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
Example #44
0
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
Example #45
0
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
Example #46
0
	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})
Example #47
0
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
Example #48
0
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
Example #49
0
    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)
Example #50
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
Example #51
0
def get_asset_naming_series():
	meta = frappe.get_meta("Asset")
	return meta.get_field("naming_series").options
Example #52
0
def get_doctype_options():
	doctype = frappe.form_dict['doctype']
	return [doctype] + [d.options for d in frappe.get_meta(doctype).get_table_fields()]
Example #53
0
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)
Example #54
0
    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)
Example #55
0
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
Example #56
0
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 ""
Example #58
0
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))
Example #59
0
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
Example #60
0
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)