diff --git a/cypress/integration/depends_on.js b/cypress/integration/depends_on.js new file mode 100644 index 0000000000..8cb4e42d3e --- /dev/null +++ b/cypress/integration/depends_on.js @@ -0,0 +1,63 @@ +context('Depends On', () => { + beforeEach(() => { + cy.login(); + cy.visit('/desk'); + }); + before(() => { + cy.login(); + cy.visit('/desk'); + cy.window().its('frappe').then(frappe => { + frappe.call('frappe.tests.ui_test_helpers.create_doctype', { + name: 'Test Depends On', + fields: [ + { + "label": "Test Field", + "fieldname": "test_field", + "fieldtype": "Data", + }, + { + "label": "Dependant Field", + "fieldname": "dependant_field", + "fieldtype": "Data", + "mandatory_depends_on": "eval:doc.test_field=='Some Value'", + "read_only_depends_on": "eval:doc.test_field=='Some Other Value'", + }, + { + "label": "Display Dependant Field", + "fieldname": "display_dependant_field", + "fieldtype": "Data", + 'depends_on': "eval:doc.test_field=='Value'" + }, + ] + }); + }); + }); + it('should set the field as mandatory depending on other fields value', () => { + cy.new_form('Test Depends On'); + cy.fill_field('test_field', 'Some Value'); + cy.get('button.primary-action').contains('Save').click(); + cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('be.visible'); + cy.get('body').click(); + cy.fill_field('test_field', 'Random value'); + cy.get('button.primary-action').contains('Save').click(); + cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('not.be.visible'); + }); + it('should set the field as read only depending on other fields value', () => { + cy.new_form('Test Depends On'); + cy.fill_field('dependant_field', 'Some Value'); + cy.fill_field('test_field', 'Some Other Value'); + cy.get('body').click(); + cy.get('.control-input [data-fieldname="dependant_field"]').should('be.disabled'); + cy.fill_field('test_field', 'Random Value'); + cy.get('body').click(); + cy.get('.control-input [data-fieldname="dependant_field"]').should('not.be.disabled'); + }); + it('should display the field depending on other fields value', () => { + cy.new_form('Test Depends On'); + cy.get('.control-input [data-fieldname="display_dependant_field"]').should('not.be.visible'); + cy.get('.control-input [data-fieldname="test_field"]').clear(); + cy.fill_field('test_field', 'Value'); + cy.get('body').click(); + cy.get('.control-input [data-fieldname="display_dependant_field"]').should('be.visible'); + }); +}); diff --git a/frappe/automation/doctype/auto_repeat/auto_repeat.py b/frappe/automation/doctype/auto_repeat/auto_repeat.py index e618c7d63e..2d9428d1fe 100644 --- a/frappe/automation/doctype/auto_repeat/auto_repeat.py +++ b/frappe/automation/doctype/auto_repeat/auto_repeat.py @@ -9,7 +9,7 @@ from frappe.desk.form import assign_to from frappe.utils.jinja import validate_template from dateutil.relativedelta import relativedelta from frappe.utils.user import get_system_managers -from frappe.utils import cstr, getdate, split_emails, add_days, today, get_last_day, get_first_day +from frappe.utils import cstr, getdate, split_emails, add_days, today, get_last_day, get_first_day, month_diff from frappe.model.document import Document from frappe.core.doctype.communication.email import make from frappe.utils.background_jobs import get_jobs @@ -48,7 +48,7 @@ class AutoRepeat(Document): if self.disabled: self.next_schedule_date = None else: - self.next_schedule_date = get_next_schedule_date(self.start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day, self.end_date) + self.next_schedule_date = get_next_schedule_date(self.start_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day, self.end_date) def unlink_if_applicable(self): if self.status == 'Completed' or self.disabled: @@ -107,27 +107,27 @@ class AutoRepeat(Document): end_date = getdate(self.end_date) if not self.end_date: - start_date = get_next_schedule_date(start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day) + next_date = get_next_schedule_date(start_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day) row = { "reference_document": self.reference_document, "frequency": self.frequency, - "next_scheduled_date": start_date + "next_scheduled_date": next_date } schedule_details.append(row) - start_date = get_next_schedule_date(start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day) if self.end_date: - start_date = get_next_schedule_date( - start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day, for_full_schedule=True) - while (getdate(start_date) < getdate(end_date)): + next_date = get_next_schedule_date( + start_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day, for_full_schedule=True) + + while (getdate(next_date) < getdate(end_date)): row = { "reference_document" : self.reference_document, "frequency" : self.frequency, - "next_scheduled_date" : start_date + "next_scheduled_date" : next_date } schedule_details.append(row) - start_date = get_next_schedule_date( - start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day, end_date, for_full_schedule=True) + next_date = get_next_schedule_date( + next_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day, end_date, for_full_schedule=True) return schedule_details @@ -268,8 +268,12 @@ class AutoRepeat(Document): ) -def get_next_schedule_date(start_date, frequency, repeat_on_day, repeat_on_last_day=False, end_date=None, for_full_schedule=False): - month_count = month_map.get(frequency) +def get_next_schedule_date(schedule_date, frequency, start_date, repeat_on_day=None, repeat_on_last_day=False, end_date=None, for_full_schedule=False): + if month_map.get(frequency): + month_count = month_map.get(frequency) + month_diff(schedule_date, start_date) - 1 + else: + month_count = 0 + day_count = 0 if month_count and repeat_on_last_day: next_date = get_next_date(start_date, month_count, 31) @@ -288,7 +292,9 @@ def get_next_schedule_date(start_date, frequency, repeat_on_day, repeat_on_last_ # next schedule date should be after or on current date if not for_full_schedule: while getdate(next_date) < getdate(today()): - next_date = get_next_date(next_date, month_count, day_count) + if month_count: + month_count += month_map.get(frequency) + next_date = get_next_date(start_date, month_count, day_count) return next_date @@ -316,8 +322,7 @@ def create_repeated_entries(data): if schedule_date == current_date and not doc.disabled: doc.create_documents() - schedule_date = get_next_schedule_date(schedule_date, doc.frequency, doc.repeat_on_day, doc.repeat_on_last_day, doc.end_date) - + schedule_date = get_next_schedule_date(schedule_date, doc.frequency, doc.start_date, doc.repeat_on_day, doc.repeat_on_last_day, doc.end_date) if schedule_date and not doc.disabled: frappe.db.set_value('Auto Repeat', doc.name, 'next_schedule_date', schedule_date) diff --git a/frappe/build.py b/frappe/build.py index 265a8c3976..f7437acf8f 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -2,7 +2,7 @@ # MIT License. See license.txt from __future__ import unicode_literals, print_function -import os, frappe, json, shutil, re, warnings +import os, frappe, json, shutil, re, warnings, tempfile from os.path import exists as path_exists, join as join_path, abspath, isdir from distutils.spawn import find_executable from six import iteritems, text_type @@ -12,6 +12,51 @@ from frappe.utils.minify import JavascriptMinify Build the `public` folders and setup languages """ + +def symlink(target, link_name, overwrite=False): + ''' + Create a symbolic link named link_name pointing to target. + If link_name exists then FileExistsError is raised, unless overwrite=True. + When trying to overwrite a directory, IsADirectoryError is raised. + + Source: https://stackoverflow.com/a/55742015/10309266 + ''' + + if not overwrite: + os.symlink(target, linkname) + return + + # os.replace() may fail if files are on different filesystems + link_dir = os.path.dirname(link_name) + + # Create link to target with temporary filename + while True: + temp_link_name = tempfile.mktemp(dir=link_dir) + + # os.* functions mimic as closely as possible system functions + # The POSIX symlink() returns EEXIST if link_name already exists + # https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html + try: + os.symlink(target, temp_link_name) + break + except FileExistsError: + pass + + # Replace link_name with temp_link_name + try: + # Pre-empt os.replace on a directory with a nicer message + if os.path.isdir(link_name): + raise IsADirectoryError("Cannot symlink over existing directory: '{}'".format(link_name)) + try: + os.replace(temp_link_name, link_name) + except AttributeError: + os.renames(temp_link_name, link_name) + except: + if os.path.islink(temp_link_name): + os.remove(temp_link_name) + raise + + app_paths = None def setup(): global app_paths @@ -118,7 +163,7 @@ def make_asset_dirs(make_copy=False, restore=False): else: shutil.rmtree(target) try: - os.symlink(source, target) + symlink(source, target, overwrite=True) except OSError: print('Cannot link {} to {}'.format(source, target)) else: diff --git a/frappe/chat/doctype/chat_room/chat_room.py b/frappe/chat/doctype/chat_room/chat_room.py index 44a6ce0f0b..609acaef7d 100644 --- a/frappe/chat/doctype/chat_room/chat_room.py +++ b/frappe/chat/doctype/chat_room/chat_room.py @@ -1,17 +1,14 @@ from __future__ import unicode_literals -# imports - standard imports -import json - # imports - module imports -from frappe.model.document import Document -from frappe import _ +from frappe.model.document import Document +from frappe import _ import frappe # imports - frappe module imports -from frappe.chat import authenticate +from frappe.chat import authenticate from frappe.core.doctype.version.version import get_diff -from frappe.chat.doctype.chat_message import chat_message +from frappe.chat.doctype.chat_message import chat_message from frappe.chat.util import ( safe_json_loads, dictify, @@ -22,13 +19,14 @@ from frappe.chat.util import ( session = frappe.session -def is_direct(owner, other, bidirectional = False): + +def is_direct(owner, other, bidirectional=False): def get_room(owner, other): - room = frappe.get_all('Chat Room', filters = [ - ['Chat Room', 'type' , 'in', ('Direct', 'Visitor')], - ['Chat Room', 'owner', '=' , owner], - ['Chat Room User', 'user' , '=' , other] - ], distinct = True) + room = frappe.get_all('Chat Room', filters=[ + ['Chat Room', 'type', 'in', ('Direct', 'Visitor')], + ['Chat Room', 'owner', '=', owner], + ['Chat Room User', 'user', '=', other] + ], distinct=True) return room @@ -38,7 +36,8 @@ def is_direct(owner, other, bidirectional = False): return exists -def get_chat_room_user_set(users, filter_ = None): + +def get_chat_room_user_set(users, filter_=None): seen, uset = set(), list() for u in users: @@ -48,12 +47,13 @@ def get_chat_room_user_set(users, filter_ = None): return uset + class ChatRoom(Document): def validate(self): if self.is_new(): - users = get_chat_room_user_set(self.users, filter_ = lambda u: u.user != session.user) + users = get_chat_room_user_set(self.users, filter_=lambda u: u.user != session.user) self.update(dict( - users = users + users=users )) if self.type == "Direct": @@ -63,7 +63,7 @@ class ChatRoom(Document): other = squashify(self.users) if self.is_new(): - if is_direct(self.owner, other.user, bidirectional = True): + if is_direct(self.owner, other.user, bidirectional=True): frappe.throw(_('Direct room with {0} already exists.').format(other.user)) if self.type == "Group" and not self.room_name: @@ -74,40 +74,44 @@ class ChatRoom(Document): before = self.get_doc_before_save() if not before: return - after = self - diff = dictify(get_diff(before, after)) + after = self + diff = dictify(get_diff(before, after)) if diff: - update = { } + update = {} for changed in diff.changed: field, old, new = changed if field == 'last_message': new = chat_message.get(new) - update.update({ field: new }) + update.update({field: new}) if diff.added or diff.removed: - update.update(dict(users = [u.user for u in self.users])) + update.update(dict(users=[u.user for u in self.users])) - update = dict(room = self.name, data = update) + update = dict(room=self.name, data=update) - frappe.publish_realtime('frappe.chat.room:update', update, room = self.name, after_commit = True) + frappe.publish_realtime('frappe.chat.room:update', update, room=self.name, + after_commit=True) -@frappe.whitelist(allow_guest = True) -def get(user, rooms = None, fields = None, filters = None): + +@frappe.whitelist(allow_guest=True) +def get(user=None, token=None, rooms=None, fields=None, filters=None): # There is this horrible bug out here. - # Looks like if frappe.call sends optional arguments (not in right order), the argument turns to an empty string. + # Looks like if frappe.call sends optional arguments (not in right order), + # the argument turns to an empty string. # I'm not even going to think searching for it. # Hence, the hack was get_if_empty (previous assign_if_none) # - Achilles Rasquinha achilles@frappe.io - authenticate(user) + data = user or token + authenticate(data) rooms, fields, filters = safe_json_loads(rooms, fields, filters) - rooms = listify(get_if_empty(rooms, [ ])) - fields = listify(get_if_empty(fields, [ ])) + rooms = listify(get_if_empty(rooms, [])) + fields = listify(get_if_empty(fields, [])) - const = [ ] # constraints + const = [] # constraints if rooms: const.append(['Chat Room', 'name', 'in', rooms]) if filters: @@ -117,24 +121,24 @@ def get(user, rooms = None, fields = None, filters = None): const.append(filters) default = ['name', 'type', 'room_name', 'creation', 'owner', 'avatar'] - handle = ['users', 'last_message'] + handle = ['users', 'last_message'] - param = [f for f in fields if f not in handle] + param = [f for f in fields if f not in handle] - rooms = frappe.get_all('Chat Room', - or_filters = [ - ['Chat Room', 'owner', '=', user], - ['Chat Room User', 'user', '=', user] - ], - filters = const, - fields = param + ['name'] if param else default, - distinct = True - ) + rooms = frappe.get_all('Chat Room', + or_filters=[ + ['Chat Room', 'owner', '=', frappe.session.user], + ['Chat Room User', 'user', '=', frappe.session.user] + ], + filters=const, + fields=param + ['name'] if param else default, + distinct=True + ) if not fields or 'users' in fields: for i, r in enumerate(rooms): droom = frappe.get_doc('Chat Room', r.name) - rooms[i]['users'] = [ ] + rooms[i]['users'] = [] for duser in droom.users: rooms[i]['users'].append(duser.user) @@ -151,46 +155,47 @@ def get(user, rooms = None, fields = None, filters = None): return rooms -@frappe.whitelist(allow_guest = True) -def create(kind, owner, users = None, name = None): - authenticate(owner) - users = safe_json_loads(users) +@frappe.whitelist(allow_guest=True) +def create(kind, token, users=None, name=None): + authenticate(token) + + users = safe_json_loads(users) create = True if kind == 'Visitor': room = squashify(frappe.db.sql(""" SELECT name FROM `tabChat Room` - WHERE owner = "{owner}" - """.format(owner = owner), as_dict = True)) + WHERE owner=%s + """, (frappe.session.user), as_dict=True)) if room: - room = frappe.get_doc('Chat Room', room.name) + room = frappe.get_doc('Chat Room', room.name) create = False if create: - room = frappe.new_doc('Chat Room') - room.type = kind - room.owner = owner + room = frappe.new_doc('Chat Room') + room.type = kind + room.owner = frappe.session.user room.room_name = name - dusers = [ ] + dusers = [] if kind != 'Visitor': if users: - users = listify(users) + users = listify(users) for user in users: - duser = frappe.new_doc('Chat Room User') + duser = frappe.new_doc('Chat Room User') duser.user = user dusers.append(duser) room.users = dusers else: - dsettings = frappe.get_single('Website Settings') + dsettings = frappe.get_single('Website Settings') room.room_name = dsettings.chat_room_name - users = [user for user in room.users] if hasattr(room, 'users') else [ ] + users = [user for user in room.users] if hasattr(room, 'users') else [] for user in dsettings.chat_operators: if user.user not in users: @@ -199,24 +204,26 @@ def create(kind, owner, users = None, name = None): chat_room_user = {"doctype": "Chat Room User", "user": user.user} room.append('users', chat_room_user) - room.save(ignore_permissions = True) + room.save(ignore_permissions=True) - room = get(owner, rooms = room.name) - users = [room.owner] + [u for u in room.users] + room = get(token=token, rooms=room.name) + if room: + users = [room.owner] + [u for u in room.users] - for u in users: - frappe.publish_realtime('frappe.chat.room:create', room, user = u, after_commit = True) + for user in users: + frappe.publish_realtime('frappe.chat.room:create', room, user=user, after_commit=True) return room -@frappe.whitelist(allow_guest = True) -def history(room, user, fields = None, limit = 10, start = None, end = None): + +@frappe.whitelist(allow_guest=True) +def history(room, user, fields=None, limit=10, start=None, end=None): if frappe.get_doc('Chat Room', room).type != 'Visitor': authenticate(user) fields = safe_json_loads(fields) - mess = chat_message.history(room, limit = limit, start = start, end = end) - mess = squashify(mess) + mess = chat_message.history(room, limit=limit, start=start, end=end) + mess = squashify(mess) - return dictify(mess) \ No newline at end of file + return dictify(mess) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 74d7fa1654..abd24fb468 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -351,16 +351,26 @@ def get_contacts(email_strings): email = get_email_without_link(email) contact_name = get_contact_name(email) - if not contact_name: - contact = frappe.get_doc({ - "doctype": "Contact", - "first_name": frappe.unscrub(email.split("@")[0]), - }) - contact.add_email(email_id=email, is_primary=True) - contact.insert(ignore_permissions=True) - contact_name = contact.name + if not contact_name and email: + email_parts = email.split("@") + first_name = frappe.unscrub(email_parts[0]) - contacts.append(contact_name) + try: + contact_name = '{0}-{1}'.format(first_name, email_parts[1]) if first_name == 'Contact' else first_name + contact = frappe.get_doc({ + "doctype": "Contact", + "first_name": contact_name, + "name": contact_name + }) + contact.add_email(email_id=email, is_primary=True) + contact.insert(ignore_permissions=True) + contact_name = contact.name + except Exception: + traceback = frappe.get_traceback() + frappe.log_error(traceback) + + if contact_name: + contacts.append(contact_name) return contacts diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 1848136bee..8793c60934 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -238,8 +238,9 @@ def get_recipients_cc_and_bcc(doc, recipients, cc, bcc, fetched_from_email_accou return recipients, cc, bcc def remove_administrator_from_email_list(email_list): - if 'Administrator' in email_list: - email_list.remove('Administrator') + administrator_email = list(filter(lambda emails: "Administrator" in emails, email_list)) + if administrator_email: + email_list.remove(administrator_email[0]) def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None): """Prepare to make multipart MIME Email @@ -304,27 +305,12 @@ def set_incoming_outgoing_accounts(doc): doc.incoming_email_account = frappe.db.get_value("Email Account", {"append_to": doc.reference_doctype, }, "email_id") - doc.outgoing_email_account = frappe.db.get_value("Email Account", - {"append_to": doc.reference_doctype, "enable_outgoing": 1}, - ["email_id", "always_use_account_email_id_as_sender", "name", - "always_use_account_name_as_sender_name"], as_dict=True) - if not doc.incoming_email_account: doc.incoming_email_account = frappe.db.get_value("Email Account", {"default_incoming": 1, "enable_incoming": 1}, "email_id") - if not doc.outgoing_email_account: - # if from address is not the default email account - doc.outgoing_email_account = frappe.db.get_value("Email Account", - {"email_id": doc.sender, "enable_outgoing": 1}, - ["email_id", "always_use_account_email_id_as_sender", "name", - "send_unsubscribe_message", "always_use_account_name_as_sender_name"], as_dict=True) or frappe._dict() - - if not doc.outgoing_email_account: - doc.outgoing_email_account = frappe.db.get_value("Email Account", - {"default_outgoing": 1, "enable_outgoing": 1}, - ["email_id", "always_use_account_email_id_as_sender", "name", - "send_unsubscribe_message", "always_use_account_name_as_sender_name"],as_dict=True) or frappe._dict() + doc.outgoing_email_account = frappe.email.smtp.get_outgoing_email_account(raise_exception_not_set=False, + append_to=doc.doctype, sender=doc.sender) if doc.sent_or_received == "Sent": doc.db_set("email_account", doc.outgoing_email_account.name) @@ -543,4 +529,4 @@ def mark_email_as_seen(name=None): frappe.response["type"] = 'binary' frappe.response["filename"] = "imaginary_pixel.png" - frappe.response["filecontent"] = buffered_obj.getvalue() \ No newline at end of file + frappe.response["filecontent"] = buffered_obj.getvalue() diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json index 622663bca4..e3242887c7 100644 --- a/frappe/core/doctype/docfield/docfield.json +++ b/frappe/core/doctype/docfield/docfield.json @@ -1,1726 +1,461 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, "autoname": "hash", - "beta": 0, "creation": "2013-02-22 01:27:33", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "label_and_type", + "label", + "fieldtype", + "fieldname", + "reqd", + "precision", + "length", + "search_index", + "in_list_view", + "in_standard_filter", + "in_global_search", + "in_preview", + "allow_in_quick_entry", + "bold", + "translatable", + "collapsible", + "collapsible_depends_on", + "column_break_6", + "options", + "default", + "fetch_from", + "fetch_if_empty", + "permissions", + "depends_on", + "hidden", + "read_only", + "unique", + "set_only_once", + "allow_bulk_edit", + "column_break_13", + "permlevel", + "ignore_user_permissions", + "allow_on_submit", + "report_hide", + "remember_last_selected_value", + "ignore_xss_filter", + "property_depends_on_section", + "mandatory_depends_on", + "column_break_38", + "read_only_depends_on", + "display", + "in_filter", + "no_copy", + "print_hide", + "print_hide_if_no_value", + "print_width", + "width", + "columns", + "column_break_22", + "description", + "oldfieldname", + "oldfieldtype" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label_and_type", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Label", - "length": 0, - "no_copy": 0, "oldfieldname": "label", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "163", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "163" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "default": "Data", - "fetch_if_empty": 0, "fieldname": "fieldtype", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Type", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldtype", "oldfieldtype": "Select", "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fieldname", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Name", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldname", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "reqd", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Mandatory", - "length": 0, - "no_copy": 0, "oldfieldname": "reqd", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", "description": "Set non-standard precision for a Float or Currency field", - "fetch_if_empty": 0, "fieldname": "precision", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Precision", - "length": 0, - "no_copy": 0, "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "print_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image', 'Int'], doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "length", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Length", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Length" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "search_index", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Index", - "length": 0, - "no_copy": 0, "oldfieldname": "search_index", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_list_view", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "In List View", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "70px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "70px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_standard_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "In Standard Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Standard Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)", - "fetch_if_empty": 0, "fieldname": "in_global_search", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "In Global Search", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Global Search" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_preview", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "In Preview", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Preview" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "allow_in_quick_entry", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Allow in Quick Entry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow in Quick Entry" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "bold", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Bold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Bold" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "translatable", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Translatable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Translatable" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:doc.fieldtype===\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Collapsible", - "length": 255, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "length": 255 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible_depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Collapsible Depends On", - "length": 0, - "no_copy": 0, - "options": "JS", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_6", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", - "fetch_if_empty": 0, "fieldname": "options", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Options", - "length": 0, - "no_copy": 0, "oldfieldname": "options", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "default", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Default", - "length": 0, - "no_copy": 0, "oldfieldname": "default", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fetch_from", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Fetch From", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch From" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.", - "fetch_if_empty": 0, "fieldname": "fetch_if_empty", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Fetch If Empty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch If Empty" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "permissions", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Display Depends On", "length": 255, - "no_copy": 0, "oldfieldname": "depends_on", "oldfieldtype": "Data", - "options": "JS", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "hidden", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Hidden", - "length": 0, - "no_copy": 0, "oldfieldname": "hidden", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "read_only", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Read Only", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "unique", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Unique", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Unique" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "Do not allow user to change after set the first time", - "fetch_if_empty": 0, "fieldname": "set_only_once", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Set Only Once", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Set Only Once" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: doc.fieldtype == \"Table\"", - "fetch_if_empty": 0, "fieldname": "allow_bulk_edit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Allow Bulk Edit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow Bulk Edit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_13", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", - "fetch_if_empty": 0, "fieldname": "permlevel", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Perm Level", - "length": 0, - "no_copy": 0, "oldfieldname": "permlevel", "oldfieldtype": "Int", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "User permissions should not apply for this Link", - "fetch_if_empty": 0, "fieldname": "ignore_user_permissions", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Ignore User Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore User Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: parent.is_submittable", - "fetch_if_empty": 0, "fieldname": "allow_on_submit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Allow on Submit", - "length": 0, - "no_copy": 0, "oldfieldname": "allow_on_submit", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "report_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Report Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "report_hide", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:(doc.fieldtype == 'Link')", - "fetch_if_empty": 0, "fieldname": "remember_last_selected_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Remember Last Selected Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Remember Last Selected Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "Don't HTML Encode HTML tags like <script> or just characters like < or >, as they could be intentionally used in this field", - "fetch_if_empty": 0, "fieldname": "ignore_xss_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Ignore XSS Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore XSS Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "display", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Display", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Display" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "In Filter", - "length": 0, - "no_copy": 0, "oldfieldname": "in_filter", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "no_copy", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "No Copy", - "length": 0, - "no_copy": 0, "oldfieldname": "no_copy", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "print_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Print Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "print_hide", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", - "fetch_if_empty": 0, "fieldname": "print_hide_if_no_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Print Hide If No Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Hide If No Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "print_width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Print Width", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Width" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Width", - "length": 0, - "no_copy": 0, "oldfieldname": "width", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", "description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)", - "fetch_if_empty": 0, "fieldname": "columns", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Columns", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Columns" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_22", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "description", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Description", - "length": 0, - "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "300px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "oldfieldname", "fieldtype": "Data", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, "oldfieldname": "oldfieldname", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Data" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "oldfieldtype", "fieldtype": "Data", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, "oldfieldname": "oldfieldtype", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Data" + }, + { + "fieldname": "mandatory_depends_on", + "fieldtype": "Code", + "label": "Mandatory Depends On", + "options": "JS" + }, + { + "fieldname": "read_only_depends_on", + "fieldtype": "Code", + "label": "Read Only Depends On", + "options": "JS" + }, + { + "fieldname": "property_depends_on_section", + "fieldtype": "Section Break", + "label": "Property Depends On" + }, + { + "fieldname": "column_break_38", + "fieldtype": "Column Break" } ], - "has_web_view": 0, - "hide_toolbar": 0, "idx": 1, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-05-28 12:19:53.415372", - "modified_by": "Administrator", + "modified": "2019-11-15 12:28:24.461628", + "modified_by": "umair@erpnext.com", "module": "Core", "name": "DocField", "owner": "Administrator", "permissions": [], - "quick_entry": 0, - "read_only": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index dbcc277e8e..de8221da29 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -905,7 +905,7 @@ def validate_fields(meta): def check_illegal_depends_on_conditions(docfield): ''' assignment operation should not be allowed in the depends on condition.''' - depends_on_fields = ["depends_on", "collapsible_depends_on"] + depends_on_fields = ["depends_on", "collapsible_depends_on", "mandatory_depends_on", "read_only_depends_on"] for field in depends_on_fields: depends_on = docfield.get(field, None) if depends_on and ("=" in depends_on) and \ diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 07a42e73a1..8d8731e012 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -96,14 +96,19 @@ class TestDocType(unittest.TestCase): def test_all_depends_on_fields_conditions(self): import re - docfields = frappe.get_all("DocField", or_filters={ + docfields = frappe.get_all("DocField", + or_filters={ "ifnull(depends_on, '')": ("!=", ''), - "ifnull(collapsible_depends_on, '')": ("!=", '') - }, fields=["parent", "depends_on", "collapsible_depends_on", "fieldname", "fieldtype"]) + "ifnull(collapsible_depends_on, '')": ("!=", ''), + "ifnull(mandatory_depends_on, '')": ("!=", ''), + "ifnull(read_only_depends_on, '')": ("!=", '') + }, + fields=["parent", "depends_on", "collapsible_depends_on", "mandatory_depends_on",\ + "read_only_depends_on", "fieldname", "fieldtype"]) pattern = """[\w\.:_]+\s*={1}\s*[\w\.@'"]+""" for field in docfields: - for depends_on in ["depends_on", "collapsible_depends_on"]: + for depends_on in ["depends_on", "collapsible_depends_on", "mandatory_depends_on", "read_only_depends_on"]: condition = field.get(depends_on) if condition: self.assertFalse(re.match(pattern, condition)) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 041b8c3011..ac89b157fa 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -197,9 +197,9 @@ class File(Document): def generate_content_hash(self): if self.content_hash or not self.file_url or self.file_url.startswith('http'): return - + file_name = self.file_url.split('/')[-1] try: - with open(get_files_path(self.file_name.lstrip("/"), is_private=self.is_private), "rb") as f: + with open(get_files_path(file_name, is_private=self.is_private), "rb") as f: self.content_hash = get_content_hash(f.read()) except IOError: frappe.msgprint(_("File {0} does not exist").format(self.file_url)) @@ -311,39 +311,6 @@ class File(Document): exists = os.path.exists(self.get_full_path()) return exists - def upload(self): - # get record details - self.attached_to_doctype = frappe.form_dict.doctype - self.attached_to_name = frappe.form_dict.docname - self.attached_to_field = frappe.form_dict.docfield - self.file_url = frappe.form_dict.file_url - self.file_name = frappe.form_dict.filename - frappe.form_dict.is_private = cint(frappe.form_dict.is_private) - - if not self.file_name and not self.file_url: - frappe.msgprint(_("Please select a file or url"), - raise_exception=True) - - file_doc = self.get_file_doc() - - comment = {} - if self.attached_to_doctype and self.attached_to_name: - comment = frappe.get_doc(self.attached_to_doctype, self.attached_to_name).add_comment("Attachment", - _ ("added {0}").format("{file_name}{icon}".format(**{ - "icon": ' ' \ - if file_doc.is_private else "", - "file_url": file_doc.file_url.replace("#", "%23") \ - if file_doc.file_name else file_doc.file_url, - "file_name": file_doc.file_name or file_doc.file_url - }))) - - return { - "name": file_doc.name, - "file_name": file_doc.file_name, - "file_url": file_doc.file_url, - "is_private": file_doc.is_private, - "comment": comment.as_dict() if comment else {} - } def get_content(self): """Returns [`file_name`, `content`] for given file name `fname`""" diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 35495954b4..5dfa3b0ace 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -368,10 +368,10 @@ class User(Document): (tab, field, '%s', field, '%s'), (new_name, old_name)) if frappe.db.exists("Chat Profile", old_name): - frappe.rename_doc("Chat Profile", old_name, new_name, force=True) + frappe.rename_doc("Chat Profile", old_name, new_name, force=True, show_alert=False) if frappe.db.exists("Notification Settings", old_name): - frappe.rename_doc("Notification Settings", old_name, new_name, force=True) + frappe.rename_doc("Notification Settings", old_name, new_name, force=True, show_alert=False) # set email frappe.db.sql("""UPDATE `tabUser` diff --git a/frappe/custom/doctype/custom_field/custom_field.json b/frappe/custom/doctype/custom_field/custom_field.json index 9b60ea2b11..22295ce833 100644 --- a/frappe/custom/doctype/custom_field/custom_field.json +++ b/frappe/custom/doctype/custom_field/custom_field.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "creation": "2013-01-10 16:34:01", "description": "Adds a custom field to a DocType", @@ -24,10 +25,8 @@ "collapsible_depends_on", "default", "depends_on", - "description", - "permlevel", - "width", - "columns", + "mandatory_depends_on", + "read_only_depends_on", "properties", "reqd", "unique", @@ -46,7 +45,11 @@ "report_hide", "search_index", "ignore_xss_filter", - "translatable" + "translatable", + "description", + "permlevel", + "width", + "columns" ], "fields": [ { @@ -349,11 +352,24 @@ "fieldname": "length", "fieldtype": "Int", "label": "Length" + }, + { + "fieldname": "mandatory_depends_on", + "fieldtype": "Code", + "label": "Mandatory Depends On", + "length": 255 + }, + { + "fieldname": "read_only_depends_on", + "fieldtype": "Code", + "label": "Read Only Depends On", + "length": 255 } ], "icon": "fa fa-glass", "idx": 1, - "modified": "2019-09-11 12:57:19.268934", + "links": [], + "modified": "2019-12-12 21:31:08.209996", "modified_by": "Administrator", "module": "Custom", "name": "Custom Field", diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index b851d40b83..8d47a075ba 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -59,6 +59,8 @@ docfield_properties = { 'report_hide': 'Check', 'allow_on_submit': 'Check', 'translatable': 'Check', + 'mandatory_depends_on': 'Data', + 'read_only_depends_on': 'Data', 'depends_on': 'Data', 'description': 'Text', 'default': 'Text', @@ -68,7 +70,8 @@ docfield_properties = { 'columns': 'Int', 'remember_last_selected_value': 'Check', 'allow_bulk_edit': 'Check', - 'auto_repeat': 'Link' + 'auto_repeat': 'Link', + 'allow_in_quick_entry': 'Check' } allowed_fieldtype_change = (('Currency', 'Float', 'Percent'), ('Small Text', 'Data'), diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json index 1f808c94c5..ab582851b5 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.json +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json @@ -1,1438 +1,396 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, + "actions": [], "autoname": "hash", - "beta": 0, "creation": "2013-02-22 01:27:32", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "label_and_type", + "label", + "fieldtype", + "fieldname", + "reqd", + "unique", + "in_list_view", + "in_standard_filter", + "in_global_search", + "bold", + "allow_in_quick_entry", + "translatable", + "column_break_7", + "precision", + "length", + "options", + "fetch_from", + "fetch_if_empty", + "permissions", + "depends_on", + "permlevel", + "hidden", + "read_only", + "collapsible", + "allow_bulk_edit", + "collapsible_depends_on", + "column_break_14", + "ignore_user_permissions", + "allow_on_submit", + "report_hide", + "remember_last_selected_value", + "property_depends_on_section", + "mandatory_depends_on", + "column_break_33", + "read_only_depends_on", + "display", + "default", + "in_filter", + "column_break_21", + "description", + "print_hide", + "print_hide_if_no_value", + "print_width", + "columns", + "width", + "is_custom_field" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label_and_type", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Label and Type", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Label and Type" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Label", - "length": 0, - "no_copy": 0, "oldfieldname": "label", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Data", - "fetch_if_empty": 0, "fieldname": "fieldtype", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Type", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldtype", "oldfieldtype": "Select", "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSignature\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fieldname", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Name", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldname", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "reqd", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Mandatory", - "length": 0, - "no_copy": 0, "oldfieldname": "reqd", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "unique", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Unique", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Unique" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_list_view", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In List View", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In List View" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_standard_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In Standard Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Standard Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)", - "fetch_if_empty": 0, "fieldname": "in_global_search", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In Global Search", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Global Search" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "bold", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Bold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Bold" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", "depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "translatable", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Translatable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Translatable" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", "description": "Set non-standard precision for a Float or Currency field", - "fetch_if_empty": 0, "fieldname": "precision", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Precision", - "length": 0, - "no_copy": 0, - "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'], doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "length", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Length", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Length" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", - "fetch_if_empty": 0, "fieldname": "options", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Options", - "length": 0, - "no_copy": 0, "oldfieldname": "options", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fetch_from", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fetch From", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch From" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.", - "fetch_if_empty": 0, "fieldname": "fetch_if_empty", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fetch If Empty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch If Empty" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "permissions", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "This field will appear only if the fieldname defined here has value OR the rules are true (examples): \nmyfield\neval:doc.myfield=='My Value'\neval:doc.age>18", - "fetch_if_empty": 0, "fieldname": "depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Depends On", - "length": 0, - "no_copy": 0, "oldfieldname": "depends_on", "oldfieldtype": "Data", - "options": "JS", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", - "fetch_if_empty": 0, "fieldname": "permlevel", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Perm Level", - "length": 0, - "no_copy": 0, "oldfieldname": "permlevel", - "oldfieldtype": "Int", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Int" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "hidden", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Hidden", - "length": 0, - "no_copy": 0, "oldfieldname": "hidden", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "read_only", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Read Only", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Read Only" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collapsible", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Collapsible" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: doc.fieldtype == \"Table\"", - "fetch_if_empty": 0, "fieldname": "allow_bulk_edit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Bulk Edit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow Bulk Edit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible_depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Collapsible Depends On", - "length": 0, - "no_copy": 0, - "options": "JS", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "ignore_user_permissions", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore User Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore User Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "allow_on_submit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Allow on Submit", - "length": 0, - "no_copy": 0, "oldfieldname": "allow_on_submit", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "report_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Report Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "report_hide", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:(doc.fieldtype == 'Link')", - "fetch_if_empty": 0, "fieldname": "remember_last_selected_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Remember Last Selected Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Remember Last Selected Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "display", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Display", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Display" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "default", "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Default", - "length": 0, - "no_copy": 0, "oldfieldname": "default", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "In Filter", - "length": 0, - "no_copy": 0, "oldfieldname": "in_filter", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "description", "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Description", - "length": 0, - "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "300px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "print_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Print Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "print_hide", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", - "fetch_if_empty": 0, "fieldname": "print_hide_if_no_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Print Hide If No Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Hide If No Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Print Width of the field, if the field is a column in a table", - "fetch_if_empty": 0, "fieldname": "print_width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Print Width", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:cur_frm.doc.istable", "description": "Number of columns for a field in a Grid (Total Columns in a grid should be less than 11)", - "fetch_if_empty": 0, "fieldname": "columns", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Columns", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Columns" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Width", - "length": 0, - "no_copy": 0, "oldfieldname": "width", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "is_custom_field", "fieldtype": "Check", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Is Custom Field", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 + }, + { + "default": "0", + "fieldname": "allow_in_quick_entry", + "fieldtype": "Check", + "label": " Allow in Quick Entry " + }, + { + "fieldname": "property_depends_on_section", + "fieldtype": "Section Break", + "label": "Property Depends On" + }, + { + "fieldname": "mandatory_depends_on", + "fieldtype": "Code", + "label": "Mandatory Depends On", + "options": "JS" + }, + { + "fieldname": "column_break_33", + "fieldtype": "Column Break" + }, + { + "fieldname": "read_only_depends_on", + "fieldtype": "Code", + "label": "Read Only Depends On", + "options": "JS" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-03-18 18:03:59.122249", + "links": [], + "modified": "2019-12-27 12:50:51.419763", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form Field", "owner": "Administrator", "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/frappe/database/mariadb/framework_mariadb.sql b/frappe/database/mariadb/framework_mariadb.sql index b1a769b189..dbe53df4e4 100644 --- a/frappe/database/mariadb/framework_mariadb.sql +++ b/frappe/database/mariadb/framework_mariadb.sql @@ -40,6 +40,8 @@ CREATE TABLE `tabDocField` ( `show_preview_popup` int(1) NOT NULL DEFAULT 0, `trigger` varchar(255) DEFAULT NULL, `collapsible_depends_on` text, + `mandatory_depends_on` text, + `read_only_depends_on` text, `depends_on` text, `permlevel` int(11) NOT NULL DEFAULT 0, `ignore_user_permissions` int(1) NOT NULL DEFAULT 0, diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index abacc5ab4c..243d0f934e 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -107,7 +107,7 @@ class PostgresDatabase(Database): from information_schema.tables where table_catalog='{0}' and table_type = 'BASE TABLE' - and table_schema='public'""".format(frappe.conf.db_name))] + and table_schema='{1}'""".format(frappe.conf.db_name, frappe.conf.get("db_schema", "public")))] def format_date(self, date): if not date: diff --git a/frappe/database/postgres/framework_postgres.sql b/frappe/database/postgres/framework_postgres.sql index cd2f02d8e4..457f6c906a 100644 --- a/frappe/database/postgres/framework_postgres.sql +++ b/frappe/database/postgres/framework_postgres.sql @@ -40,6 +40,8 @@ CREATE TABLE "tabDocField" ( "show_preview_popup" smallint NOT NULL DEFAULT 0, "trigger" varchar(255) DEFAULT NULL, "collapsible_depends_on" text, + "mandatory_depends_on" text, + "read_only_depends_on" text, "depends_on" text, "permlevel" bigint NOT NULL DEFAULT 0, "ignore_user_permissions" smallint NOT NULL DEFAULT 0, diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index 5154514c22..e724102fdf 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_rename": 1, "autoname": "field:email_account_name", "creation": "2014-09-11 12:04:34.163728", @@ -21,6 +22,7 @@ "use_imap", "email_server", "use_ssl", + "append_emails_to_sent_folder", "incoming_port", "attachment_limit", "append_to", @@ -37,6 +39,7 @@ "enable_outgoing", "smtp_server", "use_tls", + "use_ssl_for_outgoing", "smtp_port", "default_outgoing", "always_use_account_email_id_as_sender", @@ -389,10 +392,25 @@ "fieldname": "incoming_port", "fieldtype": "Data", "label": "Port" + }, + { + "default": "0", + "depends_on": "eval:!doc.domain && doc.enable_outgoing", + "fieldname": "append_emails_to_sent_folder", + "fieldtype": "Check", + "label": "Append Emails to Sent Folder" + }, + { + "default": "0", + "depends_on": "eval:!doc.domain && doc.enable_outgoing", + "fieldname": "use_ssl_for_outgoing", + "fieldtype": "Check", + "label": "Use SSL for Outgoing" } ], "icon": "fa fa-inbox", - "modified": "2019-08-31 18:01:15.568831", + "links": [], + "modified": "2019-12-18 15:56:39.744520", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 495644f652..50daf1cf72 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -7,6 +7,7 @@ import imaplib import re import json import socket +import time from frappe import _ from frappe.model.document import Document from frappe.utils import validate_email_address, cint, get_datetime, DATE_FORMAT, strip, comma_or, sanitize_html @@ -116,7 +117,8 @@ class EmailAccount(Document): fields = [ "name as domain", "use_imap", "email_server", "use_ssl", "smtp_server", "use_tls", - "smtp_port", "incoming_port" + "smtp_port", "incoming_port", "append_emails_to_sent_folder", + "use_ssl_for_outgoing" ] return frappe.db.get_value("Email Domain", domain[1], fields, as_dict=True) except Exception: @@ -128,11 +130,12 @@ class EmailAccount(Document): if not self.smtp_server: frappe.throw(_("{0} is required").format("SMTP Server")) - server = SMTPServer(login = getattr(self, "login_id", None) \ - or self.email_id, - server = self.smtp_server, - port = cint(self.smtp_port), - use_tls = cint(self.use_tls) + server = SMTPServer( + login = getattr(self, "login_id", None) or self.email_id, + server=self.smtp_server, + port=cint(self.smtp_port), + use_tls=cint(self.use_tls), + use_ssl=cint(self.use_ssl_for_outgoing) ) if self.password and not self.no_smtp_authentication: server.password = self.get_password() @@ -648,6 +651,24 @@ class EmailAccount(Document): if frappe.db.exists("Email Account", {"enable_automatic_linking": 1, "name": ('!=', self.name)}): frappe.throw(_("Automatic Linking can be activated only for one Email Account.")) + + def append_email_to_sent_folder(self, message): + + email_server = None + try: + email_server = self.get_incoming_server(in_receive=True) + except Exception: + frappe.log_error(title=_("Error while connecting to email account {0}").format(self.name)) + + if not email_server: + return + + email_server.connect() + + if email_server.imap: + email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message) + + @frappe.whitelist() def get_append_to(doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None): if not txt: txt = "" diff --git a/frappe/email/doctype/email_domain/email_domain.json b/frappe/email/doctype/email_domain/email_domain.json index 677bf876aa..a4ca19a0bd 100644 --- a/frappe/email/doctype/email_domain/email_domain.json +++ b/frappe/email/doctype/email_domain/email_domain.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "field:domain_name", "creation": "2016-03-29 10:50:48.848239", "doctype": "DocType", @@ -18,6 +19,8 @@ "outgoing_mail_settings", "smtp_server", "use_tls", + "use_ssl_for_outgoing", + "append_emails_to_sent_folder", "smtp_port" ], "fields": [ @@ -30,7 +33,7 @@ "fieldtype": "Data", "label": "domain name", "read_only": 1, - "unique": 0 + "unique": 1 }, { "fieldname": "email_id", @@ -106,10 +109,23 @@ "fieldname": "incoming_port", "fieldtype": "Data", "label": "Port" + }, + { + "default": "0", + "fieldname": "append_emails_to_sent_folder", + "fieldtype": "Check", + "label": "Append Emails to Sent Folder" + }, + { + "default": "0", + "fieldname": "use_ssl_for_outgoing", + "fieldtype": "Check", + "label": "Use SSL for Outgoing" } ], "icon": "icon-inbox", - "modified": "2019-10-09 17:56:48.834704", + "links": [], + "modified": "2019-12-18 15:57:34.445308", "modified_by": "Administrator", "module": "Email", "name": "Email Domain", @@ -127,4 +143,4 @@ ], "sort_field": "modified", "sort_order": "DESC" -} +} \ No newline at end of file diff --git a/frappe/email/doctype/email_domain/email_domain.py b/frappe/email/doctype/email_domain/email_domain.py index e800b839b9..b6585d966b 100644 --- a/frappe/email/doctype/email_domain/email_domain.py +++ b/frappe/email/doctype/email_domain/email_domain.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import validate_email_address ,cint +from frappe.utils import validate_email_address ,cint, cstr import imaplib,poplib,smtplib from frappe.email.utils import get_port @@ -49,9 +49,16 @@ class EmailDomain(Document): except Exception: pass try: - if self.use_tls and not self.smtp_port: - self.smtp_port = 587 - sess = smtplib.SMTP((self.smtp_server or "").encode('utf-8'), cint(self.smtp_port) or None) + if self.use_ssl_for_outgoing: + if not self.smtp_port: + self.smtp_port = 465 + + sess = smtplib.SMTP_SSL((self.smtp_server or "").encode('utf-8'), + cint(self.smtp_port) or None) + else: + if self.use_tls and not self.smtp_port: + self.smtp_port = 587 + sess = smtplib.SMTP(cstr(self.smtp_server or ""), cint(self.smtp_port) or None) sess.quit() except Exception: frappe.throw(_("Outgoing email account not correct")) @@ -73,6 +80,8 @@ class EmailDomain(Document): email_account.set("attachment_limit",self.attachment_limit) email_account.set("smtp_server",self.smtp_server) email_account.set("smtp_port",self.smtp_port) + email_account.set("use_ssl_for_outgoing", self.use_ssl_for_outgoing) + email_account.set("append_emails_to_sent_folder", self.append_emails_to_sent_folder) email_account.save() except Exception as e: frappe.msgprint(email_account.name) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 1c9a2fd3de..4a0a34c76e 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -380,7 +380,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals for update''', email, as_dict=True)[0] recipients_list = frappe.db.sql('''select name, recipient, status from - `tabEmail Queue Recipient` where parent=%s''',email.name,as_dict=1) + `tabEmail Queue Recipient` where parent=%s''', email.name, as_dict=1) if frappe.are_emails_muted(): frappe.msgprint(_("Emails are muted")) @@ -401,8 +401,16 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) try: + message = None + if not frappe.flags.in_test: - if not smtpserver: smtpserver = SMTPServer() + if not smtpserver: + smtpserver = SMTPServer() + + # to avoid always using default email account for outgoing + if getattr(frappe.local, "outgoing_email_account", None): + frappe.local.outgoing_email_account = {} + smtpserver.setup_email_account(email.reference_doctype, sender=email.sender) for recipient in recipients_list: @@ -417,8 +425,10 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals frappe.db.sql("""update `tabEmail Queue Recipient` set status='Sent', modified=%s where name=%s""", (now_datetime(), recipient.name), auto_commit=auto_commit) + email_sent_to_any_recipient = any("Sent" == s.status for s in recipients_list) + #if all are sent set status - if any("Sent" == s.status for s in recipients_list): + if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: @@ -430,6 +440,9 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) + if smtpserver.append_emails_to_sent_folder and email_sent_to_any_recipient: + smtpserver.email_account.append_email_to_sent_folder(encode(message)) + except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError, smtplib.SMTPHeloError, @@ -439,7 +452,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals # bad connection/timeout, retry later - if any("Sent" == s.status for s in recipients_list): + if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Partially Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: @@ -459,7 +472,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals frappe.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s, retry=retry+1 where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: - if any("Sent" == s.status for s in recipients_list): + if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Partially Errored', error=%s where name=%s""", (text_type(e), email.name), auto_commit=auto_commit) else: diff --git a/frappe/email/receive.py b/frappe/email/receive.py index e5c8457b4e..9ba080bfda 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -480,7 +480,7 @@ class Email: """Detect chartset.""" charset = part.get_content_charset() if not charset: - charset = chardet.detect(cstr(part))['encoding'] + charset = chardet.detect(safe_encode(cstr(part)))['encoding'] return charset diff --git a/frappe/email/smtp.py b/frappe/email/smtp.py index c09f3f9cdd..d735f5c445 100644 --- a/frappe/email/smtp.py +++ b/frappe/email/smtp.py @@ -8,7 +8,7 @@ import smtplib import email.utils import _socket, sys from frappe import _ -from frappe.utils import cint, parse_addr +from frappe.utils import cint, cstr, parse_addr def send(email, append_to=None, retry=1): """Deprecated: Send the message or add it to Outbox Email""" @@ -52,35 +52,38 @@ def get_outgoing_email_account(raise_exception_not_set=True, append_to=None, sen or frappe.local.outgoing_email_account.get("default")): email_account = None - if append_to: - # append_to is only valid when enable_incoming is checked + if sender_email_id: + # check if the sender has an email account with enable_outgoing + email_account = _get_email_account({"enable_outgoing": 1, + "email_id": sender_email_id}) - # in case of multiple Email Accounts with same append_to - # narrow it down based on email_id - email_account = _get_email_account({ + if not email_account and append_to: + # append_to is only valid when enable_incoming is checked + email_accounts = frappe.db.get_values("Email Account", { "enable_outgoing": 1, "enable_incoming": 1, "append_to": append_to, - "email_id": sender_email_id - }) + }, cache=True) - # else find the first Email Account with append_to - if not email_account: + if email_accounts: + _email_account = email_accounts[0] + + else: email_account = _get_email_account({ "enable_outgoing": 1, "enable_incoming": 1, "append_to": append_to }) - if not email_account and sender_email_id: - # check if the sender has email account with enable_outgoing - email_account = _get_email_account({"enable_outgoing": 1, "email_id": sender_email_id}) - if not email_account: # sender don't have the outging email account sender_email_id = None email_account = get_default_outgoing_email_account(raise_exception_not_set=raise_exception_not_set) + if not email_account and _email_account: + # if default email account is not configured then setup first email account based on append to + email_account = _email_account + if not email_account and raise_exception_not_set and cint(frappe.db.get_single_value('System Settings', 'setup_complete')): frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"), frappe.OutgoingEmailError) @@ -152,16 +155,19 @@ def _get_email_account(filters): return frappe.get_doc("Email Account", name) if name else None class SMTPServer: - def __init__(self, login=None, password=None, server=None, port=None, use_tls=None, append_to=None): + def __init__(self, login=None, password=None, server=None, port=None, use_tls=None, use_ssl=None, append_to=None): # get defaults from mail settings self._sess = None self.email_account = None self.server = None + self.append_emails_to_sent_folder = None + if server: self.server = server self.port = port self.use_tls = cint(use_tls) + self.use_ssl = cint(use_ssl) self.login = login self.password = password @@ -183,6 +189,8 @@ class SMTPServer: self.port = self.email_account.smtp_port self.use_tls = self.email_account.use_tls self.sender = self.email_account.email_id + self.use_ssl = self.email_account.use_ssl_for_outgoing + self.append_emails_to_sent_folder = self.email_account.append_emails_to_sent_folder self.always_use_account_email_id_as_sender = cint(self.email_account.get("always_use_account_email_id_as_sender")) self.always_use_account_name_as_sender_name = cint(self.email_account.get("always_use_account_name_as_sender_name")) @@ -199,11 +207,18 @@ class SMTPServer: raise frappe.OutgoingEmailError(err_msg) try: - if self.use_tls and not self.port: - self.port = 587 + if self.use_ssl: + if not self.port: + self.smtp_port = 465 - self._sess = smtplib.SMTP((self.server or "").encode('utf-8'), - cint(self.port) or None) + self._sess = smtplib.SMTP_SSL((self.server or "").encode('utf-8'), + cint(self.port) or None) + else: + if self.use_tls and not self.port: + self.port = 587 + + self._sess = smtplib.SMTP(cstr(self.server or ""), + cint(self.port) or None) if not self._sess: err_msg = _('Could not connect to outgoing email server') diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index f1f50c7662..b70a3e2d8c 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -106,13 +106,12 @@ def get_webhook_headers(doc, webhook): def get_webhook_data(doc, webhook): data = {} + doc = doc.as_dict(convert_dates_to_str=True) + if webhook.webhook_data: - for w in webhook.webhook_data: - value = doc.get(w.fieldname) - if isinstance(value, datetime.datetime): - value = frappe.utils.get_datetime_str(value) - data[w.key] = value + data = {w.key: doc.get(w.fieldname) for w in webhook.webhook_data} elif webhook.webhook_json: data = frappe.render_template(webhook.webhook_json, get_context(doc)) data = json.loads(data) + return data diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 01b5ea2d23..5660487722 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -275,7 +275,7 @@ class BaseDocument(object): doc["doctype"] = self.doctype for df in self.meta.get_table_fields(): children = self.get(df.fieldname) or [] - doc[df.fieldname] = [d.as_dict(no_nulls=no_nulls) for d in children] + doc[df.fieldname] = [d.as_dict(convert_dates_to_str=convert_dates_to_str, no_nulls=no_nulls) for d in children] if no_nulls: for k in list(doc): diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index 7dc3944750..a42b83fe97 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -27,7 +27,7 @@ def update_document_title(doctype, docname, title_field=None, old_title=None, ne @frappe.whitelist() -def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False): +def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False, show_alert=True): """ Renames a doc(dt, old) to doc(dt, new) and updates all linked fields of type "Link" @@ -99,7 +99,9 @@ def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=F frappe.clear_cache() frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype', doctype=doctype) - frappe.msgprint(_('Document renamed from {0} to {1}').format(bold(old), bold(new)), alert=True, indicator='green') + + if show_alert: + frappe.msgprint(_('Document renamed from {0} to {1}').format(bold(old), bold(new)), alert=True, indicator='green') return new diff --git a/frappe/model/workflow.py b/frappe/model/workflow.py index 2851db6780..548d713e6f 100644 --- a/frappe/model/workflow.py +++ b/frappe/model/workflow.py @@ -105,6 +105,18 @@ def apply_workflow(doc, action): return doc +@frappe.whitelist() +def can_cancel_document(doc): + doc = frappe.get_doc(frappe.parse_json(doc)) + workflow = get_workflow(doc.doctype) + for state_doc in workflow.states: + if state_doc.doc_status == '2': + for transition in workflow.transitions: + if transition.next_state == state_doc.state: + return False + return True + return True + def validate_workflow(doc): '''Validate Workflow State and Transition for the current user. diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js index f451227815..d15f2183a9 100644 --- a/frappe/public/js/frappe/chat.js +++ b/frappe/public/js/frappe/chat.js @@ -718,7 +718,7 @@ frappe.chat.room.create = function (kind, owner, users, name, fn) { return new Promise(resolve => { frappe.call("frappe.chat.doctype.chat_room.chat_room.create", - { kind: kind, owner: owner || frappe.session.user, users: users, name: name }, + { kind: kind, token: owner || frappe.session.user, users: users, name: name }, r => { let room = r.message room = { ...room, creation: new frappe.datetime.datetime(room.creation) } diff --git a/frappe/public/js/frappe/form/controls/time.js b/frappe/public/js/frappe/form/controls/time.js index d6dcf9d33d..9e4f2048f3 100644 --- a/frappe/public/js/frappe/form/controls/time.js +++ b/frappe/public/js/frappe/form/controls/time.js @@ -45,7 +45,8 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({ && ((this.last_value && this.last_value !== this.value) || (!this.datepicker.selectedDates.length))) { - var date_obj = frappe.datetime.moment_to_date_obj(moment(value, frappe.sys_defaults['time_format'])); + let time_format = frappe.sys_defaults.time_format || 'HH:mm:ss'; + var date_obj = frappe.datetime.moment_to_date_obj(moment(value, time_format)); this.datepicker.selectDate(date_obj); } }, diff --git a/frappe/public/js/frappe/form/footer/timeline.js b/frappe/public/js/frappe/form/footer/timeline.js index 623f87b7fd..6dbb7904c2 100644 --- a/frappe/public/js/frappe/form/footer/timeline.js +++ b/frappe/public/js/frappe/form/footer/timeline.js @@ -377,11 +377,11 @@ frappe.ui.form.Timeline = class Timeline { c["edit"] = ""; if(c.communication_type=="Comment" && (c.comment_type || "Comment") === "Comment") { if(frappe.model.can_delete("Comment")) { - c["delete"] = ''; + c["delete"] = ``; } if(frappe.user.name == c.sender || (frappe.user.name == 'Administrator')) { - c["edit"] = 'Edit'; + c["edit"] = `${__('Edit')}`; } } let communication_date = c.communication_date || c.creation; diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index ff573889e2..9b6c35d300 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -84,7 +84,7 @@ frappe.form.formatters = { }, Check: function(value) { if(value) { - return ''; + return ''; } else { return ''; } diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index 6affdf76e4..c1f4c7365a 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -451,27 +451,27 @@ frappe.ui.form.Layout = Class.extend({ // build dependants' dictionary var has_dep = false; - for(var fkey in this.fields_list) { + for (var fkey in this.fields_list) { var f = this.fields_list[fkey]; f.dependencies_clear = true; - if(f.df.depends_on) { + if (f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) { has_dep = true; } } - if(!has_dep)return; + if (!has_dep) return; // show / hide based on values - for(var i=me.fields_list.length-1;i>=0;i--) { + for (var i=me.fields_list.length-1;i>=0;i--) { var f = me.fields_list[i]; f.guardian_has_value = true; - if(f.df.depends_on) { + if (f.df.depends_on) { // evaluate guardian f.guardian_has_value = this.evaluate_depends_on_value(f.df.depends_on); // show / hide - if(f.guardian_has_value) { + if (f.guardian_has_value) { if(f.df.hidden_due_to_dependency) { f.df.hidden_due_to_dependency = false; f.refresh(); @@ -483,10 +483,28 @@ frappe.ui.form.Layout = Class.extend({ } } } + + if (f.df.mandatory_depends_on) { + this.set_dependant_property(f.df.mandatory_depends_on, f.df.fieldname, 'reqd'); + } + + if (f.df.read_only_depends_on) { + this.set_dependant_property(f.df.read_only_depends_on, f.df.fieldname, 'read_only'); + } } this.refresh_section_count(); }, + set_dependant_property: function(condition, fieldname, property) { + let set_property = this.evaluate_depends_on_value(condition); + if (this.frm) { + if (set_property) { + this.frm.set_df_property(fieldname, property, 1); + } else { + this.frm.set_df_property(fieldname, property, 0); + } + } + }, evaluate_depends_on_value: function(expression) { var out = null; var doc = this.doc; diff --git a/frappe/public/js/frappe/form/workflow.js b/frappe/public/js/frappe/form/workflow.js index 4eafc12a06..4eb33a5f28 100644 --- a/frappe/public/js/frappe/form/workflow.js +++ b/frappe/public/js/frappe/form/workflow.js @@ -105,7 +105,17 @@ frappe.ui.form.States = Class.extend({ }); } }); - this.setup_btn(added); + if (!added) { + //call function and clear cancel button if Cancel doc state is defined in the workfloe + frappe.xcall('frappe.model.workflow.can_cancel_document', {doc: this.frm.doc}).then((can_cancel) => { + if (!can_cancel) { + this.frm.page.clear_secondary_action(); + } + }); + } else { + this.setup_btn(added); + } + }); }, diff --git a/frappe/public/js/frappe/list/list_sidebar_group_by.js b/frappe/public/js/frappe/list/list_sidebar_group_by.js index e2db471b51..c07983964f 100644 --- a/frappe/public/js/frappe/list/list_sidebar_group_by.js +++ b/frappe/public/js/frappe/list/list_sidebar_group_by.js @@ -90,7 +90,7 @@ frappe.views.ListGroupBy = class ListGroupBy { this.render_dropdown_items(field_count_list, dropdown); this.sidebar.setup_dropdown_search(dropdown, '.group-by-value'); } else { - dropdown.find('.group-by-loading').hide(); + dropdown.find('.group-by-loading').html(`${__("No filters found")}`); } }); }); diff --git a/frappe/public/js/frappe/views/components/Desktop.vue b/frappe/public/js/frappe/views/components/Desktop.vue index dd9aff3cb7..ec663a876a 100644 --- a/frappe/public/js/frappe/views/components/Desktop.vue +++ b/frappe/public/js/frappe/views/components/Desktop.vue @@ -116,6 +116,7 @@ export default { user_section = [ { + fieldname: 'user_section', fieldtype: 'Section Break', depends_on: doc => doc.setup_for === user_value } @@ -134,6 +135,7 @@ export default { global_section = [ { + fieldname: 'global_section', fieldtype: 'Section Break', depends_on: doc => doc.setup_for === 'Everyone' } @@ -188,8 +190,11 @@ export default { update_global_modules(d) { let blocked_modules = []; for (let category of this.module_categories) { - let unchecked_options = d.get_field(`global:${category}`).get_unchecked_options(); - blocked_modules = blocked_modules.concat(unchecked_options); + let field = d.get_field(`global:${category}`); + if (field) { + let unchecked_options = field.get_unchecked_options(); + blocked_modules = blocked_modules.concat(unchecked_options); + } } frappe.call({ diff --git a/frappe/public/less/navbar.less b/frappe/public/less/navbar.less index f6145e77bb..5cb050b10f 100644 --- a/frappe/public/less/navbar.less +++ b/frappe/public/less/navbar.less @@ -204,7 +204,7 @@ .navbar-form .awesomplete { margin-left: -15px; - width: 300px; + width: 370px; @media (max-width: @screen-md) { width: 280px; diff --git a/frappe/templates/emails/energy_points_summary.html b/frappe/templates/emails/energy_points_summary.html index c560a24cfc..3cbc6e97cb 100644 --- a/frappe/templates/emails/energy_points_summary.html +++ b/frappe/templates/emails/energy_points_summary.html @@ -2,7 +2,7 @@

{{ _('Top Performer') }} 🏆

{{ frappe.get_fullname(top_performer.user) }} - {{ frappe._('gained {0} points').format(frappe.utils.cint(top_performer.energy_points)) }} + {{ _('gained {0} points').format(frappe.utils.cint(top_performer.energy_points)) }}

{% endif %} @@ -11,7 +11,7 @@

{{ _('Top Reviewer') }} ❤️

{{ frappe.get_fullname(top_reviewer.user) }} - {{ frappe._('gave {0} points').format(frappe.utils.cint(top_reviewer.given_points)) }} + {{ _('gave {0} points').format(frappe.utils.cint(top_reviewer.given_points)) }}

@@ -24,9 +24,9 @@ - - - + + + {% for user in standings %} diff --git a/frappe/templates/styles/standard.css b/frappe/templates/styles/standard.css index 0f41d01c1c..f5eeb1c7fb 100644 --- a/frappe/templates/styles/standard.css +++ b/frappe/templates/styles/standard.css @@ -49,6 +49,10 @@ } } +.disabled-check { + color: #eee; +} + .data-field { margin-top: 5px; margin-bottom: 5px; diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index 7442bf3d46..40ebc8ea6e 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -75,6 +75,23 @@ def create_contact_phone_nos_records(): doc.append('phone_nos', {'phone': '123456{}'.format(index)}) doc.insert() +@frappe.whitelist() +def create_doctype(name, fields): + fields = frappe.parse_json(fields) + if frappe.db.exists('DocType', name): + return + frappe.get_doc({ + "doctype": "DocType", + "module": "Core", + "custom": 1, + "fields": fields, + "permissions": [{ + "role": "System Manager", + "read": 1 + }], + "name": name + }).insert() + @frappe.whitelist() def create_contact_records(): if frappe.db.get_all('Contact', {'first_name': 'Test Form Contact 1'}): diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index befb9336fa..7c3b9b0482 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -16,6 +16,7 @@ def get_jenv(): set_filters(jenv) jenv.globals.update(get_safe_globals()) + jenv.globals.update(get_jenv_customization('methods')) frappe.local.jenv = jenv @@ -124,4 +125,27 @@ def set_filters(jenv): jenv.filters["flt"] = flt jenv.filters["abs_url"] = abs_url - if frappe.flags.in_setup_help: return + if frappe.flags.in_setup_help: + return + + jenv.filters.update(get_jenv_customization('filters')) + + +def get_jenv_customization(customization_type): + '''Returns a dict with filter/method name as key and definition as value''' + + import frappe + + out = {} + if not getattr(frappe.local, "site", None): + return out + + values = frappe.get_hooks("jenv", {}).get(customization_type) + if not values: + return out + + for value in values: + fn_name, fn_string = value.split(":") + out[fn_name] = frappe.get_attr(fn_string) + + return out diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index b631406a8e..c69dc430cf 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -2,14 +2,24 @@ # MIT License. See license.txt from __future__ import unicode_literals -import pdfkit, os, frappe +import io +import os +import re from distutils.version import LooseVersion -from frappe.utils import scrub_urls, get_wkhtmltopdf_version -from frappe import _ -import six, re, io + +import pdfkit +import six from bs4 import BeautifulSoup from PyPDF2 import PdfFileReader, PdfFileWriter +import frappe +from frappe import _ +from frappe.utils import get_wkhtmltopdf_version, scrub_urls + +PDF_CONTENT_ERRORS = ["ContentNotFoundError", "ContentOperationNotPermittedError", + "UnknownContentError", "RemoteHostClosedError"] + + def get_pdf(html, options=None, output=None): html = scrub_urls(html) html, options = prepare_options(html, options) @@ -30,20 +40,14 @@ def get_pdf(html, options=None, output=None): # https://pythonhosted.org/PyPDF2/PdfFileReader.html # create in-memory binary streams from filedata and create a PdfFileReader object reader = PdfFileReader(io.BytesIO(filedata)) - - except IOError as e: - if ("ContentNotFoundError" in e.message - or "ContentOperationNotPermittedError" in e.message - or "UnknownContentError" in e.message - or "RemoteHostClosedError" in e.message): + except OSError as e: + if any([error in str(e) for error in PDF_CONTENT_ERRORS]): + if not filedata: + frappe.throw(_("PDF generation failed because of broken image links")) # allow pdfs with missing images if file got created - if filedata: - if output: # output is a PdfFileWriter object - output.appendPagesFromReader(reader) - - else: - frappe.throw(_("PDF generation failed because of broken image links")) + if output: # output is a PdfFileWriter object + output.appendPagesFromReader(reader) else: raise @@ -66,6 +70,7 @@ def get_pdf(html, options=None, output=None): return filedata + def get_file_data_from_writer(writer_obj): # https://docs.python.org/3/library/io.html @@ -112,6 +117,7 @@ def prepare_options(html, options): return html, options + def read_options_from_html(html): options = {} soup = BeautifulSoup(html, "html5lib") @@ -132,6 +138,7 @@ def read_options_from_html(html): return soup.prettify(), options + def prepare_header_footer(soup): options = {} @@ -174,6 +181,7 @@ def prepare_header_footer(soup): return options + def cleanup(fname, options): if os.path.exists(fname): os.remove(fname) @@ -182,6 +190,7 @@ def cleanup(fname, options): if options.get(key) and os.path.exists(options[key]): os.remove(options[key]) + def toggle_visible_pdf(soup): for tag in soup.find_all(attrs={"class": "visible-pdf"}): # remove visible-pdf class to unhide diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index 5bc2a3157a..62d0286e03 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -48,11 +48,9 @@ def get_safe_globals(): # make available limited methods of frappe json=json, dict=dict, + _dict=frappe._dict, frappe=frappe._dict( - _=frappe._, - _dict=frappe._dict, flags=frappe.flags, - format=frappe.format_value, format_value=frappe.format_value, date_format=date_format, diff --git a/requirements.txt b/requirements.txt index 96e57fd1f7..77f49156e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,8 +34,7 @@ passlib==1.7.1 pdfkit==0.6.1 Pillow==6.2.1 premailer==3.6.1 -psycopg2-binary==2.7.5 -psycopg2==2.7.5 +psycopg2-binary==2.8.4 pyasn1==0.4.7 Pygments==2.2.0 PyJWT==1.7.1 @@ -64,4 +63,4 @@ urllib3==1.25.7 watchdog==0.8.0 Werkzeug==0.16.0 xlrd==1.2.0 -zxcvbn-python==4.4.24 \ No newline at end of file +zxcvbn-python==4.4.24
# {{ frappe._('User') }}{{ frappe._('Energy Points') }}{{ frappe._('Points Given') }}{{ _('User') }}{{ _('Energy Points') }}{{ _('Points Given') }}