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.

преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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 parent=%s", (d.from_table, d.to_table, d.match_id, 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]}