Browse Source

Merge branch 'develop'

version-14
mbauskar 8 years ago
parent
commit
7a06746992
100 changed files with 2751 additions and 1315 deletions
  1. +9
    -0
      .eslintignore
  2. +122
    -0
      .eslintrc
  3. +13
    -9
      .travis.yml
  4. +22
    -5
      frappe/__init__.py
  5. +2
    -1
      frappe/app.py
  6. +11
    -2
      frappe/boot.py
  7. +1
    -2
      frappe/build.js
  8. +5
    -3
      frappe/build.py
  9. +4
    -2
      frappe/client.py
  10. +4
    -1
      frappe/commands/__init__.py
  11. +9
    -8
      frappe/commands/site.py
  12. +33
    -13
      frappe/commands/utils.py
  13. +7
    -0
      frappe/config/desktop.py
  14. +15
    -0
      frappe/config/integrations.py
  15. +7
    -1
      frappe/config/setup.py
  16. +0
    -0
      frappe/contacts/__init__.py
  17. +1
    -1
      frappe/contacts/address_and_contact.py
  18. +0
    -0
      frappe/contacts/doctype/__init__.py
  19. +0
    -0
      frappe/contacts/doctype/address/__init__.py
  20. +1
    -1
      frappe/contacts/doctype/address/address.js
  21. +3
    -2
      frappe/contacts/doctype/address/address.json
  22. +3
    -1
      frappe/contacts/doctype/address/address.py
  23. +33
    -0
      frappe/contacts/doctype/address/test_address.py
  24. +0
    -0
      frappe/contacts/doctype/address_template/__init__.py
  25. +1
    -1
      frappe/contacts/doctype/address_template/address_template.js
  26. +8
    -4
      frappe/contacts/doctype/address_template/address_template.json
  27. +0
    -0
      frappe/contacts/doctype/address_template/address_template.py
  28. +45
    -0
      frappe/contacts/doctype/address_template/test_address_template.py
  29. +0
    -0
      frappe/contacts/doctype/contact/__init__.py
  30. +1
    -1
      frappe/contacts/doctype/contact/contact.js
  31. +65
    -3
      frappe/contacts/doctype/contact/contact.json
  32. +3
    -1
      frappe/contacts/doctype/contact/contact.py
  33. +1
    -1
      frappe/contacts/doctype/contact/test_contact.py
  34. +0
    -0
      frappe/contacts/doctype/contact/test_records.json
  35. +0
    -0
      frappe/contacts/doctype/gender/__init__.py
  36. +8
    -0
      frappe/contacts/doctype/gender/gender.js
  37. +113
    -0
      frappe/contacts/doctype/gender/gender.json
  38. +9
    -0
      frappe/contacts/doctype/gender/gender.py
  39. +9
    -0
      frappe/contacts/doctype/gender/test_gender.py
  40. +0
    -0
      frappe/contacts/doctype/salutation/__init__.py
  41. +8
    -0
      frappe/contacts/doctype/salutation/salutation.js
  42. +132
    -0
      frappe/contacts/doctype/salutation/salutation.json
  43. +9
    -0
      frappe/contacts/doctype/salutation/salutation.py
  44. +9
    -0
      frappe/contacts/doctype/salutation/test_salutation.py
  45. +0
    -0
      frappe/contacts/report/__init__.py
  46. +0
    -0
      frappe/contacts/report/addresses_and_contacts/__init__.py
  47. +0
    -0
      frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.js
  48. +2
    -2
      frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.json
  49. +0
    -0
      frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py
  50. +15
    -15
      frappe/core/doctype/communication/communication.js
  51. +1
    -1
      frappe/core/doctype/communication/communication_list.js
  52. +28
    -13
      frappe/core/doctype/communication/test_communication.py
  53. +1
    -1
      frappe/core/doctype/deleted_document/deleted_document.py
  54. +1
    -0
      frappe/core/doctype/doctype/boilerplate/controller_list.js
  55. +1
    -1
      frappe/core/doctype/doctype/doctype.js
  56. +90
    -3
      frappe/core/doctype/doctype/doctype.json
  57. +17
    -1
      frappe/core/doctype/doctype/doctype.py
  58. +1
    -1
      frappe/core/doctype/doctype/test_doctype.py
  59. +0
    -0
      frappe/core/doctype/domain/__init__.py
  60. +8
    -0
      frappe/core/doctype/domain/domain.js
  61. +95
    -0
      frappe/core/doctype/domain/domain.json
  62. +10
    -0
      frappe/core/doctype/domain/domain.py
  63. +10
    -0
      frappe/core/doctype/domain/test_domain.py
  64. +0
    -0
      frappe/core/doctype/domain_settings/__init__.py
  65. +57
    -0
      frappe/core/doctype/domain_settings/domain_settings.js
  66. +153
    -0
      frappe/core/doctype/domain_settings/domain_settings.json
  67. +12
    -0
      frappe/core/doctype/domain_settings/domain_settings.py
  68. +2
    -2
      frappe/core/doctype/error_log/error_log_list.js
  69. +2
    -2
      frappe/core/doctype/error_snapshot/error_snapshot.js
  70. +12
    -12
      frappe/core/doctype/error_snapshot/error_snapshot_list.js
  71. +1
    -1
      frappe/core/doctype/feedback_request/feedback_request.js
  72. +2
    -2
      frappe/core/doctype/feedback_request/feedback_request_list.js
  73. +1
    -1
      frappe/core/doctype/feedback_trigger/feedback_trigger.js
  74. +20
    -4
      frappe/core/doctype/feedback_trigger/feedback_trigger.json
  75. +1
    -1
      frappe/core/doctype/feedback_trigger/feedback_trigger.py
  76. +6
    -9
      frappe/core/doctype/file/file.py
  77. +12
    -12
      frappe/core/doctype/file/file_list.js
  78. +0
    -0
      frappe/core/doctype/has_domain/__init__.py
  79. +72
    -0
      frappe/core/doctype/has_domain/has_domain.json
  80. +10
    -0
      frappe/core/doctype/has_domain/has_domain.py
  81. +6
    -3
      frappe/core/doctype/module_def/module_def.json
  82. +42
    -1
      frappe/core/doctype/page/page.json
  83. +1
    -0
      frappe/core/doctype/report/boilerplate/controller.js
  84. +3
    -1
      frappe/core/doctype/report/report.py
  85. +36
    -1
      frappe/core/doctype/role/role.json
  86. +2
    -2
      frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.js
  87. +6
    -6
      frappe/core/doctype/system_settings/system_settings.js
  88. +34
    -2
      frappe/core/doctype/system_settings/system_settings.json
  89. +11
    -11
      frappe/core/doctype/user/user.js
  90. +30
    -19
      frappe/core/doctype/user/user.py
  91. +3
    -3
      frappe/core/page/data_import_tool/data_import_tool.js
  92. +13
    -13
      frappe/core/page/desktop/desktop.js
  93. +1
    -1
      frappe/core/page/modules_setup/modules_setup.js
  94. +8
    -6
      frappe/core/page/permission_manager/permission_manager.js
  95. +21
    -4
      frappe/core/page/permission_manager/permission_manager.py
  96. +13
    -11
      frappe/core/page/user_permissions/user_permissions.js
  97. +6
    -6
      frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.js
  98. +3
    -3
      frappe/custom/doctype/custom_field/custom_field.js
  99. +1135
    -1068
      frappe/custom/doctype/custom_field/custom_field.json
  100. +8
    -7
      frappe/custom/doctype/custom_field/custom_field.py

+ 9
- 0
.eslintignore View File

@@ -0,0 +1,9 @@
frappe/public/js/lib/*
frappe/public/js/frappe/misc/tests/*
frappe/public/js/frappe/views/test_runner.js
frappe/core/doctype/doctype/boilerplate/*
frappe/core/doctype/report/boilerplate/*
frappe/public/js/frappe/class.js
frappe/templates/includes/*
frappe/tests/testcafe/*
frappe/www/website_script.js

+ 122
- 0
.eslintrc View File

@@ -0,0 +1,122 @@
{
"env": {
"browser": true,
"node": true,
"es6": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
"tab",
{ "SwitchCase": 1 }
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"off"
],
"semi": [
"warn",
"always"
],
"camelcase": [
"off"
],
"no-unused-vars": [
"warn"
],
"no-redeclare": [
"warn"
],
"no-console": [
"warn"
],
"no-extra-boolean-cast": [
"off"
],
"no-control-regex": [
"off"
]
},
"root": true,
"globals": {
"frappe": true,
"$": true,
"jQuery": true,
"moment": true,
"hljs": true,
"Awesomplete": true,
"CalHeatMap": true,
"Sortable": true,
"Showdown": true,
"Taggle": true,
"Gantt": true,
"Slick": true,
"PhotoSwipe": true,
"PhotoSwipeUI_Default": true,
"fluxify": true,
"io": true,
"c3": true,
"__": true,
"_p": true,
"_f": true,
"repl": true,
"Class": true,
"locals": true,
"cint": true,
"cstr": true,
"cur_frm": true,
"cur_dialog": true,
"cur_page": true,
"cur_list": true,
"cur_tree": true,
"msg_dialog": true,
"is_null": true,
"in_list": true,
"has_common": true,
"has_words": true,
"validate_email": true,
"get_number_format": true,
"format_number": true,
"format_currency": true,
"comment_when": true,
"replace_newlines": true,
"open_url_post": true,
"toTitle": true,
"lstrip": true,
"strip": true,
"strip_html": true,
"replace_all": true,
"flt": true,
"precision": true,
"md5": true,
"CREATE": true,
"AMEND": true,
"CANCEL": true,
"copy_dict": true,
"get_number_format_info": true,
"print_table": true,
"Layout": true,
"web_form_settings": true,
"$c": true,
"$a": true,
"$i": true,
"$bg": true,
"$y": true,
"$c_obj": true,
"refresh_many": true,
"refresh_field": true,
"toggle_field": true,
"get_field_obj": true,
"get_query_params": true,
"unhide_field": true,
"hide_field": true,
"set_field_options": true,
"getCookie": true,
"getCookies": true,
"get_url_arg": true
}
}

+ 13
- 9
.travis.yml View File

@@ -4,11 +4,17 @@ dist: trusty
python:
- "2.7"

addons:
apt:
sources:
- google-chrome
packages:
- google-chrome-stable

services:
- mysql

before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start

@@ -18,26 +24,24 @@ install:
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
- sudo python install.py --develop --user travis --without-bench-setup
- sudo pip install -e ~/bench
- npm install -g testcafe

- rm $TRAVIS_BUILD_DIR/.git/shallow
- cd ~/ && bench init frappe-bench --frappe-path $TRAVIS_BUILD_DIR
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/

script:
- set -e
- bench --verbose run-tests
- bench reinstall --yes
- testcafe chrome apps/frappe/frappe/tests/testcafe/

before_script:
- mysql -u root -ptravis -e 'create database test_frappe'
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
- cd ~/frappe-bench
- npm install babel-core less chokidar babel-preset-es2015 babel-preset-es2016 babel-preset-es2017 babel-preset-babili
- bench use test_site
- bench reinstall --yes
- bench start &
- sleep 10

script:
- set -e
- bench --verbose run-tests
- bench reinstall --yes
- bench run-ui-tests --ci

+ 22
- 5
frappe/__init__.py View File

@@ -6,6 +6,7 @@ globals attached to frappe module
"""
from __future__ import unicode_literals, print_function

from six import iteritems
from werkzeug.local import Local, release_local
import os, sys, importlib, inspect, json

@@ -13,7 +14,7 @@ import os, sys, importlib, inspect, json
from .exceptions import *
from .utils.jinja import get_jenv, get_template, render_template

__version__ = '8.0.71'
__version__ = '8.1.0'
__title__ = "Frappe Framework"

local = Local()
@@ -145,10 +146,12 @@ def init(site, sites_path=None, new_site=False):
local.role_permissions = {}
local.valid_columns = {}
local.new_doc_templates = {}
local.link_count = {}

local.jenv = None
local.jloader =None
local.cache = {}
local.meta_cache = {}
local.form_dict = _dict()
local.session = _dict()

@@ -276,9 +279,9 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None,
import inspect

if inspect.isclass(raise_exception) and issubclass(raise_exception, Exception):
raise raise_exception, encode(msg)
raise raise_exception(encode(msg))
else:
raise ValidationError, encode(msg)
raise ValidationError(encode(msg))

if flags.mute_messages:
_raise_exception()
@@ -756,7 +759,7 @@ def get_doc_hooks():
if not hasattr(local, 'doc_events_hooks'):
hooks = get_hooks('doc_events', {})
out = {}
for key, value in hooks.iteritems():
for key, value in iteritems(hooks):
if isinstance(key, tuple):
for doctype in key:
append_hook(out, doctype, value)
@@ -1340,4 +1343,18 @@ def safe_eval(code, eval_globals=None, eval_locals=None):

eval_globals.update(whitelisted_globals)

return eval(code, eval_globals, eval_locals)
return eval(code, eval_globals, eval_locals)

def get_active_domains():
""" get the domains set in the Domain Settings as active domain """

active_domains = cache().hget("domains", "active_domains") or None
if active_domains is None:
domains = get_all("Has Domain", filters={ "parent": "Domain Settings" },
fields=["domain"], distinct=True)

active_domains = [row.get("domain") for row in domains]
active_domains.append("")
cache().hset("domains", "active_domains", active_domains)

return active_domains

+ 2
- 1
frappe/app.py View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals

import os
import MySQLdb
from six import iteritems

from werkzeug.wrappers import Request
from werkzeug.local import LocalManager
@@ -115,7 +116,7 @@ def init_request(request):

def make_form_dict(request):
frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
for k, v in (request.form or request.args).iteritems() })
for k, v in iteritems(request.form or request.args) })

if "_" in frappe.local.form_dict:
# _ is passed by $.ajax so that the request is not cached by the browser. So, remove _ from form_dict


+ 11
- 2
frappe/boot.py View File

@@ -2,6 +2,9 @@
# MIT License. See license.txt

from __future__ import unicode_literals

from six import iteritems

"""
bootstrap client session
"""
@@ -37,6 +40,8 @@ def get_bootinfo():
bootinfo.module_list = []
load_desktop_icons(bootinfo)
bootinfo.letter_heads = get_letter_heads()
bootinfo.active_domains = frappe.get_active_domains()
bootinfo.all_domains = [d.get("name") for d in frappe.get_all("Domain")]

bootinfo.module_app = frappe.local.module_app
bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType
@@ -69,6 +74,7 @@ def get_bootinfo():
bootinfo.treeviews = frappe.get_hooks("treeviews") or []
bootinfo.lang_dict = get_lang_dict()
bootinfo.feedback_triggers = get_enabled_feedback_trigger()
bootinfo.gsuite_enabled = get_gsuite_status()
bootinfo.update(get_email_accounts(user=frappe.session.user))

return bootinfo
@@ -176,7 +182,7 @@ def load_translations(bootinfo):
messages[name] = frappe._(name)

# only untranslated
messages = {k:v for k, v in messages.iteritems() if k!=v}
messages = {k:v for k, v in iteritems(messages) if k!=v}

bootinfo["__messages"] = messages

@@ -237,4 +243,7 @@ def get_unseen_notes():
return frappe.db.sql('''select name, title, content, notify_on_every_login from tabNote where notify_on_login=1
and expire_notification_on > %s and %s not in
(select user from `tabNote Seen By` nsb
where nsb.parent=tabNote.name)''', (frappe.utils.now(), frappe.session.user), as_dict=True)
where nsb.parent=tabNote.name)''', (frappe.utils.now(), frappe.session.user), as_dict=True)

def get_gsuite_status():
return (frappe.get_value('Gsuite Settings', None, 'enable') == '1')

+ 1
- 2
frappe/build.js View File

@@ -25,7 +25,7 @@ const action = process.argv[2] || '--build';

if (['--build', '--watch'].indexOf(action) === -1) {
console.log('Invalid argument: ', action);
return;
process.exit();
}

if (action === '--build') {
@@ -272,7 +272,6 @@ function watch_js(ondirty) {
if (sources.includes(filename)) {
pack(target, sources);
ondirty && ondirty(target);
break;
}
}
});


+ 5
- 3
frappe/build.py View File

@@ -5,6 +5,8 @@ from __future__ import unicode_literals, print_function
from frappe.utils.minify import JavascriptMinify
import subprocess

from six import iteritems

"""
Build the `public` folders and setup languages
"""
@@ -87,7 +89,7 @@ def make_asset_dirs(make_copy=False):
def build(no_compress=False, verbose=False):
assets_path = os.path.join(frappe.local.sites_path, "assets")

for target, sources in get_build_maps().iteritems():
for target, sources in iteritems(get_build_maps()):
pack(os.path.join(assets_path, target), sources, no_compress, verbose)

def get_build_maps():
@@ -100,7 +102,7 @@ def get_build_maps():
if os.path.exists(path):
with open(path) as f:
try:
for target, sources in json.loads(f.read()).iteritems():
for target, sources in iteritems(json.loads(f.read())):
# update app path
source_paths = []
for source in sources:
@@ -182,7 +184,7 @@ def scrub_html_template(content):
return content.replace("'", "\'")

def files_dirty():
for target, sources in get_build_maps().iteritems():
for target, sources in iteritems(get_build_maps()):
for f in sources:
if ':' in f: f, suffix = f.split(':')
if not os.path.exists(f) or os.path.isdir(f): continue


+ 4
- 2
frappe/client.py View File

@@ -8,6 +8,8 @@ import frappe.model
import frappe.utils
import json, os

from six import iteritems

'''
Handle RESTful requests that are mapped to the `/api/resource` route.

@@ -38,7 +40,7 @@ def get(doctype, name=None, filters=None):
if filters and not name:
name = frappe.db.get_value(doctype, json.loads(filters))
if not name:
raise Exception, "No document found for given filters"
frappe.throw(_("No document found for given filters"))

doc = frappe.get_doc(doctype, name)
if not doc.has_permission("read"):
@@ -228,7 +230,7 @@ def bulk_update(docs):
failed_docs = []
for doc in docs:
try:
ddoc = {key: val for key, val in doc.iteritems() if key not in ['doctype', 'docname']}
ddoc = {key: val for key, val in iteritems(doc) if key not in ['doctype', 'docname']}
doctype = doc['doctype']
docname = doc['docname']
doc = frappe.get_doc(doctype, docname)


+ 4
- 1
frappe/commands/__init__.py View File

@@ -29,7 +29,10 @@ def pass_context(f):
ps = pstats.Stats(pr, stream=s)\
.sort_stats('cumtime', 'tottime', 'ncalls')
ps.print_stats()
print(s.getvalue())

# print the top-100
for line in s.getvalue().splitlines()[:100]:
print(line)

return ret



+ 9
- 8
frappe/commands/site.py View File

@@ -2,6 +2,7 @@ from __future__ import unicode_literals, absolute_import, print_function
import click
import hashlib, os, sys
import frappe
from frappe import _
from _mysql_exceptions import ProgrammingError
from frappe.commands import pass_context, get_site
from frappe.commands.scheduler import _is_scheduler_enabled
@@ -45,7 +46,7 @@ def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=N
try:
# enable scheduler post install?
enable_scheduler = _is_scheduler_enabled()
except:
except Exception:
enable_scheduler = False

make_site_dirs()
@@ -122,11 +123,12 @@ def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_pas
@pass_context
def reinstall(context, admin_password=None, yes=False):
"Reinstall site ie. wipe all data and start over"
site = get_site(context)
_reinstall(site, admin_password, yes, verbose=context.verbose)

def _reinstall(site, admin_password=None, yes=False, verbose=False):
if not yes:
click.confirm('This will wipe your database. Are you sure you want to reinstall?', abort=True)

site = get_site(context)
try:
frappe.init(site=site)
frappe.connect()
@@ -141,7 +143,7 @@ def reinstall(context, admin_password=None, yes=False):
frappe.destroy()

frappe.init(site=site)
_new_site(frappe.conf.db_name, site, verbose=context.verbose, force=True, reinstall=True,
_new_site(frappe.conf.db_name, site, verbose=verbose, force=True, reinstall=True,
install_apps=installed, admin_password=admin_password)

@click.command('install-app')
@@ -373,9 +375,8 @@ def _drop_site(site, root_login='root', root_password=None, archived_sites_path=


def move(dest_dir, site):
import os
if not os.path.isdir(dest_dir):
raise Exception, "destination is not a directory or does not exist"
raise Exception("destination is not a directory or does not exist")

frappe.init(site)
old_path = frappe.utils.get_site_path()
@@ -447,7 +448,7 @@ def _set_limits(context, site, limits):
for limit, value in limits:
if limit not in ('emails', 'space', 'users', 'email_group',
'expiry', 'support_email', 'support_chat', 'upgrade_url'):
frappe.throw('Invalid limit {0}'.format(limit))
frappe.throw(_('Invalid limit {0}').format(limit))

if limit=='expiry' and value:
try:
@@ -495,7 +496,7 @@ def set_last_active_for_user(context, user=None):

from frappe.core.doctype.user.user import get_system_users
from frappe.utils.user import set_last_active_to_now
site = get_site(context)

with frappe.init_site(site):


+ 33
- 13
frappe/commands/utils.py View File

@@ -305,26 +305,45 @@ def console(context):
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, junit_xml_output=False):
"Run tests"
import frappe.test_runner
from frappe.utils import sel
tests = test

site = get_site(context)
frappe.init(site=site)

if frappe.conf.run_selenium_tests and False:
sel.start(context.verbose, driver)
ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests,
force=context.force, profile=profile, junit_xml_output=junit_xml_output)
if len(ret.failures) == 0 and len(ret.errors) == 0:
ret = 0

try:
ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests,
force=context.force, profile=profile, junit_xml_output=junit_xml_output)
if len(ret.failures) == 0 and len(ret.errors) == 0:
ret = 0
finally:
pass
if frappe.conf.run_selenium_tests:
sel.close()
if os.environ.get('CI'):
sys.exit(ret)

@click.command('run-ui-tests')
@click.option('--app', help="App to run tests on, leave blank for all apps")
@click.option('--ci', is_flag=True, default=False, help="Run in CI environment")
@pass_context
def run_ui_tests(context, app=None, ci=False):
"Run UI tests"
import subprocess

site = get_site(context)
frappe.init(site=site)

if app is None:
app = ",".join(frappe.get_installed_apps())

cmd = [
'./node_modules/.bin/nightwatch',
'--config', './apps/frappe/frappe/nightwatch.js',
'--app', app,
'--site', site
]

if ci:
cmd.extend(['--env', 'ci_server'])

sys.exit(ret)
bench_path = frappe.utils.get_bench_path()
subprocess.call(cmd, cwd=bench_path)

@click.command('serve')
@click.option('--port', default=8000)
@@ -459,6 +478,7 @@ commands = [
request,
reset_perms,
run_tests,
run_ui_tests,
serve,
set_config,
watch,


+ 7
- 0
frappe/config/desktop.py View File

@@ -64,4 +64,11 @@ def get_data():
"system_manager": 1,
"hidden": 1
},
{
"module_name": 'Contacts',
"type": 'module',
"icon": "octicon octicon-book",
"color": '#FFAEDB',
"hidden": 1,
},
]

+ 15
- 0
frappe/config/integrations.py View File

@@ -58,5 +58,20 @@ def get_data():
"description": _("Settings for OAuth Provider"),
},
]
},
{
"label": _("External Documents"),
"items": [
{
"type": "doctype",
"name": "GSuite Settings",
"description": _("Enter keys to enable integration with Google GSuite"),
},
{
"type": "doctype",
"name": "GSuite Templates",
"description": _("Google GSuite Templates to integration with DocTypes"),
},
]
}
]

+ 7
- 1
frappe/config/setup.py View File

@@ -128,6 +128,12 @@ def get_data():
"description": _("List of backups available for download"),
"icon": "fa fa-download"
},
{
"type": "doctype",
"name": "Deleted Document",
"label": _("Deleted Documents"),
"description": _("Restore or permanently delete a document.")
},
]
},
{
@@ -167,7 +173,7 @@ def get_data():
"items": [
{
"type": "page",
"label": "Print Format Builder",
"label": _("Print Format Builder"),
"name": "print-format-builder",
"description": _("Drag and Drop tool to build and customize Print Formats.")
},


frappe/email/doctype/contact/__init__.py → frappe/contacts/__init__.py View File


frappe/geo/address_and_contact.py → frappe/contacts/address_and_contact.py View File

@@ -6,7 +6,7 @@ import frappe

def load_address_and_contact(doc, key=None):
"""Loads address list and contact list in `__onload`"""
from frappe.geo.doctype.address.address import get_address_display
from frappe.contacts.doctype.address.address import get_address_display

filters = [
["Dynamic Link", "link_doctype", "=", doc.doctype],

frappe/geo/doctype/address/__init__.py → frappe/contacts/doctype/__init__.py View File


frappe/geo/doctype/address_template/__init__.py → frappe/contacts/doctype/address/__init__.py View File


frappe/geo/doctype/address/address.js → frappe/contacts/doctype/address/address.js View File

@@ -15,7 +15,7 @@ frappe.ui.form.on("Address", {
}
frm.set_query('link_doctype', "links", function() {
return {
query: "frappe.geo.address_and_contact.filter_dynamic_link_doctypes",
query: "frappe.contacts.address_and_contact.filter_dynamic_link_doctypes",
filters: {
fieldtype: "HTML",
fieldname: "address_html",

frappe/geo/doctype/address/address.json → frappe/contacts/doctype/address/address.json View File

@@ -569,10 +569,11 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-29 12:36:56.013624",
"modified": "2017-04-10 13:09:45.030542",
"modified_by": "Administrator",
"module": "Geo",
"module": "Contacts",
"name": "Address",
"name_case": "Title Case",
"owner": "Administrator",
"permissions": [
{

frappe/geo/doctype/address/address.py → frappe/contacts/doctype/address/address.py View File

@@ -13,6 +13,8 @@ from jinja2 import TemplateSyntaxError
from frappe.utils.user import is_website_user
from frappe.model.naming import make_autoname
from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links
from six import iteritems


class Address(Document):
def __setup__(self):
@@ -191,7 +193,7 @@ def address_query(doctype, txt, searchfield, start, page_len, filters):
link_name = filters.pop('link_name')

condition = ""
for fieldname, value in filters.iteritems():
for fieldname, value in iteritems(filters):
condition += " and {field}={value}".format(
field=fieldname,
value=value

+ 33
- 0
frappe/contacts/doctype/address/test_address.py View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import frappe, unittest
from frappe.contacts.doctype.address.address import get_address_display

class TestAddress(unittest.TestCase):
def test_template_works(self):
if not frappe.db.exists('Address Template', 'India'):
frappe.get_doc({
"doctype": "Address Template",
"country": 'India',
"is_default": 1
}).insert()

if not frappe.db.exists('Address', '_Test Address-Office'):
frappe.get_doc({
"address_line1": "_Test Address Line 1",
"address_title": "_Test Address",
"address_type": "Office",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000"
}).insert()

address = frappe.get_list("Address")[0].name
display = get_address_display(frappe.get_doc("Address", address).as_dict())
self.assertTrue(display)

frappe/geo/report/addresses_and_contacts/__init__.py → frappe/contacts/doctype/address_template/__init__.py View File


frappe/geo/doctype/address_template/address_template.js → frappe/contacts/doctype/address_template/address_template.js View File

@@ -6,7 +6,7 @@ frappe.ui.form.on('Address Template', {
if(frm.is_new() && !frm.doc.template) {
// set default template via js so that it is translated
frappe.call({
method: 'frappe.geo.doctype.address_template.address_template.get_default_address_template',
method: 'frappe.contacts.doctype.address_template.address_template.get_default_address_template',
callback: function(r) {
frm.set_value('template', r.message);
}

frappe/geo/doctype/address_template/address_template.json → frappe/contacts/doctype/address_template/address_template.json View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:country",
@@ -23,6 +24,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Country",
@@ -52,6 +54,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Is Default",
@@ -81,6 +84,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Template",
@@ -98,20 +102,20 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-map-marker",
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-01-13 05:11:37.499528",
"modified": "2017-04-10 13:09:53.761009",
"modified_by": "Administrator",
"module": "Geo",
"module": "Contacts",
"name": "Address Template",
"name_case": "",
"owner": "Administrator",
@@ -126,7 +130,6 @@
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 0,
"read": 1,
@@ -141,6 +144,7 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,

frappe/geo/doctype/address_template/address_template.py → frappe/contacts/doctype/address_template/address_template.py View File


+ 45
- 0
frappe/contacts/doctype/address_template/test_address_template.py View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import frappe, unittest

class TestAddressTemplate(unittest.TestCase):
def setUp(self):
self.make_default_address_template()

def test_default_is_unset(self):
a = frappe.get_doc("Address Template", "India")
a.is_default = 1
a.save()

b = frappe.get_doc("Address Template", "Brazil")
b.is_default = 1
b.save()

self.assertEqual(frappe.db.get_value("Address Template", "India", "is_default"), 0)

def tearDown(self):
a = frappe.get_doc("Address Template", "India")
a.is_default = 1
a.save()

@classmethod
def make_default_address_template(self):
template = """{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>{% if state %}{{ state }}<br>{% endif -%}{% if pincode %}{{ pincode }}<br>{% endif -%}{{ country }}<br>{% if phone %}Phone: {{ phone }}<br>{% endif -%}{% if fax %}Fax: {{ fax }}<br>{% endif -%}{% if email_id %}Email: {{ email_id }}<br>{% endif -%}"""

if not frappe.db.exists('Address Template', 'India'):
frappe.get_doc({
"doctype": "Address Template",
"country": 'India',
"is_default": 1,
"template": template
}).insert()

if not frappe.db.exists('Address Template', 'Brazil'):
frappe.get_doc({
"doctype": "Address Template",
"country": 'Brazil',
"template": template
}).insert()

+ 0
- 0
frappe/contacts/doctype/contact/__init__.py View File


frappe/email/doctype/contact/contact.js → frappe/contacts/doctype/contact/contact.js View File

@@ -31,7 +31,7 @@ frappe.ui.form.on("Contact", {
}
frm.set_query('link_doctype', "links", function() {
return {
query: "frappe.geo.address_and_contact.filter_dynamic_link_doctypes",
query: "frappe.contacts.address_and_contact.filter_dynamic_link_doctypes",
filters: {
fieldtype: "HTML",
fieldname: "contact_html",

frappe/email/doctype/contact/contact.json → frappe/contacts/doctype/contact/contact.json View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"beta": 0,
@@ -40,6 +41,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "salutation",
"fieldtype": "Link",
"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": "Salutation",
"length": 0,
"no_copy": 0,
"options": "Salutation",
"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,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -218,6 +249,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gender",
"fieldtype": "Link",
"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": "Gender",
"length": 0,
"no_copy": 0,
"options": "Gender",
"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,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 1,
@@ -542,6 +603,7 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-user",
@@ -549,15 +611,15 @@
"image_field": "image",
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-20 14:54:33.723052",
"modified": "2017-04-10 13:09:27.880530",
"modified_by": "Administrator",
"module": "Email",
"module": "Contacts",
"name": "Contact",
"name_case": "Title Case",
"owner": "Administrator",
"permissions": [
{

frappe/email/doctype/contact/contact.py → frappe/contacts/doctype/contact/contact.py View File

@@ -7,6 +7,8 @@ from frappe.utils import cstr, has_gravatar
from frappe import _
from frappe.model.document import Document
from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links
from six import iteritems


class Contact(Document):
def autoname(self):
@@ -118,7 +120,7 @@ def contact_query(doctype, txt, searchfield, start, page_len, filters):
link_name = filters.pop('link_name')

condition = ""
for fieldname, value in filters.iteritems():
for fieldname, value in iteritems(filters):
condition += " and {field}={value}".format(
field=fieldname,
value=value

frappe/email/doctype/contact/test_contact.py → frappe/contacts/doctype/contact/test_contact.py View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and Contributors
# Copyright (c) 2017, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals


frappe/email/doctype/contact/test_records.json → frappe/contacts/doctype/contact/test_records.json View File


+ 0
- 0
frappe/contacts/doctype/gender/__init__.py View File


+ 8
- 0
frappe/contacts/doctype/gender/gender.js View File

@@ -0,0 +1,8 @@
// Copyright (c) 2017, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Gender', {
refresh: function() {

}
});

+ 113
- 0
frappe/contacts/doctype/gender/gender.json View File

@@ -0,0 +1,113 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:gender",
"beta": 0,
"creation": "2017-04-10 12:11:36.526508",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gender",
"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": "Gender",
"length": 0,
"no_copy": 0,
"options": "",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-04-10 12:17:04.848338",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Gender",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "All",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

+ 9
- 0
frappe/contacts/doctype/gender/gender.py View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
from frappe.model.document import Document

class Gender(Document):
pass

+ 9
- 0
frappe/contacts/doctype/gender/test_gender.py View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import unittest

class TestGender(unittest.TestCase):
pass

+ 0
- 0
frappe/contacts/doctype/salutation/__init__.py View File


+ 8
- 0
frappe/contacts/doctype/salutation/salutation.js View File

@@ -0,0 +1,8 @@
// Copyright (c) 2017, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Salutation', {
refresh: function() {

}
});

+ 132
- 0
frappe/contacts/doctype/salutation/salutation.json View File

@@ -0,0 +1,132 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:salutation",
"beta": 0,
"creation": "2017-04-10 12:17:58.071915",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "salutation",
"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": "Salutation",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-04-10 12:55:18.855578",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Salutation",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "All",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

+ 9
- 0
frappe/contacts/doctype/salutation/salutation.py View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
from frappe.model.document import Document

class Salutation(Document):
pass

+ 9
- 0
frappe/contacts/doctype/salutation/test_salutation.py View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import unittest

class TestSalutation(unittest.TestCase):
pass

+ 0
- 0
frappe/contacts/report/__init__.py View File


+ 0
- 0
frappe/contacts/report/addresses_and_contacts/__init__.py View File


frappe/geo/report/addresses_and_contacts/addresses_and_contacts.js → frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.js View File


frappe/geo/report/addresses_and_contacts/addresses_and_contacts.json → frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.json View File

@@ -7,9 +7,9 @@
"doctype": "Report",
"idx": 2,
"is_standard": "Yes",
"modified": "2017-02-24 19:57:37.368498",
"modified": "2017-04-10 15:04:12.498920",
"modified_by": "Administrator",
"module": "Geo",
"module": "Contacts",
"name": "Addresses And Contacts",
"owner": "Administrator",
"ref_doctype": "Address",

frappe/geo/report/addresses_and_contacts/addresses_and_contacts.py → frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py View File


+ 15
- 15
frappe/core/doctype/communication/communication.js View File

@@ -33,7 +33,7 @@ frappe.ui.form.on("Communication", {

if(frm.doc.communication_type == "Feedback") {
frm.add_custom_button(__("Resend"), function() {
feedback = new frappe.utils.Feedback();
var feedback = new frappe.utils.Feedback();
feedback.resend_feedback_request(frm.doc);
});
}
@@ -111,7 +111,7 @@ frappe.ui.form.on("Communication", {
d.set_value("reference_doctype", frm.doc.reference_doctype);
d.set_value("reference_name", frm.doc.reference_name);
d.set_primary_action(__("Relink"), function () {
values = d.get_values();
var values = d.get_values();
if (values) {
frappe.confirm(
__('Are you sure you want to relink this communication to {0}?', [values["reference_name"]]),
@@ -130,7 +130,7 @@ frappe.ui.form.on("Communication", {
});
},
function () {
show_alert('Document not Relinked')
frappe.show_alert('Document not Relinked')
}
);
}
@@ -139,8 +139,8 @@ frappe.ui.form.on("Communication", {
},

mark_as_read_unread: function(frm) {
action = frm.doc.seen? "Unread": "Read";
flag = "(\\SEEN)";
var action = frm.doc.seen? "Unread": "Read";
var flag = "(\\SEEN)";

return frappe.call({
method: "frappe.email.inbox.create_email_flag_queue",
@@ -154,7 +154,7 @@ frappe.ui.form.on("Communication", {
},

reply: function(frm) {
args = frm.events.get_mail_args(frm);
var args = frm.events.get_mail_args(frm);
$.extend(args, {
subject: __("Re: {0}", [frm.doc.subject]),
recipients: frm.doc.sender
@@ -164,7 +164,7 @@ frappe.ui.form.on("Communication", {
},

reply_all: function(frm) {
args = frm.events.get_mail_args(frm)
var args = frm.events.get_mail_args(frm)
$.extend(args, {
subject: __("Re: {0}", [frm.doc.subject]),
recipients: frm.doc.sender,
@@ -174,7 +174,7 @@ frappe.ui.form.on("Communication", {
},

forward_mail: function(frm) {
args = frm.events.get_mail_args(frm)
var args = frm.events.get_mail_args(frm)
$.extend(args, {
forward: true,
subject: __("Fw: {0}", [frm.doc.subject]),
@@ -184,7 +184,7 @@ frappe.ui.form.on("Communication", {
},

get_mail_args: function(frm) {
sender_email_id = ""
var sender_email_id = ""
$.each(frappe.boot.email_accounts, function(idx, account) {
if(account.email_account == frm.doc.email_account) {
sender_email_id = account.email_id
@@ -202,11 +202,11 @@ frappe.ui.form.on("Communication", {

add_to_contact: function(frm) {
var me = this;
fullname = frm.doc.sender_full_name || ""
var fullname = frm.doc.sender_full_name || ""

names = fullname.split(" ")
first_name = names[0]
last_name = names.length >= 2? names[names.length - 1]: ""
var names = fullname.split(" ")
var first_name = names[0]
var last_name = names.length >= 2? names[names.length - 1]: ""

frappe.route_options = {
"email_id": frm.doc.sender,
@@ -225,7 +225,7 @@ frappe.ui.form.on("Communication", {
},
freeze: true,
callback: function(r) {
frappe.msgprint("Email has been marked as spam")
frappe.msgprint(__("Email has been marked as spam"))
}
})
},
@@ -238,7 +238,7 @@ frappe.ui.form.on("Communication", {
},
freeze: true,
callback: function(r) {
frappe.msgprint("Email has been moved to trash")
frappe.msgprint(__("Email has been moved to trash"))
}
})
}


+ 1
- 1
frappe/core/doctype/communication/communication_list.js View File

@@ -9,7 +9,7 @@ frappe.listview_settings['Communication'] = {
filters: [["status", "=", "Open"]],

onload: function(list_view) {
method = "frappe.email.inbox.create_email_flag_queue"
var method = "frappe.email.inbox.create_email_flag_queue"

list_view.page.add_menu_item(__("Mark as Read"), function() {
list_view.call_for_selected_items(method, { action: "Read" })


+ 28
- 13
frappe/core/doctype/communication/test_communication.py View File

@@ -9,21 +9,36 @@ test_records = frappe.get_test_records('Communication')

class TestCommunication(unittest.TestCase):

def test_parse_addr(self):
valid_email_list = ["me@example.com", "a.nonymous@example.com", "name@tag@example.com",
"foo@example.com", 'Full Name <full@example.com>',
'"Full Name with quotes and <weird@chars.com>" <weird@example.com>',
'foo@bar@google.com', 'Surname, Name <name.surname@domain.com>',
'Purchase@ABC <purchase@abc.com>', 'xyz@abc2.com <xyz@abc.com>',
'Name [something else] <name@domain.com>',
'.com@test@yahoo.com']

invalid_email_list = ['[invalid!email]', 'invalid-email',
'tes2', 'e', 'rrrrrrrr', 'manas','[[[sample]]]',
'[invalid!email].com']
def test_email(self):
valid_email_list = ["Full Name <full@example.com>",
'"Full Name with quotes and <weird@chars.com>" <weird@example.com>',
"Surname, Name <name.surname@domain.com>",
"Purchase@ABC <purchase@abc.com>", "xyz@abc2.com <xyz@abc.com>",
"Name [something else] <name@domain.com>"]

invalid_email_list = ["[invalid!email]", "invalid-email",
"tes2", "e", "rrrrrrrr", "manas","[[[sample]]]",
"[invalid!email].com"]

for x in valid_email_list:
self.assertTrue(frappe.utils.parse_addr(x)[1])

for x in invalid_email_list:
self.assertFalse(frappe.utils.parse_addr(x)[0])

def test_name(self):
valid_email_list = ["Full Name <full@example.com>",
'"Full Name with quotes and <weird@chars.com>" <weird@example.com>',
"Surname, Name <name.surname@domain.com>",
"Purchase@ABC <purchase@abc.com>", "xyz@abc2.com <xyz@abc.com>",
"Name [something else] <name@domain.com>"]

invalid_email_list = ["[invalid!email]", "invalid-email",
"tes2", "e", "rrrrrrrr", "manas","[[[sample]]]",
"[invalid!email].com"]

for x in valid_email_list:
self.assertTrue(frappe.utils.parse_addr(x))
self.assertTrue(frappe.utils.parse_addr(x)[0])

for x in invalid_email_list:
self.assertFalse(frappe.utils.parse_addr(x)[0])


+ 1
- 1
frappe/core/doctype/deleted_document/deleted_document.py View File

@@ -25,4 +25,4 @@ def restore(name):
deleted.restored = 1
deleted.db_update()

frappe.msgprint('Document Restored')
frappe.msgprint(_('Document Restored'))

+ 1
- 0
frappe/core/doctype/doctype/boilerplate/controller_list.js View File

@@ -1,3 +1,4 @@
/* eslint-disable */
frappe.listview_settings['{doctype}'] = {{
add_fields: ["status"],
filters:[["status","=", "Open"]]


+ 1
- 1
frappe/core/doctype/doctype/doctype.js View File

@@ -13,7 +13,7 @@

frappe.ui.form.on('DocType', {
refresh: function(frm) {
if(frm.is_new() && (user !== "Administrator" || !frappe.boot.developer_mode)) {
if(frm.is_new() && (frappe.session.user !== "Administrator" || !frappe.boot.developer_mode)) {
frm.set_value("custom", 1);
frm.toggle_enable("custom", 0);
}


+ 90
- 3
frappe/core/doctype/doctype/doctype.json View File

@@ -15,6 +15,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -44,6 +45,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -75,6 +77,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -106,6 +109,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -138,6 +142,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -169,6 +174,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -196,6 +202,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -227,6 +234,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -258,6 +266,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -286,6 +295,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -315,6 +325,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -346,6 +357,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -374,6 +386,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -403,6 +416,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -434,6 +448,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -462,6 +477,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -493,6 +509,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -524,6 +541,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -552,6 +570,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -582,6 +601,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -611,6 +631,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -641,6 +662,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -672,6 +694,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -702,6 +725,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -733,6 +757,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -761,6 +786,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -793,6 +819,38 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "restrict_to_domain",
"fieldtype": "Link",
"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": "Restrict To Domain",
"length": 0,
"no_copy": 0,
"options": "Domain",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -821,6 +879,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -850,6 +909,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -880,6 +940,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -910,6 +971,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -940,6 +1002,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -970,6 +1033,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -999,6 +1063,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1028,6 +1093,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1060,6 +1126,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1088,6 +1155,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1116,6 +1184,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1144,6 +1213,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1173,6 +1243,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1203,6 +1274,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1231,6 +1303,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1261,6 +1334,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1289,6 +1363,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1318,6 +1393,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1349,6 +1425,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1380,6 +1457,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1408,6 +1486,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1438,6 +1517,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1468,6 +1548,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1497,6 +1578,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1527,6 +1609,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1558,6 +1641,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1586,6 +1670,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1616,6 +1701,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1647,6 +1733,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1676,6 +1763,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1715,13 +1803,12 @@
"idx": 6,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-03 15:55:30.792653",
"modified_by": "Administrator",
"modified": "2017-05-03 16:15:40.198072",
"modified_by": "makarand@erpnext.com",
"module": "Core",
"name": "DocType",
"owner": "Administrator",


+ 17
- 1
frappe/core/doctype/doctype/doctype.py View File

@@ -35,6 +35,7 @@ class DocType(Document):
- Check fieldnames (duplication etc)
- Clear permission table for child tables
- Add `amended_from` and `amended_by` if Amendable"""

self.check_developer_mode()

self.validate_name()
@@ -49,6 +50,7 @@ class DocType(Document):
self.permissions = []

self.scrub_field_names()
self.set_default_in_list_view()
self.validate_series()
self.validate_document_type()
validate_fields(self)
@@ -71,6 +73,16 @@ class DocType(Document):
if self.default_print_format and not self.custom:
frappe.throw(_('Standard DocType cannot have default print format, use Customize Form'))

def set_default_in_list_view(self):
'''Set default in-list-view for first 4 mandatory fields'''
if not [d.fieldname for d in self.fields if d.in_list_view]:
cnt = 0
for d in self.fields:
if d.reqd and not d.hidden:
d.in_list_view = 1
cnt += 1
if cnt == 4: break

def check_developer_mode(self):
"""Throw exception if not developer mode or via patch"""
if frappe.flags.in_patch or frappe.flags.in_test:
@@ -215,6 +227,10 @@ class DocType(Document):
if not frappe.flags.in_install and hasattr(self, 'before_update'):
self.sync_global_search()

# clear from local cache
if self.name in frappe.local.meta_cache:
del frappe.local.meta_cache[self.name]

def sync_global_search(self):
'''If global search settings are changed, rebuild search properties for this table'''
global_search_fields_before_update = [d.fieldname for d in
@@ -419,7 +435,7 @@ def validate_fields(meta):
def check_in_list_view(d):
if d.in_list_view and (d.fieldtype in not_allowed_in_list_view):
frappe.throw(_("'In List View' not allowed for type {0} in row {1}").format(d.fieldtype, d.idx))
def check_in_global_search(d):
if d.in_global_search and d.fieldtype in no_value_fields:
frappe.throw(_("'In Global Search' not allowed for type {0} in row {1}")


+ 1
- 1
frappe/core/doctype/doctype/test_doctype.py View File

@@ -28,4 +28,4 @@ class TestDocType(unittest.TestCase):
frappe.delete_doc("DocType", name)

doc = self.new_doctype(name).insert()
doc.delete()
doc.delete()

+ 0
- 0
frappe/core/doctype/domain/__init__.py View File


+ 8
- 0
frappe/core/doctype/domain/domain.js View File

@@ -0,0 +1,8 @@
// Copyright (c) 2017, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Domain', {
refresh: function(frm) {

}
});

+ 95
- 0
frappe/core/doctype/domain/domain.json View File

@@ -0,0 +1,95 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:domain",
"beta": 0,
"creation": "2017-05-03 15:07:39.752820",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "domain",
"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": "Domain",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-16 13:03:25.430679",
"modified_by": "Administrator",
"module": "Core",
"name": "Domain",
"name_case": "",
"owner": "makarand@erpnext.com",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 0
}
],
"quick_entry": 1,
"read_only": 1,
"read_only_onload": 0,
"search_fields": "domain",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "domain",
"track_changes": 0,
"track_seen": 0
}

+ 10
- 0
frappe/core/doctype/domain/domain.py View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document

class Domain(Document):
pass

+ 10
- 0
frappe/core/doctype/domain/test_domain.py View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import frappe
import unittest

class TestDomain(unittest.TestCase):
pass

+ 0
- 0
frappe/core/doctype/domain_settings/__init__.py View File


+ 57
- 0
frappe/core/doctype/domain_settings/domain_settings.js View File

@@ -0,0 +1,57 @@
// Copyright (c) 2017, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Domain Settings', {
onload: function(frm) {
let domains = $('<div class="domain-editor">')
.appendTo(frm.fields_dict.domains_html.wrapper);

if(!frm.domain_editor) {
frm.domain_editor = new frappe.DomainsEditor(domains, frm);
}

frm.domain_editor.show();
},

validate: function(frm) {
if(frm.domain_editor) {
frm.domain_editor.set_items_in_table();
}
},
});

frappe.DomainsEditor = frappe.CheckboxEditor.extend({
init: function(wrapper, frm) {
var opts = {};
$.extend(opts, {
wrapper: wrapper,
frm: frm,
field_mapper: {
child_table_field: "active_domains",
item_field: "domain",
cdt: "Has Domain"
},
attribute: 'data-domain',
checkbox_selector: false,
get_items: this.get_all_domains,
editor_template: this.get_template()
});

this._super(opts);
},

get_template: function() {
return `
<div class="user-role" data-domain="{{item}}">
<input type="checkbox" style="margin-top:0px;">
{{__(item)}}
</div>
`;
},

get_all_domains: function() {
// return all the domains available in the system
this.items = frappe.boot.all_domains;
this.render_items();
},
});

+ 153
- 0
frappe/core/doctype/domain_settings/domain_settings.json View File

@@ -0,0 +1,153 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-05-03 16:28:11.295095",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "domains",
"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": "Domains",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "domains_html",
"fieldtype": "HTML",
"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": "Domains",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "active_domains",
"fieldtype": "Table",
"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": "Active Domains",
"length": 0,
"no_copy": 0,
"options": "Has Domain",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-05-12 17:01:18.615000",
"modified_by": "Administrator",
"module": "Core",
"name": "Domain Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

+ 12
- 0
frappe/core/doctype/domain_settings/domain_settings.py View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document

class DomainSettings(Document):
def on_update(self):
cache = frappe.cache()
cache.delete_key("domains", "active_domains")

+ 2
- 2
frappe/core/doctype/error_log/error_log_list.js View File

@@ -1,9 +1,9 @@
frappe.listview_settings['Error Log'] = {
add_fields: ["seen"],
get_indicator: function(doc) {
if(cint(doc.seen)) {
if(cint(doc.seen)) {
return [__("Seen"), "green", "seen,=,1"];
} else {
} else {
return [__("Not Seen"), "red", "seen,=,0"];
}
},


+ 2
- 2
frappe/core/doctype/error_snapshot/error_snapshot.js View File

@@ -1,9 +1,9 @@
frappe.ui.form.on("Error Snapshot", "load", function(frm){
frm.set_read_only(true);
frm.set_read_only(true);
});

frappe.ui.form.on("Error Snapshot", "refresh", function(frm){
frm.set_df_property("view", "options", frappe.render_template("error_snapshot", {"doc": frm.doc}));
frm.set_df_property("view", "options", frappe.render_template("error_snapshot", {"doc": frm.doc}));

if (frm.doc.relapses) {
frm.add_custom_button(__('Show Relapses'), function() {


+ 12
- 12
frappe/core/doctype/error_snapshot/error_snapshot_list.js View File

@@ -1,14 +1,14 @@
frappe.listview_settings["Error Snapshot"] = {
add_fields: ["parent_error_snapshot", "relapses", "seen"],
filters:[
["parent_error_snapshot","=",null],
["seen", "=", false]
],
get_indicator: function(doc){
if (doc.parent_error_snapshot && doc.parent_error_snapshot.length){
return [__("Relapsed"), !doc.seen ? "orange" : "blue", "parent_error_snapshot,!=,"];
} else {
return [__("First Level"), !doc.seen ? "red" : "green", "parent_error_snapshot,=,"];
}
}
add_fields: ["parent_error_snapshot", "relapses", "seen"],
filters:[
["parent_error_snapshot","=",null],
["seen", "=", false]
],
get_indicator: function(doc){
if (doc.parent_error_snapshot && doc.parent_error_snapshot.length){
return [__("Relapsed"), !doc.seen ? "orange" : "blue", "parent_error_snapshot,!=,"];
} else {
return [__("First Level"), !doc.seen ? "red" : "green", "parent_error_snapshot,=,"];
}
}
}

+ 1
- 1
frappe/core/doctype/feedback_request/feedback_request.js View File

@@ -3,7 +3,7 @@

frappe.ui.form.on('Feedback Request', {
refresh: function(frm) {
rating_icons = frappe.render_template("rating_icons", {rating: frm.doc.rating, show_label: false});
var rating_icons = frappe.render_template("rating_icons", {rating: frm.doc.rating, show_label: false});
$(frm.fields_dict.feedback_rating.wrapper).html(rating_icons);

if(frm.doc.reference_doctype && frm.doc.reference_name) {


+ 2
- 2
frappe/core/doctype/feedback_request/feedback_request_list.js View File

@@ -4,13 +4,13 @@ frappe.listview_settings['Feedback Request'] = {
},
column_render: {
rating: function(doc) {
html = ""
var html = ""
for (var i = 0; i < 5; i++) {
html += repl("<span class='indicator %(color)s'></span>",
{color: i<doc.rating? "blue": "darkgrey"})
}

return html
return html;
}
}
}

+ 1
- 1
frappe/core/doctype/feedback_trigger/feedback_trigger.js View File

@@ -37,7 +37,7 @@ frappe.ui.form.on('Feedback Trigger', {
frappe.model.with_doctype(frm.doc.document_type, function() {
var fields = frappe.get_doc("DocType", frm.doc.document_type).fields;
$.each(fields, function(idx, field) {
if(!inList(frappe.model.no_value_type, field.fieldtype) && field.options == "Email") {
if(!in_list(frappe.model.no_value_type, field.fieldtype) && field.options == "Email") {
frm.options.push(field.label);
frm.fieldname_mapper[field.label] = field.fieldname;
}


+ 20
- 4
frappe/core/doctype/feedback_trigger/feedback_trigger.json View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:document_type",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -70,6 +73,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -100,6 +104,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -130,6 +135,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -159,6 +165,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -187,6 +194,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -217,6 +225,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -245,6 +254,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -276,6 +286,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -306,6 +317,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -334,6 +346,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -363,6 +376,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -392,6 +406,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -415,12 +430,13 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -451,17 +467,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 05:19:08.819230",
"modified": "2017-05-29 16:36:04.178592",
"modified_by": "Administrator",
"module": "Core",
"name": "Feedback Trigger",
@@ -498,4 +514,4 @@
"title_field": "document_type",
"track_changes": 1,
"track_seen": 0
}
}

+ 1
- 1
frappe/core/doctype/feedback_trigger/feedback_trigger.py View File

@@ -129,7 +129,7 @@ def get_feedback_request_details(reference_doctype, reference_name, trigger="Man
"message": feedback_request_message,
}
else:
frappe.msgprint("Feedback conditions do not match")
frappe.msgprint(_("Feedback conditions do not match"))
return None

def get_feedback_request_url(reference_doctype, reference_name, recipients, trigger="Manual"):


+ 6
- 9
frappe/core/doctype/file/file.py View File

@@ -184,21 +184,18 @@ class File(NestedSet):
except (requests.exceptions.HTTPError, requests.exceptions.SSLError, IOError):
return

thumbnail = ImageOps.fit(
image,
(300, 300),
Image.ANTIALIAS
)
size = 300, 300
image.thumbnail(size)

thumbnail_url = filename + "_small." + extn

path = os.path.abspath(frappe.get_site_path("public", thumbnail_url.lstrip("/")))

try:
thumbnail.save(path)
image.save(path)
self.db_set("thumbnail_url", thumbnail_url)
except IOError:
frappe.msgprint("Unable to write file format for {0}".format(path))
frappe.msgprint(_("Unable to write file format for {0}").format(path))
return

return thumbnail_url
@@ -343,7 +340,7 @@ def get_local_image(file_url):
try:
image = Image.open(file_path)
except IOError:
frappe.msgprint("Unable to read file format for {0}".format(file_url))
frappe.msgprint(_("Unable to read file format for {0}").format(file_url))
raise

content = None
@@ -372,7 +369,7 @@ def get_web_image(file_url):
if "404" in e.args[0]:
frappe.msgprint(_("File '{0}' not found").format(file_url))
else:
frappe.msgprint("Unable to read file format for {0}".format(file_url))
frappe.msgprint(_("Unable to read file format for {0}").format(file_url))
raise

image = Image.open(StringIO.StringIO(r.content))


+ 12
- 12
frappe/core/doctype/file/file_list.js View File

@@ -42,12 +42,12 @@ frappe.listview_settings['File'] = {
doclist.list_renderer.settings.setup_dragdrop(doclist);

doclist.$page.on("click", ".list-row-checkbox", function(event) {
doclist.list_renderer.settings.add_menu_item_copy(doclist);
doclist.list_renderer.settings.add_menu_item_copy(doclist);
})
},
list_view_doc:function(doclist){
$(doclist.wrapper).on("click", 'button[list_view_doc="'+doclist.doctype+'"]', function(){
dialog = frappe.ui.get_upload_dialog({
$(doclist.wrapper).on("click", 'button[list_view_doc="'+doclist.doctype+'"]', function() {
frappe.ui.get_upload_dialog({
"args": {
"folder": doclist.current_folder,
"from_form": 1
@@ -62,7 +62,7 @@ frappe.listview_settings['File'] = {
doclist.page.add_menu_item(__("New Folder"), function() {
var d = frappe.prompt(__("Name"), function(values) {
if((values.value.indexOf("/") > -1)){
frappe.throw("Folder name should not include / !!!");
frappe.throw(__("Folder name should not include '/' (slash)"));
return;
}
var data = {
@@ -83,7 +83,7 @@ frappe.listview_settings['File'] = {

doclist.page.add_menu_item(__("Import .zip"), function() {
// make upload dialog
dialog = frappe.ui.get_upload_dialog({
frappe.ui.get_upload_dialog({
args: {
folder: doclist.current_folder,
from_form: 1
@@ -98,7 +98,7 @@ frappe.listview_settings['File'] = {
if(!r.exc) {
//doclist.refresh();
} else {
frappe.msgprint(__("Error in uploading files." + r.exc));
frappe.msgprint(__("Error in uploading files" + r.exc));
}
}
});
@@ -132,7 +132,7 @@ frappe.listview_settings['File'] = {
doclist.list_renderer.settings.add_menu_item_paste(doclist);
}
else{
frappe.throw("Please select file to copy");
frappe.throw(__("Please select file to copy"));
}
})
doclist.copy = true;
@@ -153,8 +153,8 @@ frappe.listview_settings['File'] = {
doclist.selected_files = [];
$(paste_menu).remove();
}
})
})
});
});
},
before_run: function(doclist) {
var name_filter = doclist.filter_list.get_filter("file_name");
@@ -197,7 +197,7 @@ frappe.listview_settings['File'] = {
set_primary_action:function(doclist){
doclist.page.clear_primary_action();
doclist.page.set_primary_action(__("New"), function() {
dialog = frappe.ui.get_upload_dialog({
frappe.ui.get_upload_dialog({
"args": {
"folder": doclist.current_folder,
"from_form": 1
@@ -235,5 +235,5 @@ frappe.listview_settings['File'] = {
.appendTo(doclist.breadcrumb);
}
});
}
}
};
};

+ 0
- 0
frappe/core/doctype/has_domain/__init__.py View File


+ 72
- 0
frappe/core/doctype/has_domain/has_domain.json View File

@@ -0,0 +1,72 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-05-03 15:20:22.326623",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "domain",
"fieldtype": "Link",
"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": "Domain",
"length": 0,
"no_copy": 0,
"options": "Domain",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-05-04 11:05:54.750351",
"modified_by": "Administrator",
"module": "Core",
"name": "Has Domain",
"name_case": "",
"owner": "makarand@erpnext.com",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

+ 10
- 0
frappe/core/doctype/has_domain/has_domain.py View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document

class HasDomain(Document):
pass

+ 6
- 3
frappe/core/doctype/module_def/module_def.json View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
"autoname": "field:module_name",
@@ -12,6 +13,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -36,12 +38,13 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -70,18 +73,18 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-sitemap",
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 16:41:14.342061",
"modified": "2017-06-20 14:35:17.407968",
"modified_by": "Administrator",
"module": "Core",
"name": "Module Def",


+ 42
- 1
frappe/core/doctype/page/page.json View File

@@ -14,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +74,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -102,6 +105,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -130,6 +134,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -158,6 +163,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -185,6 +191,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -216,6 +223,38 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "restrict_to_domain",
"fieldtype": "Link",
"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": "Restrict To Domain",
"length": 0,
"no_copy": 0,
"options": "Domain",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -247,6 +286,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -274,6 +314,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -317,7 +358,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-04-12 16:39:15.179130",
"modified": "2017-05-03 17:24:10.162110",
"modified_by": "Administrator",
"module": "Core",
"name": "Page",


+ 1
- 0
frappe/core/doctype/report/boilerplate/controller.js View File

@@ -1,5 +1,6 @@
// Copyright (c) 2016, {app_publisher} and contributors
// For license information, please see license.txt
/* eslint-disable */

frappe.query_reports["{name}"] = {{
"filters": [


+ 3
- 1
frappe/core/doctype/report/report.py View File

@@ -12,6 +12,8 @@ from frappe.modules.export_file import export_to_files
from frappe.modules import make_boilerplate
from frappe.core.doctype.page.page import delete_custom_role
from frappe.core.doctype.custom_role.custom_role import get_custom_allowed_roles
from six import iteritems


class Report(Document):
def validate(self):
@@ -123,7 +125,7 @@ class Report(Document):
_filters = params.get('filters') or []

if filters:
for key, value in filters.iteritems():
for key, value in iteritems(filters):
condition, _value = '=', value
if isinstance(value, (list, tuple)):
condition, _value = value


+ 36
- 1
frappe/core/doctype/role/role.json View File

@@ -9,9 +9,11 @@
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +75,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -100,6 +104,37 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "restrict_to_domain",
"fieldtype": "Link",
"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": "Restrict To Domain",
"length": 0,
"no_copy": 0,
"options": "Domain",
"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,
"unique": 0
}
],
"has_web_view": 0,
@@ -113,7 +148,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-04-18 01:50:32.995937",
"modified": "2017-05-04 11:03:41.533058",
"modified_by": "Administrator",
"module": "Core",
"name": "Role",


+ 2
- 2
frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.js View File

@@ -39,8 +39,8 @@ frappe.ui.form.on('Role Permission for Page and Report', {
},

clear_fields: function(frm) {
field = (frm.doc.set_role_for == 'Report') ? 'page' : 'report';
frm.set_value(field, '')
var field = (frm.doc.set_role_for == 'Report') ? 'page' : 'report';
frm.set_value(field, '');
},

page: function(frm) {


+ 6
- 6
frappe/core/doctype/system_settings/system_settings.js View File

@@ -7,16 +7,16 @@ frappe.ui.form.on("System Settings", "refresh", function(frm) {

$.each(data.message.defaults, function(key, val) {
frm.set_value(key, val);
sys_defaults[key] = val;
frappe.sys_defaults[key] = val;
})
}
});
});

frappe.ui.form.on("System Settings", "enable_password_policy", function(frm) {
if(frm.doc.enable_password_policy == 0){
frm.set_value("minimum_password_score", "");
}else{
frm.set_value("minimum_password_score", "2");
}
if(frm.doc.enable_password_policy == 0){
frm.set_value("minimum_password_score", "");
} else {
frm.set_value("minimum_password_score", "2");
}
});

+ 34
- 2
frappe/core/doctype/system_settings/system_settings.json View File

@@ -801,6 +801,38 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"description": "",
"fieldname": "allow_error_traceback",
"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": "Show Full Error and Allow Reporting of Issues to the Developer",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -933,7 +965,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-05-23 09:12:50.353877",
"modified": "2017-06-12 13:05:28.924098",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",
@@ -968,4 +1000,4 @@
"sort_order": "ASC",
"track_changes": 1,
"track_seen": 0
}
}

+ 11
- 11
frappe/core/doctype/user/user.js View File

@@ -18,7 +18,7 @@ frappe.ui.form.on('User', {

},
onload: function(frm) {
if(has_common(roles, ["Administrator", "System Manager"]) && !frm.doc.__islocal) {
if(has_common(frappe.user_roles, ["Administrator", "System Manager"]) && !frm.doc.__islocal) {
if(!frm.roles_editor) {
var role_area = $('<div style="min-height: 300px">')
.appendTo(frm.fields_dict.roles_html.wrapper);
@@ -35,11 +35,11 @@ frappe.ui.form.on('User', {
refresh: function(frm) {
var doc = frm.doc;

if(doc.name===user && !doc.__unsaved
if(doc.name===frappe.session.user && !doc.__unsaved
&& frappe.all_timezones
&& (doc.language || frappe.boot.user.language)
&& doc.language !== frappe.boot.user.language) {
msgprint(__("Refreshing..."));
frappe.msgprint(__("Refreshing..."));
window.location.reload();
}

@@ -53,7 +53,7 @@ frappe.ui.form.on('User', {
frappe.set_route("modules_setup");
}, null, "btn-default")

if(has_common(roles, ["Administrator", "System Manager"])) {
if(has_common(frappe.user_roles, ["Administrator", "System Manager"])) {

frm.add_custom_button(__("Set User Permissions"), function() {
frappe.route_options = {
@@ -79,10 +79,10 @@ frappe.ui.form.on('User', {
frm.roles_editor && frm.roles_editor.show();
frm.module_editor && frm.module_editor.refresh();

if(user==doc.name) {
if(frappe.session.user==doc.name) {
// update display settings
if(doc.user_image) {
frappe.boot.user_info[user].image = frappe.utils.get_file_link(doc.user_image);
frappe.boot.user_info[frappe.session.user].image = frappe.utils.get_file_link(doc.user_image);
}
}
}
@@ -102,11 +102,10 @@ frappe.ui.form.on('User', {

if (frappe.route_flags.unsaved===1){
delete frappe.route_flags.unsaved;
for ( var i=0;i<frm.doc.user_emails.length;i++){
for ( var i=0;i<frm.doc.user_emails.length;i++) {
frm.doc.user_emails[i].idx=frm.doc.user_emails[i].idx+1;
}
frm.doc.email_account
cur_frm.dirty();
cur_frm.dirty();
}
},
validate: function(frm) {
@@ -116,12 +115,12 @@ frappe.ui.form.on('User', {
},
enabled: function(frm) {
var doc = frm.doc;
if(!doc.__islocal && has_common(roles, ["Administrator", "System Manager"])) {
if(!doc.__islocal && has_common(frappe.user_roles, ["Administrator", "System Manager"])) {
frm.toggle_display(['sb1', 'sb3', 'modules_access'], doc.enabled);
frm.set_df_property('enabled', 'read_only', 0);
}

if(user!="Administrator") {
if(frappe.session.user!=="Administrator") {
frm.toggle_enable('email', doc.__islocal);
}
},
@@ -177,6 +176,7 @@ frappe.ModuleEditor = Class.extend({
});
},
bind: function() {
var me = this;
this.wrapper.on("change", ".block-module-check", function() {
var module = $(this).attr('data-module');
if($(this).prop("checked")) {


+ 30
- 19
frappe/core/doctype/user/user.py View File

@@ -59,7 +59,6 @@ class User(Document):
self.set_system_user()
self.set_full_name()
self.check_enable_disable()
self.update_gravatar()
self.ensure_unique_roles()
self.remove_all_roles_for_guest()
self.validate_username()
@@ -80,6 +79,8 @@ class User(Document):
clear_notifications(user=self.name)
frappe.clear_cache(user=self.name)
self.send_password_notification(self.__new_password)
if self.name not in ('Administrator', 'Guest') and not self.user_image:
frappe.enqueue('frappe.core.doctype.user.user.update_gravatar', name=self.name)

def has_website_permission(self, ptype, verbose=False):
"""Returns true if current user is the session user"""
@@ -87,7 +88,7 @@ class User(Document):

def check_demo(self):
if frappe.session.user == 'demo@erpnext.com':
frappe.throw('Cannot change user details in demo. Please signup for a new account at https://erpnext.com', title='Not Allowed')
frappe.throw(_('Cannot change user details in demo. Please signup for a new account at https://erpnext.com'), title=_('Not Allowed'))

def set_full_name(self):
self.full_name = " ".join(filter(None, [self.first_name, self.last_name]))
@@ -193,11 +194,6 @@ class User(Document):
print frappe.get_traceback()
pass # email server not set, don't send email


def update_gravatar(self):
if not self.user_image:
self.user_image = has_gravatar(self.name)

@Document.hook
def validate_reset_password(self):
pass
@@ -239,10 +235,16 @@ class User(Document):
from frappe.utils import get_url

link = self.reset_password()
app_title = None

method = frappe.get_hooks('get_site_info')
if method:
get_site_info = frappe.get_attr(method[0])
site_info = get_site_info({})
app_title = site_info.get('company', None)

app_title = [t for t in frappe.get_hooks('app_title') if t != 'Frappe Framework']
if app_title:
subject = _("Welcome to {0}").format(app_title[0])
subject = _("Welcome to {0}").format(app_title)
else:
subject = _("Complete Registration")

@@ -405,11 +407,6 @@ class User(Document):

self.username = ""

# should be made up of characters, numbers and underscore only
if self.username and not re.match(r"^[\w]+$", self.username):
frappe.msgprint(_("Username should not contain any special characters other than letters, numbers and underscore"))
self.username = ""

def password_strength_test(self):
""" test password strength """
if self.__new_password:
@@ -491,8 +488,17 @@ def get_timezones():
@frappe.whitelist()
def get_all_roles(arg=None):
"""return all roles"""
return [r[0] for r in frappe.db.sql("""select name from tabRole
where name not in ('Administrator', 'Guest', 'All') and not disabled order by name""")]
active_domains = frappe.get_active_domains()

roles = frappe.get_all("Role", filters={
"name": ("not in", "Administrator,Guest,All"),
"disabled": 0
}, or_filters={
"ifnull(restrict_to_domain, '')": "",
"restrict_to_domain": ("in", active_domains)
}, order_by="name")

return [ role.get("name") for role in roles ]

@frappe.whitelist()
def get_roles(arg=None):
@@ -620,16 +626,16 @@ def setup_user_email_inbox(email_account, awaiting_password, email_id, enable_ou
return

for user in user_names:
user = user.get("name")
user_name = user.get("name")

# check if inbox is alreay configured
user_inbox = frappe.db.get_value("User Email", {
"email_account": email_account,
"parent": user
"parent": user_name
}, ["name"]) or None

if not user_inbox:
add_user_email(user)
add_user_email(user_name)
else:
# update awaiting password for email account
udpate_user_email_settings = True
@@ -882,3 +888,8 @@ def handle_password_test_fail(result):
warning = result['feedback']['warning'] if 'warning' in result['feedback'] else ''
suggestions += "<br>" + _("Hint: Include symbols, numbers and capital letters in the password") + '<br>'
frappe.throw(_('Invalid Password: ' + ' '.join([warning, suggestions])))

def update_gravatar(name):
gravatar = has_gravatar(name)
if gravatar:
frappe.db.set_value('User', name, 'user_image', gravatar)

+ 3
- 3
frappe/core/page/data_import_tool/data_import_tool.js View File

@@ -22,7 +22,7 @@ frappe.DataImportTool = Class.extend({
}

if(in_list(frappe.boot.user.can_import, doctype)) {
this.select.val(doctype).change();
this.select.val(doctype).change();
}

frappe.route_options = null;
@@ -129,12 +129,12 @@ frappe.DataImportTool = Class.extend({
queued: function() {
// async, show queued
msg_dialog.clear();
msgprint(__("Import Request Queued. This may take a few moments, please be patient."));
frappe.msgprint(__("Import Request Queued. This may take a few moments, please be patient."));
},
running: function() {
// update async status as running
msg_dialog.clear();
msgprint(__("Importing..."));
frappe.msgprint(__("Importing..."));
me.write_messages([__("Importing")]);
me.has_progress = false;
},


+ 13
- 13
frappe/core/page/desktop/desktop.js View File

@@ -74,16 +74,16 @@ $.extend(frappe.desktop, {
// TEMP: test activiation without this message.
return;

if(!frappe.user.has_role('System Manager')) {
return;
}
frappe.call({
method: 'frappe.core.page.desktop.desktop.get_help_messages',
callback: function(r) {
frappe.desktop.render_help_messages(r.message);
}
});
// if(!frappe.user.has_role('System Manager')) {
// return;
// }
// frappe.call({
// method: 'frappe.core.page.desktop.desktop.get_help_messages',
// callback: function(r) {
// frappe.desktop.render_help_messages(r.message);
// }
// });

},

@@ -91,7 +91,7 @@ $.extend(frappe.desktop, {
var wrapper = frappe.desktop.wrapper.find('.help-message-wrapper');
var $help_messages = wrapper.find('.help-messages');

set_current_message = function(idx) {
var set_current_message = function(idx) {
idx = cint(idx);
wrapper.current_message_idx = idx;
wrapper.find('.left-arrow, .right-arrow').addClass('disabled');
@@ -166,7 +166,7 @@ $.extend(frappe.desktop, {
}
return false;
} else {
module = frappe.get_module(parent.attr("data-name"));
var module = frappe.get_module(parent.attr("data-name"));
if (module && module.onclick) {
module.onclick();
return false;
@@ -181,7 +181,7 @@ $.extend(frappe.desktop, {

new Sortable($("#icon-grid").get(0), {
onUpdate: function(event) {
new_order = [];
var new_order = [];
$("#icon-grid .case-wrapper").each(function(i, e) {
new_order.push($(this).attr("data-name"));
});


+ 1
- 1
frappe/core/page/modules_setup/modules_setup.js View File

@@ -59,7 +59,7 @@ frappe.pages['modules_setup'].on_page_load = function(wrapper) {
};

// application installer
if(frappe.boot.user.roles.indexOf('System Manager')!==-1) {
if(frappe.user_roles.includes('System Manager')) {
page.add_inner_button('Install Apps', function() {
frappe.set_route('applications');
});


+ 8
- 6
frappe/core/page/permission_manager/permission_manager.js View File

@@ -298,7 +298,7 @@ frappe.PermissionEngine = Class.extend({
r.message = $.map(r.message, function(p) {
return $.format('<a href="#Form/User/{0}">{1}</a>', [p, p]);
})
msgprint(__("Users with role {0}:", [__(role)])
frappe.msgprint(__("Users with role {0}:", [__(role)])
+ "<br>" + r.message.join("<br>"));
}
})
@@ -324,7 +324,7 @@ frappe.PermissionEngine = Class.extend({
},
callback: function(r) {
if(r.exc) {
msgprint(__("Did not remove"));
frappe.msgprint(__("Did not remove"));
} else {
me.refresh();
}
@@ -380,7 +380,8 @@ frappe.PermissionEngine = Class.extend({
options:me.options.roles, reqd:1,fieldname:"role"},
{fieldtype:"Select", label:__("Permission Level"),
options:[0,1,2,3,4,5,6,7,8,9], reqd:1, fieldname: "permlevel",
description: __("Level 0 is for document level permissions, higher levels for field level permissions.")}
description: __("Level 0 is for document level permissions, \
higher levels for field level permissions.")}
]
});
if(me.get_doctype()) {
@@ -404,7 +405,7 @@ frappe.PermissionEngine = Class.extend({
args: args,
callback: function(r) {
if(r.exc) {
msgprint(__("Did not add"));
frappe.msgprint(__("Did not add"));
} else {
me.refresh();
}
@@ -417,6 +418,7 @@ frappe.PermissionEngine = Class.extend({
},

show_user_permission_doctypes: function(d) {
var me = this;
if (!d.dialog) {
var fields = [];
for (var i=0, l=d.linked_doctypes.length; i<l; i++) {
@@ -476,9 +478,9 @@ frappe.PermissionEngine = Class.extend({
},
callback: function(r) {
if(r.exc) {
msgprint(__("Did not set"));
frappe.msgprint(__("Did not set"));
} else {
var msg = msgprint(__("Saved!"));
var msg = frappe.msgprint(__("Saved!"));
setTimeout(function() { msg.hide(); }, 3000);
d.user_permission_doctypes = user_permission_doctypes;
dialog.hide();


+ 21
- 4
frappe/core/page/permission_manager/permission_manager.py View File

@@ -14,11 +14,28 @@ from frappe import _
def get_roles_and_doctypes():
frappe.only_for("System Manager")
send_translations(frappe.get_lang_dict("doctype", "DocPerm"))

active_domains = frappe.get_active_domains()

doctypes = frappe.get_all("DocType", filters={
"istable": 0,
"name": ("not in", "DocType"),
}, or_filters={
"ifnull(restrict_to_domain, '')": "",
"restrict_to_domain": ("in", active_domains)
}, fields=["name"])

roles = frappe.get_all("Role", filters={
"name": ("not in", "Administrator"),
"disabled": 0,
}, or_filters={
"ifnull(restrict_to_domain, '')": "",
"restrict_to_domain": ("in", active_domains)
}, fields=["name"])

return {
"doctypes": [d[0] for d in frappe.db.sql("""select name from `tabDocType` dt where
istable=0 and name not in ('DocType')""")],
"roles": [d[0] for d in frappe.db.sql("""select name from tabRole where
name != 'Administrator' and disabled=0""")]
"doctypes": [d.get("name") for d in doctypes],
"roles": [d.get("name") for d in roles]
}

@frappe.whitelist()


+ 13
- 11
frappe/core/page/user_permissions/user_permissions.js View File

@@ -50,9 +50,9 @@ frappe.UserPermissions = Class.extend({
var me = this;

$(this.wrapper).find(".view-role-permissions").on("click", function() {
frappe.route_options = { doctype: me.get_doctype() || "" };
frappe.set_route("permission-manager");
})
frappe.route_options = { doctype: me.get_doctype() || "" };
frappe.set_route("permission-manager");
})

return frappe.call({
module:"frappe.core",
@@ -82,7 +82,7 @@ frappe.UserPermissions = Class.extend({
options: "[Select]"
});

if(roles.indexOf("System Manager")!==-1) {
if(frappe.user_roles.includes("System Manager")) {
me.download = me.wrapper.page.add_field({
fieldname: "download",
label: __("Download"),
@@ -141,7 +141,7 @@ frappe.UserPermissions = Class.extend({
primary_action: function() {
var filedata = d.fields_dict.attach.get_value();
if(!filedata) {
msgprint(_("Please attach a file"));
frappe.msgprint(__("Please attach a file"));
return;
}
frappe.call({
@@ -151,7 +151,7 @@ frappe.UserPermissions = Class.extend({
},
callback: function(r) {
if(!r.exc) {
msgprint(__("Permissions Updated"));
frappe.msgprint(__("Permissions Updated"));
d.hide();
}
}
@@ -250,9 +250,11 @@ frappe.UserPermissions = Class.extend({

$.each([[__("Allow User"), 150], [__("If Document Type"), 150], [__("Is"),150], ["", 50]],
function(i, col) {
$("<th>").html(col[0]).css("width", col[1]+"px")
.appendTo(me.table.find("thead tr"));
});
$("<th>")
.html(col[0])
.css("width", col[1]+"px")
.appendTo(me.table.find("thead tr"));
});


$.each(this.prop_list, function(i, d) {
@@ -288,7 +290,7 @@ frappe.UserPermissions = Class.extend({
},
callback: function(r) {
if(r.exc) {
msgprint(__("Did not remove"));
frappe.msgprint(__("Did not remove"));
} else {
me.refresh();
}
@@ -349,7 +351,7 @@ frappe.UserPermissions = Class.extend({
args: args,
callback: function(r) {
if(r.exc) {
msgprint(__("Did not add"));
frappe.msgprint(__("Did not add"));
} else {
me.refresh();
}


+ 6
- 6
frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.js View File

@@ -16,7 +16,7 @@ frappe.query_reports["Permitted Documents For User"] = {
"fieldtype": "Link",
"options": "DocType",
"reqd": 1,
"get_query": function() {
"get_query": function () {
return {
"query": "frappe.core.report.permitted_documents_for_user.permitted_documents_for_user.query_doctypes",
"filters": {
@@ -25,10 +25,10 @@ frappe.query_reports["Permitted Documents For User"] = {
}
}
},
{
"fieldname": "show_permissions",
"label": __("Show Permissions"),
"fieldtype": "Check"
}
{
"fieldname": "show_permissions",
"label": __("Show Permissions"),
"fieldtype": "Check"
}
]
}

+ 3
- 3
frappe/custom/doctype/custom_field/custom_field.js View File

@@ -7,10 +7,10 @@
frappe.ui.form.on('Custom Field', {
setup: function(frm) {
frm.set_query('dt', function(doc) {
filters = [
var filters = [
['DocType', 'issingle', '=', 0],
];
if(user!=="Administrator") {
if(frappe.session.user!=="Administrator") {
filters.push(['DocType', 'module', '!=', 'Core'])
}
return {
@@ -57,7 +57,7 @@ frappe.ui.form.on('Custom Field', {
fieldtype: function(frm) {
if(frm.doc.fieldtype == 'Link') {
frm.fields_dict['options_help'].disp_area.innerHTML =
__('Name of the Document Type (DocType) you want this field to be linked to. e.g. Customer');
__('Name of the Document Type (DocType) you want this field to be linked to. e.g. Customer');
} else if(frm.doc.fieldtype == 'Select') {
frm.fields_dict['options_help'].disp_area.innerHTML =
__('Options for select. Each option on a new line.')+' '+__('e.g.:')+'<br>'+__('Option 1')+'<br>'+__('Option 2')+'<br>'+__('Option 3')+'<br>';


+ 1135
- 1068
frappe/custom/doctype/custom_field/custom_field.json
File diff suppressed because it is too large
View File


+ 8
- 7
frappe/custom/doctype/custom_field/custom_field.py View File

@@ -25,15 +25,15 @@ class CustomField(Document):
self.fieldname = self.fieldname.lower()

def validate(self):
meta = frappe.get_meta(self.dt)
meta = frappe.get_meta(self.dt, cached=False)
fieldnames = [df.fieldname for df in meta.get("fields")]

if self.insert_after=='append':
self.insert_after = fieldnames[-1]

if self.insert_after and self.insert_after in fieldnames:
self.idx = fieldnames.index(self.insert_after) + 1

if not self.idx:
self.idx = len(fieldnames) + 1

self._old_fieldtype = self.db_get('fieldtype')

if not self.fieldname:
@@ -83,17 +83,18 @@ def create_custom_field_if_values_exist(doctype, df):

create_custom_field(doctype, df)


def create_custom_field(doctype, df):
df = frappe._dict(df)
if not df.fieldname and df.label:
df.fieldname = frappe.scrub(df.label)
if not frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df.fieldname}):
frappe.get_doc({
"doctype":"Custom Field",
"dt": doctype,
"permlevel": df.permlevel or 0,
"label": df.label,
"fieldname": df.fieldname or df.label.lower().replace(' ', '_'),
"fieldtype": df.fieldtype,
"fieldname": df.fieldname,
"fieldtype": df.fieldtype or 'Data',
"options": df.options,
"insert_after": df.insert_after,
"print_hide": df.print_hide,


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save