You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

326 lines
9.5 KiB

  1. """
  2. Merges (syncs) incoming doclist into the database
  3. Called when:
  4. importing .txt files
  5. importing bulk records from .csv files
  6. For regular types, deletes the record and recreates it
  7. for special types: `DocType`, `Module Def`, `DocType Mapper` there are subclasses
  8. To use::
  9. set_doc(doclist, ovr=1, ingore=1, noupdate=1)
  10. """
  11. import webnotes
  12. from webnotes.model.doc import Document
  13. # this variable is a flag that transfer process is on, to the on_update
  14. # method so that if there are other processes on import, it can do so
  15. in_transfer = 0
  16. def set_doc(doclist, ovr=0, ignore=1, onupdate=1):
  17. """
  18. Wrapper function to sync a record
  19. """
  20. global in_transfer
  21. dt = doclist[0]['doctype']
  22. if webnotes.conn.exists(doclist[0]['doctype'], doclist[0]['name']):
  23. # exists, merge if possible
  24. if dt=='DocType':
  25. ud = UpdateDocType(doclist)
  26. elif dt == 'Module Def':
  27. ud = UpdateModuleDef(doclist)
  28. elif dt == 'DocType Mapper':
  29. ud = UpdateDocTypeMapper(doclist)
  30. else:
  31. ud = UpdateDocument(doclist)
  32. else:
  33. ud = UpdateDocument(doclist)
  34. in_transfer = 1
  35. ud.sync()
  36. in_transfer = 0
  37. return '\n'.join(ud.log)
  38. #
  39. # Class to sync incoming document
  40. #
  41. class UpdateDocument:
  42. def __init__(self, in_doclist=[]):
  43. self.in_doclist = in_doclist
  44. self.doc = Document(fielddata = in_doclist[0])
  45. self.modified = self.doc.modified # make a copy
  46. self.doclist = []
  47. self.log = []
  48. self.exists = 0
  49. # sync
  50. def sync(self):
  51. is_mod = self.is_modified()
  52. if (not self.exists) or (is_mod):
  53. webnotes.conn.begin()
  54. if self.exists:
  55. self.delete_existing()
  56. self.save()
  57. self.update_modified()
  58. self.run_on_update()
  59. webnotes.conn.commit()
  60. # check modified
  61. def is_modified(self):
  62. try:
  63. timestamp = webnotes.conn.sql("select modified from `tab%s` where name=%s" % (self.doc.doctype, '%s'), self.doc.name)
  64. except Exception ,e:
  65. if(e.args[0]==1146):
  66. return
  67. else:
  68. raise e
  69. if timestamp:
  70. self.exists = 1
  71. if str(timestamp[0][0]) == self.doc.modified:
  72. self.log.append('%s %s, No change' % (self.doc.doctype, self.doc.name))
  73. else: return 1
  74. # delete existing
  75. def delete_existing(self):
  76. from webnotes.model import delete_doc
  77. delete_doc(self.doc.doctype, self.doc.name, force=1)
  78. # update modified timestamp
  79. def update_modified(self):
  80. webnotes.conn.set(self.doc, 'modified', self.modified)
  81. def save(self):
  82. # parent
  83. self.doc.save(new = 1, ignore_fields = 1, check_links=0)
  84. self.doclist = [self.doc]
  85. self.save_children()
  86. def save_children(self):
  87. for df in self.in_doclist[1:]:
  88. self.save_one_doc(df)
  89. def save_one_doc(self, df, as_new=1):
  90. d = Document(fielddata = df)
  91. d.save(new = as_new, ignore_fields = 1, check_links=0)
  92. self.doclist.append(d)
  93. def run_on_update(self):
  94. from webnotes.model.code import get_server_obj
  95. so = get_server_obj(self.doc, self.doclist)
  96. if hasattr(so, 'on_update'):
  97. so.on_update()
  98. class UpdateDocumentMerge(UpdateDocument):
  99. def __init__(self, in_doclist):
  100. self.to_update_doctype = []
  101. UpdateDocument.__init__(self, in_doclist)
  102. def delete_existing(self):
  103. pass
  104. def get_id(self, d):
  105. pass
  106. def to_update(self, d):
  107. return 1
  108. def child_exists(self, d):
  109. return self.get_id(d)
  110. def on_save(self):
  111. pass
  112. def save(self):
  113. if self.exists:
  114. # save main doc
  115. self.keep_values(self.doc)
  116. self.doc.save(ignore_fields = 1, check_links=0)
  117. self.doclist.append(self.doc)
  118. self.save_children()
  119. self.on_save()
  120. self.log.append('Updated %s' % self.doc.name)
  121. else:
  122. UpdateDocument.save(self)
  123. def save_children(self):
  124. for df in self.in_doclist[1:]:
  125. d = Document(fielddata = df)
  126. # update doctype?
  127. if d.doctype in self.to_update_doctype:
  128. # update this record?
  129. if self.to_update(d):
  130. # is it new?
  131. if self.child_exists(d):
  132. self.keep_values(d)
  133. d.save(ignore_fields = 1, check_links=0)
  134. self.log.append('updated %s, %s' % (d.doctype, d.name))
  135. else:
  136. d.save(1, ignore_fields = 1, check_links=0)
  137. self.log.append('new %s' % d.doctype)
  138. self.doclist.append(d)
  139. def keep_values(self, d):
  140. if hasattr(self, 'get_orignal_values'):
  141. ov = self.get_orignal_values(d)
  142. if ov:
  143. d.fields.update(ov)
  144. class UpdateDocType(UpdateDocumentMerge):
  145. """
  146. Import a doctype from txt to database
  147. """
  148. def __init__(self, in_doclist):
  149. UpdateDocumentMerge.__init__(self, in_doclist)
  150. self.to_update_doctype = ['DocType', 'DocField']
  151. def to_udpate(self, d):
  152. if (d.fieldtype not in ['Section Break', 'Column Break', 'HTML']) and (d.fieldname or d.label):
  153. return 1
  154. def get_id(self, d):
  155. key = d.fieldname and 'fieldname' or 'label'
  156. if d.fields.get(key):
  157. return webnotes.conn.sql("""select name, options, permlevel, reqd, print_hide, hidden
  158. from tabDocField where %s=%s and parent=%s""" % (key, '%s', '%s'), (d.fields[key], d.parent))
  159. def on_save(self):
  160. self.renum()
  161. def child_exists(self, d):
  162. if d.doctype=='DocField':
  163. return self.get_id(d)
  164. def get_orignal_values(self, d):
  165. if d.doctype=='DocField':
  166. t = self.get_id(d)[0]
  167. return {'name': t[0], 'options': t[1], 'reqd':t[3], 'print_hide':t[4], 'hidden':t[5]}
  168. if d.doctype=='DocType':
  169. return webnotes.conn.sql("select server_code, client_script from `tabDocType` where name=%s", d.name, as_dict = 1)[0]
  170. # renumber the indexes
  171. def renum(self):
  172. extra = self.get_extra_fields()
  173. self.clear_section_breaks()
  174. self.add_section_breaks_and_renum()
  175. self.fix_extra_fields(extra)
  176. # get fields not in the incoming list (to preserve order)
  177. def get_extra_fields(self):
  178. prev_field, prev_field_key, extra = '', '', []
  179. # get new fields and labels
  180. fieldnames = [d.get('fieldname') for d in self.in_doclist]
  181. labels = [d.get('label') for d in self.in_doclist]
  182. # check if all existing are present
  183. for f in webnotes.conn.sql("select fieldname, label, idx from tabDocField where parent=%s and fieldtype not in ('Section Break', 'Column Break', 'HTML') order by idx asc", self.doc.name):
  184. if f[0] and not f[0] in fieldnames:
  185. extra.append([f[0], f[1], prev_field, prev_field_key])
  186. elif f[1] and not f[1] in labels:
  187. extra.append([f[0], f[1], prev_field, prev_field_key])
  188. prev_field, prev_field_key = f[0] or f[1], f[0] and 'fieldname' or 'label'
  189. return extra
  190. # clear section breaks
  191. def clear_section_breaks(self):
  192. webnotes.conn.sql("delete from tabDocField where fieldtype in ('Section Break', 'Column Break', 'HTML') and parent=%s and ifnull(options,'')!='Custom'", self.doc.name)
  193. # add section breaks
  194. def add_section_breaks_and_renum(self):
  195. for d in self.in_doclist:
  196. if d.get('parentfield')=='fields':
  197. if d.get('fieldtype') in ('Section Break', 'Column Break', 'HTML'):
  198. tmp = Document(fielddata = d)
  199. tmp.fieldname = ''
  200. tmp.name = None
  201. tmp.save(1, ignore_fields = 1, check_links=0)
  202. else:
  203. webnotes.conn.sql("update tabDocField set idx=%s where %s=%s and parent=%s" % \
  204. ('%s', d.get('fieldname') and 'fieldname' or 'label', '%s', '%s'), (d.get('idx'), d.get('fieldname') or d.get('label'), self.doc.name))
  205. # adjust the extra fields
  206. def fix_extra_fields(self, extra):
  207. # push fields down at new idx
  208. for e in extra:
  209. # get idx of the prev to extra field
  210. idx = 0
  211. if e[2]:
  212. idx = webnotes.conn.sql("select idx from tabDocField where %s=%s and parent=%s" % (e[3], '%s', '%s'), (e[2], self.doc.name))
  213. idx = idx and idx[0][0] or 0
  214. if idx:
  215. webnotes.conn.sql("update tabDocField set idx=idx+1 where idx>%s and parent=%s", (idx, self.doc.name))
  216. webnotes.conn.sql("update tabDocField set idx=%s where %s=%s and parent=%s" % \
  217. ('%s', e[0] and 'fieldname' or 'label', '%s', '%s'), (idx+1, e[0] or e[1], self.doc.name))
  218. def run_on_update(self):
  219. from webnotes.model.code import get_server_obj
  220. so = get_server_obj(self.doc, self.doclist)
  221. if hasattr(so, 'on_update'):
  222. so.on_update()
  223. class UpdateModuleDef(UpdateDocumentMerge):
  224. """
  225. Merge `Module Def`
  226. """
  227. def __init__(self, in_doclist):
  228. UpdateDocumentMerge.__init__(self, in_doclist)
  229. self.to_update_doctype = ['Module Def', 'Module Def Item']
  230. def get_id(self, d):
  231. return webnotes.conn.sql("select name from `tabModule Def Item` where doc_type=%s and doc_name=%s and display_name=%s and parent=%s", (d.doc_type, d.doc_name, d.display_name, d.parent))
  232. def to_update(self, d):
  233. if d.doctype=='Module Def Item': return 1
  234. def get_orignal_values(self, d):
  235. if d.doctype=='Module Def Item':
  236. return {'name': self.get_id(d)[0][0]}
  237. if d.doctype=='Module Def':
  238. return webnotes.conn.sql("select module_seq, disabled, is_hidden from `tabModule Def` where name=%s", d.name, as_dict = 1)[0]
  239. def run_on_update(self):
  240. # no scripts for Module Def
  241. pass
  242. class UpdateDocTypeMapper(UpdateDocumentMerge):
  243. """
  244. Merge `DocType Mapper`
  245. """
  246. def __init__(self, in_doclist):
  247. UpdateDocumentMerge.__init__(self, in_doclist)
  248. self.to_update_doctype = ['Field Mapper Detail', 'Table Mapper Detail']
  249. def get_id(self, d):
  250. if d.doctype=='Field Mapper Detail':
  251. return webnotes.conn.sql("select name from `tabField Mapper Detail` where from_field=%s and to_field=%s and match_id=%s and parent=%s", (d.from_field, d.to_field, d.match_id, d.parent))
  252. elif d.doctype=='Table Mapper Detail':
  253. return webnotes.conn.sql("select name from `tabTable Mapper Detail` where from_table=%s and to_table = %s and match_id=%s and validation_logic=%s and parent=%s", (d.from_table, d.to_table, d.match_id, d.validation_logic, d.parent))
  254. def get_orignal_values(self, d):
  255. if d.doctype in ['Field Mapper Detail', 'Table Mapper Detail']:
  256. return {'name': self.get_id(d)[0][0]}