Merge branch 'staging' into develop

This commit is contained in:
Sagar Vora 2019-01-29 18:24:11 +05:30
commit ef82f39f99
200 changed files with 577 additions and 781 deletions

View file

@ -17,7 +17,13 @@ from faker import Faker
from .exceptions import *
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
__version__ = '10.1.70'
# Hamless for Python 3
# For Python 2 set default encoding to utf-8
if sys.version[0] == '2':
reload(sys)
sys.setdefaultencoding("utf-8")
__version__ = '10.1.71'
__title__ = "Frappe Framework"
local = Local()

View file

@ -0,0 +1,19 @@
- Dynamic [Frappe Charts](https://github.com/frappe/charts) with Report Builder (built by @pratu16x7)
- New Frappe Chat for easier internal communication (built by @achillesrasquinha)
- [Frappe DataTable](https://github.com/frappe/datatable) for better reports (built by @netchampfaris)
- Google Calendar can now be integrated with Frappe
- Files can now be uploaded using drag-and-drop
- Enhanced List View and Tree View
- Bulk Actions from List View
- Quill editor has been introduced in place of Summernote
- HTML Editor has been introduced
- New User Permissions
- Subscriptions in ERPNext now moved to Auto Repeat in Frappe
- Support for Razorpay and PayPal subscriptions
- Better Social login, Workflow
- Messages for when user goes online/offline
- Logout from all sessions on password change
- Desktop icons can now be selected from a dialog box
- Changes have been made to ensure Frappe is compatible with Python 3
- Better documentation is now available with support for more languages
- A lot of other fixes have been done to ensure a better overall user experience

View file

@ -1,2 +1,2 @@
### User Permissions
- User Permission is now a DocType, a new UX for the existing Role and User Permission managers to make it easy to enter permissions. For more details please check <a href="https://erpnext.org/docs/user/manual/en/setting-up/users-and-permissions/user-permissions">User Permissions</a>
- User Permission is now a DocType, a new UX for the existing Role and User Permission managers to make it easy to enter permissions. For more details please check <a href="https://erpnext.com/docs/user/manual/en/setting-up/users-and-permissions/user-permissions">User Permissions</a>

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe import _

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - standard imports
import json

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - standard imports
import unittest

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - module imports
from frappe.model.document import Document
from frappe import _

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - standard imports
import unittest
@ -16,7 +18,7 @@ class TestChatProfile(unittest.TestCase):
# def test_create(self):
# with self.assertRaises(frappe.ValidationError):
# chat_profile.create(test_user)
# user = get_user_doc(session.user)
# if not user.chat_profile:
# chat_profile.create(user.name)
@ -47,7 +49,7 @@ class TestChatProfile(unittest.TestCase):
# ))
# user = get_user_doc(session.user)
# prev = chat_profile.get(user.name)
# prev = chat_profile.get(user.name)
# chat_profile.update(user.name, data = dict(
# status = 'Offline'

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - standard imports
import json

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - module imports
from frappe.model.document import Document
import frappe

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - module imports
from frappe.chat.util.util import (
get_user_doc,

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - standard imports
import unittest
@ -7,6 +9,7 @@ from frappe.chat.util import (
safe_json_loads
)
import frappe
import six
class TestChatUtil(unittest.TestCase):
def test_safe_json_loads(self):
@ -15,10 +18,10 @@ class TestChatUtil(unittest.TestCase):
number = safe_json_loads("1.0")
self.assertEqual(type(number), float)
string = safe_json_loads("foobar")
self.assertEqual(type(string), str)
self.assertEqual(type(string), six.text_type)
array = safe_json_loads('[{ "foo": "bar" }]')
self.assertEqual(type(array), list)

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
# imports - third-party imports
import requests
@ -26,7 +28,7 @@ def get_user_doc(user = None):
user = user or session.user
user = frappe.get_doc('User', user)
return user
def squashify(what):
@ -43,9 +45,9 @@ def safe_json_loads(*args):
arg = json.loads(arg)
except Exception as e:
pass
results.append(arg)
return squashify(results)
def filter_dict(what, keys, ignore = False):
@ -68,7 +70,7 @@ def get_if_empty(a, b):
if not a:
a = b
return a
def listify(arg):
if not isinstance(arg, list):
arg = [arg]
@ -89,7 +91,7 @@ def check_url(what, raise_err = False):
raise ValueError('{what} not a valid URL.')
else:
return False
return True
def create_test_user(module):
@ -110,5 +112,5 @@ def get_emojis():
if resp.ok:
emojis = resp.json()
redis.hset('frappe_emojis', 'emojis', emojis)
return dictify(emojis)

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.chat.util import filter_dict, safe_json_loads

View file

@ -1,6 +1,6 @@
from __future__ import unicode_literals, absolute_import, print_function
import click
import json, sys
import sys
import frappe
from frappe.utils import cint
from frappe.commands import pass_context, get_site

View file

@ -1,6 +1,5 @@
from __future__ import unicode_literals, absolute_import, print_function
import click
import frappe
from frappe.commands import pass_context, get_site
# translation

View file

@ -601,58 +601,27 @@ def get_version():
@click.option('--db_type')
@click.option('--root_password')
def setup_global_help(db_type=None, root_password=None):
'''setup help table in a separate database that will be
'''Deprecated: setup help table in a separate database that will be
shared by the whole bench and set `global_help_setup` as 1 in
common_site_config.json'''
from frappe.installer import update_site_config
frappe.local.flags = frappe._dict()
frappe.local.flags.in_setup_help = True
frappe.local.flags.in_install = True
frappe.local.lang = 'en'
frappe.local.conf = frappe.get_site_config(sites_path='.')
update_site_config('global_help_setup', 1,
site_config_path=os.path.join('.', 'common_site_config.json'))
if root_password:
frappe.local.conf.root_password = root_password
if not frappe.local.conf.db_type:
frappe.local.conf.db_type = db_type
from frappe.utils.help import sync
sync()
print_in_app_help_deprecation()
@click.command('get-docs-app')
@click.argument('app')
def get_docs_app(app):
'''Get the docs app for given app'''
from frappe.utils.help import setup_apps_for_docs
setup_apps_for_docs(app)
'''Deprecated: Get the docs app for given app'''
print_in_app_help_deprecation()
@click.command('get-all-docs-apps')
def get_all_docs_apps():
'''Get docs apps for all apps'''
from frappe.utils.help import setup_apps_for_docs
for app in frappe.get_installed_apps():
setup_apps_for_docs(app)
'''Deprecated: Get docs apps for all apps'''
print_in_app_help_deprecation()
@click.command('setup-help')
@pass_context
def setup_help(context):
'''Setup help table in the current site (called after migrate)'''
from frappe.utils.help import sync
for site in context.sites:
try:
frappe.init(site)
frappe.connect()
sync()
finally:
frappe.destroy()
'''Deprecated: Setup help table in the current site (called after migrate)'''
print_in_app_help_deprecation()
@click.command('rebuild-global-search')
@pass_context
@ -716,6 +685,10 @@ def auto_deploy(context, app, migrate=False, restart=False, remote='upstream'):
else:
print('No Updates')
def print_in_app_help_deprecation():
print("In app help has been removed.\nYou can access the documentation on erpnext.com/docs or frappe.io/docs")
return
commands = [
build,
clear_cache,
@ -746,8 +719,5 @@ commands = [
watch,
_bulk_rename,
add_to_email_queue,
setup_global_help,
setup_help,
rebuild_global_search,
auto_deploy
rebuild_global_search
]

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
import frappe.defaults
import unittest

View file

@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import frappe.share
import unittest

View file

@ -1,8 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
def get_parent_doc(doc):
"""Returns document of `reference_doctype`, `reference_doctype`"""

View file

@ -18,7 +18,7 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2018-11-01 19:35:43.552429",
"modified": "2019-01-28 12:45:17.158069",
"modified_by": "Administrator",
"module": "Core",
"name": "edit-profile",
@ -129,19 +129,6 @@
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "roles",
"fieldtype": "Table",
"hidden": 0,
"label": "Roles Assigned",
"max_length": 0,
"max_value": 0,
"options": "Has Role",
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
}
]
}

View file

@ -9,6 +9,9 @@ frappe.ui.form.on('Custom Field', {
frm.set_query('dt', function(doc) {
var filters = [
['DocType', 'issingle', '=', 0],
['DocType', 'custom', '=', 0],
['DocType', 'name', 'not in', frappe.model.core_doctypes_list],
['DocType', 'restrict_to_domain', 'in', frappe.boot.active_domains]
];
if(frappe.session.user!=="Administrator") {
filters.push(['DocType', 'module', 'not in', ['Core', 'Custom']])
@ -32,15 +35,21 @@ frappe.ui.form.on('Custom Field', {
return frappe.call({
method: 'frappe.custom.doctype.custom_field.custom_field.get_fields_label',
args: { doctype: frm.doc.dt, fieldname: frm.doc.fieldname },
callback: function(r, rt) {
set_field_options('insert_after', r.message);
var fieldnames = $.map(r.message, function(v) { return v.value; });
callback: function(r) {
if(r) {
if(r._server_messages && r._server_messages.length) {
frm.set_value("dt", "");
} else {
set_field_options('insert_after', r.message);
var fieldnames = $.map(r.message, function(v) { return v.value; });
if(insert_after==null || !in_list(fieldnames, insert_after)) {
insert_after = fieldnames[-1];
if(insert_after==null || !in_list(fieldnames, insert_after)) {
insert_after = fieldnames[-1];
}
frm.set_value('insert_after', insert_after);
}
}
frm.set_value('insert_after', insert_after);
}
});

View file

@ -8,6 +8,7 @@ from frappe.utils import cstr
from frappe import _
from frappe.model.document import Document
from frappe.model.docfield import supports_translation
from frappe.model import core_doctypes_list
class CustomField(Document):
def autoname(self):
@ -85,6 +86,14 @@ class CustomField(Document):
@frappe.whitelist()
def get_fields_label(doctype=None):
meta = frappe.get_meta(doctype)
if doctype in core_doctypes_list:
return frappe.msgprint(_("Custom Fields cannot be added to core DocTypes."))
if meta.custom:
return frappe.msgprint(_("Custom Fields can only be added to a standard DocType."))
return [{"value": df.fieldname or "", "label": _(df.label or "")}
for df in frappe.get_meta(doctype).get("fields")]

View file

@ -13,9 +13,7 @@ frappe.ui.form.on("Customize Form", {
filters: [
['DocType', 'issingle', '=', 0],
['DocType', 'custom', '=', 0],
['DocType', 'name', 'not in', 'DocType, DocField, DocPerm, User, Role, Has Role, \
Page, Has Role, Module Def, Print Format, Report, Customize Form, \
Customize Form Field, Property Setter, Custom Field, Custom Script'],
['DocType', 'name', 'not in', frappe.model.core_doctypes_list],
['DocType', 'restrict_to_domain', 'in', frappe.boot.active_domains]
]
};
@ -39,8 +37,14 @@ frappe.ui.form.on("Customize Form", {
doc: frm.doc,
freeze: true,
callback: function(r) {
frm.refresh();
frm.trigger("setup_sortable");
if(r) {
if(r._server_messages && r._server_messages.length) {
frm.set_value("doc_type", "");
} else {
frm.refresh();
frm.trigger("setup_sortable");
}
}
}
});
} else {

View file

@ -11,7 +11,7 @@ import frappe.translate
from frappe import _
from frappe.utils import cint
from frappe.model.document import Document
from frappe.model import no_value_fields
from frappe.model import no_value_fields, core_doctypes_list
from frappe.core.doctype.doctype.doctype import validate_fields_for_doctype
from frappe.model.docfield import supports_translation
@ -85,6 +85,12 @@ class CustomizeForm(Document):
meta = frappe.get_meta(self.doc_type)
if self.doc_type in core_doctypes_list:
return frappe.msgprint(_("Core DocTypes cannot be customized."))
if meta.custom:
return frappe.msgprint(_("Only standard DocTypes are allowed to be customized from Customize Form."))
# doctype properties
for property in doctype_properties:
self.set(property, meta.get(property))

View file

@ -9,28 +9,28 @@ from frappe.core.doctype.doctype.doctype import InvalidFieldNameError
test_dependencies = ["Custom Field", "Property Setter"]
class TestCustomizeForm(unittest.TestCase):
def insert_custom_field(self):
frappe.delete_doc_if_exists("Custom Field", "User-test_custom_field")
frappe.delete_doc_if_exists("Custom Field", "Event-test_custom_field")
frappe.get_doc({
"doctype": "Custom Field",
"dt": "User",
"dt": "Event",
"label": "Test Custom Field",
"description": "A Custom Field for Testing",
"fieldtype": "Select",
"in_list_view": 1,
"options": "\nCustom 1\nCustom 2\nCustom 3",
"default": "Custom 3",
"insert_after": frappe.get_meta('User').fields[-1].fieldname
"insert_after": frappe.get_meta('Event').fields[-1].fieldname
}).insert()
def setUp(self):
self.insert_custom_field()
frappe.db.commit()
frappe.clear_cache(doctype="User")
frappe.clear_cache(doctype="Event")
def tearDown(self):
frappe.delete_doc("Custom Field", "User-test_custom_field")
frappe.delete_doc("Custom Field", "Event-test_custom_field")
frappe.db.commit()
frappe.clear_cache(doctype="User")
frappe.clear_cache(doctype="Event")
def get_customize_form(self, doctype=None):
d = frappe.get_doc("Customize Form")
@ -45,78 +45,67 @@ class TestCustomizeForm(unittest.TestCase):
self.assertEqual(len(d.get("fields")), 0)
d = self.get_customize_form("Event")
self.assertEqual(d.doc_type, "Event")
self.assertEqual(len(d.get("fields")), 27)
self.assertEquals(d.doc_type, "Event")
self.assertEquals(len(d.get("fields")), 30)
d = self.get_customize_form("User")
self.assertEqual(d.doc_type, "User")
d = self.get_customize_form("Event")
self.assertEquals(d.doc_type, "Event")
self.assertEqual(len(d.get("fields")),
len(frappe.get_doc("DocType", d.doc_type).fields) + 1)
self.assertEqual(d.get("fields")[-1].fieldname, "test_custom_field")
self.assertEqual(d.get("fields", {"fieldname": "location"})[0].in_list_view, 1)
self.assertEquals(d.get("fields")[-1].fieldname, "test_custom_field")
self.assertEquals(d.get("fields", {"fieldname": "event_type"})[0].in_list_view, 1)
return d
def test_save_customization_property(self):
d = self.get_customize_form("User")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "allow_copy"}, "value"), None)
d = self.get_customize_form("Event")
self.assertEquals(frappe.db.get_value("Property Setter",
{"doc_type": "Event", "property": "allow_copy"}, "value"), None)
d.allow_copy = 1
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "allow_copy"}, "value"), '1')
self.assertEquals(frappe.db.get_value("Property Setter",
{"doc_type": "Event", "property": "allow_copy"}, "value"), '1')
d.allow_copy = 0
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "allow_copy"}, "value"), None)
self.assertEquals(frappe.db.get_value("Property Setter",
{"doc_type": "Event", "property": "allow_copy"}, "value"), None)
def test_save_customization_field_property(self):
d = self.get_customize_form("User")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "reqd", "field_name": "location"}, "value"), None)
d = self.get_customize_form("Event")
self.assertEquals(frappe.db.get_value("Property Setter",
{"doc_type": "Event", "property": "reqd", "field_name": "repeat_this_event"}, "value"), None)
location_field = d.get("fields", {"fieldname": "location"})[0]
location_field.reqd = 1
repeat_this_event_field = d.get("fields", {"fieldname": "repeat_this_event"})[0]
repeat_this_event_field.reqd = 1
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "reqd", "field_name": "location"}, "value"), '1')
self.assertEquals(frappe.db.get_value("Property Setter",
{"doc_type": "Event", "property": "reqd", "field_name": "repeat_this_event"}, "value"), '1')
location_field = d.get("fields", {"fieldname": "location"})[0]
location_field.reqd = 0
repeat_this_event_field = d.get("fields", {"fieldname": "repeat_this_event"})[0]
repeat_this_event_field.reqd = 0
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "reqd", "field_name": "location"}, "value"), None)
# for not allowing to change mandatory property of standard fields
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "reqd", "field_name": "email"}, "value"), None)
email_field = d.get("fields", {"fieldname": "email"})[0]
email_field.reqd = 0
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Property Setter",
{"doc_type": "User", "property": "reqd", "field_name": "email"}, "value"), None)
self.assertEquals(frappe.db.get_value("Property Setter",
{"doc_type": "Event", "property": "reqd", "field_name": "repeat_this_event"}, "value"), None)
def test_save_customization_custom_field_property(self):
d = self.get_customize_form("User")
self.assertEqual(frappe.db.get_value("Custom Field", "User-test_custom_field", "reqd"), 0)
d = self.get_customize_form("Event")
self.assertEquals(frappe.db.get_value("Custom Field", "Event-test_custom_field", "reqd"), 0)
custom_field = d.get("fields", {"fieldname": "test_custom_field"})[0]
custom_field.reqd = 1
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Custom Field", "User-test_custom_field", "reqd"), 1)
self.assertEquals(frappe.db.get_value("Custom Field", "Event-test_custom_field", "reqd"), 1)
custom_field = d.get("fields", {"is_custom_field": True})[0]
custom_field.reqd = 0
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Custom Field", "User-test_custom_field", "reqd"), 0)
self.assertEquals(frappe.db.get_value("Custom Field", "Event-test_custom_field", "reqd"), 0)
def test_save_customization_new_field(self):
d = self.get_customize_form("User")
d = self.get_customize_form("Event")
last_fieldname = d.fields[-1].fieldname
d.append("fields", {
"label": "Test Add Custom Field Via Customize Form",
@ -124,19 +113,19 @@ class TestCustomizeForm(unittest.TestCase):
"is_custom_field": 1
})
d.run_method("save_customization")
self.assertEqual(frappe.db.get_value("Custom Field",
"User-test_add_custom_field_via_customize_form", "fieldtype"), "Data")
self.assertEquals(frappe.db.get_value("Custom Field",
"Event-test_add_custom_field_via_customize_form", "fieldtype"), "Data")
self.assertEqual(frappe.db.get_value("Custom Field",
"User-test_add_custom_field_via_customize_form", 'insert_after'), last_fieldname)
self.assertEquals(frappe.db.get_value("Custom Field",
"Event-test_add_custom_field_via_customize_form", 'insert_after'), last_fieldname)
frappe.delete_doc("Custom Field", "User-test_add_custom_field_via_customize_form")
self.assertEqual(frappe.db.get_value("Custom Field",
"User-test_add_custom_field_via_customize_form"), None)
frappe.delete_doc("Custom Field", "Event-test_add_custom_field_via_customize_form")
self.assertEquals(frappe.db.get_value("Custom Field",
"Event-test_add_custom_field_via_customize_form"), None)
def test_save_customization_remove_field(self):
d = self.get_customize_form("User")
d = self.get_customize_form("Event")
custom_field = d.get("fields", {"fieldname": "test_custom_field"})[0]
d.get("fields").remove(custom_field)
d.run_method("save_customization")
@ -148,24 +137,24 @@ class TestCustomizeForm(unittest.TestCase):
def test_reset_to_defaults(self):
d = frappe.get_doc("Customize Form")
d.doc_type = "User"
d.doc_type = "Event"
d.run_method('reset_to_defaults')
self.assertEqual(d.get("fields", {"fieldname": "location"})[0].in_list_view, 0)
self.assertEquals(d.get("fields", {"fieldname": "repeat_this_event"})[0].in_list_view, 0)
frappe.local.test_objects["Property Setter"] = []
make_test_records_for_doctype("Property Setter")
def test_set_allow_on_submit(self):
d = self.get_customize_form("User")
d.get("fields", {"fieldname": "first_name"})[0].allow_on_submit = 1
d = self.get_customize_form("Event")
d.get("fields", {"fieldname": "subject"})[0].allow_on_submit = 1
d.get("fields", {"fieldname": "test_custom_field"})[0].allow_on_submit = 1
d.run_method("save_customization")
d = self.get_customize_form("User")
d = self.get_customize_form("Event")
# don't allow for standard fields
self.assertEqual(d.get("fields", {"fieldname": "first_name"})[0].allow_on_submit or 0, 0)
self.assertEquals(d.get("fields", {"fieldname": "subject"})[0].allow_on_submit or 0, 0)
# allow for custom field
self.assertEqual(d.get("fields", {"fieldname": "test_custom_field"})[0].allow_on_submit, 1)
@ -193,4 +182,12 @@ class TestCustomizeForm(unittest.TestCase):
# undo
df.default = None
d.run_method("save_customization")
d.run_method("save_customization")
def test_core_doctype_customization(self):
d = self.get_customize_form('User')
e = self.get_customize_form('Custom Field')
# core doctype is invalid, hence no attributes are set
self.assertEquals(d.get("fields"), [])
self.assertEquals(e.get("fields"), [])

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
from six import with_metaclass
from abc import ABCMeta, abstractmethod
from frappe.utils.password import get_decrypted_password

View file

@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest

View file

@ -12,8 +12,15 @@ import json
@frappe.whitelist()
@frappe.read_only()
def get_notifications():
if frappe.flags.in_install:
return
if (frappe.flags.in_install or
not frappe.db.get_single_value('System Settings', 'setup_complete')):
return {
"open_count_doctype": {},
"open_count_module": {},
"open_count_other": {},
"targets": {},
"new_messages": []
}
config = get_notification_config()
@ -108,7 +115,8 @@ def get_notifications_for_doctypes(config, notification_count):
except Exception as e:
# OperationalError: (1412, 'Table definition has changed, please retry transaction')
if e.args[0]!=1412:
# InternalError: (1684, 'Table definition is being modified by concurrent DDL statement')
if e.args[0] not in (1412, 1684):
raise
else:
@ -148,7 +156,7 @@ def get_notifications_for_targets(config, notification_percent):
frappe.clear_messages()
pass
except Exception as e:
if e.args[0]!=1412:
if e.args[0] not in (1412, 1684):
raise
else:

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import os
import frappe
from frappe import _

View file

@ -220,9 +220,6 @@ def runquery(q='', ret=0, from_export=0):
def runquery_csv():
global out
# run query
res = runquery(from_export = 1)
q = frappe.form_dict.get('query')
rep_name = frappe.form_dict.get('report_name')
@ -234,9 +231,6 @@ def runquery_csv():
if not rep_name: rep_name = 'DataExport'
# Headings
heads = []
rows = [[rep_name], out['colnames']] + out['values']
from six import StringIO

View file

@ -254,7 +254,7 @@ def export_query():
if row and (i in visible_idx):
row_list = []
for idx in range(len(data.columns)):
row_list.append(row.get(columns[idx]["fieldname"],""))
row_list.append(row.get(columns[idx]["fieldname"], row.get(columns[idx]["label"], "")))
result.append(row_list)
elif not row:
result.append([])

View file

@ -42,7 +42,6 @@ def get_form_params():
else:
data["save_user_settings"] = True
doctype = data["doctype"]
fields = data["fields"]
for field in fields:
@ -213,7 +212,7 @@ def delete_items():
"""delete selected items"""
import json
il = sorted(json.loads(frappe.form_dict.get('items')), reverse=True, key=str)
il = sorted(json.loads(frappe.form_dict.get('items')), reverse=True, key=frappe.safe_decode)
doctype = frappe.form_dict.get('doctype')
failed = []

View file

@ -1130,6 +1130,39 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "no_smtp_authentication",
"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": "Disable SMTP server authentication",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -1566,4 +1599,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
}

View file

@ -72,7 +72,7 @@ class EmailAccount(Document):
if self.enable_outgoing:
self.check_smtp()
else:
if self.enable_incoming or self.enable_outgoing:
if self.enable_incoming or (self.enable_outgoing and not self.no_smtp_authentication):
frappe.throw(_("Password is required or select Awaiting Password"))
if self.notify_if_unreplied:
@ -134,8 +134,9 @@ class EmailAccount(Document):
port = cint(self.smtp_port),
use_tls = cint(self.use_tls)
)
if self.password:
if self.password and not self.no_smtp_authentication:
server.password = self.get_password()
server.sess
def get_incoming_server(self, in_receive=False, email_sync_rule="UNSEEN"):

View file

@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe, os
import unittest, email

View file

@ -6,7 +6,7 @@ import frappe, re, os
from frappe.utils.pdf import get_pdf
from frappe.email.smtp import get_outgoing_email_account
from frappe.utils import (get_url, scrub_urls, strip, expand_relative_urls, cint,
split_emails, to_markdown, markdown, encode, random_string, parse_addr)
split_emails, to_markdown, markdown, random_string, parse_addr)
import email.utils
from six import iteritems, text_type, string_types
from email.mime.multipart import MIMEMultipart

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
import json

View file

@ -88,7 +88,7 @@ def get_outgoing_email_account(raise_exception_not_set=True, append_to=None, sen
if email_account:
if email_account.enable_outgoing and not getattr(email_account, 'from_site_config', False):
raise_exception = True
if email_account.smtp_server in ['localhost','127.0.0.1']:
if email_account.smtp_server in ['localhost','127.0.0.1'] or email_account.no_smtp_authentication:
raise_exception = False
email_account.password = email_account.get_password(raise_exception=raise_exception)
email_account.default_sender = email.utils.formataddr((email_account.name, email_account.get("email_id")))
@ -170,11 +170,14 @@ class SMTPServer:
self.email_account = get_outgoing_email_account(raise_exception_not_set=False, append_to=append_to, sender=sender)
if self.email_account:
self.server = self.email_account.smtp_server
self.login = getattr(self.email_account, "login_id", None) or self.email_account.email_id
if self.email_account.ascii_encode_password:
self.password = frappe.safe_encode(self.email_account.password, 'ascii')
self.login = (getattr(self.email_account, "login_id", None) or self.email_account.email_id)
if not self.email_account.no_smtp_authentication:
if self.email_account.ascii_encode_password:
self.password = frappe.safe_encode(self.email_account.password, 'ascii')
else:
self.password = self.email_account.password
else:
self.password = self.email_account.password
self.password = None
self.port = self.email_account.smtp_port
self.use_tls = self.email_account.use_tls
self.sender = self.email_account.email_id
@ -210,7 +213,7 @@ class SMTPServer:
self._sess.ehlo()
if self.login and self.password:
ret = self._sess.login((self.login or ""), (self.password or ""))
ret = self._sess.login(str(self.login or ""), str(self.password or ""))
# check if logged correctly
if ret[0]!=235:

View file

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe, unittest, os, base64
import unittest, os, base64
from frappe.email.email_body import (replace_filename_with_cid,
get_email, inline_style_in_html, get_header)

View file

@ -1,4 +1,4 @@
from __future__ import print_function
from __future__ import print_function, unicode_literals
import requests
import json
import frappe

View file

@ -1,6 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: See license.txt
from __future__ import unicode_literals
import frappe
test_records = frappe.get_test_records('Country')

View file

@ -3,5 +3,6 @@
# pre loaded
from __future__ import unicode_literals
import frappe
test_records = frappe.get_test_records('Currency')

View file

@ -12,7 +12,7 @@ source_link = "https://github.com/frappe/frappe"
app_license = "MIT"
develop_version = '12.x.x-develop'
staging_version = '11.0.3-beta.51'
staging_version = '11.1.0'
app_email = "info@frappe.io"

View file

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import frappe
from datetime import datetime
from dateutil.parser import parse

View file

@ -1,4 +1,5 @@
# see license
from __future__ import unicode_literals
from frappe.model.document import Document
class SocialLoginKeys(Document):

View file

@ -2,6 +2,7 @@
# Copyright (c) 2017, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
def run_webhooks(doc, method):
@ -37,7 +38,7 @@ def run_webhooks(doc, method):
def _webhook_request(webhook):
if not webhook.name in frappe.flags.webhooks_executed.get(doc.name, []):
frappe.enqueue("frappe.integrations.doctype.webhook.webhook.enqueue_webhook",
frappe.enqueue("frappe.integrations.doctype.webhook.webhook.enqueue_webhook",
enqueue_after_commit=True, doc=doc, webhook=webhook)
# keep list of webhooks executed for this doc in this request

View file

@ -14,7 +14,6 @@ from frappe.website import render, router
from frappe.desk.doctype.desktop_icon.desktop_icon import sync_desktop_icons
from frappe.core.doctype.language.language import sync_languages
from frappe.modules.utils import sync_customizations
import frappe.utils.help
def migrate(verbose=True, rebuild_website=False):
'''Migrate all apps to the latest version, will:
@ -60,10 +59,6 @@ def migrate(verbose=True, rebuild_website=False):
frappe.db.commit()
if not frappe.conf.get('global_help_setup'):
# sync help if not set as global
frappe.utils.help.sync()
clear_notifications()
frappe.publish_realtime("version-update")

View file

@ -4,7 +4,6 @@
# model __init__.py
from __future__ import unicode_literals
import frappe
import json
data_fieldtypes = (
'Currency',
@ -45,6 +44,27 @@ default_fields = ('doctype','name','owner','creation','modified','modified_by',
'parent','parentfield','parenttype','idx','docstatus')
optional_fields = ("_user_tags", "_comments", "_assign", "_liked_by", "_seen")
table_fields = ('Table', 'Table MultiSelect')
core_doctypes_list = ('DocType', 'DocField', 'DocPerm', 'User', 'Role', 'Has Role',
'Page', 'Module Def', 'Print Format', 'Report', 'Customize Form',
'Customize Form Field', 'Property Setter', 'Custom Field', 'Custom Script')
def copytables(srctype, src, srcfield, tartype, tar, tarfield, srcfields, tarfields=[]):
if not tarfields:
tarfields = srcfields
l = []
data = src.get(srcfield)
for d in data:
newrow = tar.append(tarfield)
newrow.idx = d.idx
for i in range(len(srcfields)):
newrow.set(tarfields[i], d.get(srcfields[i]))
l.append(newrow)
return l
def db_exists(dt, dn):
return frappe.db.exists(dt, dn)
def delete_fields(args_dict, delete=0):
"""

View file

@ -451,6 +451,19 @@ class DatabaseQuery(object):
value = get_time(f.value).strftime("%H:%M:%S.%f")
fallback = "'00:00:00'"
elif f.operator.lower() == "is":
if f.value == 'set':
f.operator = '!='
elif f.value == 'not set':
f.operator = '='
value = ""
fallback = '""'
can_be_null = True
if 'ifnull' not in column_name:
column_name = 'ifnull({}, {})'.format(column_name, fallback)
elif f.operator.lower() in ("like", "not like") or (isinstance(f.value, string_types) and
(not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])):
value = "" if f.value==None else f.value

View file

@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
# select doctypes that are accessed by the user (not read_only) first, so that the

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
# Settings saved per user basis
# such as page_limit, filters, last_view

View file

@ -1 +1,2 @@
from __future__ import unicode_literals
from .utils import *

View file

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, os, json
import frappe, os
import frappe.model
from frappe.modules import scrub, get_module_path, scrub_dt_dn

View file

@ -1,4 +1,4 @@
from __future__ import print_function
from __future__ import print_function, unicode_literals
import frappe
import pytz

View file

@ -222,7 +222,6 @@ frappe.patches.v11_0.rename_workflow_action_to_workflow_action_master #13-06-201
frappe.patches.v11_0.rename_email_alert_to_notification #13-06-2018
frappe.patches.v11_0.delete_duplicate_user_permissions
frappe.patches.v11_0.set_dropbox_file_backup
frappe.patches.v11_0.get_docs_apps_if_not_present
frappe.patches.v10_0.set_default_locking_time
frappe.patches.v11_0.rename_google_maps_doctype
frappe.patches.v10_0.modify_smallest_currency_fraction

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
"""
Run this after updating country_info.json and or
"""

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.utils.password import LegacyPassword

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
'''
Modify the Integer 10 Digits Value to BigInt 20 Digit value

View file

@ -1,6 +1,7 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
"""
Run this after updating country_info.json and or
"""

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,6 +1,7 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe, json
def execute():

View file

@ -1,6 +0,0 @@
import frappe
from frappe.utils.help import setup_apps_for_docs
def execute():
for app in frappe.get_installed_apps():
setup_apps_for_docs(app)

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe, json
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.desk.form.linked_with import get_linked_doctypes
from frappe.patches.v11_0.replicate_old_user_permissions import get_doctypes_to_skip

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc

View file

@ -1,7 +1,8 @@
import frappe
from frappe.model.rename_doc import rename_doc
def execute():
if frappe.db.exists("DocType","Google Maps") and not frappe.db.exists("DocType","Google Maps Settings"):
rename_doc('DocType', 'Google Maps', 'Google Maps Settings')
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc
def execute():
if frappe.db.exists("DocType","Google Maps") and not frappe.db.exists("DocType","Google Maps Settings"):
rename_doc('DocType', 'Google Maps', 'Google Maps Settings')
frappe.reload_doc('integrations', 'doctype', 'google_maps_settings')

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.model.rename_doc import rename_doc

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
import json
from frappe.utils import cint

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
from frappe.utils.password import get_decrypted_password

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.utils.rename_field import rename_field
from frappe.modules import scrub, get_doctype_module

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
import frappe.share

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
def execute():
from frappe.geo.country_info import get_all

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe.utils, os
def execute():

View file

@ -1,4 +1,4 @@
from __future__ import print_function
from __future__ import print_function, unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

View file

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe
def execute():

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