diff --git a/cgi-bin/core/doctype/doctype/doctype.txt b/cgi-bin/core/doctype/doctype/doctype.txt index 452dc26203..f368fcd9fb 100644 --- a/cgi-bin/core/doctype/doctype/doctype.txt +++ b/cgi-bin/core/doctype/doctype/doctype.txt @@ -5,14 +5,14 @@ { 'creation': '2009-05-12 11:19:11', 'docstatus': 0, - 'modified': '2011-05-16 10:19:14', + 'modified': '2011-09-07 15:28:18', 'modified_by': 'Administrator', 'owner': 'Administrator' }, # These values are common for all DocType { - '_last_update': '1307624201', + '_last_update': '1311674341', 'allow_copy': 0, 'allow_email': 0, 'allow_print': 0, @@ -21,7 +21,6 @@ 'doctype': 'DocType', 'hide_heading': 0, 'hide_toolbar': 0, - 'idx': 0, 'issingle': 0, 'istable': 0, 'module': 'Core', @@ -32,7 +31,7 @@ 'section_style': 'Simple', 'server_code_error': ' ', 'show_in_menu': 0, - 'version': 8 + 'version': 11 }, # These values are common for all DocField @@ -52,7 +51,8 @@ 'parent': 'DocType', 'parentfield': 'permissions', 'parenttype': 'DocType', - 'read': 1 + 'read': 1, + 'role': 'Administrator' }, # DocType, DocType @@ -61,22 +61,13 @@ 'name': 'DocType' }, - # DocPerm - { - 'doctype': 'DocPerm', - 'permlevel': 0, - 'role': 'System Manager' - }, - # DocPerm { 'cancel': 0, 'create': 1, 'doctype': 'DocPerm', 'execute': 0, - 'idx': 1, 'permlevel': 0, - 'role': 'Administrator', 'submit': 0, 'write': 1 }, @@ -84,9 +75,7 @@ # DocPerm { 'doctype': 'DocPerm', - 'idx': 2, - 'permlevel': 1, - 'role': 'Administrator' + 'permlevel': 1 }, # DocField @@ -94,7 +83,6 @@ 'doctype': 'DocField', 'fieldtype': 'Section Break', 'hidden': 0, - 'idx': 1, 'label': 'Options', 'oldfieldtype': 'Section Break', 'reqd': 0, @@ -105,7 +93,6 @@ { 'doctype': 'DocField', 'fieldtype': 'Column Break', - 'idx': 2, 'label': 'Settings', 'oldfieldtype': 'Column Break', 'width': '50%' @@ -116,7 +103,6 @@ 'doctype': 'DocField', 'fieldname': 'module', 'fieldtype': 'Link', - 'idx': 3, 'label': 'Module', 'oldfieldname': 'module', 'oldfieldtype': 'Link', @@ -129,7 +115,6 @@ 'doctype': 'DocField', 'fieldname': 'version', 'fieldtype': 'Int', - 'idx': 4, 'label': 'Version', 'oldfieldname': 'version', 'oldfieldtype': 'Int' @@ -141,7 +126,6 @@ 'fieldname': 'name', 'fieldtype': 'Data', 'hidden': 1, - 'idx': 5, 'label': 'Name', 'oldfieldname': 'name', 'oldfieldtype': 'Data', @@ -155,7 +139,6 @@ 'fieldname': 'autoname', 'fieldtype': 'Data', 'hidden': 0, - 'idx': 6, 'label': 'Auto Name', 'oldfieldname': 'autoname', 'oldfieldtype': 'Data', @@ -169,7 +152,6 @@ 'fieldname': 'owner', 'fieldtype': 'Link', 'hidden': 1, - 'idx': 7, 'label': 'Owner', 'oldfieldname': 'owner', 'oldfieldtype': 'Link', @@ -182,7 +164,6 @@ 'doctype': 'DocField', 'fieldname': 'name_case', 'fieldtype': 'Select', - 'idx': 8, 'label': 'Name Case', 'oldfieldname': 'name_case', 'oldfieldtype': 'Select', @@ -195,7 +176,6 @@ 'fieldname': 'search_fields', 'fieldtype': 'Data', 'hidden': 0, - 'idx': 9, 'label': 'Search Fields', 'oldfieldname': 'search_fields', 'oldfieldtype': 'Data', @@ -210,7 +190,6 @@ 'doctype': 'DocField', 'fieldname': 'subject', 'fieldtype': 'Data', - 'idx': 10, 'label': 'Subject' }, @@ -221,7 +200,6 @@ 'doctype': 'DocField', 'fieldname': 'tag_fields', 'fieldtype': 'Data', - 'idx': 11, 'label': 'tag_fields' }, @@ -231,7 +209,6 @@ 'fieldname': 'istable', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 12, 'label': 'Is Table', 'oldfieldname': 'istable', 'oldfieldtype': 'Check', @@ -245,7 +222,6 @@ 'fieldname': 'read_only', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 13, 'label': 'Not In Search', 'oldfieldname': 'read_only', 'oldfieldtype': 'Check', @@ -258,7 +234,6 @@ 'doctype': 'DocField', 'fieldname': 'in_create', 'fieldtype': 'Check', - 'idx': 14, 'label': 'Not In Create', 'oldfieldname': 'in_create', 'oldfieldtype': 'Check' @@ -270,7 +245,6 @@ 'fieldname': 'issingle', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 15, 'label': 'Is Single', 'oldfieldname': 'issingle', 'oldfieldtype': 'Check', @@ -284,7 +258,6 @@ 'doctype': 'DocField', 'fieldname': 'read_only_onload', 'fieldtype': 'Check', - 'idx': 16, 'label': 'Show Print First', 'oldfieldname': 'read_only_onload', 'oldfieldtype': 'Check' @@ -295,7 +268,6 @@ 'doctype': 'DocField', 'fieldname': 'show_in_menu', 'fieldtype': 'Check', - 'idx': 17, 'label': 'Show In Pages', 'oldfieldname': 'show_in_menu', 'oldfieldtype': 'Check' @@ -306,7 +278,6 @@ 'doctype': 'DocField', 'fieldname': 'document_type', 'fieldtype': 'Select', - 'idx': 18, 'label': 'Document Type', 'oldfieldname': 'document_type', 'oldfieldtype': 'Select', @@ -318,7 +289,6 @@ 'doctype': 'DocField', 'fieldtype': 'Column Break', 'hidden': 0, - 'idx': 19, 'label': 'Display', 'oldfieldtype': 'Column Break', 'reqd': 0, @@ -331,7 +301,6 @@ 'doctype': 'DocField', 'fieldname': 'is_transaction_doc', 'fieldtype': 'Check', - 'idx': 20, 'label': 'Is Transaction Doc', 'oldfieldname': 'is_transaction_doc', 'oldfieldtype': 'Check' @@ -342,7 +311,6 @@ 'doctype': 'DocField', 'fieldname': 'use_template', 'fieldtype': 'Check', - 'idx': 21, 'label': 'Use Template', 'oldfieldname': 'use_template', 'oldfieldtype': 'Check' @@ -354,7 +322,6 @@ 'fieldname': 'print_outline', 'fieldtype': 'Select', 'hidden': 0, - 'idx': 22, 'label': 'Print Outline', 'oldfieldname': 'print_outline', 'oldfieldtype': 'Select', @@ -369,7 +336,6 @@ 'fieldname': 'allow_print', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 23, 'label': 'Hide Print', 'oldfieldname': 'allow_print', 'oldfieldtype': 'Check', @@ -383,7 +349,6 @@ 'fieldname': 'allow_email', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 24, 'label': 'Hide Email', 'oldfieldname': 'allow_email', 'oldfieldtype': 'Check', @@ -396,7 +361,6 @@ 'doctype': 'DocField', 'fieldname': 'in_dialog', 'fieldtype': 'Check', - 'idx': 25, 'label': 'In Dialog', 'oldfieldname': 'in_dialog', 'oldfieldtype': 'Check' @@ -408,7 +372,6 @@ 'fieldname': 'allow_copy', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 26, 'label': 'Hide Copy', 'oldfieldname': 'allow_copy', 'oldfieldtype': 'Check', @@ -422,7 +385,6 @@ 'fieldname': 'hide_toolbar', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 27, 'label': 'Hide Toolbar', 'oldfieldname': 'hide_toolbar', 'oldfieldtype': 'Check', @@ -436,7 +398,6 @@ 'fieldname': 'hide_heading', 'fieldtype': 'Check', 'hidden': 0, - 'idx': 28, 'label': 'Hide Heading', 'oldfieldname': 'hide_heading', 'oldfieldtype': 'Check', @@ -449,7 +410,6 @@ 'doctype': 'DocField', 'fieldname': 'allow_attach', 'fieldtype': 'Check', - 'idx': 29, 'label': 'Allow Attach', 'oldfieldname': 'allow_attach', 'oldfieldtype': 'Check', @@ -462,7 +422,6 @@ 'fieldname': 'max_attachments', 'fieldtype': 'Int', 'hidden': 1, - 'idx': 30, 'label': 'Max Attachments', 'oldfieldname': 'max_attachments', 'oldfieldtype': 'Int' @@ -473,7 +432,6 @@ 'doctype': 'DocField', 'fieldname': 'allow_rename', 'fieldtype': 'Check', - 'idx': 31, 'label': 'Allow Rename', 'oldfieldname': 'allow_rename', 'oldfieldtype': 'Check' @@ -484,7 +442,6 @@ 'doctype': 'DocField', 'fieldname': 'section_style', 'fieldtype': 'Select', - 'idx': 32, 'label': 'Section Style', 'oldfieldname': 'section_style', 'oldfieldtype': 'Select', @@ -497,7 +454,6 @@ 'fieldname': 'colour', 'fieldtype': 'Select', 'hidden': 0, - 'idx': 33, 'label': 'Colour', 'oldfieldname': 'colour', 'oldfieldtype': 'Select', @@ -512,7 +468,6 @@ 'fieldname': 'smallicon', 'fieldtype': 'Select', 'hidden': 0, - 'idx': 34, 'label': 'Small Icon', 'oldfieldname': 'smallicon', 'oldfieldtype': 'Select', @@ -521,11 +476,18 @@ 'search_index': 0 }, + # DocField + { + 'doctype': 'DocField', + 'fieldname': 'default_print_format', + 'fieldtype': 'Data', + 'label': 'Default Print Format' + }, + # DocField { 'doctype': 'DocField', 'fieldtype': 'Section Break', - 'idx': 35, 'label': 'Permissions', 'oldfieldtype': 'Section Break' }, @@ -534,7 +496,6 @@ { 'doctype': 'DocField', 'fieldtype': 'Column Break', - 'idx': 36, 'label': 'Roles and Permissions', 'oldfieldtype': 'Column Break', 'width': '70%' @@ -547,7 +508,6 @@ 'fieldname': 'permissions', 'fieldtype': 'Table', 'hidden': 0, - 'idx': 37, 'label': 'Permissions', 'oldfieldname': 'permissions', 'oldfieldtype': 'Table', @@ -561,7 +521,6 @@ 'doctype': 'DocField', 'fieldname': 'allow_trash', 'fieldtype': 'Check', - 'idx': 38, 'label': 'Allow Trash', 'oldfieldname': 'allow_trash', 'oldfieldtype': 'Check' @@ -571,7 +530,6 @@ { 'doctype': 'DocField', 'fieldtype': 'Column Break', - 'idx': 39, 'label': 'Print Formats', 'oldfieldtype': 'Column Break', 'width': '30%' @@ -583,7 +541,6 @@ 'fieldname': 'formats', 'fieldtype': 'Table', 'hidden': 0, - 'idx': 40, 'label': 'Formats', 'oldfieldname': 'formats', 'oldfieldtype': 'Table', @@ -597,7 +554,6 @@ 'doctype': 'DocField', 'fieldtype': 'Section Break', 'hidden': 0, - 'idx': 41, 'label': 'Fields', 'oldfieldtype': 'Section Break', 'reqd': 0, @@ -609,7 +565,6 @@ 'doctype': 'DocField', 'fieldtype': 'Column Break', 'hidden': 0, - 'idx': 42, 'label': 'Document Fields', 'oldfieldtype': 'Column Break', 'reqd': 0, @@ -622,7 +577,6 @@ 'fieldname': 'fields', 'fieldtype': 'Table', 'hidden': 0, - 'idx': 43, 'label': 'Fields', 'oldfieldname': 'fields', 'oldfieldtype': 'Table', @@ -636,7 +590,6 @@ 'doctype': 'DocField', 'fieldtype': 'Section Break', 'hidden': 0, - 'idx': 44, 'label': 'Description', 'oldfieldtype': 'Section Break', 'reqd': 0, @@ -649,7 +602,6 @@ 'fieldname': 'description', 'fieldtype': 'Text', 'hidden': 0, - 'idx': 45, 'label': 'Description', 'oldfieldname': 'description', 'oldfieldtype': 'Text', diff --git a/cgi-bin/core/doctype/doctype_mapper/doctype_mapper.py b/cgi-bin/core/doctype/doctype_mapper/doctype_mapper.py index 89cf74efae..2280f87cb5 100644 --- a/cgi-bin/core/doctype/doctype_mapper/doctype_mapper.py +++ b/cgi-bin/core/doctype/doctype_mapper/doctype_mapper.py @@ -21,41 +21,17 @@ class DocType: def __init__(self, doc, doclist=[]): self.doc = doc self.doclist = doclist - self.prefix = is_testing and 'test' or 'tab' self.ref_doc = '' + # Autoname - #--------- + #--------------------------------------------------------------------------- def autoname(self): self.doc.name = make_autoname(self.doc.from_doctype + '-' + self.doc.to_doctype) - - def map_fields_with_same_name(self, from_doctype, to_doctype, from_doc, to_doc, fld_list): - """ - Returns field list with same name in from and to doctype - """ - exception_flds = [f[0] for f in fld_list if f[2] == 'No'] - exception_flds += default_fields - exception_flds += ['amended_from', 'amendment_date', 'file_list', 'naming_series', 'status'] - - map_fld_list = [ - [d[0], d[0], 'Yes'] for d in sql(""" - select t1.fieldname - from `tabDocField` t1, `tabDocField` t2 - where t1.parent = %s and t2.parent = %s - and t1.fieldname = t2.fieldname - and t1.docstatus != 2 and t2.docstatus != 2 - and ifnull(t1.fieldname, '') != '' - """,(from_doctype, to_doctype)) if d[0] not in exception_flds - ] - - self.set_value(map_fld_list, from_doc, to_doc) - # Maps the fields in 'To DocType' - #-------------------------------- + #--------------------------------------------------------------------------- def dt_map(self, from_doctype, to_doctype, from_docname, to_doc, doclist, from_to_list = '[]'): - - # definition of arguments ''' String : contains the name of DocType initiating the function String : contains the name of DocType created by the function @@ -64,6 +40,10 @@ class DocType: String : contains doclist of 'to_doctype' String : contains list of tables which will be mapped ''' + + if not from_docname: + msgprint(from_doctype + " not selected for mapping", raise_exception=1) + # Validate reference doc docstatus self.ref_doc = from_docname self.check_ref_docstatus() @@ -71,85 +51,111 @@ class DocType: if not doclist: doclist.append(to_doc) - tbl_list = sql("select from_table, to_table, from_field, to_field, match_id, validation_logic from `tabTable Mapper Detail` where parent ='%s' order by match_id" % (from_doctype + "-" + to_doctype)) - - for t in tbl_list: - from_table_name = t[0] - to_table_name = t[1] - from_table_fname = t[2] - to_table_fname = t[3] - match_id = t[4] - validation_logic = t[5] - - - from_to = [from_table_name, to_table_name] + tbl_list = sql("select from_table, to_table, from_field, to_field, match_id, validation_logic from `tabTable Mapper Detail` where parent ='%s' order by match_id" % self.doc.name, as_dict=1) - if from_to in eval(from_to_list): - fld_list = sql("select from_field, to_field, map from `tabField Mapper Detail` where parent = '%s' and match_id = %s" % (from_doctype + "-" + to_doctype, match_id)) - if not from_docname: - msgprint(from_doctype + " not selected for mapping") - raise Exception - - # Parent to parent mapping - if from_table_name == self.doc.from_doctype and to_table_name == self.doc.to_doctype: - - # Check validation - nm = sql("select name from `tab%s` where name = '%s' and %s" % (from_doctype, from_docname, validation_logic)) - nm = nm and nm[0][0] or '' - - # If validation failed raise exception - if not nm: - msgprint("Validation failed in doctype mapper. Please contact Administrator.") - raise Exception - - from_doc = Document(from_doctype, nm) - - # Map fields with same name + for t in tbl_list: + if [t['from_table'], t['to_table']] in eval(from_to_list): + self.map_fields(t, from_doctype, from_docname, to_doc, doclist) + + # Doclist is required when called from server side for refreshing table + return doclist - self.map_fields_with_same_name(from_doctype, to_doctype, from_doc, to_doc, fld_list) - # Maps field in parent - - if fld_list: - self.set_value(fld_list, from_doc, to_doc) + #--------------------------------------------------------------------------- + def map_fields(self, t, from_dt, from_dn, to_doc, doclist): + """ + Creates from, to obj and maps flds as per mapper and with same name + """ + flds = self.get_mapper_fields(t) + flds += self.get_fields_with_same_name(t, flds) - # Parent to child OR child to child mapping + if flds: + from_docnames = self.get_docnames(t, from_dt, from_dn) + + for dn in from_docnames: + # Creates object for 'From DocType', it can be parent or child + from_doc_obj = Document(t['from_table'], dn[0]) + + # Add a row in target table in 'To DocType' and returns obj + if t['to_table'] != self.doc.to_doctype: + to_doc_obj = addchild(to_doc, t['to_field'], t['to_table'], 1, doclist) else: - dnlist = () - if from_table_name == self.doc.from_doctype: - dnlist = ((from_docname,),) - else: - dnlist = sql("select name from `tab%s` where parent='%s' and parenttype = '%s' and %s order by idx" % (from_table_name, from_docname, self.doc.from_doctype, validation_logic)) - - for dn in dnlist: - # Add a row in target table in 'To DocType' and returns obj - ch = addchild(to_doc, t[3], t[1], 1, doclist) - # Creates object for 'From DocType', it can be parent or child - d = Document(t[0], dn[0]) - # Map fields with same name - self.map_fields_with_same_name(from_table_name, t[1], d, ch, fld_list) - # Map values - if fld_list: - self.set_value(fld_list, d, ch) + to_doc_obj = to_doc + self.set_value(flds, from_doc_obj, to_doc_obj) + + #--------------------------------------------------------------------------- + def get_docnames(self, t, from_dt, from_dn): + """ + Returns docnames of source document (parent/child) + """ + docnames = () + if t['from_table'] == self.doc.from_doctype: + docnames = sql("select name from `tab%s` where name = '%s' and %s" % (from_dt, from_dn, t['validation_logic'])) + if not docnames: + msgprint("Validation failed in doctype mapper. Please contact Administrator.", raise_exception=1) + else: + docnames = sql("select name from `tab%s` where parent='%s' and parenttype = '%s' and %s order by idx" % (t['from_table'], from_dn, self.doc.from_doctype, t['validation_logic'])) + + return docnames + + + #--------------------------------------------------------------------------- + def get_mapper_fields(self, t): + return [[f[0], f[1], f[2]] for f in sql(""" + select from_field, to_field, map + from `tabField Mapper Detail` + where parent = '%s' and match_id = %s + """ % (self.doc.name, t['match_id']))] - # Required when called from server side for refreshing table - return doclist + #--------------------------------------------------------------------------- + def get_fields_with_same_name(self, t, flds): + """ + Returns field list with same name in from and to doctype + """ - # Assigns value to "To Doctype" - #------------------------------ + exception_flds = default_fields + exception_flds += [f[1] for f in flds] + + similar_flds = [ + [d[0], d[0], 'Yes'] for d in sql(""" + select t1.fieldname + from `tabDocField` t1, `tabDocField` t2 + where t1.parent = %s and t2.parent = %s + and t1.fieldname = t2.fieldname + and t1.docstatus != 2 and t2.docstatus != 2 + and ifnull(t1.no_copy, 0) = 0 + and ifnull(t1.fieldname, '') != '' + and t1.fieldtype not in ('Table', 'Section Break', 'Column Break', 'HTML') + """,(t['from_table'], t['to_table'])) if d[0] not in exception_flds + ] + + return similar_flds + + #--------------------------------------------------------------------------- def set_value(self, fld_list, obj, to_doc): + """ + Assigns value to fields in "To Doctype" + """ for f in fld_list: if f[2] == 'Yes': if f[0].startswith('eval:'): - to_doc.fields[f[1]] = eval(f[0][5:]) + try: + val = eval(f[0][5:]) + except: + val = '' + + to_doc.fields[f[1]] = val else: to_doc.fields[f[1]] = obj.fields.get(f[0]) - # Validate - #--------- + + #--------------------------------------------------------------------------- def validate(self): + """ + Validate mapper while saving + """ for d in getlist(self.doclist, 'field_mapper_details'): # Automatically assigns default value if not entered if not d.match_id: @@ -164,10 +170,13 @@ class DocType: # Check wrong field name self.check_fields_in_dt() - - # Check if any wrong fieldname entered - #-------------------------------------- + + + #--------------------------------------------------------------------------- def check_fields_in_dt(self): + """ + Check if any wrong fieldname entered in mapper + """ for d in getlist(self.doclist, 'field_mapper_details'): table_name = sql("select from_table, to_table from `tabTable Mapper Detail` where parent ='%s' and match_id = '%s'" % (self.doc.name, d.match_id)) @@ -181,6 +190,7 @@ class DocType: if not exists2 and d.to_field not in default_fields: msgprint('"' + cstr(d.to_field) + '" does not exists in DocType "' + cstr(table_name[0][1]) + '"') + # Check consistency of value with reference document #--------------------------------------------------- def validate_reference_value(self, obj, to_docname): @@ -230,7 +240,6 @@ class DocType: if cl[2] == '=' and (ft[1] == 'Currency' or ft[1] == 'Float'): consistent = sql("select name, %s from `tab%s` where name = '%s' and '%s' - %s <= 0.5" % (cl[0], t.from_table, child_obj.fields[t.reference_key], flt(cur_val), cl[0])) else: - #consistent = sql("select name, %s from `tab%s` where name = '%s' and '%s' %s %s" % (cl[0], t.from_table, child_obj.fields[t.reference_key], cur_val, cl[2], cl[0])) consistent = sql("select name, %s from `tab%s` where name = '%s' and '%s' %s ifnull(%s, '')" % (cl[0], t.from_table, child_obj.fields[t.reference_key], ft[1] in ('Currency', 'Float', 'Int') and flt(cur_val) or cstr(cur_val), cl[2], cl[0])) if not self.ref_doc: @@ -248,22 +257,21 @@ class DocType: from_fld_label = sql("select label from tabDocField where parent = '%s' and fieldname = '%s'" % (from_table, from_field)) op_in_words = {'=':'equal to ', '>=':'greater than equal to ', '>':'greater than ', '<=':'less than equal to ', '<':'less than '} - msgprint(to_fld_label[0][0] + " should be " + op_in_words[operator] + from_fld_label[0][0] + " of " + self.doc.from_doctype + ": " + self.ref_doc) - raise Exception, "Validation Error." + msgprint(to_fld_label[0][0] + " should be " + op_in_words[operator] + from_fld_label[0][0] + " of " + self.doc.from_doctype + ": " + self.ref_doc, raise_exception=1) def check_ref_docstatus(self): if self.ref_doc: det = sql("select name, docstatus from `tab%s` where name = '%s'" % (self.doc.from_doctype, self.ref_doc)) if not det: - msgprint(self.doc.from_doctype + ": " + self.ref_doc + " does not exists in the system") - raise Exception, "Validation Error." + msgprint(self.doc.from_doctype + ": " + self.ref_doc + " does not exists in the system", raise_exception=1) elif self.doc.ref_doc_submitted and det[0][1] != 1: - msgprint(self.doc.from_doctype + ": " + self.ref_doc + " is not Submitted Document.") - raise Exception, "Validation Error." + msgprint(self.doc.from_doctype + ": " + self.ref_doc + " is not Submitted Document.", raise_exception=1) def on_update(self): + """ + If developer_mode = 1, mapper will be written to files + """ import webnotes.defs if hasattr(webnotes.defs, 'developer_mode') and webnotes.defs.developer_mode: from webnotes.modules.export_module import export_to_files - export_to_files(record_list=[[self.doc.doctype, self.doc.name]]) - + export_to_files(record_list=[[self.doc.doctype, self.doc.name]]) diff --git a/cgi-bin/webnotes/defs_template.py b/cgi-bin/webnotes/defs_template.py index 80e3113129..823edc0356 100644 --- a/cgi-bin/webnotes/defs_template.py +++ b/cgi-bin/webnotes/defs_template.py @@ -48,8 +48,26 @@ modules_path = '' # saved to the modules folder # developer_mode = 0 + +# +# Auto Clear Cache: If set, automatically clears cache on refresh +# + auto_cache_clear = 0 +# +# Admin Email Notification: If the admin_email_notification is set, +# then only sent notification email from the system +# + +admin_email_notification = 0 + +# +# Global Send Email: Global email settings, if 1 then only mail will go from the system +# + +global_send_email = 1 + # # Time Zone: Useful if your users are across timezones # diff --git a/cgi-bin/webnotes/install_lib/install.py b/cgi-bin/webnotes/install_lib/install.py index 68c9fbd2fa..c22dcdcb6f 100755 --- a/cgi-bin/webnotes/install_lib/install.py +++ b/cgi-bin/webnotes/install_lib/install.py @@ -119,7 +119,7 @@ class Installer: self.dbman.delete_user(target) # create user and db - self.dbman.create_user(target,getattr(webnotes.defs,'db_password',None)) + self.dbman.create_user(target,self.get_db_password(target)) if verbose: print "Created user %s" % target # create a database @@ -173,7 +173,7 @@ def make_scheduler(root_login, root_password, verbose): dbman.delete_user('master_scheduler') # create user and db - dbman.create_user('master_scheduler', getattr(webnotes.defs,'db_password',None)) + dbman.create_user('master_scheduler', getattr(webnotes.defs,'scheduler_password',None)) if verbose: print "Created user master_scheduler" # create a database diff --git a/cgi-bin/webnotes/model/import_docs.py b/cgi-bin/webnotes/model/import_docs.py index 524462c35b..4dcdb9c060 100644 --- a/cgi-bin/webnotes/model/import_docs.py +++ b/cgi-bin/webnotes/model/import_docs.py @@ -291,6 +291,7 @@ class CSVImport: cur_doc = Document(fielddata = fd) cur_doc.doctype, cur_doc.parenttype, cur_doc.parentfield = self.dt_list[0], len(self.dt_list) > 1 and self.dt_list[1] or '', len(self.dt_list) > 1 and self.dt_list[2] or '' obj = '' + webnotes.message_log = [] # save the document try: if webnotes.conn.in_transaction: @@ -321,7 +322,8 @@ class CSVImport: except Exception: sql("ROLLBACK") - self.msg.append('
Validation: %s
' % str(webnotes.message_log[-1:])) + self.msg.append('
Validation Error: %s
' % str((webnotes.message_log and webnotes.message_log[0]) or webnotes.utils.getTraceback())) + self.msg.append('
Did not import
') # do import # -------------------------------------------------------------------- diff --git a/cgi-bin/webnotes/modules/patch.py b/cgi-bin/webnotes/modules/patch.py index 5ecd84446c..4bc0d17c5c 100644 --- a/cgi-bin/webnotes/modules/patch.py +++ b/cgi-bin/webnotes/modules/patch.py @@ -5,6 +5,10 @@ def run(log_exception=1): from patches import patch from webnotes.utils import cint + if webnotes.conn.cur_db_name=='accounts': + # no patches on accounts + return + next_patch = cint(webnotes.conn.get_global('next_patch')) if next_patch <= patch.last_patch: @@ -31,7 +35,8 @@ def write_log(): patch_log.write(('\n\nError in %s:\n' % webnotes.conn.cur_db_name) + webnotes.getTraceback()) patch_log.close() - from webnotes.utils import sendmail - subj = 'Error in running patches in %s' % webnotes.conn.cur_db_name - msg = subj + '

Login User: ' + webnotes.user.name + '

' + webnotes.getTraceback() - sendmail(['developer@erpnext.com'], sender='automail@erpnext.com', subject= subj, parts=[['text/plain', msg]]) + if getattr(webnotes.defs,'admin_email_notification',0): + from webnotes.utils import sendmail + subj = 'Error in running patches in %s' % webnotes.conn.cur_db_name + msg = subj + '

Login User: ' + webnotes.user.name + '

' + webnotes.getTraceback() + sendmail(['developers@erpnext.com'], sender='automail@erpnext.com', subject= subj, parts=[['text/plain', msg]]) diff --git a/cgi-bin/webnotes/profile.py b/cgi-bin/webnotes/profile.py index b74fa08e5c..fc57cbabbb 100644 --- a/cgi-bin/webnotes/profile.py +++ b/cgi-bin/webnotes/profile.py @@ -162,12 +162,12 @@ class Profile: # update tab Profile webnotes.conn.sql("UPDATE tabProfile SET password=password(%s) WHERE name=%s", (pwd, profile[0][0])) - + self.send_email("Password Reset", "

Dear %s%s,

your password has been changed to %s

[Automatically Generated]

" % (profile[0][2], (profile[0][3] and (' ' + profile[0][3]) or ''), pwd), profile[0][1]) def send_email(self, subj, mess, email): import webnotes.utils.email_lib - + webnotes.utils.email_lib.sendmail(email, msg=mess, subject=subj) # update recent documents diff --git a/cgi-bin/webnotes/utils/email_lib/__init__.py b/cgi-bin/webnotes/utils/email_lib/__init__.py index abda347923..7d0572d46b 100644 --- a/cgi-bin/webnotes/utils/email_lib/__init__.py +++ b/cgi-bin/webnotes/utils/email_lib/__init__.py @@ -29,19 +29,18 @@ def sendmail(recipients, sender='', msg='', subject='[No Subject]', parts=[], cc email = EMail(sender, recipients, subject, reply_to=reply_to) email.cc = cc - - if msg: - if template: - msg = make_html_body(msg, template) + + if msg: + if template: + msg = make_html_body(msg, template).encode('utf-8') else: # if not html, then lets put some whitespace if (not '
' in msg) or (not '

' in msg): - msg = msg.replace('\n','
') - + msg = msg.replace('\n','
') footer = get_footer() - msg = msg + (footer or '') - email.set_text(html2text(msg)) - email.set_html(msg) + msg = msg + (footer or '') + email.set_text(html2text(msg)) + email.set_html(msg) for p in parts: email.set_message(p[1]) for a in attach: diff --git a/cgi-bin/webnotes/utils/email_lib/html2text.py b/cgi-bin/webnotes/utils/email_lib/html2text.py index 66258d2477..d81c970546 100644 --- a/cgi-bin/webnotes/utils/email_lib/html2text.py +++ b/cgi-bin/webnotes/utils/email_lib/html2text.py @@ -447,7 +447,8 @@ def html2text_file(html, out=wrapwrite, baseurl=''): return h.close() def html2text(html, baseurl=''): - return optwrap(html2text_file(html, None, baseurl)) + txt = html2text_file(html.decode('utf-8'), None, baseurl) + return optwrap(txt.encode('utf-8')) if __name__ == "__main__": baseurl = '' diff --git a/cgi-bin/webnotes/utils/email_lib/send.py b/cgi-bin/webnotes/utils/email_lib/send.py index 2eff8ed9bc..52e4572459 100644 --- a/cgi-bin/webnotes/utils/email_lib/send.py +++ b/cgi-bin/webnotes/utils/email_lib/send.py @@ -16,6 +16,9 @@ class EMail: """ def __init__(self, sender='', recipients=[], subject='', from_defs=0, alternative=0, reply_to=None): from email.mime.multipart import MIMEMultipart + from email import Charset + Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8') + if type(recipients)==str: recipients = recipients.replace(';', ',') recipients = recipients.split(',') @@ -36,7 +39,8 @@ class EMail: Attach message in the text portion of multipart/alternative """ from email.mime.text import MIMEText - part = MIMEText(message, 'plain') + msg = unicode(message, 'utf-8') + part = MIMEText(msg.encode('utf-8'), 'plain', 'UTF-8') self.msg_multipart.attach(part) def set_html(self, message): diff --git a/cgi-bin/webnotes/utils/nestedset.py b/cgi-bin/webnotes/utils/nestedset.py index 97cf156074..cb9f195849 100644 --- a/cgi-bin/webnotes/utils/nestedset.py +++ b/cgi-bin/webnotes/utils/nestedset.py @@ -8,77 +8,222 @@ # ------------------------------------------ -import webnotes +import webnotes, unittest + +class TestNSM(unittest.TestCase): + + def setUp(self): + from webnotes.model.doc import Document + self.root = Document(fielddata={'doctype':'nsmtest', 'name':'T001', 'parent':None}) + self.first_child = Document(fielddata={'doctype':'nsmtest', 'name':'C001', 'parent_node':'T001'}) + self.first_sibling = Document(fielddata={'doctype':'nsmtest', 'name':'C002', 'parent_node':'T001'}) + self.grand_child = Document(fielddata={'doctype':'nsmtest', 'name':'GC001', 'parent_node':'C001'}) + + webnotes.conn.sql(""" + create table `tabnsmtest` ( + name varchar(120) not null primary key, + creation datetime, + modified datetime, + modified_by varchar(40), + owner varchar(40), + docstatus int(1) default '0', + parent varchar(120), + parentfield varchar(120), + parenttype varchar(120), + idx int(8), + parent_node varchar(180), + old_parent varchar(180), + lft int, + rgt int) ENGINE=InnoDB""") + + def test_root(self): + self.root.save(1) + update_nsm(self.root) + self.assertTrue(self.root.lft==1) + self.assertTrue(self.root.rgt==2) + + def test_first_child(self): + self.root.save(1) + update_nsm(self.root) + + self.first_child.save(1) + update_nsm(self.first_child) + + self.root._loadfromdb() + + self.assertTrue(self.root.lft==1) + self.assertTrue(self.first_child.lft==2) + self.assertTrue(self.first_child.rgt==3) + self.assertTrue(self.root.rgt==4) + + def test_sibling(self): + self.test_first_child() + + self.first_sibling.save(1) + update_nsm(self.first_sibling) + + self.root._loadfromdb() + self.first_child._loadfromdb() + + self.assertTrue(self.root.lft==1) + self.assertTrue(self.first_child.lft==2) + self.assertTrue(self.first_child.rgt==3) + self.assertTrue(self.first_sibling.lft==4) + self.assertTrue(self.first_sibling.rgt==5) + self.assertTrue(self.root.rgt==6) + + def test_remove_sibling(self): + self.test_sibling() + self.first_sibling.parent_node = '' + update_nsm(self.first_sibling) + + self.root._loadfromdb() + self.first_child._loadfromdb() + + self.assertTrue(self.root.lft==1) + self.assertTrue(self.first_child.lft==2) + self.assertTrue(self.first_child.rgt==3) + self.assertTrue(self.root.rgt==4) + self.assertTrue(self.first_sibling.lft==5) + self.assertTrue(self.first_sibling.rgt==6) + + def test_change_parent(self): + self.test_sibling() + + # add grand child + self.grand_child.save(1) + update_nsm(self.grand_child) + + # check lft rgt + self.assertTrue(self.grand_child.lft==3) + self.assertTrue(self.grand_child.rgt==4) + + # change parent + self.grand_child.parent_node = 'C002' + self.grand_child.save() + + # update + update_nsm(self.grand_child) + + # check lft rgt + self.assertTrue(self.grand_child.lft==5) + self.assertTrue(self.grand_child.rgt==6) + + + def tearDown(self): + webnotes.conn.sql("drop table tabnsmtest") + + # called in the on_update method def update_nsm(doc_obj): # get fields, data from the DocType - d = doc_obj.doc + pf, opf = 'parent_node', 'old_parent' - if hasattr(doc_obj,'nsm_parent_field'): - pf = doc_obj.nsm_parent_field - if hasattr(doc_obj,'nsm_oldparent_field'): - opf = doc_obj.nsm_oldparent_field - p, op = d.fields[pf], d.fields.get(opf, '') + + if str(doc_obj.__class__)=='webnotes.model.doc.Document': + # passed as a Document object + d = doc_obj + else: + # passed as a DocType object + d = doc_obj.doc + if hasattr(doc_obj,'nsm_parent_field'): + pf = doc_obj.nsm_parent_field + if hasattr(doc_obj,'nsm_oldparent_field'): + opf = doc_obj.nsm_oldparent_field + + p, op = d.fields.get(pf, ''), d.fields.get(opf, '') # has parent changed (?) or parent is None (root) - if not doc_obj.doc.lft and not doc_obj.doc.rgt: - update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf) + if not d.lft and not d.rgt: + update_add_node(d.doctype, d.name, p or '', pf) elif op != p: - update_remove_node(doc_obj.doc.doctype, doc_obj.doc.name) - update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf) + update_remove_node(d.doctype, d.name) + update_add_node(d.doctype, d.name, p or '', pf) + # set old parent webnotes.conn.set(d, opf, p or '') + + # reload + d._loadfromdb() def rebuild_tree(doctype, parent_field): + """ + call rebuild_node for all root nodes + """ # get all roots right = 1 result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='' or `%s` IS NULL" % (doctype, parent_field, parent_field)) for r in result: right = rebuild_node(doctype, r[0], right, parent_field) -def rebuild_node(doctype, parent, left, parent_field): +def rebuild_node(doctype, parent, left, parent_field, cnt = 0): + """ + reset lft, rgt and recursive call for all children + """ + from webnotes.utils import now + n = now() + # the right value of this node is the left value + 1 - right = left+1 + right = left+1 # get all children of this node result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='%s'" % (doctype, parent_field, parent)) for r in result: - right = rebuild_node(doctype, r[0], right, parent_field) + right = rebuild_node(doctype, r[0], right, parent_field, cnt) # we've got the left value, and now that we've processed # the children of this node we also know the right value - webnotes.conn.sql('UPDATE `tab%s` SET lft=%s, rgt=%s WHERE name="%s"' % (doctype,left,right,parent)) + webnotes.conn.sql("UPDATE `tab%s` SET lft=%s, rgt=%s, modified='%s' WHERE name='%s'" % (doctype,left,right,n,parent)) + + # commit after every 100 + cnt += 1 + if cnt % 100 == 0: + cnt = 0 + webnotes.conn.sql("commit") + webnotes.conn.sql("start transaction") #return the right value of this node + 1 return right+1 def update_add_node(doctype, name, parent, parent_field): + """ + insert a new node + """ + from webnotes.utils import now + n = now() + # get the last sibling of the parent if parent: right = webnotes.conn.sql("select rgt from `tab%s` where name='%s'" % (doctype, parent))[0][0] else: # root right = webnotes.conn.sql("select ifnull(max(rgt),0)+1 from `tab%s` where ifnull(`%s`,'') =''" % (doctype, parent_field))[0][0] right = right or 1 - + # update all on the right - webnotes.conn.sql("update `tab%s` set rgt = rgt+2 where rgt >= %s" %(doctype,right)) - webnotes.conn.sql("update `tab%s` set lft = lft+2 where lft >= %s" %(doctype,right)) + webnotes.conn.sql("update `tab%s` set rgt = rgt+2, modified='%s' where rgt >= %s" %(doctype,n,right)) + webnotes.conn.sql("update `tab%s` set lft = lft+2, modified='%s' where lft >= %s" %(doctype,n,right)) # update index of new node if webnotes.conn.sql("select * from `tab%s` where lft=%s or rgt=%s"% (doctype, right, right+1)): webnotes.msgprint("Nested set error. Please send mail to support") raise Exception - webnotes.conn.sql("update `tab%s` set lft=%s, rgt=%s where name='%s'" % (doctype,right,right+1,name)) + webnotes.conn.sql("update `tab%s` set lft=%s, rgt=%s, modified='%s' where name='%s'" % (doctype,right,right+1,n,name)) return right def update_remove_node(doctype, name): + """ + remove a node + """ + from webnotes.utils import now + n = now() + left = webnotes.conn.sql("select lft from `tab%s` where name='%s'" % (doctype,name)) if left[0][0]: # reset this node - webnotes.conn.sql("update `tab%s` set lft=0, rgt=0 where name='%s'" % (doctype,name)) + webnotes.conn.sql("update `tab%s` set lft=0, rgt=0, modified='%s' where name='%s'" % (doctype,n,name)) # update all on the right - webnotes.conn.sql("update `tab%s` set rgt = rgt-2 where rgt > %s" %(doctype,left[0][0])) - webnotes.conn.sql("update `tab%s` set lft = lft-2 where lft > %s" %(doctype,left[0][0])) + webnotes.conn.sql("update `tab%s` set rgt = rgt-2, modified='%s' where rgt > %s" %(doctype,n,left[0][0])) + webnotes.conn.sql("update `tab%s` set lft = lft-2, modified='%s' where lft > %s" %(doctype,n,left[0][0])) diff --git a/cgi-bin/webnotes/utils/scheduler.py b/cgi-bin/webnotes/utils/scheduler.py index 7caa1fd6ee..879063a1d2 100644 --- a/cgi-bin/webnotes/utils/scheduler.py +++ b/cgi-bin/webnotes/utils/scheduler.py @@ -162,7 +162,7 @@ def cancel_event(event): if __name__=='__main__': import os,sys - cgi_bin_path = os.path.sep.join(__file__.split(os.path.sep)[:-3]) + cgi_bin_path = os.path.sep.join(os.path.abspath(__file__).split(os.path.sep)[:-3]) sys.path.append(cgi_bin_path) diff --git a/images/icons/folder.gif b/images/icons/folder.gif deleted file mode 100644 index 45b191d8ae..0000000000 Binary files a/images/icons/folder.gif and /dev/null differ diff --git a/images/ui/rc/comment_top.gif b/images/ui/rc/comment_top.gif deleted file mode 100644 index 4efd7147e5..0000000000 Binary files a/images/ui/rc/comment_top.gif and /dev/null differ diff --git a/images/ui/rc/tab-left-CCC.gif b/images/ui/rc/tab-left-CCC.gif deleted file mode 100644 index f6f3a545b8..0000000000 Binary files a/images/ui/rc/tab-left-CCC.gif and /dev/null differ diff --git a/images/ui/rc/tab-left-EEE.gif b/images/ui/rc/tab-left-EEE.gif deleted file mode 100644 index f04d0c6b97..0000000000 Binary files a/images/ui/rc/tab-left-EEE.gif and /dev/null differ diff --git a/images/ui/rc/tab-right-CCC.gif b/images/ui/rc/tab-right-CCC.gif deleted file mode 100644 index 9995e00278..0000000000 Binary files a/images/ui/rc/tab-right-CCC.gif and /dev/null differ diff --git a/images/ui/rc/tab-right-EEE.gif b/images/ui/rc/tab-right-EEE.gif deleted file mode 100644 index 0dd0d03b99..0000000000 Binary files a/images/ui/rc/tab-right-EEE.gif and /dev/null differ diff --git a/images/ui/rc/tb-left-bottom.gif b/images/ui/rc/tb-left-bottom.gif deleted file mode 100644 index e9c4be326a..0000000000 Binary files a/images/ui/rc/tb-left-bottom.gif and /dev/null differ diff --git a/images/ui/rc/tb-right-bottom.gif b/images/ui/rc/tb-right-bottom.gif deleted file mode 100644 index a49e00012b..0000000000 Binary files a/images/ui/rc/tb-right-bottom.gif and /dev/null differ diff --git a/images/ui/rc/tray-left-bottom.gif b/images/ui/rc/tray-left-bottom.gif deleted file mode 100644 index 46c0e43a7c..0000000000 Binary files a/images/ui/rc/tray-left-bottom.gif and /dev/null differ diff --git a/images/ui/rc/tray-left-top.gif b/images/ui/rc/tray-left-top.gif deleted file mode 100644 index 171db8e4c9..0000000000 Binary files a/images/ui/rc/tray-left-top.gif and /dev/null differ diff --git a/js/app.js b/js/app.js index 38231c5bb5..641554aca7 100644 --- a/js/app.js +++ b/js/app.js @@ -107,8 +107,7 @@ function startup() { // for debug if(_startup_data.server_messages) msgprint(_startup_data.server_messages); } else { - if($i('startup_div')) - $c('startup',{},callback,null,1); + $c('startup',{},callback,null,1); } } @@ -177,17 +176,6 @@ function setup_calendar() { startup_list.push(setup_calendar); -// ie6 fixed pos fix -if(isIE6) { - var scroll_list = [] - window.onscroll = function() { - for(var i=0; i2)logout();}}