Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

11 лет назад
12 лет назад
11 лет назад
12 лет назад
13 лет назад
11 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
11 лет назад
11 лет назад
12 лет назад
11 лет назад
12 лет назад
11 лет назад
12 лет назад
13 лет назад
11 лет назад
13 лет назад
13 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. """
  4. Get metadata (main doctype with fields and permissions with all table doctypes)
  5. - if exists in cache, get it from cache
  6. - add custom fields
  7. - override properties from PropertySetter
  8. - sort based on prev_field
  9. - optionally, post process (add js, css, select fields), or without
  10. """
  11. from __future__ import unicode_literals
  12. # imports
  13. import json
  14. import webnotes
  15. import webnotes.model
  16. import webnotes.model.doc
  17. import webnotes.model.doclist
  18. from webnotes.utils import cint
  19. doctype_cache = webnotes.local('doctype_doctype_cache')
  20. docfield_types = webnotes.local('doctype_docfield_types')
  21. # doctype_cache = {}
  22. # docfield_types = None
  23. def get(doctype, processed=False, cached=True):
  24. """return doclist"""
  25. if cached:
  26. doclist = from_cache(doctype, processed)
  27. if doclist:
  28. if processed:
  29. update_language(doclist)
  30. return DocTypeDocList(doclist)
  31. load_docfield_types()
  32. # main doctype doclist
  33. doclist = get_doctype_doclist(doctype)
  34. # add doctypes of table fields
  35. table_types = [d.options for d in doclist \
  36. if d.doctype=='DocField' and d.fieldtype=='Table']
  37. for table_doctype in table_types:
  38. doclist += get_doctype_doclist(table_doctype)
  39. if processed:
  40. add_code(doctype, doclist)
  41. expand_selects(doclist)
  42. add_print_formats(doclist)
  43. add_search_fields(doclist)
  44. add_workflows(doclist)
  45. add_linked_with(doclist)
  46. to_cache(doctype, processed, doclist)
  47. if processed:
  48. update_language(doclist)
  49. return DocTypeDocList(doclist)
  50. def load_docfield_types():
  51. webnotes.local.doctype_docfield_types = dict(webnotes.conn.sql("""select fieldname, fieldtype from tabDocField
  52. where parent='DocField'"""))
  53. def add_workflows(doclist):
  54. from webnotes.model.workflow import get_workflow_name
  55. doctype = doclist[0].name
  56. # get active workflow
  57. workflow_name = get_workflow_name(doctype)
  58. if workflow_name and webnotes.conn.exists("Workflow", workflow_name):
  59. doclist += webnotes.get_doclist("Workflow", workflow_name)
  60. # add workflow states (for icons and style)
  61. for state in map(lambda d: d.state, doclist.get({"doctype":"Workflow Document State"})):
  62. doclist += webnotes.get_doclist("Workflow State", state)
  63. def get_doctype_doclist(doctype):
  64. """get doclist of single doctype"""
  65. doclist = webnotes.get_doclist('DocType', doctype)
  66. add_custom_fields(doctype, doclist)
  67. apply_property_setters(doctype, doclist)
  68. sort_fields(doclist)
  69. return doclist
  70. def sort_fields(doclist):
  71. """sort on basis of previous_field"""
  72. from webnotes.model.doclist import DocList
  73. newlist = DocList([])
  74. pending = doclist.get({"doctype":"DocField"})
  75. if doclist[0].get("_idx"):
  76. for fieldname in json.loads(doclist[0].get("_idx")):
  77. d = doclist.get({"fieldname": fieldname})
  78. if d:
  79. newlist.append(d[0])
  80. pending.remove(d[0])
  81. else:
  82. maxloops = 20
  83. while (pending and maxloops>0):
  84. maxloops -= 1
  85. for d in pending[:]:
  86. if d.previous_field:
  87. # field already added
  88. for n in newlist:
  89. if n.fieldname==d.previous_field:
  90. newlist.insert(newlist.index(n)+1, d)
  91. pending.remove(d)
  92. break
  93. else:
  94. newlist.append(d)
  95. pending.remove(d)
  96. # recurring at end
  97. if pending:
  98. newlist += pending
  99. # renum
  100. idx = 1
  101. for d in newlist:
  102. d.idx = idx
  103. idx += 1
  104. doclist.get({"doctype":["!=", "DocField"]}).extend(newlist)
  105. def apply_property_setters(doctype, doclist):
  106. for ps in webnotes.conn.sql("""select * from `tabProperty Setter` where
  107. doc_type=%s""", (doctype,), as_dict=1):
  108. if ps['doctype_or_field']=='DocType':
  109. if ps.get('property_type', None) in ('Int', 'Check'):
  110. ps['value'] = cint(ps['value'])
  111. doclist[0].fields[ps['property']] = ps['value']
  112. else:
  113. docfield = filter(lambda d: d.doctype=="DocField" and d.fieldname==ps['field_name'],
  114. doclist)
  115. if not docfield: continue
  116. if docfield_types.get(ps['property'], None) in ('Int', 'Check'):
  117. ps['value'] = cint(ps['value'])
  118. docfield[0].fields[ps['property']] = ps['value']
  119. def add_custom_fields(doctype, doclist):
  120. try:
  121. res = webnotes.conn.sql("""SELECT * FROM `tabCustom Field`
  122. WHERE dt = %s AND docstatus < 2""", (doctype,), as_dict=1)
  123. except Exception, e:
  124. if e.args[0]==1146:
  125. return doclist
  126. else:
  127. raise
  128. for r in res:
  129. custom_field = webnotes.model.doc.Document(fielddata=r)
  130. # convert to DocField
  131. custom_field.fields.update({
  132. 'doctype': 'DocField',
  133. 'parent': doctype,
  134. 'parentfield': 'fields',
  135. 'parenttype': 'DocType',
  136. '__custom_field': 1
  137. })
  138. doclist.append(custom_field)
  139. return doclist
  140. def add_linked_with(doclist):
  141. """add list of doctypes this doctype is 'linked' with"""
  142. doctype = doclist[0].name
  143. links = webnotes.conn.sql("""select parent, fieldname from tabDocField
  144. where (fieldtype="Link" and options=%s)
  145. or (fieldtype="Select" and options=%s)""", (doctype, "link:"+ doctype))
  146. links += webnotes.conn.sql("""select dt as parent, fieldname from `tabCustom Field`
  147. where (fieldtype="Link" and options=%s)
  148. or (fieldtype="Select" and options=%s)""", (doctype, "link:"+ doctype))
  149. links = dict(links)
  150. if not links:
  151. return {}
  152. ret = {}
  153. for dt in links:
  154. ret[dt] = { "fieldname": links[dt] }
  155. for grand_parent, options in webnotes.conn.sql("""select parent, options from tabDocField
  156. where fieldtype="Table"
  157. and options in (select name from tabDocType
  158. where istable=1 and name in (%s))""" % ", ".join(["%s"] * len(links)) ,tuple(links)):
  159. ret[grand_parent] = {"child_doctype": options, "fieldname": links[options] }
  160. if options in ret:
  161. del ret[options]
  162. doclist[0].fields["__linked_with"] = ret
  163. def from_cache(doctype, processed):
  164. """ load doclist from cache.
  165. sets flag __from_cache in first doc of doclist if loaded from cache"""
  166. # from memory
  167. if doctype_cache and not processed and doctype in doctype_cache:
  168. doclist = doctype_cache[doctype]
  169. doclist[0].fields["__from_cache"] = 1
  170. return doclist
  171. doclist = webnotes.cache().get_value(cache_name(doctype, processed))
  172. if doclist:
  173. from webnotes.model.doclist import DocList
  174. doclist = DocList([webnotes.model.doc.Document(fielddata=d)
  175. for d in doclist])
  176. doclist[0].fields["__from_cache"] = 1
  177. return doclist
  178. def to_cache(doctype, processed, doclist):
  179. if not doctype_cache:
  180. webnotes.local.doctype_doctype_cache = {}
  181. webnotes.cache().set_value(cache_name(doctype, processed),
  182. [d.fields for d in doclist])
  183. if not processed:
  184. doctype_cache[doctype] = doclist
  185. def cache_name(doctype, processed):
  186. """returns cache key"""
  187. suffix = ""
  188. if processed:
  189. suffix = ":Raw"
  190. return "doctype:" + doctype + suffix
  191. def clear_cache(doctype=None):
  192. def clear_single(dt):
  193. webnotes.cache().delete_value(cache_name(dt, False))
  194. webnotes.cache().delete_value(cache_name(dt, True))
  195. if doctype_cache and (dt in doctype_cache):
  196. del doctype_cache[dt]
  197. if doctype:
  198. clear_single(doctype)
  199. # clear all parent doctypes
  200. for dt in webnotes.conn.sql("""select parent from tabDocField
  201. where fieldtype="Table" and options=%s""", (doctype,)):
  202. clear_single(dt[0])
  203. # clear all notifications
  204. from webnotes.core.doctype.notification_count.notification_count import delete_notification_count_for
  205. delete_notification_count_for(doctype)
  206. else:
  207. # clear all
  208. for dt in webnotes.conn.sql("""select name from tabDocType"""):
  209. clear_single(dt[0])
  210. def add_code(doctype, doclist):
  211. import os
  212. from webnotes.modules import scrub, get_module_path
  213. doc = doclist[0]
  214. path = os.path.join(get_module_path(doc.module), 'doctype', scrub(doc.name))
  215. def _add_code(fname, fieldname):
  216. fpath = os.path.join(path, fname)
  217. if os.path.exists(fpath):
  218. with open(fpath, 'r') as f:
  219. doc.fields[fieldname] = f.read()
  220. _add_code(scrub(doc.name) + '.js', '__js')
  221. _add_code(scrub(doc.name) + '.css', '__css')
  222. _add_code('%s_list.js' % scrub(doc.name), '__list_js')
  223. _add_code('%s_calendar.js' % scrub(doc.name), '__calendar_js')
  224. _add_code('%s_map.js' % scrub(doc.name), '__map_js')
  225. add_embedded_js(doc)
  226. def add_embedded_js(doc):
  227. """embed all require files"""
  228. import re, os
  229. from webnotes import conf
  230. js = doc.fields.get('__js') or ''
  231. # custom script
  232. custom = webnotes.conn.get_value("Custom Script", {"dt": doc.name,
  233. "script_type": "Client"}, "script") or ""
  234. js = (js + '\n' + custom).encode("utf-8")
  235. if "{% include" in js:
  236. js = webnotes.get_jenv().from_string(js).render()
  237. doc.fields["__js"] = js
  238. def expand_selects(doclist):
  239. for d in filter(lambda d: d.fieldtype=='Select' \
  240. and (d.options or '').startswith('link:'), doclist):
  241. doctype = d.options.split("\n")[0][5:]
  242. d.link_doctype = doctype
  243. d.options = '\n'.join([''] + [o.name for o in webnotes.conn.sql("""select
  244. name from `tab%s` where docstatus<2 order by name asc""" % doctype, as_dict=1)])
  245. def add_print_formats(doclist):
  246. print_formats = webnotes.conn.sql("""select * FROM `tabPrint Format`
  247. WHERE doc_type=%s AND docstatus<2""", (doclist[0].name,), as_dict=1)
  248. for pf in print_formats:
  249. doclist.append(webnotes.model.doc.Document('Print Format', fielddata=pf))
  250. def get_property(dt, prop, fieldname=None):
  251. """get a doctype property"""
  252. doctypelist = get(dt)
  253. if fieldname:
  254. field = doctypelist.get_field(fieldname)
  255. return field and field.fields.get(prop) or None
  256. else:
  257. return doctypelist[0].fields.get(prop)
  258. def get_link_fields(doctype):
  259. """get docfields of links and selects with "link:" """
  260. doctypelist = get(doctype)
  261. return doctypelist.get({"fieldtype":"Link"}).extend(doctypelist.get({"fieldtype":"Select",
  262. "options": "^link:"}))
  263. def add_validators(doctype, doclist):
  264. for validator in webnotes.conn.sql("""select name from `tabDocType Validator` where
  265. for_doctype=%s""", (doctype,), as_dict=1):
  266. doclist.extend(webnotes.get_doclist('DocType Validator', validator.name))
  267. def add_search_fields(doclist):
  268. """add search fields found in the doctypes indicated by link fields' options"""
  269. for lf in doclist.get({"fieldtype": "Link", "options":["!=", "[Select]"]}):
  270. if lf.options:
  271. search_fields = get(lf.options)[0].search_fields
  272. if search_fields:
  273. lf.search_fields = map(lambda sf: sf.strip(), search_fields.split(","))
  274. def update_language(doclist):
  275. """update language"""
  276. if webnotes.local.lang != 'en':
  277. doclist[0].fields["__messages"] = webnotes.get_lang_dict("doctype", doclist[0].name)
  278. class DocTypeDocList(webnotes.model.doclist.DocList):
  279. def get_field(self, fieldname, parent=None, parentfield=None):
  280. filters = {"doctype":"DocField"}
  281. if isinstance(fieldname, dict):
  282. filters.update(fieldname)
  283. else:
  284. filters["fieldname"] = fieldname
  285. # if parentfield, get the name of the parent table
  286. if parentfield:
  287. parent = self.get_options(parentfield)
  288. if parent:
  289. filters["parent"] = parent
  290. else:
  291. filters["parent"] = self[0].name
  292. fields = self.get(filters)
  293. if fields:
  294. return fields[0]
  295. def get_fieldnames(self, filters=None):
  296. if not filters: filters = {}
  297. filters.update({"doctype": "DocField", "parent": self[0].name})
  298. return map(lambda df: df.fieldname, self.get(filters))
  299. def get_options(self, fieldname, parent=None, parentfield=None):
  300. return self.get_field(fieldname, parent, parentfield).options
  301. def get_label(self, fieldname, parent=None, parentfield=None):
  302. return self.get_field(fieldname, parent, parentfield).label
  303. def get_table_fields(self):
  304. return self.get({"doctype": "DocField", "fieldtype": "Table"})
  305. def get_parent_doclist(self):
  306. return webnotes.doclist([self[0]] + self.get({"parent": self[0].name}))
  307. def get_restricted_fields(self, restricted_types):
  308. restricted_fields = self.get({
  309. "doctype":"DocField",
  310. "fieldtype":"Link",
  311. "parent": self[0].name,
  312. "ignore_restrictions":("!=", 1),
  313. "options":("in", restricted_types)
  314. })
  315. if self[0].name in restricted_types:
  316. restricted_fields.append(webnotes._dict({"label":"Name", "fieldname":"name", "options": self[0].name}))
  317. return restricted_fields
  318. def get_permissions(self, user=None):
  319. user_roles = webnotes.get_roles(user)
  320. return [p for p in self.get({"doctype": "DocPerm"})
  321. if cint(p.permlevel)==0 and (p.role=="All" or p.role in user_roles)]
  322. def rename_field(doctype, old_fieldname, new_fieldname, lookup_field=None):
  323. """this function assumes that sync is NOT performed"""
  324. import webnotes.model
  325. doctype_list = get(doctype)
  326. old_field = doctype_list.get_field(lookup_field or old_fieldname)
  327. if not old_field:
  328. print "rename_field: " + (lookup_field or old_fieldname) + " not found."
  329. if old_field.fieldtype == "Table":
  330. # change parentfield of table mentioned in options
  331. webnotes.conn.sql("""update `tab%s` set parentfield=%s
  332. where parentfield=%s""" % (old_field.options.split("\n")[0], "%s", "%s"),
  333. (new_fieldname, old_fieldname))
  334. elif old_field.fieldtype not in webnotes.model.no_value_fields:
  335. # copy
  336. if doctype_list[0].issingle:
  337. webnotes.conn.sql("""update `tabSingles` set field=%s
  338. where doctype=%s and field=%s""",
  339. (new_fieldname, doctype, old_fieldname))
  340. else:
  341. webnotes.conn.sql("""update `tab%s` set `%s`=`%s`""" % \
  342. (doctype, new_fieldname, old_fieldname))