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.
 
 
 
 
 
 

233 lines
6.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. Merges (syncs) incoming doclist into the database
  25. Called when:
  26. importing .txt files
  27. importing bulk records from .csv files
  28. For regular types, deletes the record and recreates it
  29. for special types: `DocType`, `Module Def`, `DocType Mapper` there are subclasses
  30. To use::
  31. set_doc(doclist, ovr=1, ingore=1, noupdate=1)
  32. """
  33. import webnotes
  34. from webnotes.model.doc import Document
  35. # this variable is a flag that transfer process is on, to the on_update
  36. # method so that if there are other processes on import, it can do so
  37. in_transfer = 0
  38. no_sync = {
  39. "Report": ["disabled"]
  40. }
  41. def set_doc(doclist, ovr=0, ignore=1, onupdate=1):
  42. """
  43. Wrapper function to sync a record
  44. """
  45. if doclist[0].doctype == "DocType":
  46. from webnotes.model.sync import merge_doctype
  47. return merge_doctype(doclist, force=ovr)
  48. global in_transfer
  49. dt = doclist[0]['doctype']
  50. if webnotes.conn.exists(doclist[0]['doctype'], doclist[0]['name']):
  51. # exists, merge if possible
  52. if dt == 'DocType Mapper':
  53. ud = UpdateDocTypeMapper(doclist)
  54. else:
  55. ud = UpdateDocument(doclist)
  56. else:
  57. ud = UpdateDocument(doclist)
  58. in_transfer = 1
  59. ud.sync()
  60. in_transfer = 0
  61. return '\n'.join(ud.log)
  62. class UpdateDocument:
  63. def __init__(self, in_doclist=[]):
  64. self.in_doclist = in_doclist
  65. self.doc = Document(fielddata = in_doclist[0])
  66. self.old_doc = None
  67. self.modified = self.doc.modified # make a copy
  68. self.doclist = []
  69. self.log = []
  70. self.exists = 0
  71. # sync
  72. def sync(self):
  73. is_mod = self.is_modified()
  74. if (not self.exists) or (is_mod):
  75. webnotes.conn.begin()
  76. if self.exists:
  77. self.delete_existing()
  78. self.save()
  79. self.run_on_update()
  80. self.update_modified()
  81. webnotes.conn.commit()
  82. # check modified
  83. def is_modified(self):
  84. try:
  85. timestamp = webnotes.conn.get_value(self.doc.doctype, self.doc.name, "modified")
  86. except Exception ,e:
  87. if(e.args[0]==1146):
  88. return
  89. else:
  90. raise e
  91. if timestamp:
  92. self.exists = 1
  93. if str(timestamp) == self.doc.modified:
  94. self.log.append('%s %s, No change' % (self.doc.doctype, self.doc.name))
  95. else: return 1
  96. # delete existing
  97. def delete_existing(self):
  98. from webnotes.model import delete_doc
  99. self.old_doc = webnotes.doc(self.doc.doctype, self.doc.name)
  100. delete_doc(self.doc.doctype, self.doc.name, force=1)
  101. # update modified timestamp
  102. def update_modified(self):
  103. webnotes.conn.sql("""update `tab{doctype}`
  104. SET modified=%s WHERE name=%s""".format(doctype=self.doc.doctype),
  105. (self.modified, self.doc.name))
  106. def save(self):
  107. # parent
  108. self.update_no_sync(self.doc)
  109. self.doc.save(new = 1, check_links=0)
  110. self.doclist = [self.doc]
  111. self.save_children()
  112. def save_children(self):
  113. for df in self.in_doclist[1:]:
  114. self.save_one_doc(df)
  115. def update_no_sync(self, d):
  116. if d.doctype in no_sync and self.old_doc:
  117. for fieldname in no_sync[d.doctype]:
  118. d.fields[fieldname] = self.old_doc.fields.get(fieldname)
  119. def save_one_doc(self, df, as_new=1):
  120. d = Document(fielddata = df)
  121. d.save(new = as_new, check_links=0)
  122. self.doclist.append(d)
  123. def run_on_update(self):
  124. from webnotes.model.code import get_obj
  125. so = get_obj(doc=self.doc, doclist=self.doclist)
  126. if hasattr(so, 'on_update'):
  127. so.on_update()
  128. class UpdateDocumentMerge(UpdateDocument):
  129. def __init__(self, in_doclist):
  130. self.to_update_doctype = []
  131. UpdateDocument.__init__(self, in_doclist)
  132. def delete_existing(self):
  133. pass
  134. def get_id(self, d):
  135. pass
  136. def to_update(self, d):
  137. return 1
  138. def child_exists(self, d):
  139. return self.get_id(d)
  140. def on_save(self):
  141. pass
  142. def save(self):
  143. if self.exists:
  144. # save main doc
  145. self.keep_values(self.doc)
  146. self.doc.save(check_links=0)
  147. self.doclist.append(self.doc)
  148. self.save_children()
  149. self.on_save()
  150. self.log.append('Updated %s' % self.doc.name)
  151. else:
  152. UpdateDocument.save(self)
  153. def save_children(self):
  154. for df in self.in_doclist[1:]:
  155. d = Document(fielddata = df)
  156. # update doctype?
  157. if d.doctype in self.to_update_doctype:
  158. # update this record?
  159. if self.to_update(d):
  160. # is it new?
  161. if self.child_exists(d):
  162. self.keep_values(d)
  163. d.save(check_links=0)
  164. self.log.append('updated %s, %s' % (d.doctype, d.name))
  165. else:
  166. d.save(1, check_links=0)
  167. self.log.append('new %s' % d.doctype)
  168. self.doclist.append(d)
  169. def keep_values(self, d):
  170. if hasattr(self, 'get_orignal_values'):
  171. ov = self.get_orignal_values(d)
  172. if ov:
  173. d.fields.update(ov)
  174. class UpdateDocTypeMapper(UpdateDocumentMerge):
  175. """
  176. Merge `DocType Mapper`
  177. """
  178. def __init__(self, in_doclist):
  179. UpdateDocumentMerge.__init__(self, in_doclist)
  180. self.to_update_doctype = ['Field Mapper Detail', 'Table Mapper Detail']
  181. def get_id(self, d):
  182. if d.doctype=='Field Mapper Detail':
  183. 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))
  184. elif d.doctype=='Table Mapper Detail':
  185. 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))
  186. def get_orignal_values(self, d):
  187. if d.doctype in ['Field Mapper Detail', 'Table Mapper Detail']:
  188. return {'name': self.get_id(d)[0][0]}