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/__init__.py b/frappe/__init__.py
index b383ae958e..5e797fd8cd 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -321,10 +321,19 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None,
return
if as_table and type(msg) in (list, tuple):
- out.msg = '
' + ''.join([''+''.join(['| %s | ' % c for c in r])+'
' for r in msg]) + '
'
- if flags.print_messages and out.msg:
- print("Message: " + repr(out.msg).encode("utf-8"))
+ table_rows = ''
+ for row in msg:
+ table_row_data = ''
+ for data in row:
+ table_row_data += '{} | '.format(data)
+ table_rows += '{}
'.format(table_row_data)
+
+ out.message = ''''''.format(table_rows)
+
+ if flags.print_messages and out.message:
+ print("Message: " + repr(out.message).encode("utf-8"))
if title:
out.title = title
@@ -363,7 +372,6 @@ def throw(msg, exc=ValidationError, title=None):
msgprint(msg, raise_exception=exc, title=title, indicator='red')
def emit_js(js, user=False, **kwargs):
- from frappe.realtime import publish_realtime
if user == False:
user = session.user
publish_realtime('eval_js', js, user=user, **kwargs)
@@ -767,8 +775,8 @@ def get_meta_module(doctype):
import frappe.modules
return frappe.modules.load_doctype_module(doctype)
-def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False,
- ignore_permissions=False, flags=None, ignore_on_trash=False, ignore_missing=True):
+def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None,
+ for_reload=False, ignore_permissions=False, flags=None, ignore_on_trash=False, ignore_missing=True):
"""Delete a document. Calls `frappe.model.delete_doc.delete_doc`.
:param doctype: DocType of document to be delete.
@@ -805,8 +813,8 @@ def reload_doc(module, dt=None, dn=None, force=False, reset_permissions=False):
def rename_doc(*args, **kwargs):
"""Rename a document. Calls `frappe.model.rename_doc.rename_doc`"""
- from frappe.model.rename_doc import rename_doc
- return rename_doc(*args, **kwargs)
+ from frappe.model.rename_doc import rename_doc as _rename_doc
+ return _rename_doc(*args, **kwargs)
def get_module(modulename):
"""Returns a module object for given Python module name using `importlib.import_module`."""
@@ -814,11 +822,11 @@ def get_module(modulename):
def scrub(txt):
"""Returns sluggified string. e.g. `Sales Order` becomes `sales_order`."""
- return txt.replace(' ','_').replace('-', '_').lower()
+ return txt.replace(' ', '_').replace('-', '_').lower()
def unscrub(txt):
"""Returns titlified string. e.g. `sales_order` becomes `Sales Order`."""
- return txt.replace('_',' ').replace('-', ' ').title()
+ return txt.replace('_', ' ').replace('-', ' ').title()
def get_module_path(module, *joins):
"""Get the path of the given module name.
@@ -980,7 +988,8 @@ def setup_module_map():
if not (local.app_modules and local.module_app):
local.module_app, local.app_modules = {}, {}
for app in get_all_apps(True):
- if app=="webnotes": app="frappe"
+ if app == "webnotes":
+ app = "frappe"
local.app_modules.setdefault(app, [])
for module in get_module_list(app):
module = scrub(module)
@@ -999,7 +1008,10 @@ def get_file_items(path, raise_not_found=False, ignore_empty_lines=True):
if content:
content = frappe.utils.strip(content)
- return [p.strip() for p in content.splitlines() if (not ignore_empty_lines) or (p.strip() and not p.startswith("#"))]
+ return [
+ p.strip() for p in content.splitlines()
+ if (not ignore_empty_lines) or (p.strip() and not p.startswith("#"))
+ ]
else:
return []
@@ -1161,8 +1173,8 @@ def compare(val1, condition, val2):
import frappe.utils
return frappe.utils.compare(val1, condition, val2)
-def respond_as_web_page(title, html, success=None, http_status_code=None,
- context=None, indicator_color=None, primary_action='/', primary_label = None, fullpage=False,
+def respond_as_web_page(title, html, success=None, http_status_code=None, context=None,
+ indicator_color=None, primary_action='/', primary_label = None, fullpage=False,
width=None, template='message'):
"""Send response as a web page with a message rather than JSON. Used to show permission errors etc.
@@ -1351,7 +1363,8 @@ def format(*args, **kwargs):
import frappe.utils.formatters
return frappe.utils.formatters.format_value(*args, **kwargs)
-def get_print(doctype=None, name=None, print_format=None, style=None, html=None, as_pdf=False, doc=None, output = None, no_letterhead = 0, password=None):
+def get_print(doctype=None, name=None, print_format=None, style=None,
+ html=None, as_pdf=False, doc=None, output=None, no_letterhead=0, password=None):
"""Get Print Format for given document.
:param doctype: DocType of document.
@@ -1382,7 +1395,8 @@ def get_print(doctype=None, name=None, print_format=None, style=None, html=None,
else:
return html
-def attach_print(doctype, name, file_name=None, print_format=None, style=None, html=None, doc=None, lang=None, print_letterhead=True, password=None):
+def attach_print(doctype, name, file_name=None, print_format=None,
+ style=None, html=None, doc=None, lang=None, print_letterhead=True, password=None):
from frappe.utils import scrub_urls
if not file_name: file_name = name
@@ -1398,16 +1412,28 @@ def attach_print(doctype, name, file_name=None, print_format=None, style=None, h
no_letterhead = not print_letterhead
+ kwargs = dict(
+ print_format=print_format,
+ style=style,
+ html=html,
+ doc=doc,
+ no_letterhead=no_letterhead,
+ password=password
+ )
+
+ content = ''
if int(print_settings.send_print_as_pdf or 0):
- out = {
- "fname": file_name + ".pdf",
- "fcontent": get_print(doctype, name, print_format=print_format, style=style, html=html, as_pdf=True, doc=doc, no_letterhead=no_letterhead, password=password)
- }
+ ext = ".pdf"
+ kwargs["as_pdf"] = True
+ content = get_print(doctype, name, **kwargs)
else:
- out = {
- "fname": file_name + ".html",
- "fcontent": scrub_urls(get_print(doctype, name, print_format=print_format, style=style, html=html, doc=doc, no_letterhead=no_letterhead, password=password)).encode("utf-8")
- }
+ ext = ".html"
+ content = scrub_urls(get_print(doctype, name, **kwargs)).encode('utf-8')
+
+ out = {
+ "fname": file_name + ext,
+ "fcontent": content
+ }
local.flags.ignore_print_permissions = False
#reset lang to original local lang
@@ -1526,7 +1552,12 @@ def log_error(message=None, title=None):
method=title)).insert(ignore_permissions=True)
def get_desk_link(doctype, name):
- return '{2} {1}'.format(doctype, name, _(doctype))
+ html = '{doctype_local} {name}'
+ return html.format(
+ doctype=doctype,
+ name=name,
+ doctype_local=_(doctype)
+ )
def bold(text):
return '{0}'.format(text)
@@ -1545,10 +1576,9 @@ def safe_eval(code, eval_globals=None, eval_locals=None):
if not eval_globals:
eval_globals = {}
+
eval_globals['__builtins__'] = {}
-
eval_globals.update(whitelisted_globals)
-
return eval(code, eval_globals, eval_locals)
def get_system_settings(key):
@@ -1560,9 +1590,11 @@ def get_active_domains():
from frappe.core.doctype.domain_settings.domain_settings import get_active_domains
return get_active_domains()
-def get_version(doctype, name, limit = None, head = False, raise_err = True):
+def get_version(doctype, name, limit=None, head=False, raise_err=True):
'''
- Returns a list of version information of a given DocType (Applicable only if DocType has changes tracked).
+ Returns a list of version information of a given DocType.
+
+ Note: Applicable only if DocType has changes tracked.
Example
>>> frappe.get_version('User', 'foobar@gmail.com')
@@ -1575,34 +1607,29 @@ def get_version(doctype, name, limit = None, head = False, raise_err = True):
}
]
'''
- meta = get_meta(doctype)
+ meta = get_meta(doctype)
if meta.track_changes:
- names = db.sql("""
- SELECT name from tabVersion
- WHERE ref_doctype = '{doctype}' AND docname = '{name}'
- {order_by}
- {limit}
- """.format(
- doctype = doctype,
- name = name,
- order_by = 'ORDER BY creation' if head else '',
- limit = 'LIMIT {limit}'.format(limit = limit) if limit else ''
- ))
+ names = db.get_all('Version', filters={
+ 'ref_doctype': doctype,
+ 'docname': name,
+ 'order_by': 'creation' if head else None,
+ 'limit': limit
+ }, as_list=1)
from frappe.chat.util import squashify, dictify, safe_json_loads
- versions = [ ]
+ versions = []
for name in names:
name = squashify(name)
- doc = get_doc('Version', name)
+ doc = get_doc('Version', name)
data = doc.data
data = safe_json_loads(data)
data = dictify(dict(
- version = data,
- user = doc.owner,
- creation = doc.creation
+ version=data,
+ user=doc.owner,
+ creation=doc.creation
))
versions.append(data)
@@ -1610,16 +1637,14 @@ def get_version(doctype, name, limit = None, head = False, raise_err = True):
return versions
else:
if raise_err:
- raise ValueError('{doctype} has no versions tracked.'.format(
- doctype = doctype
- ))
+ raise ValueError(_('{0} has no versions tracked.').format(doctype))
-@whitelist(allow_guest = True)
+@whitelist(allow_guest=True)
def ping():
return "pong"
-def safe_encode(param, encoding = 'utf-8'):
+def safe_encode(param, encoding='utf-8'):
try:
param = param.encode(encoding)
except Exception:
@@ -1627,7 +1652,7 @@ def safe_encode(param, encoding = 'utf-8'):
return param
-def safe_decode(param, encoding = 'utf-8'):
+def safe_decode(param, encoding='utf-8'):
try:
param = param.decode(encoding)
except Exception:
@@ -1638,9 +1663,9 @@ def parse_json(val):
from frappe.utils import parse_json
return parse_json(val)
-def mock(type, size = 1, locale = 'en'):
- results = [ ]
- faker = Faker(locale)
+def mock(type, size=1, locale='en'):
+ results = []
+ faker = Faker(locale)
if not type in dir(faker):
raise ValueError('Not a valid mock type.')
else:
@@ -1649,7 +1674,4 @@ def mock(type, size = 1, locale = 'en'):
results.append(data)
from frappe.chat.util import squashify
-
- results = squashify(results)
-
- return results
+ return squashify(results)
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/commands/utils.py b/frappe/commands/utils.py
index d29f0a9c97..11f8e69b95 100644
--- a/frappe/commands/utils.py
+++ b/frappe/commands/utils.py
@@ -460,6 +460,15 @@ def run_tests(context, app=None, module=None, doctype=None, test=(),
tests = test
site = get_site(context)
+
+ allow_tests = frappe.get_conf(site).allow_tests
+
+ if not (allow_tests or os.environ.get('CI')):
+ click.secho('Testing is disabled for the site!', bold=True)
+ click.secho('You can enable tests by entering following command:')
+ click.secho('bench --site {0} set-config allow_tests true'.format(site), fg='green')
+ return
+
frappe.init(site=site)
frappe.flags.skip_before_tests = skip_before_tests
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 c459362b17..b8e0bbbe7b 100644
--- a/frappe/core/doctype/doctype/doctype.py
+++ b/frappe/core/doctype/doctype/doctype.py
@@ -907,7 +907,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/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 4c5fe76bed..5b54491d88 100644
--- a/frappe/custom/doctype/customize_form/customize_form.py
+++ b/frappe/custom/doctype/customize_form/customize_form.py
@@ -62,6 +62,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',
@@ -71,7 +73,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 bf9e0e33c8..46940cc846 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 6bd20d241b..16114f8cf8 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 74285e2182..bbfe5f46c4 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()
@@ -244,13 +247,13 @@ class EmailAccount(Document):
exceptions = []
seen_status = []
uid_reindexed = False
+ email_server = None
if frappe.local.flags.in_test:
incoming_mails = test_mails
else:
email_sync_rule = self.build_email_sync_rule()
- email_server = None
try:
email_server = self.get_incoming_server(in_receive=True, email_sync_rule=email_sync_rule)
except Exception:
@@ -290,7 +293,7 @@ class EmailAccount(Document):
else:
frappe.db.commit()
- if communication:
+ if communication and hasattr(communication, "_attachments"):
attachments = [d.file_name for d in communication._attachments]
communication.notify(attachments=attachments, fetched_from_email_account=True)
@@ -302,7 +305,7 @@ class EmailAccount(Document):
raise Exception(frappe.as_json(exceptions))
def handle_bad_emails(self, email_server, uid, raw, reason):
- if cint(email_server.settings.use_imap):
+ if email_server and cint(email_server.settings.use_imap):
import email
try:
mail = email.message_from_string(raw)
@@ -636,6 +639,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):
txt = txt if txt else ""
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..62b0d9ea3f 100755
--- a/frappe/email/queue.py
+++ b/frappe/email/queue.py
@@ -6,7 +6,7 @@ import frappe
import sys
from six.moves import html_parser as HTMLParser
import smtplib, quopri, json
-from frappe import msgprint, _, safe_decode
+from frappe import msgprint, _, safe_decode, safe_encode
from frappe.email.smtp import SMTPServer, get_outgoing_email_account
from frappe.email.email_body import get_email, get_formatted_html, add_attachment
from frappe.utils.verified_command import get_signed_params, verify_request
@@ -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:
@@ -550,7 +563,7 @@ def prepare_message(email, recipient, recipients_list):
print_format_file.update({"parent": message})
add_attachment(**print_format_file)
- return message.as_string()
+ return safe_encode(message.as_string())
def clear_outbox():
"""Remove low priority older than 31 days in Outbox and expire mails not sent for 7 days.
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..aa025465e5 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"""
@@ -41,6 +41,8 @@ def get_outgoing_email_account(raise_exception_not_set=True, append_to=None, sen
try getting settings from `site_config.json`."""
sender_email_id = None
+ _email_account = None
+
if sender:
sender_email_id = parse_addr(sender)[1]
@@ -52,35 +54,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 +157,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 +191,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 +209,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/email/test_email_body.py b/frappe/email/test_email_body.py
index 26c4e5ba5d..f44c6e775a 100644
--- a/frappe/email/test_email_body.py
+++ b/frappe/email/test_email_body.py
@@ -3,9 +3,10 @@
from __future__ import unicode_literals
import unittest, os, base64
+from frappe import safe_decode
from frappe.email.receive import Email
from frappe.email.email_body import (replace_filename_with_cid,
- get_email, inline_style_in_html, get_header)
+ get_email, inline_style_in_html, get_header)
from frappe.email.queue import prepare_message, get_email_queue
from six import PY3
@@ -57,7 +58,7 @@ This is the text version of this email
formatted='' + uni_chr1 + 'abcd' + uni_chr2 + '
',
text_content='whatever')
result = prepare_message(email=email, recipient='test@test.com', recipients_list=[])
- self.assertTrue("=EA=80=80abcd=DE=B4
" in result)
+ self.assertTrue(b"=EA=80=80abcd=DE=B4
" in result)
def test_prepare_message_returns_cr_lf(self):
email = get_email_queue(
@@ -67,7 +68,8 @@ This is the text version of this email
content='\n this is a test of newlines\n' + '
',
formatted='\n this is a test of newlines\n' + '
',
text_content='whatever')
- result = prepare_message(email=email, recipient='test@test.com', recipients_list=[])
+ result = safe_decode(prepare_message(email=email,
+ recipient='test@test.com', recipients_list=[]))
if PY3:
self.assertTrue(result.count('\n') == result.count("\r"))
else:
@@ -81,9 +83,10 @@ This is the text version of this email
subject='Test Subject',
content='Whatever
',
text_content='whatever',
- message_id= "a.really.long.message.id.that.should.not.wrap.until.998.if.it.does.then.exchange.will.break" +
- ".really.long.message.id.that.should.not.wrap.unti")
- result = prepare_message(email=email, recipient='test@test.com', recipients_list=[])
+ message_id="a.really.long.message.id.that.should.not.wrap.until.998.if.it.does.then.exchange.will.break" +
+ ".really.long.message.id.that.should.not.wrap.unti")
+ result = safe_decode(prepare_message(email=email, recipient='test@test.com',
+ recipients_list=[]))
self.assertTrue(
"a.really.long.message.id.that.should.not.wrap.until.998.if.it.does.then.exchange.will.break" +
".really.long.message.id.that.should.not.wrap.unti" in result)
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 a50bf9fdaf..cbbe2b267e 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/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 @@
| # |
- {{ frappe._('User') }} |
- {{ frappe._('Energy Points') }} |
- {{ frappe._('Points Given') }} |
+ {{ _('User') }} |
+ {{ _('Energy Points') }} |
+ {{ _('Points Given') }} |
{% 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/background_jobs.py b/frappe/utils/background_jobs.py
index c1ac7581dc..65b2326733 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -142,6 +142,8 @@ def start_worker(queue=None, quiet = False):
with Connection(redis_connection):
queues = get_queue_list(queue)
logging_level = "INFO"
+ if quiet:
+ logging_level = "WARNING"
Worker(queues, name=get_worker_name(queue)).work(logging_level = logging_level)
def get_worker_name(queue):
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