[enhancement] bulk update tool!

This commit is contained in:
Rushabh Mehta 2016-07-15 16:28:20 +05:30
parent 058c95cbdd
commit db9ba845e5
11 changed files with 318 additions and 11 deletions

View file

@ -1180,6 +1180,17 @@ def attach_print(doctype, name, file_name=None, print_format=None, style=None, h
return out
def publish_progress(*args, **kwargs):
"""Show the user progress for a long request
:param percent: Percent progress
:param title: Title
:param doctype: Optional, for DocType
:param name: Optional, for Document name
"""
import frappe.async
return frappe.async.publish_progress(*args, **kwargs)
def publish_realtime(*args, **kwargs):
"""Publish real-time updates

View file

@ -86,6 +86,9 @@ def remove_old_task_logs():
def is_file_old(file_path):
return ((time.time() - os.stat(file_path).st_mtime) > TASK_LOG_MAX_AGE)
def publish_progress(percent, title=None, doctype=None, docname=None):
publish_realtime('progress', {'percent': percent, 'title': title},
user=frappe.session.user, doctype=doctype, docname=docname)
def publish_realtime(event=None, message=None, room=None,
user=None, doctype=None, docname=None, task_id=None,

View file

@ -36,7 +36,8 @@ def get_bootinfo():
load_desktop_icons(bootinfo)
bootinfo.module_app = frappe.local.module_app
bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where issingle=1""")
bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType
where issingle=1""")
add_home_page(bootinfo, doclist)
bootinfo.page_info = get_allowed_pages()
load_translations(bootinfo)

View file

@ -109,6 +109,13 @@ def get_data():
"description": _("Rename many items by uploading a .csv file."),
"hide_count": True
},
{
"type": "doctype",
"name": "Bulk Update",
"label": _("Bulk Update"),
"description": _("Update many values at one time."),
"hide_count": True
},
{
"type": "page",
"name": "backups",

View file

@ -0,0 +1,36 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bulk Update', {
refresh: function(frm) {
frm.page.set_primary_action(__('Update'), function() {
frappe.call({
method: 'frappe.desk.doctype.bulk_update.bulk_update.update',
args: {
doctype: frm.doc.document_type,
field: frm.doc.field,
value: frm.doc.update_value,
condition: frm.doc.condition,
limit: frm.doc.limit
},
callback: function() {
frappe.hide_progress();
}
});
});
},
document_type: function(frm) {
// set field options
frappe.model.with_doctype(frm.doc.document_type, function() {
var options = $.map(frappe.get_meta(frm.doc.document_type).fields,
function(d) {
if(d.fieldname && frappe.model.no_value_type.indexOf(d.fieldtype)===-1) {
return d.fieldname;
}
return null;
}
);
frm.set_df_property('field', 'options', options);
});
}
});

View file

@ -0,0 +1,187 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-07-15 05:51:29.224123",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "document_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Document Type",
"length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "field",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Field",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "update_value",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Update Value",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "SQL Conditions. Example: status=\"Open\"",
"fieldname": "condition",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Condition",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "500",
"description": "Max 500 records at a time",
"fieldname": "limit",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Limit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2016-07-15 06:24:42.575613",
"modified_by": "Administrator",
"module": "Desk",
"name": "Bulk Update",
"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": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View file

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
from frappe.utils import cint
class BulkUpdate(Document):
pass
@frappe.whitelist()
def update(doctype, field, value, condition='', limit=500):
if not limit or cint(limit) > 500:
limit = 500
if condition:
condition = ' where ' + condition
if ';' in condition:
frappe.throw('; not allowed in condition')
items = frappe.db.sql_list('select name from `tab{0}`{1} limit 0, {2}'.format(doctype,
condition, limit), debug=1)
n = len(items)
for i, d in enumerate(items):
doc = frappe.get_doc(doctype, d)
doc.set(field, value)
doc.save()
frappe.publish_progress(float(i)*100/n,
title = _('Updating Records'), doctype='Bulk Update', docname='Bulk Update')
# clear messages
frappe.local.message_log = []
frappe.msgprint(_('{0} records updated').format(n), title=_('Success'), indicator='green')

View file

@ -6,7 +6,7 @@ frappe.start_app = function() {
return;
frappe.assets.check();
frappe.provide('frappe.app');
$.extend(frappe.app, new frappe.Application());
frappe.app = new frappe.Application();
}
$(document).ready(function() {
@ -249,22 +249,28 @@ frappe.Application = Class.extend({
$('<link rel="icon" href="' + link + '" type="image/x-icon">').appendTo("head");
},
trigger_primary_action: function() {
if(cur_dialog) {
// trigger primary
cur_dialog.get_primary_btn().trigger("click");
} else if(cur_frm && cur_frm.page.btn_primary.is(':visible')) {
cur_frm.page.btn_primary.trigger('click');
} else if(frappe.container.page.save_action) {
frappe.container.page.save_action();
}
},
setup_keyboard_shortcuts: function() {
var me = this;
$(document)
.keydown("meta+g ctrl+g", function(e) {
$("#navbar-search").focus()
$("#navbar-search").focus();
return false;
})
.keydown("meta+s ctrl+s", function(e) {
e.preventDefault();
if(cur_dialog) {
// trigger primary
cur_dialog.get_primary_btn().trigger("click");
} else if(cur_frm && cur_frm.page.btn_primary.is(':visible')) {
cur_frm.page.btn_primary.trigger('click');
} else if(frappe.container.page.save_action) {
frappe.container.page.save_action();
}
me.trigger_primary_action();
return false;
})
.keydown("meta+b ctrl+b", function(e) {

View file

@ -421,6 +421,13 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
this.has_input = true;
this.bind_change_event();
this.bind_focusout();
// somehow this event does not bubble up to document
// after v7, if you can debug, remove this
this.$input.keydown("ctrl+s meta+s", function(e) {
e.preventDefault();
frappe.app && frappe.app.trigger_primary_action();
});
},
set_input_attributes: function() {
this.$input

View file

@ -31,6 +31,16 @@ frappe.socket = {
eval(message);
});
frappe.socket.socket.on('progress', function(data) {
if(data.percent) {
if(data.percent==100) {
frappe.hide_progress();
} else {
frappe.show_progress(data.title || __("Progress"), data.percent, 100);
}
}
});
frappe.socket.setup_listeners();
frappe.socket.setup_reconnect();