Merge branch 'develop' into version-12
This commit is contained in:
commit
0e6de280aa
20 changed files with 143 additions and 79 deletions
|
|
@ -23,7 +23,7 @@ if sys.version[0] == '2':
|
|||
reload(sys)
|
||||
sys.setdefaultencoding("utf-8")
|
||||
|
||||
__version__ = '12.0.14'
|
||||
__version__ = '12.0.15'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
@ -1039,7 +1039,13 @@ def get_newargs(fn, kwargs):
|
|||
if hasattr(fn, 'fnargs'):
|
||||
fnargs = fn.fnargs
|
||||
else:
|
||||
fnargs, varargs, varkw, defaults = inspect.getargspec(fn)
|
||||
try:
|
||||
fnargs, varargs, varkw, defaults = inspect.getargspec(fn)
|
||||
except ValueError:
|
||||
fnargs = inspect.getfullargspec(fn).args
|
||||
varargs = inspect.getfullargspec(fn).varargs
|
||||
varkw = inspect.getfullargspec(fn).varkw
|
||||
defaults = inspect.getfullargspec(fn).defaults
|
||||
|
||||
newargs = {}
|
||||
for a in kwargs:
|
||||
|
|
@ -1409,8 +1415,9 @@ def publish_progress(*args, **kwargs):
|
|||
|
||||
:param percent: Percent progress
|
||||
:param title: Title
|
||||
:param doctype: Optional, for DocType
|
||||
:param name: Optional, for Document name
|
||||
:param doctype: Optional, for document type
|
||||
:param docname: Optional, for document name
|
||||
:param description: Optional description
|
||||
"""
|
||||
import frappe.realtime
|
||||
return frappe.realtime.publish_progress(*args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -10,20 +10,16 @@ test_records = frappe.get_test_records('Role')
|
|||
class TestUser(unittest.TestCase):
|
||||
def test_disable_role(self):
|
||||
frappe.get_doc("User", "test@example.com").add_roles("_Test Role 3")
|
||||
|
||||
|
||||
role = frappe.get_doc("Role", "_Test Role 3")
|
||||
role.disabled = 1
|
||||
role.save()
|
||||
|
||||
|
||||
self.assertTrue("_Test Role 3" not in frappe.get_roles("test@example.com"))
|
||||
|
||||
frappe.get_doc("User", "test@example.com").add_roles("_Test Role 3")
|
||||
self.assertTrue("_Test Role 3" not in frappe.get_roles("test@example.com"))
|
||||
|
||||
|
||||
role = frappe.get_doc("Role", "_Test Role 3")
|
||||
role.disabled = 0
|
||||
role.save()
|
||||
|
||||
|
||||
frappe.get_doc("User", "test@example.com").add_roles("_Test Role 3")
|
||||
self.assertTrue("_Test Role 3" in frappe.get_roles("test@example.com"))
|
||||
|
||||
|
|
@ -38,7 +38,6 @@
|
|||
"mute_sounds",
|
||||
"change_password",
|
||||
"new_password",
|
||||
"send_password_update_notification",
|
||||
"logout_all_sessions",
|
||||
"reset_password_key",
|
||||
"last_password_reset_date",
|
||||
|
|
@ -299,13 +298,6 @@
|
|||
"label": "Set New Password",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "send_password_update_notification",
|
||||
"fieldtype": "Check",
|
||||
"label": "Send Password Update Notification"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "logout_all_sessions",
|
||||
|
|
@ -593,7 +585,7 @@
|
|||
"idx": 413,
|
||||
"image_field": "user_image",
|
||||
"max_attachments": 5,
|
||||
"modified": "2019-08-09 10:34:56.912283",
|
||||
"modified": "2019-09-18 14:14:01.233124",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "User",
|
||||
|
|
|
|||
|
|
@ -153,10 +153,6 @@ class User(Document):
|
|||
if new_password and not self.flags.in_insert:
|
||||
_update_password(user=self.name, pwd=new_password, logout_all_sessions=self.logout_all_sessions)
|
||||
|
||||
if self.send_password_update_notification and self.enabled:
|
||||
self.password_update_mail(new_password)
|
||||
frappe.msgprint(_("New password emailed"))
|
||||
|
||||
def set_system_user(self):
|
||||
'''Set as System User if any of the given roles has desk_access'''
|
||||
if self.has_desk_access() or self.name == 'Administrator':
|
||||
|
|
@ -250,10 +246,6 @@ class User(Document):
|
|||
self.send_login_mail(_("Password Reset"),
|
||||
"password_reset", {"link": link}, now=True)
|
||||
|
||||
def password_update_mail(self, password):
|
||||
self.send_login_mail(_("Password Update"),
|
||||
"password_update", {"new_password": password}, now=True)
|
||||
|
||||
def send_welcome_mail_to_user(self):
|
||||
from frappe.utils import get_url
|
||||
link = self.reset_password()
|
||||
|
|
|
|||
|
|
@ -607,7 +607,7 @@ class Database(object):
|
|||
"""Update multiple values. Alias for `set_value`."""
|
||||
return self.set_value(*args, **kwargs)
|
||||
|
||||
def set_value(self, dt, dn, field, val, modified=None, modified_by=None,
|
||||
def set_value(self, dt, dn, field, val=None, modified=None, modified_by=None,
|
||||
update_modified=True, debug=False):
|
||||
"""Set a single value in the database, do not call the ORM triggers
|
||||
but update the modified timestamp (unless specified not to).
|
||||
|
|
|
|||
|
|
@ -31,7 +31,14 @@ def runserverobj(method, docs=None, dt=None, dn=None, arg=None, args=None):
|
|||
except ValueError:
|
||||
args = args
|
||||
|
||||
fnargs, varargs, varkw, defaults = inspect.getargspec(getattr(doc, method))
|
||||
try:
|
||||
fnargs, varargs, varkw, defaults = inspect.getargspec(getattr(doc, method))
|
||||
except ValueError:
|
||||
fnargs = inspect.getfullargspec(getattr(doc, method)).args
|
||||
varargs = inspect.getfullargspec(getattr(doc, method)).varargs
|
||||
varkw = inspect.getfullargspec(getattr(doc, method)).varkw
|
||||
defaults = inspect.getfullargspec(getattr(doc, method)).defaults
|
||||
|
||||
if not fnargs or (len(fnargs)==1 and fnargs[0]=="self"):
|
||||
r = doc.run_method(method)
|
||||
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ def get_linked_doctypes(columns, data):
|
|||
for idx, col in enumerate(columns):
|
||||
df = columns_dict[idx]
|
||||
if df.get("fieldtype")=="Link":
|
||||
if isinstance(col, string_types):
|
||||
if data and isinstance(data[0], (list, tuple)):
|
||||
linked_doctypes[df["options"]] = idx
|
||||
else:
|
||||
# dict
|
||||
|
|
|
|||
|
|
@ -454,6 +454,18 @@ class BaseDocument(object):
|
|||
doctype = df.options
|
||||
if not doctype:
|
||||
frappe.throw(_("Options not set for link field {0}").format(df.fieldname))
|
||||
|
||||
meta = frappe.get_meta(doctype)
|
||||
if meta.has_field('disabled'):
|
||||
if not (
|
||||
frappe.flags.in_import
|
||||
or frappe.flags.in_migrate
|
||||
or frappe.flags.in_install
|
||||
or frappe.flags.in_patch
|
||||
):
|
||||
disabled = frappe.get_value(doctype, self.get(df.fieldname), 'disabled')
|
||||
if disabled:
|
||||
frappe.throw(_("{0} is disabled").format(frappe.bold(self.get(df.fieldname))))
|
||||
else:
|
||||
doctype = self.get(df.options)
|
||||
if not doctype:
|
||||
|
|
|
|||
|
|
@ -458,18 +458,6 @@ class DatabaseQuery(object):
|
|||
value = get_between_date_filter(f.value, df)
|
||||
fallback = "'0001-01-01 00:00:00'"
|
||||
|
||||
elif df and df.fieldtype=="Date":
|
||||
value = frappe.db.format_date(f.value)
|
||||
fallback = "'0001-01-01'"
|
||||
|
||||
elif (df and df.fieldtype=="Datetime") or isinstance(f.value, datetime):
|
||||
value = frappe.db.format_datetime(f.value)
|
||||
fallback = "'0001-01-01 00:00:00'"
|
||||
|
||||
elif df and df.fieldtype=="Time":
|
||||
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 = '!='
|
||||
|
|
@ -483,6 +471,18 @@ class DatabaseQuery(object):
|
|||
if 'ifnull' not in column_name:
|
||||
column_name = 'ifnull({}, {})'.format(column_name, fallback)
|
||||
|
||||
elif df and df.fieldtype=="Date":
|
||||
value = frappe.db.format_date(f.value)
|
||||
fallback = "'0001-01-01'"
|
||||
|
||||
elif (df and df.fieldtype=="Datetime") or isinstance(f.value, datetime):
|
||||
value = frappe.db.format_datetime(f.value)
|
||||
fallback = "'0001-01-01 00:00:00'"
|
||||
|
||||
elif df and df.fieldtype=="Time":
|
||||
value = get_time(f.value).strftime("%H:%M:%S.%f")
|
||||
fallback = "'00:00:00'"
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
|
|||
|
||||
delete_from_table(doctype, name, ignore_doctypes, None)
|
||||
|
||||
if not (frappe.flags.in_migrate or frappe.flags.in_install or frappe.flags.in_test):
|
||||
if not (for_reload or frappe.flags.in_migrate or frappe.flags.in_install or frappe.flags.in_test):
|
||||
try:
|
||||
delete_controllers(name, doc.module)
|
||||
except (FileNotFoundError, OSError):
|
||||
|
|
|
|||
|
|
@ -1232,6 +1232,18 @@ class Document(BaseDocument):
|
|||
frappe.bold(self.meta.get_label(from_date_field)),
|
||||
), frappe.exceptions.InvalidDates)
|
||||
|
||||
def get_assigned_users(self):
|
||||
assignments = frappe.get_all('ToDo',
|
||||
fields=['owner'],
|
||||
filters={
|
||||
'reference_type': self.doctype,
|
||||
'reference_name': self.name,
|
||||
'status': ('!=', 'Cancelled'),
|
||||
})
|
||||
|
||||
users = set([assignment.owner for assignment in assignments])
|
||||
return users
|
||||
|
||||
def execute_action(doctype, name, action, **kwargs):
|
||||
'''Execute an action on a document (called by background worker)'''
|
||||
doc = frappe.get_doc(doctype, name)
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ def sync_customizations_for_doctype(data, folder):
|
|||
custom_doctype, doctype_fieldname), doc_type)
|
||||
|
||||
for d in data[key]:
|
||||
_insert(data)
|
||||
_insert(d)
|
||||
|
||||
else:
|
||||
for d in data[key]:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import frappe
|
|||
import unittest
|
||||
from .energy_point_log import get_energy_points as _get_energy_points, create_review_points_log, review
|
||||
from frappe.utils.testutils import add_custom_field, clear_custom_fields
|
||||
from frappe.desk.form.assign_to import add as assign_to
|
||||
|
||||
class TestEnergyPointLog(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
|
|
@ -185,7 +186,31 @@ class TestEnergyPointLog(unittest.TestCase):
|
|||
self.assertEquals(points_after_todo_creation,
|
||||
points_before_todo_creation + todo_point_rule.points)
|
||||
|
||||
def create_energy_point_rule_for_todo(multiplier_field=None, for_doc_event='Custom', max_points=None):
|
||||
def test_point_allocation_for_assigned_users(self):
|
||||
todo = create_a_todo()
|
||||
|
||||
assign_users_to_todo(todo.name, ['test@example.com', 'test2@example.com'])
|
||||
|
||||
test_user_before_points = get_points('test@example.com')
|
||||
test2_user_before_points = get_points('test2@example.com')
|
||||
|
||||
rule = create_energy_point_rule_for_todo(for_assigned_users=1)
|
||||
|
||||
todo.status = 'Closed'
|
||||
todo.save()
|
||||
|
||||
test_user_after_points = get_points('test@example.com')
|
||||
test2_user_after_points = get_points('test2@example.com')
|
||||
|
||||
self.assertEquals(test_user_after_points,
|
||||
test_user_before_points + rule.points)
|
||||
|
||||
self.assertEquals(test2_user_after_points,
|
||||
test2_user_before_points + rule.points)
|
||||
|
||||
|
||||
def create_energy_point_rule_for_todo(multiplier_field=None, for_doc_event='Custom',
|
||||
max_points=None, for_assigned_users=0):
|
||||
name = 'ToDo Closed'
|
||||
point_rule = frappe.db.get_all(
|
||||
'Energy Point Rule',
|
||||
|
|
@ -204,6 +229,7 @@ def create_energy_point_rule_for_todo(multiplier_field=None, for_doc_event='Cust
|
|||
'condition': 'doc.status == "Closed"',
|
||||
'for_doc_event': for_doc_event,
|
||||
'user_field': 'owner',
|
||||
'for_assigned_users': for_assigned_users,
|
||||
'multiplier_field': multiplier_field,
|
||||
'max_points': max_points
|
||||
}).insert(ignore_permissions=1)
|
||||
|
|
@ -216,4 +242,12 @@ def create_a_todo():
|
|||
|
||||
|
||||
def get_points(user, point_type='energy_points'):
|
||||
return _get_energy_points(user).get(point_type) or 0
|
||||
return _get_energy_points(user).get(point_type) or 0
|
||||
|
||||
def assign_users_to_todo(todo_name, users):
|
||||
for user in users:
|
||||
assign_to({
|
||||
'assign_to': user,
|
||||
'doctype': 'ToDo',
|
||||
'name': todo_name
|
||||
})
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
"for_doc_event",
|
||||
"condition",
|
||||
"points",
|
||||
"for_assigned_users",
|
||||
"user_field",
|
||||
"multiplier_field",
|
||||
"max_points"
|
||||
|
|
@ -56,11 +57,11 @@
|
|||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.for_assigned_users || doc.for_doc_event==='New'",
|
||||
"description": "The user from this field will be rewarded points",
|
||||
"fieldname": "user_field",
|
||||
"fieldtype": "Select",
|
||||
"label": "User Field",
|
||||
"reqd": 1
|
||||
"label": "User Field"
|
||||
},
|
||||
{
|
||||
"fieldname": "multiplier_field",
|
||||
|
|
@ -69,7 +70,7 @@
|
|||
},
|
||||
{
|
||||
"depends_on": "eval:doc.multiplier_field",
|
||||
"description": "Maximum points allowed after multiplying points with the multiplier value\n(Note: For no limit set value as 0)",
|
||||
"description": "Maximum points allowed after multiplying points with the multiplier value\n(Note: For no limit leave this field empty or set 0)",
|
||||
"fieldname": "max_points",
|
||||
"fieldtype": "Int",
|
||||
"label": "Maximum Points"
|
||||
|
|
@ -84,9 +85,17 @@
|
|||
"fieldtype": "Select",
|
||||
"label": "For Document Event",
|
||||
"options": "New\nSubmit\nCancel\nCustom"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.for_doc_event !=='New'",
|
||||
"description": "Users assigned to the reference document will get points.",
|
||||
"fieldname": "for_assigned_users",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allot Points To Assigned Users"
|
||||
}
|
||||
],
|
||||
"modified": "2019-09-05 14:22:27.664645",
|
||||
"modified": "2019-09-20 11:26:26.101557",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Social",
|
||||
"name": "Energy Point Rule",
|
||||
|
|
|
|||
|
|
@ -31,21 +31,24 @@ class EnergyPointRule(Document):
|
|||
|
||||
reference_doctype = doc.doctype
|
||||
reference_name = doc.name
|
||||
user = doc.get(self.user_field)
|
||||
users = []
|
||||
if self.for_assigned_users:
|
||||
users = doc.get_assigned_users()
|
||||
else:
|
||||
users = [doc.get(self.user_field)]
|
||||
rule = self.name
|
||||
|
||||
# incase of zero as result after roundoff
|
||||
if not points: return
|
||||
|
||||
# if user_field has no value
|
||||
if not user or user == 'Administrator': return
|
||||
|
||||
try:
|
||||
create_energy_points_log(reference_doctype, reference_name, {
|
||||
'points': points,
|
||||
'user': user,
|
||||
'rule': rule
|
||||
})
|
||||
for user in users:
|
||||
if not user or user == 'Administrator': continue
|
||||
create_energy_points_log(reference_doctype, reference_name, {
|
||||
'points': points,
|
||||
'user': user,
|
||||
'rule': rule
|
||||
})
|
||||
except Exception as e:
|
||||
frappe.log_error(frappe.get_traceback(), 'apply_energy_point')
|
||||
|
||||
|
|
|
|||
|
|
@ -21,17 +21,21 @@ def allocate_review_points():
|
|||
settings.point_allocation_periodicity):
|
||||
return
|
||||
|
||||
user_point_map = {}
|
||||
|
||||
for level in settings.review_levels:
|
||||
create_review_points(level)
|
||||
users = get_users_with_role(level.role)
|
||||
for user in users:
|
||||
user_point_map.setdefault(user, 0)
|
||||
# to avoid duplicate point allocation
|
||||
user_point_map[user] = max([user_point_map[user], level.review_points])
|
||||
|
||||
for user, points in user_point_map.items():
|
||||
create_review_points_log(user, points)
|
||||
|
||||
settings.last_point_allocation_date = today()
|
||||
settings.save(ignore_permissions=True)
|
||||
|
||||
def create_review_points(level):
|
||||
users = get_users_with_role(level.role)
|
||||
for user in users:
|
||||
create_review_points_log(user, level.review_points)
|
||||
|
||||
def can_allocate_today(last_date, periodicity):
|
||||
if not last_date:
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
<p>{{_("Dear")}} {{ first_name }}{% if last_name %} {{ last_name}}{% endif %},</p>
|
||||
<p>{{_("Your password has been updated. Here is your new password")}}: <b>{{ new_password }}</b></p>
|
||||
<p>{{_("Thank you")}},<br>
|
||||
{{ user_fullname }}</p>
|
||||
|
|
@ -59,7 +59,7 @@ def get_email_address(user=None):
|
|||
if not user:
|
||||
user = frappe.session.user
|
||||
|
||||
return frappe.db.get_value("User", user, ["email"], as_dict=True).get("email")
|
||||
return frappe.db.get_value("User", user, "email")
|
||||
|
||||
def get_formatted_email(user):
|
||||
"""get Email Address of user formatted as: `John Doe <johndoe@example.com>`"""
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@
|
|||
<div class="login-content page-card" style="margin-top: 30px;">
|
||||
<form class="form-signin form-login" role="form">
|
||||
<div class="page-card-head">
|
||||
<span class="indicator blue" data-text="{{ _("Login") }}"></span>
|
||||
<span class="indicator blue" data-text="{{ _('Login') }}"></span>
|
||||
</div>
|
||||
|
||||
<input type="text" id="login_email"
|
||||
class="form-control"
|
||||
placeholder="{% if login_name_placeholder %}{{ login_name_placeholder }}{% else %}{{ _("Email address") }}{% endif %}"
|
||||
placeholder="{% if login_name_placeholder %}{{ login_name_placeholder }}{% else %}{{ _('Email Address') }}{% endif %}"
|
||||
required autofocus>
|
||||
|
||||
<div class="password-field" style="position: relative;">
|
||||
|
|
@ -66,12 +66,12 @@
|
|||
<div class="login-content page-card" style="margin-top: 20px;">
|
||||
<form class="form-signin form-signup hide" role="form">
|
||||
<div class="page-card-head">
|
||||
<span class="indicator blue" data-text="{{ _("Sign Up") }}"></span>
|
||||
<span class="indicator blue" data-text="{{ _('Sign Up') }}"></span>
|
||||
</div>
|
||||
<input type="text" id="signup_fullname"
|
||||
class="form-control" placeholder="{{ _('Full Name') }}" required autofocus>
|
||||
<input type="email" id="signup_email"
|
||||
class="form-control" placeholder="{{ _('Email address') }}" required>
|
||||
class="form-control" placeholder="{{ _('Email Address') }}" required>
|
||||
<button class="btn btn-sm btn-primary btn-block btn-signup" type="submit">{{ _("Sign up") }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -84,9 +84,9 @@
|
|||
<div class="login-content page-card" style="margin-top: 20px;">
|
||||
<form class="form-signin form-forgot hide" role="form">
|
||||
<div class="page-card-head">
|
||||
<span class="indicator blue" data-text="{{ _("Forgot Password") }}"></span></div>
|
||||
<span class="indicator blue" data-text="{{ _('Forgot Password') }}"></span></div>
|
||||
<input type="email" id="forgot_email"
|
||||
class="form-control" placeholder="{{ _('Email address') }}" required autofocus>
|
||||
class="form-control" placeholder="{{ _('Email Address') }}" required autofocus>
|
||||
<button class="btn btn-sm btn-primary btn-block btn-forgot" type="submit">{{ _("Reset Password") }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ def get_context(context):
|
|||
ldap_settings = LDAPSettings.get_ldap_client_settings()
|
||||
context["ldap_settings"] = ldap_settings
|
||||
|
||||
login_name_placeholder = [_("Email address")]
|
||||
login_name_placeholder = [_("Email Address")]
|
||||
|
||||
if frappe.utils.cint(frappe.get_system_settings("allow_login_using_mobile_number")):
|
||||
login_name_placeholder.append(_("Mobile number"))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue