選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

315 行
7.5 KiB

  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. from __future__ import unicode_literals
  23. """
  24. Model utilities, unclassified functions
  25. """
  26. def expand(docs):
  27. """
  28. Expand a doclist sent from the client side. (Internally used by the request handler)
  29. """
  30. def xzip(a,b):
  31. d = {}
  32. for i in range(len(a)):
  33. d[a[i]] = b[i]
  34. return d
  35. from webnotes.utils import load_json
  36. docs = load_json(docs)
  37. clist = []
  38. for d in docs['_vl']:
  39. doc = xzip(docs['_kl'][d[0]], d);
  40. clist.append(doc)
  41. return clist
  42. def compress(doclist):
  43. """
  44. Compress a doclist before sending it to the client side. (Internally used by the request handler)
  45. """
  46. if doclist and hasattr(doclist[0],'fields'):
  47. docs = [d.fields for d in doclist]
  48. else:
  49. docs = doclist
  50. kl, vl = {}, []
  51. forbidden = ['server_code_compiled']
  52. # scan for keys & values
  53. for d in docs:
  54. dt = d['doctype']
  55. if not (dt in kl.keys()):
  56. kl[dt] = ['doctype','localname','__oldparent','__unsaved']
  57. # add client script for doctype, doctype due to ambiguity
  58. if dt=='DocType' and '__client_script' not in kl[dt]:
  59. kl[dt].append('__client_script')
  60. for f in d.keys():
  61. if not (f in kl[dt]) and not (f in forbidden):
  62. # if key missing, then append
  63. kl[dt].append(f)
  64. # build values
  65. tmp = []
  66. for f in kl[dt]:
  67. v = d.get(f)
  68. if type(v)==long:
  69. v=int(v)
  70. tmp.append(v)
  71. vl.append(tmp)
  72. #errprint(str({'_vl':vl,'_kl':kl}))
  73. return {'_vl':vl,'_kl':kl}
  74. def getlist(doclist, field):
  75. """
  76. Filter a list of records for a specific field from the full doclist
  77. Example::
  78. # find all phone call details
  79. dl = getlist(self.doclist, 'contact_updates')
  80. pl = []
  81. for d in dl:
  82. if d.type=='Phone':
  83. pl.append(d)
  84. """
  85. from webnotes.utils import cint
  86. l = []
  87. for d in doclist:
  88. if d.parent and (not d.parent.lower().startswith('old_parent:')) and d.parentfield == field:
  89. l.append(d)
  90. l.sort(lambda a, b: cint(a.idx) - cint(b.idx))
  91. return l
  92. # Copy doclist
  93. # ------------
  94. def copy_doclist(doclist, no_copy = []):
  95. """
  96. Save & return a copy of the given doclist
  97. Pass fields that are not to be copied in `no_copy`
  98. """
  99. from webnotes.model.doc import Document
  100. cl = []
  101. # main doc
  102. c = Document(fielddata = doclist[0].fields.copy())
  103. # clear no_copy fields
  104. for f in no_copy:
  105. if c.fields.has_key(f):
  106. c.fields[f] = None
  107. c.name = None
  108. c.save(1)
  109. cl.append(c)
  110. # new parent name
  111. parent = c.name
  112. # children
  113. for d in doclist[1:]:
  114. c = Document(fielddata = d.fields.copy())
  115. c.name = None
  116. # clear no_copy fields
  117. for f in no_copy:
  118. if c.fields.has_key(f):
  119. c.fields[f] = None
  120. c.parent = parent
  121. c.save(1)
  122. cl.append(c)
  123. return cl
  124. def getvaluelist(doclist, fieldname):
  125. """
  126. Returns a list of values of a particualr fieldname from all Document object in a doclist
  127. """
  128. l = []
  129. for d in doclist:
  130. l.append(d.fields[fieldname])
  131. return l
  132. def _make_html(doc, link_list):
  133. from webnotes.utils import cstr
  134. out = '<table class="simpletable">'
  135. for k in doc.fields.keys():
  136. if k!='server_code_compiled':
  137. v = cstr(doc.fields[k])
  138. # link field
  139. if v and (k in link_list.keys()):
  140. dt = link_list[k]
  141. if isinstance(dt, basestring) and dt.startswith('link:'):
  142. dt = dt[5:]
  143. v = '<a href="index.cgi?page=Form/%s/%s">%s</a>' % (dt, v, v)
  144. out += '\t<tr><td>%s</td><td>%s</td></tr>\n' % (cstr(k), v)
  145. out += '</table>'
  146. return out
  147. def to_html(doclist):
  148. """
  149. Return a simple HTML format of the doclist
  150. """
  151. out = ''
  152. link_lists = {}
  153. for d in doclist:
  154. if not link_lists.get(d.doctype):
  155. link_lists[d.doctype] = d.make_link_list()
  156. out += _make_html(d, link_lists[d.doctype])
  157. return out
  158. def commonify_doclist(doclist, with_comments=1):
  159. """
  160. Makes a doclist more readable by extracting common properties.
  161. This is used for printing Documents in files
  162. """
  163. from webnotes.utils import get_common_dict, get_diff_dict
  164. def make_common(doclist):
  165. c = {}
  166. if with_comments:
  167. c['##comment'] = 'These values are common in all dictionaries'
  168. for k in common_keys:
  169. c[k] = doclist[0][k]
  170. return c
  171. def strip_common_and_idx(d):
  172. for k in common_keys:
  173. if k in d: del d[k]
  174. if 'idx' in d: del d['idx']
  175. return d
  176. def make_common_dicts(doclist):
  177. common_dict = {} # one per doctype
  178. # make common dicts for all records
  179. for d in doclist:
  180. if not d['doctype'] in common_dict:
  181. d1 = d.copy()
  182. del d1['name']
  183. common_dict[d['doctype']] = d1
  184. else:
  185. common_dict[d['doctype']] = get_common_dict(common_dict[d['doctype']], d)
  186. return common_dict
  187. common_keys = ['owner','docstatus','creation','modified','modified_by']
  188. common_dict = make_common_dicts(doclist)
  189. # make docs
  190. final = []
  191. for d in doclist:
  192. f = strip_common_and_idx(get_diff_dict(common_dict[d['doctype']], d))
  193. f['doctype'] = d['doctype'] # keep doctype!
  194. # strip name for child records (only an auto generated number!)
  195. if f['doctype'] != doclist[0]['doctype']:
  196. del f['name']
  197. if with_comments:
  198. f['##comment'] = d['doctype'] + ('name' in f and (', ' + f['name']) or '')
  199. final.append(f)
  200. # add commons
  201. commons = []
  202. for d in common_dict.values():
  203. d['name']='__common__'
  204. if with_comments:
  205. d['##comment'] = 'These values are common for all ' + d['doctype']
  206. commons.append(strip_common_and_idx(d))
  207. common_values = make_common(doclist)
  208. return [common_values]+commons+final
  209. def uncommonify_doclist(dl):
  210. """
  211. Expands an commonified doclist
  212. """
  213. # first one has common values
  214. common_values = dl[0]
  215. common_dict = {}
  216. final = []
  217. idx_dict = {}
  218. for d in dl[1:]:
  219. if 'name' in d and d['name']=='__common__':
  220. # common for a doctype -
  221. del d['name']
  222. common_dict[d['doctype']] = d
  223. else:
  224. dt = d['doctype']
  225. if not dt in idx_dict: idx_dict[dt] = 1;
  226. d1 = common_values.copy()
  227. # update from common and global
  228. d1.update(common_dict[dt])
  229. d1.update(d)
  230. # idx by sequence
  231. d1['idx'] = idx_dict[dt]
  232. # increment idx
  233. idx_dict[dt] += 1
  234. final.append(d1)
  235. return final
  236. def pprint_doclist(doclist, with_comments = 1):
  237. """
  238. Pretty Prints a doclist with common keys separated and comments
  239. """
  240. from webnotes.utils import pprint_dict
  241. dictlist =[pprint_dict(d) for d in commonify_doclist(doclist, with_comments)]
  242. title = '# '+doclist[0]['doctype']+', '+doclist[0]['name']
  243. return title + '\n[\n' + ',\n'.join(dictlist) + '\n]'
  244. def peval_doclist(txt):
  245. """
  246. Restore a pretty printed doclist
  247. """
  248. if txt.startswith('#'):
  249. return uncommonify_doclist(eval(txt))
  250. else:
  251. return eval(txt)
  252. return uncommonify_doclist(eval(txt))