25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

373 lines
12 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe
  5. from frappe import _
  6. from frappe.utils import cint
  7. from frappe.model.naming import validate_name
  8. from frappe.model.dynamic_links import get_dynamic_link_map
  9. from frappe.utils.password import rename_password
  10. @frappe.whitelist()
  11. def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False):
  12. """
  13. Renames a doc(dt, old) to doc(dt, new) and
  14. updates all linked fields of type "Link"
  15. """
  16. if not frappe.db.exists(doctype, old):
  17. return
  18. force = cint(force)
  19. merge = cint(merge)
  20. meta = frappe.get_meta(doctype)
  21. # call before_rename
  22. old_doc = frappe.get_doc(doctype, old)
  23. out = old_doc.run_method("before_rename", old, new, merge) or {}
  24. new = (out.get("new") or new) if isinstance(out, dict) else (out or new)
  25. if doctype != "DocType":
  26. new = validate_rename(doctype, new, meta, merge, force, ignore_permissions)
  27. if not merge:
  28. rename_parent_and_child(doctype, old, new, meta)
  29. # update link fields' values
  30. link_fields = get_link_fields(doctype)
  31. update_link_field_values(link_fields, old, new, doctype)
  32. rename_dynamic_links(doctype, old, new)
  33. if doctype=='DocType':
  34. rename_doctype(doctype, old, new, force)
  35. update_attachments(doctype, old, new)
  36. if merge:
  37. frappe.delete_doc(doctype, old)
  38. # call after_rename
  39. new_doc = frappe.get_doc(doctype, new)
  40. # copy any flags if required
  41. new_doc._local = getattr(old_doc, "_local", None)
  42. new_doc.run_method("after_rename", old, new, merge)
  43. rename_versions(doctype, old, new)
  44. if not merge:
  45. rename_password(doctype, old, new)
  46. # update user_permissions
  47. frappe.db.sql("""update tabDefaultValue set defvalue=%s where parenttype='User Permission'
  48. and defkey=%s and defvalue=%s""", (new, doctype, old))
  49. frappe.clear_cache()
  50. return new
  51. def update_attachments(doctype, old, new):
  52. try:
  53. if old != "File Data" and doctype != "DocType":
  54. frappe.db.sql("""update `tabFile` set attached_to_name=%s
  55. where attached_to_name=%s and attached_to_doctype=%s""", (new, old, doctype))
  56. except Exception, e:
  57. if e.args[0]!=1054: # in patch?
  58. raise
  59. def rename_versions(doctype, old, new):
  60. frappe.db.sql("""update tabVersion set docname=%s where ref_doctype=%s and docname=%s""",
  61. (new, doctype, old))
  62. def rename_parent_and_child(doctype, old, new, meta):
  63. # rename the doc
  64. frappe.db.sql("update `tab%s` set name=%s where name=%s" % (frappe.db.escape(doctype), '%s', '%s'),
  65. (new, old))
  66. update_autoname_field(doctype, new, meta)
  67. update_child_docs(old, new, meta)
  68. def update_autoname_field(doctype, new, meta):
  69. # update the value of the autoname field on rename of the docname
  70. if meta.get('autoname'):
  71. field = meta.get('autoname').split(':')
  72. if field and field[0] == "field":
  73. frappe.db.sql("update `tab%s` set %s=%s where name=%s" % (frappe.db.escape(doctype), field[1], '%s', '%s'),
  74. (new, new))
  75. def validate_rename(doctype, new, meta, merge, force, ignore_permissions):
  76. # using for update so that it gets locked and someone else cannot edit it while this rename is going on!
  77. exists = frappe.db.sql("select name from `tab{doctype}` where name=%s for update".format(doctype=frappe.db.escape(doctype)), new)
  78. exists = exists[0][0] if exists else None
  79. if merge and not exists:
  80. frappe.msgprint(_("{0} {1} does not exist, select a new target to merge").format(doctype, new), raise_exception=1)
  81. if exists and exists != new:
  82. # for fixing case, accents
  83. exists = None
  84. if (not merge) and exists:
  85. frappe.msgprint(_("Another {0} with name {1} exists, select another name").format(doctype, new), raise_exception=1)
  86. if not (ignore_permissions or frappe.has_permission(doctype, "write")):
  87. frappe.msgprint(_("You need write permission to rename"), raise_exception=1)
  88. if not (force or ignore_permissions) and not meta.allow_rename:
  89. frappe.msgprint(_("{0} not allowed to be renamed").format(_(doctype)), raise_exception=1)
  90. # validate naming like it's done in doc.py
  91. new = validate_name(doctype, new, merge=merge)
  92. return new
  93. def rename_doctype(doctype, old, new, force=False):
  94. # change options for fieldtype Table
  95. update_options_for_fieldtype("Table", old, new)
  96. update_options_for_fieldtype("Link", old, new)
  97. # change options where select options are hardcoded i.e. listed
  98. select_fields = get_select_fields(old, new)
  99. update_link_field_values(select_fields, old, new, doctype)
  100. update_select_field_values(old, new)
  101. # change parenttype for fieldtype Table
  102. update_parenttype_values(old, new)
  103. def update_child_docs(old, new, meta):
  104. # update "parent"
  105. for df in meta.get_table_fields():
  106. frappe.db.sql("update `tab%s` set parent=%s where parent=%s" \
  107. % (frappe.db.escape(df.options), '%s', '%s'), (new, old))
  108. def update_link_field_values(link_fields, old, new, doctype):
  109. for field in link_fields:
  110. if field['issingle']:
  111. frappe.db.sql("""\
  112. update `tabSingles` set value=%s
  113. where doctype=%s and field=%s and value=%s""",
  114. (new, field['parent'], field['fieldname'], old))
  115. else:
  116. # because the table hasn't been renamed yet!
  117. parent = field['parent'] if field['parent']!=new else old
  118. frappe.db.sql("""\
  119. update `tab%s` set `%s`=%s
  120. where `%s`=%s""" \
  121. % (frappe.db.escape(parent), frappe.db.escape(field['fieldname']), '%s',
  122. frappe.db.escape(field['fieldname']), '%s'),
  123. (new, old))
  124. def get_link_fields(doctype):
  125. # get link fields from tabDocField
  126. link_fields = frappe.db.sql("""\
  127. select parent, fieldname,
  128. (select issingle from tabDocType dt
  129. where dt.name = df.parent) as issingle
  130. from tabDocField df
  131. where
  132. df.options=%s and df.fieldtype='Link'""", (doctype,), as_dict=1)
  133. # get link fields from tabCustom Field
  134. custom_link_fields = frappe.db.sql("""\
  135. select dt as parent, fieldname,
  136. (select issingle from tabDocType dt
  137. where dt.name = df.dt) as issingle
  138. from `tabCustom Field` df
  139. where
  140. df.options=%s and df.fieldtype='Link'""", (doctype,), as_dict=1)
  141. # add custom link fields list to link fields list
  142. link_fields += custom_link_fields
  143. # remove fields whose options have been changed using property setter
  144. property_setter_link_fields = frappe.db.sql("""\
  145. select ps.doc_type as parent, ps.field_name as fieldname,
  146. (select issingle from tabDocType dt
  147. where dt.name = ps.doc_type) as issingle
  148. from `tabProperty Setter` ps
  149. where
  150. ps.property_type='options' and
  151. ps.field_name is not null and
  152. ps.value=%s""", (doctype,), as_dict=1)
  153. link_fields += property_setter_link_fields
  154. return link_fields
  155. def update_options_for_fieldtype(fieldtype, old, new):
  156. if frappe.conf.developer_mode:
  157. for name in frappe.db.sql_list("""select parent from
  158. tabDocField where options=%s""", old):
  159. doctype = frappe.get_doc("DocType", name)
  160. save = False
  161. for f in doctype.fields:
  162. if f.options == old:
  163. f.options = new
  164. save = True
  165. if save:
  166. doctype.save()
  167. else:
  168. frappe.db.sql("""update `tabDocField` set options=%s
  169. where fieldtype=%s and options=%s""", (new, fieldtype, old))
  170. frappe.db.sql("""update `tabCustom Field` set options=%s
  171. where fieldtype=%s and options=%s""", (new, fieldtype, old))
  172. frappe.db.sql("""update `tabProperty Setter` set value=%s
  173. where property='options' and value=%s""", (new, old))
  174. def get_select_fields(old, new):
  175. """
  176. get select type fields where doctype's name is hardcoded as
  177. new line separated list
  178. """
  179. # get link fields from tabDocField
  180. select_fields = frappe.db.sql("""\
  181. select parent, fieldname,
  182. (select issingle from tabDocType dt
  183. where dt.name = df.parent) as issingle
  184. from tabDocField df
  185. where
  186. df.parent != %s and df.fieldtype = 'Select' and
  187. df.options like "%%%%%s%%%%" """ \
  188. % ('%s', frappe.db.escape(old)), (new,), as_dict=1)
  189. # get link fields from tabCustom Field
  190. custom_select_fields = frappe.db.sql("""\
  191. select dt as parent, fieldname,
  192. (select issingle from tabDocType dt
  193. where dt.name = df.dt) as issingle
  194. from `tabCustom Field` df
  195. where
  196. df.dt != %s and df.fieldtype = 'Select' and
  197. df.options like "%%%%%s%%%%" """ \
  198. % ('%s', frappe.db.escape(old)), (new,), as_dict=1)
  199. # add custom link fields list to link fields list
  200. select_fields += custom_select_fields
  201. # remove fields whose options have been changed using property setter
  202. property_setter_select_fields = frappe.db.sql("""\
  203. select ps.doc_type as parent, ps.field_name as fieldname,
  204. (select issingle from tabDocType dt
  205. where dt.name = ps.doc_type) as issingle
  206. from `tabProperty Setter` ps
  207. where
  208. ps.doc_type != %s and
  209. ps.property_type='options' and
  210. ps.field_name is not null and
  211. ps.value like "%%%%%s%%%%" """ \
  212. % ('%s', frappe.db.escape(old)), (new,), as_dict=1)
  213. select_fields += property_setter_select_fields
  214. return select_fields
  215. def update_select_field_values(old, new):
  216. frappe.db.sql("""\
  217. update `tabDocField` set options=replace(options, %s, %s)
  218. where
  219. parent != %s and fieldtype = 'Select' and
  220. (options like "%%%%\\n%s%%%%" or options like "%%%%%s\\n%%%%")""" % \
  221. ('%s', '%s', '%s', frappe.db.escape(old), frappe.db.escape(old)), (old, new, new))
  222. frappe.db.sql("""\
  223. update `tabCustom Field` set options=replace(options, %s, %s)
  224. where
  225. dt != %s and fieldtype = 'Select' and
  226. (options like "%%%%\\n%s%%%%" or options like "%%%%%s\\n%%%%")""" % \
  227. ('%s', '%s', '%s', frappe.db.escape(old), frappe.db.escape(old)), (old, new, new))
  228. frappe.db.sql("""\
  229. update `tabProperty Setter` set value=replace(value, %s, %s)
  230. where
  231. doc_type != %s and field_name is not null and
  232. property='options' and
  233. (value like "%%%%\\n%s%%%%" or value like "%%%%%s\\n%%%%")""" % \
  234. ('%s', '%s', '%s', frappe.db.escape(old), frappe.db.escape(old)), (old, new, new))
  235. def update_parenttype_values(old, new):
  236. child_doctypes = frappe.db.sql("""\
  237. select options, fieldname from `tabDocField`
  238. where parent=%s and fieldtype='Table'""", (new,), as_dict=1)
  239. custom_child_doctypes = frappe.db.sql("""\
  240. select options, fieldname from `tabCustom Field`
  241. where dt=%s and fieldtype='Table'""", (new,), as_dict=1)
  242. child_doctypes += custom_child_doctypes
  243. fields = [d['fieldname'] for d in child_doctypes]
  244. property_setter_child_doctypes = frappe.db.sql("""\
  245. select value as options from `tabProperty Setter`
  246. where doc_type=%s and property='options' and
  247. field_name in ("%s")""" % ('%s', '", "'.join(fields)),
  248. (new,))
  249. child_doctypes += property_setter_child_doctypes
  250. child_doctypes = (d['options'] for d in child_doctypes)
  251. for doctype in child_doctypes:
  252. frappe.db.sql("""\
  253. update `tab%s` set parenttype=%s
  254. where parenttype=%s""" % (doctype, '%s', '%s'),
  255. (new, old))
  256. def rename_dynamic_links(doctype, old, new):
  257. for df in get_dynamic_link_map().get(doctype, []):
  258. # dynamic link in single, just one value to check
  259. if frappe.get_meta(df.parent).issingle:
  260. refdoc = frappe.db.get_singles_dict(df.parent)
  261. if refdoc.get(df.options)==doctype and refdoc.get(df.fieldname)==old:
  262. frappe.db.sql("""update tabSingles set value=%s where
  263. field=%s and value=%s and doctype=%s""", (new, df.fieldname, old, df.parent))
  264. else:
  265. # because the table hasn't been renamed yet!
  266. parent = df.parent if df.parent != new else old
  267. # replace for each value where renamed
  268. for to_change in frappe.db.sql_list("""select name from `tab{parent}` where
  269. {options}=%s and {fieldname}=%s""".format(parent=parent, options=df.options,
  270. fieldname=df.fieldname), (doctype, old)):
  271. frappe.db.sql("""update `tab{parent}` set {fieldname}=%s
  272. where name=%s""".format(**df), (new, to_change))
  273. def bulk_rename(doctype, rows=None, via_console = False):
  274. """Bulk rename documents
  275. :param doctype: DocType to be renamed
  276. :param rows: list of documents as `((oldname, newname), ..)`"""
  277. if not rows:
  278. frappe.throw(_("Please select a valid csv file with data"))
  279. if not via_console:
  280. max_rows = 500
  281. if len(rows) > max_rows:
  282. frappe.throw(_("Maximum {0} rows allowed").format(max_rows))
  283. rename_log = []
  284. for row in rows:
  285. # if row has some content
  286. if len(row) > 1 and row[0] and row[1]:
  287. try:
  288. if rename_doc(doctype, row[0], row[1]):
  289. msg = _("Successful: {0} to {1}").format(row[0], row[1])
  290. frappe.db.commit()
  291. else:
  292. msg = _("Ignored: {0} to {1}").format(row[0], row[1])
  293. except Exception, e:
  294. msg = _("** Failed: {0} to {1}: {2}").format(row[0], row[1], repr(e))
  295. frappe.db.rollback()
  296. if via_console:
  297. print msg
  298. else:
  299. rename_log.append(msg)
  300. if not via_console:
  301. return rename_log