Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

223 рядки
6.7 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 now_datetime, cint
  7. import re
  8. from six import string_types
  9. def set_new_name(doc):
  10. """
  11. Sets the `name` property for the document based on various rules.
  12. 1. If amended doc, set suffix.
  13. 2. If `autoname` method is declared, then call it.
  14. 3. If `autoname` property is set in the DocType (`meta`), then build it using the `autoname` property.
  15. 4. If no rule defined, use hash.
  16. :param doc: Document to be named.
  17. """
  18. doc.run_method("before_naming")
  19. autoname = frappe.get_meta(doc.doctype).autoname or ""
  20. if autoname.lower() != "prompt" and not frappe.flags.in_import:
  21. doc.name = None
  22. if getattr(doc, "amended_from", None):
  23. _set_amended_name(doc)
  24. return
  25. elif getattr(doc.meta, "issingle", False):
  26. doc.name = doc.doctype
  27. else:
  28. doc.run_method("autoname")
  29. if not doc.name and autoname:
  30. if autoname.startswith('field:'):
  31. fieldname = autoname[6:]
  32. doc.name = (doc.get(fieldname) or "").strip()
  33. if not doc.name:
  34. frappe.throw(_("{0} is required").format(doc.meta.get_label(fieldname)))
  35. raise Exception('Name is required')
  36. if autoname.startswith("naming_series:"):
  37. set_name_by_naming_series(doc)
  38. elif "#" in autoname:
  39. doc.name = make_autoname(autoname)
  40. elif autoname.lower()=='prompt':
  41. # set from __newname in save.py
  42. if not doc.name:
  43. frappe.throw(_("Name not set via prompt"))
  44. if not doc.name or autoname=='hash':
  45. doc.name = make_autoname('hash', doc.doctype)
  46. doc.name = validate_name(doc.doctype, doc.name, frappe.get_meta(doc.doctype).get_field("name_case"))
  47. def set_name_by_naming_series(doc):
  48. """Sets name by the `naming_series` property"""
  49. if not doc.naming_series:
  50. doc.naming_series = get_default_naming_series(doc.doctype)
  51. if not doc.naming_series:
  52. frappe.throw(frappe._("Naming Series mandatory"))
  53. doc.name = make_autoname(doc.naming_series+'.#####', '', doc)
  54. def make_autoname(key='', doctype='', doc=''):
  55. """
  56. Creates an autoname from the given key:
  57. **Autoname rules:**
  58. * The key is separated by '.'
  59. * '####' represents a series. The string before this part becomes the prefix:
  60. Example: ABC.#### creates a series ABC0001, ABC0002 etc
  61. * 'MM' represents the current month
  62. * 'YY' and 'YYYY' represent the current year
  63. *Example:*
  64. * DE/./.YY./.MM./.##### will create a series like
  65. DE/09/01/0001 where 09 is the year, 01 is the month and 0001 is the series
  66. """
  67. if key=="hash":
  68. return frappe.generate_hash(doctype, 10)
  69. if not "#" in key:
  70. key = key + ".#####"
  71. elif not "." in key:
  72. frappe.throw(_("Invalid naming series (. missing)") + (_(" for {0}").format(doctype) if doctype else ""))
  73. parts = key.split('.')
  74. n = parse_naming_series(parts, doctype, doc)
  75. return n
  76. def parse_naming_series(parts, doctype= '', doc = ''):
  77. n = ''
  78. if isinstance(parts, string_types):
  79. parts = parts.split('.')
  80. series_set = False
  81. today = now_datetime()
  82. for e in parts:
  83. part = ''
  84. if e.startswith('#'):
  85. if not series_set:
  86. digits = len(e)
  87. part = getseries(n, digits, doctype)
  88. series_set = True
  89. elif e=='YY':
  90. part = today.strftime('%y')
  91. elif e=='MM':
  92. part = today.strftime('%m')
  93. elif e=='DD':
  94. part = today.strftime("%d")
  95. elif e=='YYYY':
  96. part = today.strftime('%Y')
  97. elif doc and doc.get(e):
  98. part = doc.get(e)
  99. else: part = e
  100. if isinstance(part, string_types):
  101. n+=part
  102. return n
  103. def getseries(key, digits, doctype=''):
  104. # series created ?
  105. current = frappe.db.sql("select `current` from `tabSeries` where name=%s for update", (key,))
  106. if current and current[0][0] is not None:
  107. current = current[0][0]
  108. # yes, update it
  109. frappe.db.sql("update tabSeries set current = current+1 where name=%s", (key,))
  110. current = cint(current) + 1
  111. else:
  112. # no, create it
  113. frappe.db.sql("insert into tabSeries (name, current) values (%s, 1)", (key,))
  114. current = 1
  115. return ('%0'+str(digits)+'d') % current
  116. def revert_series_if_last(key, name):
  117. if ".#" in key:
  118. prefix, hashes = key.rsplit(".", 1)
  119. if '.' in prefix:
  120. prefix = parse_naming_series(prefix.split('.'))
  121. if "#" not in hashes:
  122. return
  123. else:
  124. prefix = key
  125. count = cint(name.replace(prefix, ""))
  126. current = frappe.db.sql("select `current` from `tabSeries` where name=%s for update", (prefix,))
  127. if current and current[0][0]==count:
  128. frappe.db.sql("update tabSeries set current=current-1 where name=%s", prefix)
  129. def get_default_naming_series(doctype):
  130. """get default value for `naming_series` property"""
  131. naming_series = frappe.get_meta(doctype).get_field("naming_series").options or ""
  132. if naming_series:
  133. naming_series = naming_series.split("\n")
  134. return naming_series[0] or naming_series[1]
  135. else:
  136. return None
  137. def validate_name(doctype, name, case=None, merge=False):
  138. if not name: return 'No Name Specified for %s' % doctype
  139. if name.startswith('New '+doctype):
  140. frappe.throw(_('There were some errors setting the name, please contact the administrator'), frappe.NameError)
  141. if case=='Title Case': name = name.title()
  142. if case=='UPPER CASE': name = name.upper()
  143. name = name.strip()
  144. if not frappe.get_meta(doctype).get("issingle") and (doctype == name) and (name!="DocType"):
  145. frappe.throw(_("Name of {0} cannot be {1}").format(doctype, name), frappe.NameError)
  146. special_characters = "<>"
  147. if re.findall("[{0}]+".format(special_characters), name):
  148. message = ", ".join("'{0}'".format(c) for c in special_characters)
  149. frappe.throw(_("Name cannot contain special characters like {0}").format(message), frappe.NameError)
  150. return name
  151. def _set_amended_name(doc):
  152. am_id = 1
  153. am_prefix = doc.amended_from
  154. if frappe.db.get_value(doc.doctype, doc.amended_from, "amended_from"):
  155. am_id = cint(doc.amended_from.split('-')[-1]) + 1
  156. am_prefix = '-'.join(doc.amended_from.split('-')[:-1]) # except the last hyphen
  157. doc.name = am_prefix + '-' + str(am_id)
  158. return doc.name
  159. def append_number_if_name_exists(doctype, value, fieldname='name', separator='-'):
  160. exists = frappe.db.exists(doctype,
  161. value if fieldname == 'name' else {fieldname: value})
  162. if exists:
  163. # should be escaped 2 times since
  164. # python string will parse the first escape
  165. escaped_value = re.escape(re.escape(value))
  166. last = frappe.db.sql("""select {fieldname} from `tab{doctype}`
  167. where {fieldname} regexp '^{value}{separator}[[:digit:]]+'
  168. order by length({fieldname}) desc,
  169. {fieldname} desc limit 1""".format(doctype=doctype,
  170. value=escaped_value, fieldname=fieldname, separator=separator))
  171. if last:
  172. count = str(cint(last[0][0].rsplit(separator, 1)[1]) + 1)
  173. else:
  174. count = "1"
  175. value = "{0}{1}{2}".format(value, separator, count)
  176. return value