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

319 рядки
7.6 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. return {'_vl':vl,'_kl':kl}
  73. def getlist(doclist, field):
  74. """
  75. Filter a list of records for a specific field from the full doclist
  76. Example::
  77. # find all phone call details
  78. dl = getlist(self.doclist, 'contact_updates')
  79. pl = []
  80. for d in dl:
  81. if d.type=='Phone':
  82. pl.append(d)
  83. """
  84. from webnotes.utils import cint
  85. l = []
  86. for d in doclist:
  87. if d.parentfield == field:
  88. l.append(d)
  89. l.sort(lambda a, b: cint(a.idx) - cint(b.idx))
  90. return l
  91. # Copy doclist
  92. # ------------
  93. def copy_doclist(doclist, no_copy = []):
  94. """
  95. Save & return a copy of the given doclist
  96. Pass fields that are not to be copied in `no_copy`
  97. """
  98. from webnotes.model.doc import Document
  99. cl = []
  100. # main doc
  101. c = Document(fielddata = doclist[0].fields.copy())
  102. # clear no_copy fields
  103. for f in no_copy:
  104. if c.fields.has_key(f):
  105. c.fields[f] = None
  106. c.name = None
  107. c.save(1)
  108. cl.append(c)
  109. # new parent name
  110. parent = c.name
  111. # children
  112. for d in doclist[1:]:
  113. c = Document(fielddata = d.fields.copy())
  114. c.name = None
  115. # clear no_copy fields
  116. for f in no_copy:
  117. if c.fields.has_key(f):
  118. c.fields[f] = None
  119. c.parent = parent
  120. c.save(1)
  121. cl.append(c)
  122. return cl
  123. def getvaluelist(doclist, fieldname):
  124. """
  125. Returns a list of values of a particualr fieldname from all Document object in a doclist
  126. """
  127. l = []
  128. for d in doclist:
  129. l.append(d.fields[fieldname])
  130. return l
  131. def _make_html(doc, link_list):
  132. from webnotes.utils import cstr
  133. out = '<table class="simpletable">'
  134. for k in doc.fields.keys():
  135. if k!='server_code_compiled':
  136. v = cstr(doc.fields[k])
  137. # link field
  138. if v and (k in link_list.keys()):
  139. dt = link_list[k]
  140. if isinstance(dt, basestring) and dt.startswith('link:'):
  141. dt = dt[5:]
  142. v = '<a href="index.cgi?page=Form/%s/%s">%s</a>' % (dt, v, v)
  143. out += '\t<tr><td>%s</td><td>%s</td></tr>\n' % (cstr(k), v)
  144. out += '</table>'
  145. return out
  146. def to_html(doclist):
  147. """
  148. Return a simple HTML format of the doclist
  149. """
  150. out = ''
  151. link_lists = {}
  152. for d in doclist:
  153. if not link_lists.get(d.doctype):
  154. link_lists[d.doctype] = d.make_link_list()
  155. out += _make_html(d, link_lists[d.doctype])
  156. return out
  157. def commonify_doclist(doclist, with_comments=1):
  158. """
  159. Makes a doclist more readable by extracting common properties.
  160. This is used for printing Documents in files
  161. """
  162. from webnotes.utils import get_common_dict, get_diff_dict
  163. def make_common(doclist):
  164. c = {}
  165. if with_comments:
  166. c['##comment'] = 'These values are common in all dictionaries'
  167. for k in common_keys:
  168. c[k] = doclist[0][k]
  169. return c
  170. def strip_common_and_idx(d):
  171. for k in common_keys:
  172. if k in d: del d[k]
  173. if 'idx' in d: del d['idx']
  174. return d
  175. def make_common_dicts(doclist):
  176. common_dict = {} # one per doctype
  177. # make common dicts for all records
  178. for d in doclist:
  179. if not d['doctype'] in common_dict:
  180. d1 = d.copy()
  181. del d1['name']
  182. common_dict[d['doctype']] = d1
  183. else:
  184. common_dict[d['doctype']] = get_common_dict(common_dict[d['doctype']], d)
  185. return common_dict
  186. common_keys = ['owner','docstatus','creation','modified','modified_by']
  187. common_dict = make_common_dicts(doclist)
  188. # make docs
  189. final = []
  190. for d in doclist:
  191. f = strip_common_and_idx(get_diff_dict(common_dict[d['doctype']], d))
  192. f['doctype'] = d['doctype'] # keep doctype!
  193. # strip name for child records (only an auto generated number!)
  194. if f['doctype'] != doclist[0]['doctype']:
  195. del f['name']
  196. if with_comments:
  197. f['##comment'] = d['doctype'] + ('name' in f and (', ' + f['name']) or '')
  198. final.append(f)
  199. # add commons
  200. commons = []
  201. for d in common_dict.values():
  202. d['name']='__common__'
  203. if with_comments:
  204. d['##comment'] = 'These values are common for all ' + d['doctype']
  205. commons.append(strip_common_and_idx(d))
  206. common_values = make_common(doclist)
  207. return [common_values]+commons+final
  208. def uncommonify_doclist(dl):
  209. """
  210. Expands an commonified doclist
  211. """
  212. # first one has common values
  213. common_values = dl[0]
  214. common_dict = {}
  215. final = []
  216. idx_dict = {}
  217. for d in dl[1:]:
  218. if 'name' in d and d['name']=='__common__':
  219. # common for a doctype -
  220. del d['name']
  221. common_dict[d['doctype']] = d
  222. else:
  223. dt = d['doctype']
  224. if not dt in idx_dict: idx_dict[dt] = 1;
  225. d1 = common_values.copy()
  226. # update from common and global
  227. d1.update(common_dict[dt])
  228. d1.update(d)
  229. # idx by sequence
  230. d1['idx'] = idx_dict[dt]
  231. # increment idx
  232. idx_dict[dt] += 1
  233. final.append(d1)
  234. return final
  235. def pprint_doclist(doclist, with_comments = 1):
  236. """
  237. Pretty Prints a doclist with common keys separated and comments
  238. """
  239. from webnotes.utils import pprint_dict
  240. dictlist =[pprint_dict(d) for d in commonify_doclist(doclist, with_comments)]
  241. title = '# '+doclist[0]['doctype']+', '+doclist[0]['name']
  242. return title + '\n[\n' + ',\n'.join(dictlist) + '\n]'
  243. def peval_doclist(txt):
  244. """
  245. Restore a pretty printed doclist
  246. """
  247. if txt.startswith('#'):
  248. return uncommonify_doclist(eval(txt))
  249. else:
  250. return eval(txt)
  251. return uncommonify_doclist(eval(txt))
  252. def round_doc(doc, precision_map):
  253. from webnotes.utils import flt
  254. for fieldname, precision in precision_map.items():
  255. doc.fields[fieldname] = flt(doc.fields.get(fieldname), precision)