Ejemplo n.º 1
0
    def get_html_table(self, columns=None, data=None):

        date_time = global_date_format(now()) + ' ' + format_time(now())
        report_doctype = dataent.db.get_value('Report', self.report,
                                              'ref_doctype')

        return dataent.render_template(
            'dataent/templates/emails/auto_email_report.html', {
                'title':
                self.name,
                'description':
                self.description,
                'date_time':
                date_time,
                'columns':
                columns,
                'data':
                data,
                'report_url':
                get_url_to_report(self.report, self.report_type,
                                  report_doctype),
                'report_name':
                self.report,
                'edit_report_settings':
                get_link_to_form('Auto Email Report', self.name)
            })
Ejemplo n.º 2
0
def backup(context,
           with_files=False,
           backup_path_db=None,
           backup_path_files=None,
           backup_path_private_files=None,
           quiet=False):
    "Backup"
    from dataent.utils.backups import scheduled_backup
    verbose = context.verbose
    for site in context.sites:
        dataent.init(site=site)
        dataent.connect()
        odb = scheduled_backup(
            ignore_files=not with_files,
            backup_path_db=backup_path_db,
            backup_path_files=backup_path_files,
            backup_path_private_files=backup_path_private_files,
            force=True)
        if verbose:
            from dataent.utils import now
            print("database backup taken -", odb.backup_path_db, "- on", now())
            if with_files:
                print("files backup taken -", odb.backup_path_files, "- on",
                      now())
                print("private files backup taken -",
                      odb.backup_path_private_files, "- on", now())

        dataent.destroy()
Ejemplo n.º 3
0
    def __init__(self, content):
        """Parses headers, content, attachments from given raw message.

		:param content: Raw message."""
        if six.PY2:
            self.mail = email.message_from_string(safe_encode(content))
        else:
            if isinstance(content, bytes):
                self.mail = email.message_from_bytes(content)
            else:
                self.mail = email.message_from_string(content)

        self.text_content = ''
        self.html_content = ''
        self.attachments = []
        self.cid_map = {}
        self.parse()
        self.set_content_and_type()
        self.set_subject()
        self.set_from()
        self.message_id = (self.mail.get('Message-ID') or "").strip(" <>")

        if self.mail["Date"]:
            try:
                utc = email.utils.mktime_tz(
                    email.utils.parsedate_tz(self.mail["Date"]))
                utc_dt = datetime.datetime.utcfromtimestamp(utc)
                self.date = convert_utc_to_user_timezone(utc_dt).strftime(
                    '%Y-%m-%d %H:%M:%S')
            except:
                self.date = now()
        else:
            self.date = now()
        if self.date > now():
            self.date = now()
Ejemplo n.º 4
0
 def update_status(self):
     status = dataent.db.get_value("Issue", self.name, "status")
     if self.status != "Open" and status == "Open" and not self.first_responded_on:
         self.first_responded_on = now()
     if self.status == "Closed" and status != "Closed":
         self.resolution_date = now()
     if self.status == "Open" and status != "Open":
         # if no date, it should be set as None and not a blank string "", as per mysql strict config
         self.resolution_date = None
Ejemplo n.º 5
0
def send_message(subject="Website Query", message="", sender=""):
	if not message:
		dataent.response["message"] = 'Please write something'
		return

	if not sender:
		dataent.response["message"] = 'Email Address Required'
		return

	# guest method, cap max writes per hour
	if dataent.db.sql("""select count(*) from `tabCommunication`
		where `sent_or_received`="Received"
		and TIMEDIFF(%s, modified) < '01:00:00'""", now())[0][0] > max_communications_per_hour:
		dataent.response["message"] = "Sorry: we believe we have received an unreasonably high number of requests of this kind. Please try later"
		return

	# send email
	forward_to_email = dataent.db.get_value("Contact Us Settings", None, "forward_to_email")
	if forward_to_email:
		dataent.sendmail(recipients=forward_to_email, sender=sender, content=message, subject=subject)


	# add to to-do ?
	dataent.get_doc(dict(
		doctype = 'Communication',
		sender=sender,
		subject= _('New Message from Website Contact Page'),
		sent_or_received='Received',
		content=message,
		status='Open',
	)).insert(ignore_permissions=True)

	return "okay"
Ejemplo n.º 6
0
def get_context(context):
    """generate rss feed"""

    host = get_request_site_address()

    blog_list = dataent.db.sql("""\
		select route as name, published_on, modified, title, content from `tabBlog Post`
		where ifnull(published,0)=1
		order by published_on desc limit 20""",
                               as_dict=1)

    for blog in blog_list:
        blog_page = cstr(quote(blog.name.encode("utf-8")))
        blog.link = urljoin(host, blog_page)
        blog.content = escape_html(blog.content or "")

    if blog_list:
        modified = max((blog['modified'] for blog in blog_list))
    else:
        modified = now()

    blog_settings = dataent.get_doc('Blog Settings', 'Blog Settings')

    context = {
        'title': blog_settings.blog_title or "Blog",
        'description': blog_settings.blog_introduction or "",
        'modified': modified,
        'items': blog_list,
        'link': host + '/blog'
    }

    # print context
    return context
Ejemplo n.º 7
0
def rebuild_node(doctype, parent, left, parent_field):
    """
		reset lft, rgt and recursive call for all children
	"""
    from dataent.utils import now
    n = now()

    # the right value of this node is the left value + 1
    right = left + 1

    # get all children of this node
    result = dataent.db.sql(
        "SELECT name FROM `tab{0}` WHERE `{1}`=%s".format(
            doctype, parent_field), (parent))
    for r in result:
        right = rebuild_node(doctype, r[0], right, parent_field)

    # we've got the left value, and now that we've processed
    # the children of this node we also know the right value
    dataent.db.sql(
        """UPDATE `tab{0}` SET lft=%s, rgt=%s, modified=%s
		WHERE name=%s""".format(doctype), (left, right, n, parent))

    #return the right value of this node + 1
    return right + 1
Ejemplo n.º 8
0
def create_asset_movement(**args):
	args = dataent._dict(args)

	if not args.transaction_date:
		args.transaction_date = now()

	movement = dataent.new_doc("Asset Movement")
	movement.update({
		"asset": args.asset,
		"transaction_date": args.transaction_date,
		"target_location": args.target_location,
		"company": args.company,
		'purpose': args.purpose or 'Receipt',
		'serial_no': args.serial_no,
		'quantity': len(get_serial_nos(args.serial_no)) if args.serial_no else 1,
		'from_employee': "_T-Employee-00001" or args.from_employee,
		'to_employee': args.to_employee
	})

	if args.source_location:
		movement.update({
			'source_location': args.source_location
		})

	movement.insert()
	movement.submit()

	return movement
Ejemplo n.º 9
0
    def test_allow_overproduction(self):
        allow_overproduction("overproduction_percentage_for_work_order", 0)
        wo_order = make_wo_order_test_record(planned_start_date=now(), qty=2)
        test_stock_entry.make_stock_entry(item_code="_Test Item",
                                          target="_Test Warehouse - _TC",
                                          qty=10,
                                          basic_rate=5000.0)
        test_stock_entry.make_stock_entry(
            item_code="_Test Item Home Desktop 100",
            target="_Test Warehouse - _TC",
            qty=10,
            basic_rate=1000.0)

        s = dataent.get_doc(
            make_stock_entry(wo_order.name,
                             "Material Transfer for Manufacture", 3))
        s.insert()
        self.assertRaises(StockOverProductionError, s.submit)

        allow_overproduction("overproduction_percentage_for_work_order", 50)
        s.load_from_db()
        s.submit()
        self.assertEqual(s.docstatus, 1)

        allow_overproduction("overproduction_percentage_for_work_order", 0)
Ejemplo n.º 10
0
    def touch(self, doctype, docname):
        """Update the modified timestamp of this document."""
        from dataent.utils import now
        modified = now()
        dataent.db.sql(
            """update `tab{doctype}` set `modified`=%s
			where name=%s""".format(doctype=doctype), (modified, docname))
        return modified
Ejemplo n.º 11
0
 def update_modified(self):
     '''Update modified timestamp'''
     self.set("modified", now())
     dataent.db.set_value(self.doctype,
                          self.name,
                          'modified',
                          self.modified,
                          update_modified=False)
Ejemplo n.º 12
0
    def change_modified_of_parent(self):
        """Change the timestamp of parent DocType if the current one is a child to clear caches."""
        if dataent.flags.in_import:
            return
        parent_list = dataent.db.sql(
            """SELECT parent
			from tabDocField where fieldtype="Table" and options=%s""", self.name)
        for p in parent_list:
            dataent.db.sql('UPDATE tabDocType SET modified=%s WHERE `name`=%s',
                           (now(), p[0]))
Ejemplo n.º 13
0
 def test_planned_operating_cost(self):
     wo_order = make_wo_order_test_record(item="_Test FG Item 2",
                                          planned_start_date=now(),
                                          qty=1,
                                          do_not_save=True)
     wo_order.set_work_order_operations()
     cost = wo_order.planned_operating_cost
     wo_order.qty = 2
     wo_order.set_work_order_operations()
     self.assertEqual(wo_order.planned_operating_cost, cost * 2)
Ejemplo n.º 14
0
    def test_over_production_for_sales_order(self):
        so = make_sales_order(item_code="_Test FG Item", qty=2)

        allow_overproduction("overproduction_percentage_for_sales_order", 0)
        wo_order = make_wo_order_test_record(planned_start_date=now(),
                                             sales_order=so.name,
                                             qty=3,
                                             do_not_save=True)

        self.assertRaises(OverProductionError, wo_order.save)

        allow_overproduction("overproduction_percentage_for_sales_order", 50)
        wo_order = make_wo_order_test_record(planned_start_date=now(),
                                             sales_order=so.name,
                                             qty=3)

        wo_order.submit()
        self.assertEqual(wo_order.docstatus, 1)

        allow_overproduction("overproduction_percentage_for_sales_order", 0)
Ejemplo n.º 15
0
def remove_ref_doc_link_from_jv(ref_type, ref_no):
	linked_jv = dataent.db.sql_list("""select parent from `tabJournal Entry Account`
		where reference_type=%s and reference_name=%s and docstatus < 2""", (ref_type, ref_no))

	if linked_jv:
		dataent.db.sql("""update `tabJournal Entry Account`
			set reference_type=null, reference_name = null,
			modified=%s, modified_by=%s
			where reference_type=%s and reference_name=%s
			and docstatus < 2""", (now(), dataent.session.user, ref_type, ref_no))

		dataent.msgprint(_("Journal Entries {0} are un-linked".format("\n".join(linked_jv))))
Ejemplo n.º 16
0
def remove_ref_doc_link_from_pe(ref_type, ref_no):
	linked_pe = dataent.db.sql_list("""select parent from `tabPayment Entry Reference`
		where reference_doctype=%s and reference_name=%s and docstatus < 2""", (ref_type, ref_no))

	if linked_pe:
		dataent.db.sql("""update `tabPayment Entry Reference`
			set allocated_amount=0, modified=%s, modified_by=%s
			where reference_doctype=%s and reference_name=%s
			and docstatus < 2""", (now(), dataent.session.user, ref_type, ref_no))

		for pe in linked_pe:
			pe_doc = dataent.get_doc("Payment Entry", pe)
			pe_doc.set_total_allocated_amount()
			pe_doc.set_unallocated_amount()
			pe_doc.clear_unallocated_reference_document_rows()

			dataent.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s,
				base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s
				where name=%s""", (pe_doc.total_allocated_amount, pe_doc.base_total_allocated_amount,
					pe_doc.unallocated_amount, now(), dataent.session.user, pe))

		dataent.msgprint(_("Payment Entries {0} are un-linked".format("\n".join(linked_pe))))
Ejemplo n.º 17
0
    def validate_dates(self):
        if self.end_date:
            if self.start_date and get_datetime(self.end_date) < get_datetime(
                    self.start_date):
                dataent.throw(_("End Date cannot be before Start Date!"))

            # If the current date is past end date, and
            # web page is published, empty the end date
            if self.published and now() > self.end_date:
                self.end_date = None

                dataent.msgprint(
                    _("Clearing end date, as it cannot be in the past for published pages."
                      ))
Ejemplo n.º 18
0
    def db_set(self,
               fieldname,
               value=None,
               update_modified=True,
               notify=False,
               commit=False):
        '''Set a value in the document object, update the timestamp and update the database.

		WARNING: This method does not trigger controller validations and should
		be used very carefully.

		:param fieldname: fieldname of the property to be updated, or a {"field":"value"} dictionary
		:param value: value of the property to be updated
		:param update_modified: default True. updates the `modified` and `modified_by` properties
		:param notify: default False. run doc.notify_updated() to send updates via socketio
		:param commit: default False. run dataent.db.commit()
		'''
        if isinstance(fieldname, dict):
            self.update(fieldname)
        else:
            self.set(fieldname, value)

        if update_modified and (
                self.doctype, self.name) not in dataent.flags.currently_saving:
            # don't update modified timestamp if called from post save methods
            # like on_update or on_submit
            self.set("modified", now())
            self.set("modified_by", dataent.session.user)

        # to trigger notification on value change
        self.run_method('before_change')

        dataent.db.set_value(self.doctype,
                             self.name,
                             fieldname,
                             value,
                             self.modified,
                             self.modified_by,
                             update_modified=update_modified)

        self.run_method('on_change')

        if notify:
            self.notify_update()

        self.clear_cache()
        if commit:
            dataent.db.commit()
Ejemplo n.º 19
0
def unlink_ref_doc_from_payment_entries(ref_doc):
	remove_ref_doc_link_from_jv(ref_doc.doctype, ref_doc.name)
	remove_ref_doc_link_from_pe(ref_doc.doctype, ref_doc.name)

	dataent.db.sql("""update `tabGL Entry`
		set against_voucher_type=null, against_voucher=null,
		modified=%s, modified_by=%s
		where against_voucher_type=%s and against_voucher=%s
		and voucher_no != ifnull(against_voucher, '')""",
		(now(), dataent.session.user, ref_doc.doctype, ref_doc.name))

	if ref_doc.doctype in ("Sales Invoice", "Purchase Invoice"):
		ref_doc.set("advances", [])

		dataent.db.sql("""delete from `tab{0} Advance` where parent = %s"""
			.format(ref_doc.doctype), ref_doc.name)
Ejemplo n.º 20
0
    def set_user_and_timestamp(self):
        self._original_modified = self.modified
        self.modified = now()
        self.modified_by = dataent.session.user
        if not self.creation:
            self.creation = self.modified
        if not self.owner:
            self.owner = self.modified_by

        for d in self.get_all_children():
            d.modified = self.modified
            d.modified_by = self.modified_by
            if not d.owner:
                d.owner = self.owner
            if not d.creation:
                d.creation = self.creation

        dataent.flags.currently_saving.append((self.doctype, self.name))
Ejemplo n.º 21
0
def set_default_profile(pos_profile, company):
	modified = now()
	user = dataent.session.user
	company = dataent.db.escape(company)

	if pos_profile and company:
		dataent.db.sql(""" update `tabPOS Profile User` pfu, `tabPOS Profile` pf
			set
				pfu.default = 0, pf.modified = %s, pf.modified_by = %s
			where
				pfu.user = %s and pf.name = pfu.parent and pf.company = %s
				and pfu.default = 1""", (modified, user, user, company), auto_commit=1)

		dataent.db.sql(""" update `tabPOS Profile User` pfu, `tabPOS Profile` pf
			set
				pfu.default = 1, pf.modified = %s, pf.modified_by = %s
			where
				pfu.user = %s and pf.name = pfu.parent and pf.company = %s and pf.name = %s
			""", (modified, user, user, company, pos_profile), auto_commit=1)
Ejemplo n.º 22
0
    def test_scrap_material_qty(self):
        wo_order = make_wo_order_test_record(planned_start_date=now(), qty=2)

        # add raw materials to stores
        test_stock_entry.make_stock_entry(item_code="_Test Item",
                                          target="Stores - _TC",
                                          qty=10,
                                          basic_rate=5000.0)
        test_stock_entry.make_stock_entry(
            item_code="_Test Item Home Desktop 100",
            target="Stores - _TC",
            qty=10,
            basic_rate=1000.0)

        s = dataent.get_doc(
            make_stock_entry(wo_order.name,
                             "Material Transfer for Manufacture", 2))
        for d in s.get("items"):
            d.s_warehouse = "Stores - _TC"
        s.insert()
        s.submit()

        s = dataent.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
        s.insert()
        s.submit()

        wo_order_details = dataent.db.get_value(
            "Work Order",
            wo_order.name,
            ["scrap_warehouse", "qty", "produced_qty", "bom_no"],
            as_dict=1)

        scrap_item_details = get_scrap_item_details(wo_order_details.bom_no)

        self.assertEqual(wo_order_details.produced_qty, 2)

        for item in s.items:
            if item.bom_no and item.item_code in scrap_item_details:
                self.assertEqual(wo_order_details.scrap_warehouse,
                                 item.t_warehouse)
                self.assertEqual(
                    flt(wo_order_details.qty) *
                    flt(scrap_item_details[item.item_code]), item.qty)
Ejemplo n.º 23
0
def check_publish_status():
    web_pages = dataent.get_all(
        "Web Page", fields=["name", "published", "start_date", "end_date"])
    now_date = get_datetime(now())

    for page in web_pages:
        start_date = page.start_date if page.start_date else ""
        end_date = page.end_date if page.end_date else ""

        if page.published:
            # Unpublish pages that are outside the set date ranges
            if (start_date
                    and now_date < start_date) or (end_date
                                                   and now_date > end_date):
                dataent.db.set_value("Web Page", page.name, "published", 0)
        else:
            # Publish pages that are inside the set date ranges
            if start_date:
                if not end_date or (end_date and now_date < end_date):
                    dataent.db.set_value("Web Page", page.name, "published", 1)
Ejemplo n.º 24
0
def update_add_node(doc, parent, parent_field):
    """
		insert a new node
	"""

    n = now()

    doctype = doc.doctype
    name = doc.name

    # get the last sibling of the parent
    if parent:
        left, right = dataent.db.sql(
            "select lft, rgt from `tab{0}` where name=%s".format(doctype),
            parent)[0]
        validate_loop(doc.doctype, doc.name, left, right)
    else:  # root
        right = dataent.db.sql("select ifnull(max(rgt),0)+1 from `tab%s` \
			where ifnull(`%s`,'') =''" % (doctype, parent_field))[0][0]
    right = right or 1

    # update all on the right
    dataent.db.sql(
        "update `tab{0}` set rgt = rgt+2, modified=%s where rgt >= %s".format(
            doctype), (n, right))
    dataent.db.sql(
        "update `tab{0}` set lft = lft+2, modified=%s where lft >= %s".format(
            doctype), (n, right))

    # update index of new node
    if dataent.db.sql(
            "select * from `tab{0}` where lft=%s or rgt=%s".format(doctype),
        (right, right + 1)):
        dataent.msgprint(
            _("Nested set error. Please contact the Administrator."))
        raise Exception

    dataent.db.sql(
        "update `tab{0}` set lft=%s, rgt=%s, modified=%s where name=%s".format(
            doctype), (right, right + 1, n, name))
    return right
Ejemplo n.º 25
0
    def db_insert(self):
        """INSERT the document (with valid columns) in the database."""
        if not self.name:
            # name will be set by document class in most cases
            set_new_name(self)

        if not self.creation:
            self.creation = self.modified = now()
            self.created_by = self.modifield_by = dataent.session.user

        d = self.get_valid_dict(convert_dates_to_str=True)

        columns = list(d)
        try:
            dataent.db.sql(
                """insert into `tab{doctype}`
				({columns}) values ({values})""".format(
                    doctype=self.doctype,
                    columns=", ".join(["`" + c + "`" for c in columns]),
                    values=", ".join(["%s"] * len(columns))), list(d.values()))
        except Exception as e:
            if e.args[0] == 1062:
                if "PRIMARY" in cstr(e.args[1]):
                    if self.meta.autoname == "hash":
                        # hash collision? try again
                        self.name = None
                        self.db_insert()
                        return

                    raise dataent.DuplicateEntryError(self.doctype, self.name,
                                                      e)

                elif "Duplicate" in cstr(e.args[1]):
                    # unique constraint
                    self.show_unique_validation_message(e)
                else:
                    raise
            else:
                raise
        self.set("__islocal", False)
Ejemplo n.º 26
0
def get_new_messages():
    last_update = dataent.cache().hget("notifications_last_update",
                                       dataent.session.user)
    now_timestamp = now()
    dataent.cache().hset("notifications_last_update", dataent.session.user,
                         now_timestamp)

    if not last_update:
        return []

    if last_update and time_diff_in_seconds(now_timestamp, last_update) > 1800:
        # no update for 30 mins, consider only the last 30 mins
        last_update = (now_datetime() -
                       relativedelta(seconds=1800)).strftime(DATETIME_FORMAT)

    return dataent.db.sql("""select sender_full_name, content
		from `tabCommunication`
			where communication_type in ('Chat', 'Notification')
			and reference_doctype='user'
			and reference_name = %s
			and creation > %s
			order by creation desc""", (dataent.session.user, last_update),
                          as_dict=1)
Ejemplo n.º 27
0
    def set_value(self,
                  dt,
                  dn,
                  field,
                  val,
                  modified=None,
                  modified_by=None,
                  update_modified=True,
                  debug=False):
        """Set a single value in the database, do not call the ORM triggers
		but update the modified timestamp (unless specified not to).

		**Warning:** this function will not call Document events and should be avoided in normal cases.

		:param dt: DocType name.
		:param dn: Document name.
		:param field: Property / field name or dictionary of values to be updated
		:param value: Value to be updated.
		:param modified: Use this as the `modified` timestamp.
		:param modified_by: Set this user as `modified_by`.
		:param update_modified: default True. Set as false, if you don't want to update the timestamp.
		:param debug: Print the query in the developer / js console.
		"""
        if not modified:
            modified = now()
        if not modified_by:
            modified_by = dataent.session.user

        to_update = {}
        if update_modified:
            to_update = {"modified": modified, "modified_by": modified_by}

        if isinstance(field, dict):
            to_update.update(field)
        else:
            to_update.update({field: val})

        if dn and dt != dn:
            # with table
            conditions, values = self.build_conditions(dn)

            values.update(to_update)

            set_values = []
            for key in to_update:
                set_values.append('`{0}`=%({0})s'.format(key))

            self.sql("""update `tab{0}`
				set {1} where {2}""".format(dt, ', '.join(set_values), conditions),
                     values,
                     debug=debug)

        else:
            # for singles
            keys = list(to_update)
            self.sql('''
				delete from tabSingles
				where field in ({0}) and
					doctype=%s'''.format(', '.join(['%s'] * len(keys))),
                     list(keys) + [dt],
                     debug=debug)
            for key, value in iteritems(to_update):
                self.sql(
                    '''insert into tabSingles(doctype, field, value) values (%s, %s, %s)''',
                    (dt, key, value),
                    debug=debug)

        if dt in self.value_cache:
            del self.value_cache[dt]

        dataent.clear_document_cache(dt, dn)
Ejemplo n.º 28
0
 def before_insert(self):
     self.full_name = get_fullname(self.user)
     self.date = now()
Ejemplo n.º 29
0
def set_as_cancel(voucher_type, voucher_no):
    dataent.db.sql(
        """update `tabStock Ledger Entry` set is_cancelled='Yes',
		modified=%s, modified_by=%s
		where voucher_no=%s and voucher_type=%s""",
        (now(), dataent.session.user, voucher_type, voucher_no))
Ejemplo n.º 30
0
def update_move_node(doc, parent_field):
    n = now()
    parent = doc.get(parent_field)

    if parent:
        new_parent = dataent.db.sql("""select lft, rgt from `tab{0}`
			where name = %s""".format(doc.doctype),
                                    parent,
                                    as_dict=1)[0]

        validate_loop(doc.doctype, doc.name, new_parent.lft, new_parent.rgt)

    # move to dark side
    dataent.db.sql(
        """update `tab{0}` set lft = -lft, rgt = -rgt, modified=%s
		where lft >= %s and rgt <= %s""".format(doc.doctype), (n, doc.lft, doc.rgt))

    # shift left
    diff = doc.rgt - doc.lft + 1
    dataent.db.sql(
        """update `tab{0}` set lft = lft -%s, rgt = rgt - %s, modified=%s
		where lft > %s""".format(doc.doctype), (diff, diff, n, doc.rgt))

    # shift left rgts of ancestors whose only rgts must shift
    dataent.db.sql(
        """update `tab{0}` set rgt = rgt - %s, modified=%s
		where lft < %s and rgt > %s""".format(doc.doctype),
        (diff, n, doc.lft, doc.rgt))

    if parent:
        new_parent = dataent.db.sql("""select lft, rgt from `tab%s`
			where name = %s""" % (doc.doctype, '%s'),
                                    parent,
                                    as_dict=1)[0]

        # set parent lft, rgt
        dataent.db.sql(
            """update `tab{0}` set rgt = rgt + %s, modified=%s
			where name = %s""".format(doc.doctype), (diff, n, parent))

        # shift right at new parent
        dataent.db.sql(
            """update `tab{0}` set lft = lft + %s, rgt = rgt + %s, modified=%s
			where lft > %s""".format(doc.doctype), (diff, diff, n, new_parent.rgt))

        # shift right rgts of ancestors whose only rgts must shift
        dataent.db.sql(
            """update `tab{0}` set rgt = rgt + %s, modified=%s
			where lft < %s and rgt > %s""".format(doc.doctype),
            (diff, n, new_parent.lft, new_parent.rgt))

        new_diff = new_parent.rgt - doc.lft
    else:
        # new root
        max_rgt = dataent.db.sql("""select max(rgt) from `tab{0}`""".format(
            doc.doctype))[0][0]
        new_diff = max_rgt + 1 - doc.lft

    # bring back from dark side
    dataent.db.sql(
        """update `tab{0}` set lft = -lft + %s, rgt = -rgt + %s, modified=%s
		where lft < 0""".format(doc.doctype), (new_diff, new_diff, n))