From 255cea887a3b4d27489134e1a43137743f93546e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 5 Mar 2013 14:12:33 +0530 Subject: [PATCH] updated sync --- conf/Framework.sql | 1 + conf/conf.py | 2 +- core/doctype/doctype/doctype.py | 20 +- core/doctype/letter_head/letter_head.txt | 2 - core/doctype/page/page.py | 4 +- core/doctype/page/page.txt | 1 - webnotes/__init__.py | 6 +- webnotes/install_lib/install.py | 8 + webnotes/model/bean.py | 50 +++-- webnotes/model/code.py | 2 +- webnotes/model/meta.py | 9 +- webnotes/model/sync.py | 91 +-------- webnotes/model/utils.py | 69 ++++--- webnotes/modules/export_file.py | 4 +- webnotes/modules/import_file.py | 65 ++++++- webnotes/modules/import_merge.py | 232 ----------------------- 16 files changed, 156 insertions(+), 410 deletions(-) delete mode 100644 webnotes/modules/import_merge.py diff --git a/conf/Framework.sql b/conf/Framework.sql index 5920a8cacf..38c4636863 100644 --- a/conf/Framework.sql +++ b/conf/Framework.sql @@ -38,6 +38,7 @@ CREATE TABLE `tabDocField` ( `default` text, `description` text, `in_filter` int(1) DEFAULT NULL, + `in_list_view` int(1) DEFAULT NULL, `no_column` int(1) DEFAULT NULL, `read_only` int(1) DEFAULT NULL, `print_width` varchar(180) DEFAULT NULL, diff --git a/conf/conf.py b/conf/conf.py index b282dc78bc..8025ea17f1 100644 --- a/conf/conf.py +++ b/conf/conf.py @@ -12,7 +12,7 @@ files_path = 'public/files' max_file_size = 1000000 # generate schema (.txt files) -developer_mode = 1 +developer_mode = 0 # clear cache on refresh auto_cache_clear = 0 diff --git a/core/doctype/doctype/doctype.py b/core/doctype/doctype/doctype.py index 4bb06fc76a..6e355c9603 100644 --- a/core/doctype/doctype/doctype.py +++ b/core/doctype/doctype/doctype.py @@ -79,28 +79,30 @@ class DocType: validate_fields(self.doclist.get({"doctype":"DocField"})) validate_permissions(self.doclist.get({"doctype":"DocPerm"})) self.set_version() - - def on_update(self): self.make_amendable() self.make_file_list() - - sql = webnotes.conn.sql - # make schma changes + + def on_update(self): from webnotes.model.db_schema import updatedb updatedb(self.doc.name) self.change_modified_of_parent() import conf - from webnotes.modules.import_merge import in_transfer + from webnotes.modules.import_file import in_import - if (not in_transfer) and getattr(conf,'developer_mode', 0): + if (not in_import) and getattr(conf,'developer_mode', 0): self.export_doc() self.make_controller_template() webnotes.clear_cache(doctype=self.doc.name) - + def on_trash(self): + webnotes.conn.sql("delete from `tabCustom Field` where dt = %s", name) + webnotes.conn.sql("delete from `tabCustom Script` where dt = %s", name) + webnotes.conn.sql("delete from `tabProperty Setter` where doc_type = %s", name) + webnotes.conn.sql("delete from `tabSearch Criteria` where doc_type = %s", name) + def export_doc(self): from webnotes.modules.export_file import export_to_files export_to_files(record_list=[['DocType', self.doc.name]]) @@ -142,7 +144,6 @@ class DocType: idx_list = [d.idx for d in temp_doclist if d.idx] max_idx = idx_list and max(idx_list) or 0 new.idx = max_idx + 1 - new.save() def make_amendable(self): """ @@ -166,7 +167,6 @@ class DocType: new.print_hide = 1 new.no_copy = 1 new.idx = max_idx + 1 - new.save() max_idx += 1 def validate_fields_for_doctype(doctype): diff --git a/core/doctype/letter_head/letter_head.txt b/core/doctype/letter_head/letter_head.txt index afae0e1a2a..4b8ce346c6 100644 --- a/core/doctype/letter_head/letter_head.txt +++ b/core/doctype/letter_head/letter_head.txt @@ -14,7 +14,6 @@ "doctype": "DocType", "autoname": "field:letter_head_name", "name": "__common__", - "colour": "White:FFF", "server_code_error": " ", "max_attachments": 3, "version": 1 @@ -55,7 +54,6 @@ }, { "depends_on": "letter_head_name", - "colour": "White:FFF", "doctype": "DocField", "label": "Preview", "fieldname": "preview", diff --git a/core/doctype/page/page.py b/core/doctype/page/page.py index fdd81575a7..e7cfbd8f38 100644 --- a/core/doctype/page/page.py +++ b/core/doctype/page/page.py @@ -53,8 +53,8 @@ class DocType: it will write out a .html file """ import conf - from webnotes.modules.import_merge import in_transfer - if not in_transfer and getattr(conf,'developer_mode', 0) and self.doc.standard=='Yes': + from webnotes.modules.import_file import in_import + if not in_import and getattr(conf,'developer_mode', 0) and self.doc.standard=='Yes': from webnotes.modules.export_file import export_to_files from webnotes.modules import get_module_path, scrub import os diff --git a/core/doctype/page/page.txt b/core/doctype/page/page.txt index fd1bdd0e54..82220efb21 100644 --- a/core/doctype/page/page.txt +++ b/core/doctype/page/page.txt @@ -33,7 +33,6 @@ "parent": "Page", "read": 1, "cancel": 0, - "execute": 0, "name": "__common__", "create": 1, "doctype": "DocPerm", diff --git a/webnotes/__init__.py b/webnotes/__init__.py index bbb89ec67c..9d0b6251d1 100644 --- a/webnotes/__init__.py +++ b/webnotes/__init__.py @@ -312,9 +312,9 @@ def get_doctype(doctype, processed=False): import webnotes.model.doctype return webnotes.model.doctype.get(doctype, processed) -def delete_doc(doctype=None, name=None, doclist = None, force=0): - import webnotes.model - webnotes.model.delete_doc(doctype, name, doclist, force) +def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes=[], for_reload=False): + import webnotes.model.utils + webnotes.model.utils.delete_doc(doctype, name, doclist, force, ignore_doctypes, for_reload) def clear_perms(doctype): conn.sql("""delete from tabDocPerm where parent=%s""", doctype) diff --git a/webnotes/install_lib/install.py b/webnotes/install_lib/install.py index c59ddb1b15..26713a2da0 100755 --- a/webnotes/install_lib/install.py +++ b/webnotes/install_lib/install.py @@ -144,6 +144,14 @@ class Installer: doc = webnotes.doc(fielddata=d) doc.insert() webnotes.conn.commit() + + # from webnotes.modules.import_file import import_files + # + # import_files([ + # ["core", "doctype", "docperm"], + # ["core", "doctype", "docfield"], + # ["core", "doctype", "doctype"], + # ]) def set_all_patches_as_completed(self): try: diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py index 2d1cf67c11..279ba86e98 100644 --- a/webnotes/model/bean.py +++ b/webnotes/model/bean.py @@ -42,7 +42,11 @@ class Bean: def __init__(self, dt=None, dn=None): self.docs = [] self.obj = None - self.ignore_permissions = 0 + self.ignore_permissions = False + self.ignore_children_type = [] + self.ignore_check_links = False + self.ignore_validate = False + if isinstance(dt, basestring) and not dn: dn = dt if dt and dn: @@ -75,15 +79,9 @@ class Bean: self.run_method("onload") def __iter__(self): - """ - Make this iterable - """ return self.docs.__iter__() def from_compressed(self, data, docname): - """ - Expand called from client - """ from webnotes.model.utils import expand self.docs = expand(data) self.set_doclist(self.docs) @@ -100,27 +98,18 @@ class Bean: self.obj.doc = self.doc def make_obj(self): - """ - Create a DocType object - """ if self.obj: return self.obj self.obj = webnotes.get_obj(doc=self.doc, doclist=self.doclist) self.controller = self.obj return self.obj def to_dict(self): - """ - return as a list of dictionaries - """ return [d.fields for d in self.docs] def check_if_latest(self, method="save"): - """ - Raises exception if the modified time is not the same as in the database - """ from webnotes.model.meta import is_single - if (not is_single(self.doc.doctype)) and (not cint(self.doc.fields.get('__islocal'))): + if not cint(self.doc.fields.get('__islocal')) and not is_single(self.doc.doctype): tmp = webnotes.conn.sql(""" SELECT modified, docstatus FROM `tab%s` WHERE name="%s" for update""" % (self.doc.doctype, self.doc.name), as_dict=True) @@ -158,6 +147,8 @@ class Bean: labels[self.to_docstatus], raise_exception=DocstatusTransitionError) def check_links(self): + if self.ignore_check_links: + return ref, err_list = {}, [] for d in self.docs: if not ref.get(d.doctype): @@ -209,6 +200,7 @@ class Bean: def run_method(self, method): self.make_obj() + if hasattr(self.obj, method): getattr(self.obj, method)() if hasattr(self.obj, 'custom_' + method): @@ -224,7 +216,7 @@ class Bean: def save_main(self): try: - self.doc.save(cint(self.doc.fields.get('__islocal'))) + self.doc.save(check_links = False) except NameError, e: webnotes.msgprint('%s "%s" already exists' % (self.doc.doctype, self.doc.name)) @@ -241,7 +233,7 @@ class Bean: d.parent = self.doc.name # rename if reqd d.parenttype = self.doc.doctype - d.save(new = cint(d.fields.get('__islocal'))) + d.save(check_links=False) child_map.setdefault(d.doctype, []).append(d.name) @@ -251,14 +243,15 @@ class Bean: tablefields = webnotes.model.meta.get_table_fields(self.doc.doctype) for dt in tablefields: - cnames = child_map.get(dt[0]) or [] - if cnames: - webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s and - name not in (%s)""" % (dt[0], '%s', '%s', ','.join(['%s'] * len(cnames))), - tuple([self.doc.name, self.doc.doctype] + cnames)) - else: - webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s""" \ - % (dt[0], '%s', '%s'), (self.doc.name, self.doc.doctype)) + if dt[0] not in self.ignore_children_type: + cnames = child_map.get(dt[0]) or [] + if cnames: + webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s and + name not in (%s)""" % (dt[0], '%s', '%s', ','.join(['%s'] * len(cnames))), + tuple([self.doc.name, self.doc.doctype] + cnames)) + else: + webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s""" \ + % (dt[0], '%s', '%s'), (self.doc.name, self.doc.doctype)) def insert(self): self.doc.fields["__islocal"] = 1 @@ -271,7 +264,8 @@ class Bean: if self.ignore_permissions or webnotes.has_permission(self.doc.doctype, "write", self.doc): self.to_docstatus = 0 self.prepare_for_save("save") - self.run_method('validate') + if not self.ignore_validate: + self.run_method('validate') self.save_main() self.save_children() self.run_method('on_update') diff --git a/webnotes/model/code.py b/webnotes/model/code.py index 7271a27507..6b939a8d1b 100644 --- a/webnotes/model/code.py +++ b/webnotes/model/code.py @@ -91,7 +91,7 @@ def get_server_obj(doc, doclist = [], basedoctype = ''): from core.doctype.custom_script.custom_script import get_custom_server_script # get doctype details - module = get_doctype_module(doc.doctype) + module = get_doctype_module(doc.doctype) or "core" if not module: return diff --git a/webnotes/model/meta.py b/webnotes/model/meta.py index b84fcc078f..970bfb206d 100644 --- a/webnotes/model/meta.py +++ b/webnotes/model/meta.py @@ -67,8 +67,13 @@ def get_table_fields(doctype): child_tables = [[d[0], d[1]] for d in webnotes.conn.sql("select options, fieldname from tabDocField \ where parent='%s' and fieldtype='Table'" % doctype, as_list=1)] - custom_child_tables = [[d[0], d[1]] for d in webnotes.conn.sql("select options, fieldname from `tabCustom Field` \ - where dt='%s' and fieldtype='Table'" % doctype, as_list=1)] + try: + custom_child_tables = [[d[0], d[1]] for d in webnotes.conn.sql("select options, fieldname from `tabCustom Field` \ + where dt='%s' and fieldtype='Table'" % doctype, as_list=1)] + except Exception, e: + if e.args[0]!=1146: + raise e + custom_child_tables = [] return child_tables + custom_child_tables diff --git a/webnotes/model/sync.py b/webnotes/model/sync.py index c79748dc1e..33d72fb74c 100644 --- a/webnotes/model/sync.py +++ b/webnotes/model/sync.py @@ -34,89 +34,10 @@ def walk_and_sync(start_path, force=0, sync_everything = False): module_name = path.split(os.sep)[-3] doctype = path.split(os.sep)[-2] name = path.split(os.sep)[-1] - - if doctype == 'doctype': - sync_doctype(module_name, name, force) - else: - if reload_doc(module_name, doctype, name, force): - print module_name + ' | ' + doctype + ' | ' + name + + + if reload_doc(module_name, doctype, name, force): + print module_name + ' | ' + doctype + ' | ' + name + webnotes.conn.commit() - return modules - - -# docname in small letters with underscores -def sync_doctype(module_name, docname, force=0): - """sync doctype from file if modified""" - with open(get_file_path(module_name, docname), 'r') as f: - from webnotes.modules.utils import peval_doclist - doclist = peval_doclist(f.read()) - - if merge_doctype(doclist, force): - print module_name, '|', docname - - #raise Exception - return doclist[0].get('name') - -def merge_doctype(doclist, force=False): - modified = doclist[0]['modified'] - if not doclist: - raise Exception('Bean could not be evaluated') - - db_modified = str(webnotes.conn.get_value(doclist[0].get('doctype'), - doclist[0].get('name'), 'modified')) - - if modified == db_modified and not force: - return - - webnotes.conn.begin() - - delete_doctype_docfields(doclist) - save_doctype_docfields(doclist) - save_perms_if_none_exist(doclist) - webnotes.conn.sql("""UPDATE `tab{doctype}` - SET modified=%s WHERE name=%s""".format(doctype=doclist[0]['doctype']), - (modified, doclist[0]['name'])) - - webnotes.conn.commit() - return True - -def get_file_path(module_name, docname): - if not (module_name and docname): - raise Exception('No Module Name or DocName specified') - module = __import__(module_name) - module_init_path = os.path.abspath(module.__file__) - module_path = os.sep.join(module_init_path.split(os.sep)[:-1]) - return os.sep.join([module_path, 'doctype', docname, docname + '.txt']) - -def delete_doctype_docfields(doclist): - parent = doclist[0].get('name') - if not parent: raise Exception('Could not determine parent') - webnotes.conn.sql("DELETE FROM `tabDocType` WHERE name=%s", parent) - webnotes.conn.sql("DELETE FROM `tabDocField` WHERE parent=%s", parent) - -def save_doctype_docfields(doclist): - from webnotes.model.doc import Document - parent_doc = Document(fielddata=doclist[0]) - parent_doc.save(1, check_links=0, - ignore_fields=1) - idx = 1 - for d in doclist: - if d.get('doctype') != 'DocField': continue - d['idx'] = idx - Document(fielddata=d).save(1, check_links=0, ignore_fields=1) - idx += 1 - - update_schema(parent_doc.name) - -def update_schema(docname): - from webnotes.model.db_schema import updatedb - updatedb(docname) - - webnotes.clear_cache(doctype=docname) - -def save_perms_if_none_exist(doclist): - if not webnotes.conn.sql("""select count(*) from tabDocPerm - where parent=%s""", doclist[0].name)[0][0]: - for d in doclist: - if d.get('doctype') != 'DocPerm': continue - webnotes.doc(fielddata=d).save(1, check_links=0, ignore_fields=1) + return modules \ No newline at end of file diff --git a/webnotes/model/utils.py b/webnotes/model/utils.py index 21c83ff420..d2420cf72e 100644 --- a/webnotes/model/utils.py +++ b/webnotes/model/utils.py @@ -143,12 +143,11 @@ def getvaluelist(doclist, fieldname): l.append(d.fields[fieldname]) return l -def delete_doc(doctype=None, name=None, doclist = None, force=0): +def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes=[], for_reload=False): """ Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record """ import webnotes.model.meta - sql = webnotes.conn.sql # get from form if not doctype: @@ -162,42 +161,19 @@ def delete_doc(doctype=None, name=None, doclist = None, force=0): if not webnotes.conn.exists(doctype, name): return - # permission - if webnotes.session.user!="Administrator" and not webnotes.has_permission(doctype, "cancel"): - webnotes.msgprint("User not allowed to delete.", raise_exception=1) - - tablefields = webnotes.model.meta.get_table_fields(doctype) - - # check if submitted - d = webnotes.conn.sql("select docstatus from `tab%s` where name=%s" % (doctype, '%s'), name) - if d and int(d[0][0]) == 1: - webnotes.msgprint("Submitted Record '%s' '%s' cannot be deleted" % (doctype, name)) - raise Exception - - # call on_trash if required - from webnotes.model.code import get_obj - if doclist: - obj = get_obj(doclist=doclist) - else: - obj = get_obj(doctype, name) - - if hasattr(obj,'on_trash'): - obj.on_trash() - - if doctype=='DocType': - webnotes.conn.sql("delete from `tabCustom Field` where dt = %s", name) - webnotes.conn.sql("delete from `tabCustom Script` where dt = %s", name) - webnotes.conn.sql("delete from `tabProperty Setter` where doc_type = %s", name) - webnotes.conn.sql("delete from `tabSearch Criteria` where doc_type = %s", name) - - # check if links exist - if not force: - check_if_doc_is_linked(doctype, name) - + if not for_reload: + check_permission_and_not_submitted(doctype, name) + run_on_trash(doctype, name, doclist) + # check if links exist + if not force: + check_if_doc_is_linked(doctype, name) + try: + tablefields = webnotes.model.meta.get_table_fields(doctype) webnotes.conn.sql("delete from `tab%s` where name=%s" % (doctype, "%s"), name) for t in tablefields: - webnotes.conn.sql("delete from `tab%s` where parent = %s" % (t[0], '%s'), name) + if t[0] not in ignore_doctypes: + webnotes.conn.sql("delete from `tab%s` where parent = %s" % (t[0], '%s'), name) except Exception, e: if e.args[0]==1451: webnotes.msgprint("Cannot delete %s '%s' as it is referenced in another record. You must delete the referred record first" % (doctype, name)) @@ -205,7 +181,27 @@ def delete_doc(doctype=None, name=None, doclist = None, force=0): raise e return 'okay' - + +def check_permission_and_not_submitted(self): + # permission + if webnotes.session.user!="Administrator" and not webnotes.has_permission(doctype, "cancel"): + webnotes.msgprint(_("User not allowed to delete."), raise_exception=True) + + # check if submitted + if webnotes.conn.get_value(doctype, name, "docstatus") == 1: + webnotes.msgprint(_("Submitted Record cannot be deleted")+": "+name+"("+doctype+")", + raise_exception=True) + +def run_on_trash(doctype, name, doclist): + # call on_trash if required + if doclist: + obj = webnotes.get_obj(doclist=doclist) + else: + obj = webnotes.get_obj(doctype, name) + + if hasattr(obj,'on_trash'): + obj.on_trash() + class LinkExistsError(webnotes.ValidationError): pass def check_if_doc_is_linked(dt, dn, method="Delete"): @@ -229,7 +225,6 @@ def check_if_doc_is_linked(dt, dn, method="Delete"): item[1] and item[2] or link_dt), raise_exception=LinkExistsError) - def round_floats_in_doc(doc, precision_map): from webnotes.utils import flt for fieldname, precision in precision_map.items(): diff --git a/webnotes/modules/export_file.py b/webnotes/modules/export_file.py index ac0675a7d5..883d02c60d 100644 --- a/webnotes/modules/export_file.py +++ b/webnotes/modules/export_file.py @@ -34,8 +34,8 @@ def export_to_files(record_list=[], record_module=None, verbose=0): """ Export record_list to files. record_list is a list of lists ([doctype],[docname] ) , """ - from webnotes.modules.import_merge import in_transfer - if in_transfer: + from webnotes.modules.import_file import in_import + if in_import: return module_doclist =[] diff --git a/webnotes/modules/import_file.py b/webnotes/modules/import_file.py index 947c16416a..8022c51c81 100644 --- a/webnotes/modules/import_file.py +++ b/webnotes/modules/import_file.py @@ -25,6 +25,8 @@ from __future__ import unicode_literals import webnotes, os from webnotes.modules import scrub, get_module_path, scrub_dt_dn +in_import = False + def import_files(module, dt=None, dn=None, force=False): if type(module) is list: for m in module: @@ -33,12 +35,16 @@ def import_files(module, dt=None, dn=None, force=False): return import_file(module, dt, dn, force) def import_file(module, dt, dn, force=False): - """Sync a file from txt if modifed, return false if not updated""" + """Sync a file from txt if modifed, return false if not updated""" + global in_import + in_import = True dt, dn = scrub_dt_dn(dt, dn) path = os.path.join(get_module_path(module), os.path.join(dt, dn, dn + '.txt')) - return import_file_by_path(path, force) + ret = import_file_by_path(path, force) + in_import = False + return ret def import_file_by_path(path, force=False): if os.path.exists(path): @@ -54,8 +60,7 @@ def import_file_by_path(path, force=False): if doc['modified']== str(webnotes.conn.get_value(doc['doctype'], doc['name'], 'modified')): return False - from webnotes.modules.import_merge import set_doc - set_doc(doclist, 1, 1, 1) + import_doclist(doclist) # since there is a new timestamp on the file, update timestamp in webnotes.conn.sql("update `tab%s` set modified=%s where name=%s" % \ @@ -65,3 +70,55 @@ def import_file_by_path(path, force=False): else: raise Exception, '%s missing' % path +ignore_values = { + "Report": ["disabled"], +} + +ignore_doctypes = ["Page Role", "DocPerm"] + +def import_doclist(doclist): + doctype = doclist[0]["doctype"] + name = doclist[0]["name"] + old_doc = None + + doctypes = set([d["doctype"] for d in doclist]) + ignore = list(doctypes.intersection(set(ignore_doctypes))) + + if doctype in ignore_values: + if webnotes.conn.exists(doctype, name): + old_doc = webnotes.doc(doctype, name) + + # delete old + webnotes.delete_doc(doctype, name, force=1, ignore_doctypes =ignore, for_reload=True) + + # don't overwrite ignored docs + doclist1 = remove_ignored_docs_if_they_already_exist(doclist, ignore, name) + + # update old values (if not to be overwritten) + if doctype in ignore_values and old_doc: + update_original_values(doclist1, doctype, old_doc) + + # reload_new + new_bean = webnotes.bean(doclist1) + new_bean.ignore_children_type = ignore + new_bean.ignore_check_links = True + new_bean.ignore_validate = True + new_bean.insert() + +def remove_ignored_docs_if_they_already_exist(doclist, ignore, name): + doclist1 = doclist + if ignore: + has_records = [] + for d in ignore: + if webnotes.conn.get_value(d, {"parent":name}): + has_records.append(d) + + if has_records: + doclist1 = filter(lambda d: d["doctype"] not in has_records, doclist) + + return doclist1 + +def update_original_values(doclist, doctype, old_doc): + for key in ignore_values[doctype]: + doclist[0][key] = old_doc.fields[key] + \ No newline at end of file diff --git a/webnotes/modules/import_merge.py b/webnotes/modules/import_merge.py deleted file mode 100644 index b864a8913f..0000000000 --- a/webnotes/modules/import_merge.py +++ /dev/null @@ -1,232 +0,0 @@ -# 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]} - -