Merge pull request #9957 from hrwX/multiple_assignments

This commit is contained in:
Chinmay Pai 2020-05-18 18:26:12 +05:30 committed by GitHub
commit 38ffe0d016
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 178 additions and 124 deletions

View file

@ -44,7 +44,7 @@ class AssignmentRule(Document):
user = self.get_user()
assign_to.add(dict(
assign_to = user,
assign_to = [user],
doctype = doc.get('doctype'),
name = doc.get('name'),
description = frappe.render_template(self.description, doc),

View file

@ -71,7 +71,7 @@ class TestEvent(unittest.TestCase):
ev = frappe.get_doc(self.test_records[0]).insert()
add({
"assign_to": "test@example.com",
"assign_to": ["test@example.com"],
"doctype": "Event",
"name": ev.name,
"description": "Test Assignment"
@ -83,7 +83,7 @@ class TestEvent(unittest.TestCase):
# add another one
add({
"assign_to": self.test_user,
"assign_to": [self.test_user],
"doctype": "Event",
"name": ev.name,
"description": "Test Assignment"

View file

@ -13,7 +13,7 @@ class TestNotificationLog(unittest.TestCase):
user = get_user()
assign_task({
"assign_to": user,
"assign_to": [user],
"doctype": 'ToDo',
"name": todo.name,
"description": todo.description

View file

@ -11,6 +11,7 @@ from frappe.desk.doctype.notification_log.notification_log import enqueue_create
get_title, get_title_html
import frappe.utils
import frappe.share
import json
class DuplicateToDoError(frappe.ValidationError): pass
@ -19,17 +20,17 @@ def get(args=None):
if not args:
args = frappe.local.form_dict
return frappe.get_all('ToDo', fields = ['owner', 'description'], filters = dict(
return frappe.get_all('ToDo', fields=['owner', 'name'], filters=dict(
reference_type = args.get('doctype'),
reference_name = args.get('name'),
status = ('!=', 'Cancelled')
), limit = 5)
), limit=5)
@frappe.whitelist()
def add(args=None):
"""add in someone's to do list
args = {
"assign_to": ,
"assign_to": [],
"doctype": ,
"name": ,
"description": ,
@ -40,56 +41,68 @@ def add(args=None):
if not args:
args = frappe.local.form_dict
if frappe.db.sql("""SELECT `owner`
FROM `tabToDo`
WHERE `reference_type`=%(doctype)s
AND `reference_name`=%(name)s
AND `status`='Open'
AND `owner`=%(assign_to)s""", args):
frappe.throw(_("Already in user's To Do list"), DuplicateToDoError)
else:
from frappe.utils import nowdate
users_with_duplicate_todo = []
shared_with_users = []
if not args.get('description'):
args['description'] = _('Assignment for {0} {1}').format(args['doctype'], args['name'])
d = frappe.get_doc({
"doctype":"ToDo",
"owner": args['assign_to'],
for assign_to in frappe.parse_json(args.get("assign_to")):
filters = {
"reference_type": args['doctype'],
"reference_name": args['name'],
"description": args.get('description'),
"priority": args.get("priority", "Medium"),
"status": "Open",
"date": args.get('date', nowdate()),
"assigned_by": args.get('assigned_by', frappe.session.user),
'assignment_rule': args.get('assignment_rule')
}).insert(ignore_permissions=True)
"owner": assign_to
}
# set assigned_to if field exists
if frappe.get_meta(args['doctype']).get_field("assigned_to"):
frappe.db.set_value(args['doctype'], args['name'], "assigned_to", args['assign_to'])
if frappe.get_all("ToDo", filters=filters):
users_with_duplicate_todo.append(assign_to)
else:
from frappe.utils import nowdate
doc = frappe.get_doc(args['doctype'], args['name'])
if not args.get('description'):
args['description'] = _('Assignment for {0} {1}').format(args['doctype'], args['name'])
# if assignee does not have permissions, share
if not frappe.has_permission(doc=doc, user=args['assign_to']):
frappe.share.add(doc.doctype, doc.name, args['assign_to'])
frappe.msgprint(_('Shared with user {0} with read access').format(args['assign_to']), alert=True)
d = frappe.get_doc({
"doctype": "ToDo",
"owner": assign_to,
"reference_type": args['doctype'],
"reference_name": args['name'],
"description": args.get('description'),
"priority": args.get("priority", "Medium"),
"status": "Open",
"date": args.get('date', nowdate()),
"assigned_by": args.get('assigned_by', frappe.session.user),
'assignment_rule': args.get('assignment_rule')
}).insert(ignore_permissions=True)
# make this document followed by assigned user
follow_document(args['doctype'], args['name'], args['assign_to'])
# set assigned_to if field exists
if frappe.get_meta(args['doctype']).get_field("assigned_to"):
frappe.db.set_value(args['doctype'], args['name'], "assigned_to", assign_to)
# notify
notify_assignment(d.assigned_by, d.owner, d.reference_type, d.reference_name, action='ASSIGN',\
description=args.get("description"))
doc = frappe.get_doc(args['doctype'], args['name'])
# if assignee does not have permissions, share
if not frappe.has_permission(doc=doc, user=assign_to):
frappe.share.add(doc.doctype, doc.name, assign_to)
shared_with_users.append(assign_to)
# make this document followed by assigned user
follow_document(args['doctype'], args['name'], assign_to)
# notify
notify_assignment(d.assigned_by, d.owner, d.reference_type, d.reference_name, action='ASSIGN',
description=args.get("description"))
if shared_with_users:
user_list = format_message_for_assign_to(shared_with_users)
frappe.msgprint(_("Shared with the following Users with Read access:{0}").format(user_list, alert=True))
if users_with_duplicate_todo:
user_list = format_message_for_assign_to(users_with_duplicate_todo)
frappe.msgprint(_("Already in the following Users ToDo list:{0}").format(user_list, alert=True))
return get(args)
@frappe.whitelist()
def add_multiple(args=None):
import json
if not args:
args = frappe.local.form_dict
@ -183,3 +196,5 @@ def notify_assignment(assigned_by, owner, doc_type, doc_name, action='CLOSE',
enqueue_create_notification(owner, notification_doc)
def format_message_for_assign_to(users):
return "<br><br>" + "<br>".join(users)

View file

@ -87,23 +87,17 @@ frappe.ui.form.AssignTo = Class.extend({
if(!me.assign_to) {
me.assign_to = new frappe.ui.form.AssignToDialog({
obj: me,
method: 'frappe.desk.form.assign_to.add',
method: "frappe.desk.form.assign_to.add",
doctype: me.frm.doctype,
docname: me.frm.docname,
callback: function(r) {
frm: me.frm,
callback: function (r) {
me.render(r.message);
}
});
}
me.assign_to.dialog.clear();
if(me.frm.meta.title_field) {
me.assign_to.dialog.set_value("description", me.frm.doc[me.frm.meta.title_field])
}
me.assign_to.dialog.show();
me.assign_to = null;
},
remove: function(owner) {
var me = this;
@ -130,81 +124,126 @@ frappe.ui.form.AssignTo = Class.extend({
frappe.ui.form.AssignToDialog = Class.extend({
init: function(opts){
var me = this
var dialog = new frappe.ui.Dialog({
title: __('Add to To Do'),
fields: [
{ fieldtype: 'Link', fieldname: 'assign_to', options: 'User', label: __("Assign To"), reqd: true, filters: { 'user_type': 'System User' }},
{ fieldtype: 'Check', fieldname: 'myself', label: __("Assign to me"), "default": 0 },
{ fieldtype: 'Small Text', fieldname: 'description', label: __("Comment") },
{ fieldtype: 'Section Break' },
{ fieldtype: 'Column Break' },
{ fieldtype: 'Date', fieldname: 'date', label: __("Complete By") },
{ fieldtype: 'Column Break' },
{ fieldtype: 'Select', fieldname: 'priority', label: __("Priority"),
options: [
{ value: 'Low', label: __('Low') },
{ value: 'Medium', label: __('Medium') },
{ value: 'High', label: __('High') }
],
// Pick up priority from the source document, if it exists and is available in ToDo
'default': ["Low", "Medium", "High"].includes(opts.obj.frm && opts.obj.frm.doc.priority
? opts.obj.frm.doc.priority : 'Medium')
},
],
primary_action: function() { frappe.ui.add_assignment(opts, this) },
primary_action_label: __("Add")
})
$.extend(me, dialog);
$.extend(this, opts);
me.dialog = dialog;
me.dialog.fields_dict.assign_to.get_query = "frappe.core.doctype.user.user.user_query";
var myself = me.dialog.get_input("myself").on("click", function() {
me.toggle_myself(this);
});
me.toggle_myself(myself);
},
toggle_myself: function(myself) {
var me = this;
if($(myself).prop("checked")) {
me.dialog.set_value("assign_to", frappe.session.user);
me.dialog.get_field("notify").$wrapper.toggle(false);
me.dialog.get_field("assign_to").$wrapper.toggle(false);
} else {
me.dialog.set_value("assign_to", "");
me.dialog.get_field("assign_to").$wrapper.toggle(true);
}
this.make();
this.set_description_from_doc();
},
make: function() {
let me = this;
});
me.dialog = new frappe.ui.Dialog({
title: __('Add to ToDo'),
fields: me.get_fields(),
primary_action_label: __("Add"),
primary_action: function() {
let args = me.dialog.get_values();
frappe.ui.add_assignment = function(opts, dialog) {
var assign_to = dialog.fields_dict.assign_to.get_value();
var args = dialog.get_values();
if(args && assign_to) {
dialog.set_message('Assigning...');
return frappe.call({
method: opts.method,
args: $.extend(args, {
doctype: opts.doctype,
name: opts.docname,
assign_to: assign_to,
bulk_assign: opts.bulk_assign || false,
re_assign: opts.re_assign || false
}),
btn: dialog.get_primary_btn(),
callback: function(r) {
if(!r.exc) {
if(opts.callback){
opts.callback(r);
}
dialog && dialog.hide();
} else {
dialog.clear_message();
if (args && args.assign_to) {
me.dialog.set_message("Assigning...");
frappe.call({
method: me.method,
args: $.extend(args, {
doctype: me.doctype,
name: me.docname,
assign_to: args.assign_to,
bulk_assign: me.bulk_assign || false,
re_assign: me.re_assign || false
}),
btn: me.dialog.get_primary_btn(),
callback: function(r) {
if (!r.exc) {
if (me.callback) {
me.callback(r);
}
me.dialog && me.dialog.hide();
} else {
me.dialog.clear_message();
}
},
});
}
},
});
},
assign_to_me: function() {
let me = this;
let assign_to = [];
if (me.dialog.get_value("assign_to_me")) {
assign_to.push(frappe.session.user);
}
me.dialog.set_value("assign_to", assign_to);
},
set_description_from_doc: function() {
let me = this;
if (me.frm && me.frm.meta.title_field) {
me.dialog.set_value("description", me.frm.doc[me.frm.meta.title_field]);
}
},
get_fields: function() {
let me = this;
return [
{
fieldtype: 'MultiSelectPills',
fieldname: 'assign_to',
label: __("Assign To"),
reqd: true,
get_data: function(txt) {
return frappe.db.get_link_options("User", txt, {user_type: "System User", enabled: 1});
}
},
{
label: __("Assign to me"),
fieldtype: 'Check',
fieldname: 'assign_to_me',
default: 0,
onchange: () => me.assign_to_me()
},
{
label: __("Comment"),
fieldtype: 'Small Text',
fieldname: 'description'
},
{
fieldtype: 'Section Break'
},
{
fieldtype: 'Column Break'
},
{
label: __("Complete By"),
fieldtype: 'Date',
fieldname: 'date'
},
{
fieldtype: 'Column Break'
},
{
label: __("Priority"),
fieldtype: 'Select',
fieldname: 'priority',
options: [
{
value: 'Low',
label: __('Low')
},
{
value: 'Medium',
label: __('Medium')
},
{
value: 'High',
label: __('High')
}
],
// Pick up priority from the source document, if it exists and is available in ToDo
default: ["Low", "Medium", "High"].includes(me.frm && me.frm.doc.priority ? me.frm.doc.priority : 'Medium')
}
];
}
}
});

View file

@ -306,7 +306,7 @@ def get_points(user, point_type='energy_points'):
def assign_users_to_todo(todo_name, users):
for user in users:
assign_to({
'assign_to': user,
'assign_to': [user],
'doctype': 'ToDo',
'name': todo_name
})

View file

@ -60,7 +60,7 @@ class TestAssign(unittest.TestCase):
def assign(doc, user):
return frappe.desk.form.assign_to.add({
"assign_to": user,
"assign_to": [user],
"doctype": doc.doctype,
"name": doc.name,
"description": 'test',