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

270 lines
6.7 KiB

  1. """
  2. Transactions are defined as collection of classes, a DocList represents collection of Document
  3. objects for a transaction with main and children.
  4. Group actions like save, etc are performed on doclists
  5. """
  6. import webnotes
  7. from webnotes.utils import cint
  8. class DocList:
  9. """
  10. Collection of Documents with one parent and multiple children
  11. """
  12. def __init__(self, dt=None, dn=None):
  13. self.docs = []
  14. self.obj = None
  15. self.to_docstatus = 0
  16. if dt and dn:
  17. self.load_from_db(dt, dn)
  18. def load_from_db(self, dt, dn):
  19. """
  20. Load doclist from dt
  21. """
  22. from webnotes.model.doc import Document, getchildren
  23. doc = Document(dt, dn, prefix=prefix)
  24. # get all children types
  25. tablefields = webnotes.model.meta.get_table_fields(dt)
  26. # load chilren
  27. doclist = [doc,]
  28. for t in tablefields:
  29. doclist += getchildren(doc.name, t[0], t[1], dt, prefix=prefix)
  30. self.docs = docs
  31. def __iter__(self):
  32. """
  33. Make this iterable
  34. """
  35. return self.docs.__iter__()
  36. def from_compressed(self, data, docname):
  37. """
  38. Expand called from client
  39. """
  40. from webnotes.model.utils import expand
  41. self.docs = expand(data)
  42. self.objectify(docname)
  43. def objectify(self, docname=None):
  44. """
  45. Converts self.docs from a list of dicts to list of Documents
  46. """
  47. from webnotes.model.doc import Document
  48. self.docs = [Document(fielddata=d) for d in self.docs]
  49. if not docname:
  50. self.doc, self.children = self.docs[0], self.docs[1:]
  51. else:
  52. self.doc = None
  53. self.children = []
  54. for d in self.docs:
  55. if d.name == docname:
  56. self.doc = d
  57. else:
  58. self.children.append(d)
  59. # catch all if no self.doc
  60. if not self.doc:
  61. self.doc, self.children = self.docs[0], self.docs[1:]
  62. def make_obj(self):
  63. """
  64. Create a DocType object
  65. """
  66. if self.obj: return self.obj
  67. from webnotes.model.code import get_obj
  68. self.obj = get_obj(doc=self.doc, doclist=self.children)
  69. return self.obj
  70. def next(self):
  71. """
  72. Next doc
  73. """
  74. return self.docs.next()
  75. def to_dict(self):
  76. """
  77. return as a list of dictionaries
  78. """
  79. return [d.fields for d in self.docs]
  80. def check_if_latest(self):
  81. """
  82. Raises exception if the modified time is not the same as in the database
  83. """
  84. from webnotes.model.meta import is_single
  85. if (not is_single(self.doc.doctype)) and (not cint(self.doc.fields.get('__islocal'))):
  86. tmp = webnotes.conn.sql("""
  87. SELECT modified FROM `tab%s` WHERE name="%s" for update"""
  88. % (self.doc.doctype, self.doc.name))
  89. if tmp and str(tmp[0][0]) != str(self.doc.modified):
  90. webnotes.msgprint("""
  91. Document has been modified after you have opened it.
  92. To maintain the integrity of the data, you will not be able to save your changes.
  93. Please refresh this document. [%s/%s]""" % (tmp[0][0], self.doc.modified), raise_exception=1)
  94. def check_permission(self):
  95. """
  96. Raises exception if permission is not valid
  97. """
  98. if not self.doc.check_perm(verbose=1):
  99. webnotes.msgprint("Not enough permission to save %s" % self.doc.doctype, raise_exception=1)
  100. def check_links(self):
  101. """
  102. Checks integrity of links (throws exception if links are invalid)
  103. """
  104. ref, err_list = {}, []
  105. for d in self.docs:
  106. if not ref.get(d.doctype):
  107. ref[d.doctype] = d.make_link_list()
  108. err_list += d.validate_links(ref[d.doctype])
  109. if err_list:
  110. webnotes.msgprint("""[Link Validation] Could not find the following values: %s.
  111. Please correct and resave. Document Not Saved.""" % ', '.join(err_list), raise_exception=1)
  112. def update_timestamps_and_docstatus(self):
  113. """
  114. Update owner, creation, modified_by, modified, docstatus
  115. """
  116. from webnotes.utils import now
  117. ts = now()
  118. user = webnotes.__dict__.get('session', {}).get('user') or 'Administrator'
  119. for d in self.docs:
  120. if self.doc.__islocal:
  121. d.owner = user
  122. d.creation = ts
  123. d.modified_by = user
  124. d.modified = ts
  125. if d.docstatus != 2: # don't update deleted
  126. d.docstatus = self.to_docstatus
  127. def prepare_for_save(self, check_links):
  128. """
  129. Set owner, modified etc before saving
  130. """
  131. self.check_if_latest()
  132. self.check_permission()
  133. if check_links:
  134. self.check_links()
  135. self.update_timestamps_and_docstatus()
  136. def run_method(self, method):
  137. """
  138. Run a method and custom_method
  139. """
  140. self.make_obj()
  141. if hasattr(self.obj, method):
  142. getattr(self.obj, method)()
  143. if hasattr(self.obj, 'custom_' + method):
  144. getattr(self.obj, 'custom_' + method)()
  145. from webnotes.model.triggers import fire_event
  146. fire_event(self.doc, method)
  147. def save_main(self):
  148. """
  149. Save the main doc
  150. """
  151. try:
  152. self.doc.save(cint(self.doc.__islocal))
  153. except NameError, e:
  154. webnotes.msgprint('%s "%s" already exists' % (self.doc.doctype, self.doc.name))
  155. # prompt if cancelled
  156. if webnotes.conn.get_value(self.doc.doctype, self.doc.name, 'docstatus')==2:
  157. webnotes.msgprint('[%s "%s" has been cancelled]' % (self.doc.doctype, self.doc.name))
  158. webnotes.errprint(webnotes.utils.getTraceback())
  159. raise e
  160. def save_children(self):
  161. """
  162. Save Children, with the new parent name
  163. """
  164. for d in self.children:
  165. deleted, local = d.fields.get('__deleted',0), d.fields.get('__islocal',0)
  166. if cint(local) and cint(deleted):
  167. pass
  168. elif d.fields.has_key('parent'):
  169. if d.parent and (not d.parent.startswith('old_parent:')):
  170. d.parent = self.doc.name # rename if reqd
  171. d.parenttype = self.doc.doctype
  172. d.save(new = cint(local))
  173. def save(self, check_links=1):
  174. """
  175. Save the list
  176. """
  177. self.prepare_for_save(check_links)
  178. self.run_method('validate')
  179. self.save_main()
  180. self.save_children()
  181. self.run_method('on_update')
  182. def submit(self):
  183. """
  184. Save & Submit - set docstatus = 1, run "on_submit"
  185. """
  186. if self.doc.docstatus != 0:
  187. msgprint("Only draft can be submitted", raise_exception=1)
  188. self.to_docstatus = 1
  189. self.save()
  190. self.run_method('on_submit')
  191. def cancel(self):
  192. """
  193. Cancel - set docstatus 2, run "on_cancel"
  194. """
  195. if self.doc.docstatus != 1:
  196. msgprint("Only submitted can be cancelled", raise_exception=1)
  197. self.to_docstatus = 2
  198. self.prepare_for_save(1)
  199. self.save_main()
  200. self.save_children()
  201. self.run_method('on_cancel')
  202. def update_after_submit(self):
  203. """
  204. Update after submit - some values changed after submit
  205. """
  206. if self.doc.docstatus != 1:
  207. msgprint("Only to called after submit", raise_exception=1)
  208. self.to_docstatus = 1
  209. self.prepare_for_save(1)
  210. self.save_main()
  211. self.save_children()
  212. self.run_method('on_update_after_submit')
  213. # for bc
  214. def getlist(doclist, parentfield):
  215. """
  216. Return child records of a particular type
  217. """
  218. import webnotes.model.utils
  219. return webnotes.model.utils.getlist(doclist, parentfield)
  220. def copy_doclist(doclist, no_copy = []):
  221. """
  222. Make a copy of the doclist
  223. """
  224. import webnotes.model.utils
  225. return webnotes.model.utils.copy_doclist(doclist, no_copy)