|
- # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
- #
- # MIT License (MIT)
- #
- # Permission is hereby granted, free of charge, to any person obtaining a
- # copy of this software and associated documentation files (the "Software"),
- # to deal in the Software without restriction, including without limitation
- # the rights to use, copy, modify, merge, publish, distribute, sublicense,
- # and/or sell copies of the Software, and to permit persons to whom the
- # Software is furnished to do so, subject to the following conditions:
- #
- # The above copyright notice and this permission notice shall be included in
- # all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
- # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- #
-
- from __future__ import unicode_literals
- """
- Merges (syncs) incoming doclist into the database
- Called when:
- importing .txt files
- importing bulk records from .csv files
-
- For regular types, deletes the record and recreates it
- for special types: `DocType`, `Module Def`, `DocType Mapper` there are subclasses
-
- To use::
- set_doc(doclist, ovr=1, ingore=1, noupdate=1)
- """
-
- import webnotes
- from webnotes.model.doc import Document
-
- # this variable is a flag that transfer process is on, to the on_update
- # method so that if there are other processes on import, it can do so
- in_transfer = 0
-
- no_sync = {
- "Report": ["disabled"]
- }
-
- def set_doc(doclist, ovr=0, ignore=1, onupdate=1):
- """
- Wrapper function to sync a record
- """
- if doclist[0].doctype == "DocType":
- from webnotes.model.sync import merge_doctype
- return merge_doctype(doclist, force=ovr)
-
- global in_transfer
- dt = doclist[0]['doctype']
-
- if webnotes.conn.exists(doclist[0]['doctype'], doclist[0]['name']):
- # exists, merge if possible
-
- if dt == 'DocType Mapper':
- ud = UpdateDocTypeMapper(doclist)
- else:
- ud = UpdateDocument(doclist)
- else:
- ud = UpdateDocument(doclist)
-
- in_transfer = 1
- ud.sync()
- in_transfer = 0
- return '\n'.join(ud.log)
-
-
- class UpdateDocument:
- def __init__(self, in_doclist=[]):
- self.in_doclist = in_doclist
- self.doc = Document(fielddata = in_doclist[0])
- self.old_doc = None
- self.modified = self.doc.modified # make a copy
- self.doclist = []
-
- self.log = []
- self.exists = 0
-
- # sync
- def sync(self):
- is_mod = self.is_modified()
-
- if (not self.exists) or (is_mod):
- webnotes.conn.begin()
- if self.exists:
- self.delete_existing()
- self.save()
- self.run_on_update()
- self.update_modified()
- webnotes.conn.commit()
-
- # check modified
- def is_modified(self):
- try:
- timestamp = webnotes.conn.get_value(self.doc.doctype, self.doc.name, "modified")
- except Exception ,e:
- if(e.args[0]==1146):
- return
- else:
- raise e
-
- if timestamp:
- self.exists = 1
- if str(timestamp) == self.doc.modified:
- self.log.append('%s %s, No change' % (self.doc.doctype, self.doc.name))
- else: return 1
-
- # delete existing
- def delete_existing(self):
- from webnotes.model import delete_doc
- self.old_doc = webnotes.doc(self.doc.doctype, self.doc.name)
- delete_doc(self.doc.doctype, self.doc.name, force=1)
-
- # update modified timestamp
- def update_modified(self):
- webnotes.conn.sql("""update `tab{doctype}`
- SET modified=%s WHERE name=%s""".format(doctype=self.doc.doctype),
- (self.modified, self.doc.name))
-
- def save(self):
- # parent
- self.update_no_sync(self.doc)
- self.doc.save(new = 1, check_links=0)
- self.doclist = [self.doc]
- self.save_children()
-
- def save_children(self):
- for df in self.in_doclist[1:]:
- self.save_one_doc(df)
-
- def update_no_sync(self, d):
- if d.doctype in no_sync and self.old_doc:
- for fieldname in no_sync[d.doctype]:
- d.fields[fieldname] = self.old_doc.fields.get(fieldname)
-
- def save_one_doc(self, df, as_new=1):
- d = Document(fielddata = df)
- d.save(new = as_new, check_links=0)
- self.doclist.append(d)
-
- def run_on_update(self):
- from webnotes.model.code import get_obj
- so = get_obj(doc=self.doc, doclist=self.doclist)
- if hasattr(so, 'on_update'):
- so.on_update()
-
-
- class UpdateDocumentMerge(UpdateDocument):
- def __init__(self, in_doclist):
- self.to_update_doctype = []
- UpdateDocument.__init__(self, in_doclist)
-
- def delete_existing(self):
- pass
-
- def get_id(self, d):
- pass
-
- def to_update(self, d):
- return 1
-
- def child_exists(self, d):
- return self.get_id(d)
-
- def on_save(self):
- pass
-
- def save(self):
- if self.exists:
- # save main doc
- self.keep_values(self.doc)
- self.doc.save(check_links=0)
- self.doclist.append(self.doc)
- self.save_children()
- self.on_save()
- self.log.append('Updated %s' % self.doc.name)
- else:
- UpdateDocument.save(self)
-
- def save_children(self):
- for df in self.in_doclist[1:]:
- d = Document(fielddata = df)
-
- # update doctype?
- if d.doctype in self.to_update_doctype:
-
- # update this record?
- if self.to_update(d):
-
- # is it new?
- if self.child_exists(d):
- self.keep_values(d)
- d.save(check_links=0)
- self.log.append('updated %s, %s' % (d.doctype, d.name))
- else:
- d.save(1, check_links=0)
- self.log.append('new %s' % d.doctype)
- self.doclist.append(d)
-
- def keep_values(self, d):
- if hasattr(self, 'get_orignal_values'):
- ov = self.get_orignal_values(d)
- if ov:
- d.fields.update(ov)
-
-
- class UpdateDocTypeMapper(UpdateDocumentMerge):
- """
- Merge `DocType Mapper`
- """
- def __init__(self, in_doclist):
- UpdateDocumentMerge.__init__(self, in_doclist)
- self.to_update_doctype = ['Field Mapper Detail', 'Table Mapper Detail']
-
- def get_id(self, d):
- if d.doctype=='Field Mapper Detail':
- 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))
- elif d.doctype=='Table Mapper Detail':
- 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))
-
- def get_orignal_values(self, d):
- if d.doctype in ['Field Mapper Detail', 'Table Mapper Detail']:
- return {'name': self.get_id(d)[0][0]}
-
|