diff --git a/core/doctype/workflow/workflow.js b/core/doctype/workflow/workflow.js index 006b06eac8..dd207e84a2 100644 --- a/core/doctype/workflow/workflow.js +++ b/core/doctype/workflow/workflow.js @@ -25,7 +25,8 @@ wn.core.Workflow = wn.ui.form.Controller.extend({ fieldtype: ["not in", wn.model.no_value_type] }), function(d) { return d.fieldname; }); - wn.meta.get_docfield("Workflow Document State", "update_field").options = fields; + wn.meta.get_docfield("Workflow Document State", "update_field").options + = [""].concat(fields); } }); diff --git a/public/build.json b/public/build.json index fa914df27d..8fc1521ffe 100644 --- a/public/build.json +++ b/public/build.json @@ -94,6 +94,7 @@ "lib/public/js/wn/model/sync.js", "lib/public/js/wn/model/create_new.js", "lib/public/js/wn/model/perm.js", + "lib/public/js/wn/model/workflow.js", "lib/public/js/wn/misc/user.js", "lib/public/js/wn/misc/utils.js", diff --git a/public/js/legacy/widgets/form/fields.js b/public/js/legacy/widgets/form/fields.js index 265d216b06..3eed7c8220 100644 --- a/public/js/legacy/widgets/form/fields.js +++ b/public/js/legacy/widgets/form/fields.js @@ -125,9 +125,6 @@ Field.prototype.set_description = function(txt) { } } -// Field Refresh -// -------------------------------------------------------------------------------------------- - Field.prototype.get_status = function() { // if used in filters if(this.in_filter) @@ -143,39 +140,51 @@ Field.prototype.get_status = function() { var ret; // permission level - if(cur_frm.editable && p && p[WRITE] && !this.df.disabled)ret='Write'; - else if(p && p[READ])ret='Read'; - else ret='None'; - - // binary - if(this.df.fieldtype=='Binary') - ret = 'None'; // no display for binary + if(p && p[WRITE] && !this.df.disabled) + ret='Write'; + else if(p && p[READ]) + ret='Read'; + else + ret='None'; // hidden - if(cint(this.df.hidden)) + if(cint(this.df.hidden)) { ret = 'None'; + } // for submit - if(ret=='Write' && cint(cur_frm.doc.docstatus) > 0) ret = 'Read'; + if(ret=='Write' && cint(cur_frm.doc.docstatus) > 0) { + ret = 'Read'; + } // allow on submit var a_o_s = cint(this.df.allow_on_submit); - if(a_o_s && (this.in_grid || (this.frm && this.frm.not_in_container))) { + if(a_o_s && (this.in_grid || (this.frm && this.frm.meta.istable))) { + // if grid is allow-on-submit, everything in it is too! a_o_s = null; - if(this.in_grid) a_o_s = this.grid.field.df.allow_on_submit; // take from grid - if(this.frm && this.frm.not_in_container) { a_o_s = cur_grid.field.df.allow_on_submit;} // take from grid - } - - if(cur_frm.editable && a_o_s && cint(cur_frm.doc.docstatus)>0 && !this.df.hidden) { - tmp_perm = wn.perm.get_perm(cur_frm.doctype, cur_frm.docname, 1); - if(tmp_perm[this.df.permlevel] && tmp_perm[this.df.permlevel][WRITE]) { - ret='Write'; + if(this.in_grid) + a_o_s = this.grid.field.df.allow_on_submit; + if(this.frm.meta.istable) { + a_o_s = cur_grid.field.df.allow_on_submit; } } - // make a field read_only if read_only is checked (disregards write permission) - if(cint(this.df.read_only) && ret=="Write") ret = "Read"; + if(ret=="Read" && a_o_s && cint(cur_frm.doc.docstatus)==1 && + cur_frm.perm[this.df.permlevel][WRITE]) { + ret='Write'; + } + + // workflow state + if(ret=="Write" && cur_frm.read_only) { + ret = 'Read'; + } + + // make a field read_only if read_only + // is checked (disregards write permission) + if(ret=="Write" && cint(this.df.read_only)) { + ret = "Read"; + } return ret; } diff --git a/public/js/legacy/widgets/form/form.js b/public/js/legacy/widgets/form/form.js index 189d6689d0..bda3728ccf 100644 --- a/public/js/legacy/widgets/form/form.js +++ b/public/js/legacy/widgets/form/form.js @@ -56,7 +56,7 @@ _f.Frm = function(doctype, parent, in_form) { this.refresh_if_stale_for = 600; var me = this; - this.is_editable = {}; + this.last_view_is_edit = {}; this.opendocs = {}; this.sections = []; this.grids = []; @@ -254,9 +254,9 @@ _f.Frm.prototype.rename_notify = function(dt, old, name) { else return; - // editable - this.is_editable[name] = this.is_editable[old]; - delete this.is_editable[old]; + // view_is_edit + this.last_view_is_edit[name] = this.last_view_is_edit[old]; + delete this.last_view_is_edit[old]; // cleanup if(this && this.opendocs[old]) { @@ -458,16 +458,8 @@ _f.Frm.prototype.check_doc_perm = function() { var dt = this.parent_doctype?this.parent_doctype : this.doctype; var dn = this.parent_docname?this.parent_docname : this.docname; this.perm = wn.perm.get_perm(dt, dn); - this.orig_perm = wn.perm.get_perm(dt, dn, 1); if(!this.perm[0][READ]) { - if(user=='Guest') { - // allow temp access? via encryted akey - if(_f.temp_access[dt] && _f.temp_access[dt][dn]) { - this.perm = [[1,0,0]] - return 1; - } - } window.history.back(); return 0; } @@ -492,6 +484,9 @@ _f.Frm.prototype.refresh = function(docname) { // check permissions if(!this.check_doc_perm()) return; + // read only (workflow) + this.read_only = wn.workflow.is_read_only(this.doctype, this.docname); + // set the doc this.doc = wn.model.get_doc(this.doctype, this.docname); @@ -519,20 +514,20 @@ _f.Frm.prototype.refresh = function(docname) { this.setnewdoc(this.docname); } - // editable + // view_is_edit if(this.doc.__islocal) - this.is_editable[this.docname] = 1; // new is editable + this.last_view_is_edit[this.docname] = 1; // new is view_is_edit - this.editable = this.is_editable[this.docname]; + this.view_is_edit = this.last_view_is_edit[this.docname]; - if(this.editable || (!this.editable && this.meta.istable)) { - // show form layout (with fields etc) - // ---------------------------------- + if(this.view_is_edit || (!this.view_is_edit && this.meta.istable)) { if(this.print_wrapper) { $dh(this.print_wrapper); $ds(this.page_layout.wrapper); } + + // header if(!this.meta.istable) { this.refresh_header(); @@ -570,8 +565,6 @@ _f.Frm.prototype.refresh = function(docname) { } } else { - // show print layout - // ---------------------------------- this.refresh_header(); if(this.print_wrapper) { this.refresh_print_layout(); @@ -586,9 +579,10 @@ _f.Frm.prototype.refresh = function(docname) { _f.Frm.prototype.refresh_footer = function() { var f = this.page_layout.footer; if(f.save_area) { - if(this.editable && (!this.meta.hide_toolbar) && (!this.meta.in_dialog || this.in_form) - && this.doc.docstatus==0 && !this.meta.istable && this.perm[0][WRITE] - && (this.fields && this.fields.length > 7) && !this.save_disabled) { + // if save button is there in the header + if(this.frm_head && this.frm_head.appframe.toolbar + && this.frm_head.appframe.toolbar.find(".btn-save").length && !this.save_disabled + && (this.fields && this.fields.length > 7)) { f.show_save(); } else { f.hide_save(); @@ -729,15 +723,15 @@ _f.Frm.prototype.setnewdoc = function(docname) { // Client Script this.runclientscript('onload', this.doctype, this.docname); - this.is_editable[docname] = 1; - if(cint(this.meta.read_only_onload)) this.is_editable[docname] = 0; + this.last_view_is_edit[docname] = 1; + if(cint(this.meta.read_only_onload)) this.last_view_is_edit[docname] = 0; this.opendocs[docname] = true; } _f.Frm.prototype.edit_doc = function() { // set fields - this.is_editable[this.docname] = true; + this.last_view_is_edit[this.docname] = true; this.refresh(); } @@ -996,7 +990,8 @@ _f.Frm.prototype.set_value_in_locals = function(dt, dn, fn, v) { } _f.Frm.prototype.set_unsaved = function() { - if(cur_frm.doc.__unsaved) return; + if(cur_frm.doc.__unsaved) + return; cur_frm.doc.__unsaved = 1; var frm_head; diff --git a/public/js/legacy/widgets/form/form_fields.js b/public/js/legacy/widgets/form/form_fields.js index 0ae7e88b53..4c1d5a6b28 100644 --- a/public/js/legacy/widgets/form/form_fields.js +++ b/public/js/legacy/widgets/form/form_fields.js @@ -207,29 +207,13 @@ _f.TableField.prototype.refresh = function() { this.df['default']=''; this.grid.can_add_rows = false; - this.grid.can_edit = false + this.grid.can_edit = false; + if(st=='Write') { - if(cur_frm.editable && this.perm[this.df.permlevel] && this.perm[this.df.permlevel][WRITE]) { - this.grid.can_edit = true; - if(this.df['default'].toLowerCase()!='no toolbar') - this.grid.can_add_rows = true; - } + this.grid.can_edit = true; + if(this.df['default'].toLowerCase()!='no toolbar') + this.grid.can_add_rows = true; - // submitted or cancelled - if(cur_frm.editable && cur_frm.doc.docstatus > 0) { - if(this.df.allow_on_submit && cur_frm.doc.docstatus==1) { - this.grid.can_edit = true; - if(this.df['default'].toLowerCase()=='no toolbar') { - this.grid.can_add_rows = false; - } else { - this.grid.can_add_rows = true; - } - } else { - this.grid.can_add_rows = false; - this.grid.can_edit = false; - } - } - if(this.df['default'].toLowerCase()=='no add rows') { this.grid.can_add_rows = false; } diff --git a/public/js/legacy/widgets/form/form_header.js b/public/js/legacy/widgets/form/form_header.js index fd8c7b7e6a..1fe8b34b17 100644 --- a/public/js/legacy/widgets/form/form_header.js +++ b/public/js/legacy/widgets/form/form_header.js @@ -109,6 +109,8 @@ _f.FrmHeader = Class.extend({ cur_frm.save('Update', null, this); }, '') } + + this.set_primary_button(); }, set_label: function(labinfo) { this.$w.find('.label').remove(); @@ -133,23 +135,19 @@ _f.FrmHeader = Class.extend({ // Edit if(cur_frm.meta.read_only_onload && !cur_frm.doc.__islocal) { - if(!cur_frm.editable) - this.appframe.add_button('Edit', function() { - cur_frm.edit_doc(); - },'icon-pencil'); - else - this.appframe.add_button('Print View', function() { - cur_frm.is_editable[cur_frm.docname] = 0; - cur_frm.refresh(); }, 'icon-print' ); + this.appframe.add_button('Print View', function() { + cur_frm.last_view_is_edit[cur_frm.docname] = 0; + cur_frm.refresh(); }, 'icon-print' ); } var docstatus = cint(cur_frm.doc.docstatus); + // Save - if(docstatus==0 && p[WRITE]) { + if(docstatus==0 && p[WRITE] && !cur_frm.read_only) { this.appframe.add_button('Save', function() { cur_frm.save('Save', null, this);}, 'icon-save'); - this.appframe.buttons['Save'].addClass('btn-info') - .html(" Save (Ctrl+S)"); + this.appframe.buttons['Save'].addClass("btn-save") + .html(" Save"); } // Submit @@ -168,11 +166,29 @@ _f.FrmHeader = Class.extend({ this.appframe.add_button('Amend', function() { cur_frm.amend_doc() }, 'icon-pencil'); } + this.set_primary_button(); }, - show: function() { - }, - hide: function() { - + set_primary_button: function() { + if(!this.appframe.toolbar) + return; + + var buttons = this.appframe.buttons; + + // highlight save + this.appframe.toolbar.find("button").removeClass("btn-info"); + if(buttons["Save"]) { + buttons["Save"].addClass("btn-info"); + } + + // highlight submit button + if(buttons["Submit"] && !cur_frm.doc.__unsaved) { + this.appframe.toolbar.find("button").removeClass("btn-info"); + buttons["Submit"].addClass("btn-info"); + // highlight update button + } else if(buttons["Update"] && cur_frm.doc.__unsaved) { + this.appframe.toolbar.find("button").removeClass("btn-info"); + buttons["Update"].addClass("btn-info"); + } }, hide_close: function() { this.$w.find('.close').toggle(false); diff --git a/public/js/legacy/widgets/form/grid.js b/public/js/legacy/widgets/form/grid.js index 2268285dbf..d8f35aaa33 100644 --- a/public/js/legacy/widgets/form/grid.js +++ b/public/js/legacy/widgets/form/grid.js @@ -250,7 +250,7 @@ _f.Grid.prototype.set_cell_value = function(cell) { $y($td(t,0,0),{paddingLeft:'4px'}); $td(t,0,0).innerHTML = cell.row.rowIndex + 1; - if(cur_frm.editable && this.can_edit) { + if(this.can_edit) { $("") .click(function() { _f.cur_grid = me; diff --git a/public/js/wn/form/states.js b/public/js/wn/form/states.js index e822c9e4d2..42c01807a0 100644 --- a/public/js/wn/form/states.js +++ b/public/js/wn/form/states.js @@ -23,7 +23,12 @@ wn.ui.form.States = Class.extend({ init: function(opts) { $.extend(this, opts); - this.state_fieldname = wn.meta.get_state_fieldname(this.frm.doctype); + this.state_fieldname = wn.workflow.get_state_fieldname(this.frm.doctype); + + // no workflow? + if(!this.state_fieldname) + return; + this.make(); this.bind_action(); @@ -37,20 +42,47 @@ wn.ui.form.States = Class.extend({ this.$wrapper = $('
\
\ \ + \ + \ \
\ + \
').appendTo(this.frm.page_layout.body_header); this.$wrapper.toggle(false); + this.setup_help(); }, - + + setup_help: function() { + var me = this; + this.$wrapper.find(".btn-help").click(function() { + wn.workflow.setup(me.frm.doctype); + var state = me.get_state(); + var d = new wn.ui.Dialog({ + title: "Workflow: " + + wn.workflow.workflows[me.frm.doctype].name + }) + var next_html = $.map(wn.workflow.get_transitions(me.frm.doctype, state), + function(d) { + return d.action.bold() + " by Role " + d.allowed; + }).join(", ") || "None: End of Workflow".bold(); + + $(d.body).html("

Current status: " + state.bold() + "

" + + "

Document is only editable by users of role: " + wn.workflow.get_document_state(me.frm.doctype, + state).allow_edit.bold() + "

" + + "

Next actions: "+ next_html +"

" + + (me.frm.doc.__islocal ? "
Workflow will start after saving
" : "") + + "

Note: Other permission rules may also apply

" + ).css({padding: '15px'}); + d.show(); + }); + }, + refresh: function() { // hide if its not yet saved this.$wrapper.toggle(false); if(this.frm.doc.__islocal) { this.set_default_state(); - return; } // state text @@ -68,26 +100,25 @@ wn.ui.form.States = Class.extend({ .addClass("icon-" + state_doc.icon); // set the style - this.$wrapper.find(".btn").removeClass() + this.$wrapper.find(".btn:first").removeClass() .addClass("btn dropdown-toggle") .addClass("btn-" + state_doc.style.toLowerCase()); // show actions from that state this.show_actions(state); - // disable if not allowed - if(!this.frm.doc.__islocal) - this.$wrapper.toggle(true); + this.$wrapper.toggle(true); + if(this.frm.doc.__islocal) { + this.$wrapper.find('.btn:first').attr('disabled', true); + } } }, show_actions: function(state) { var $ul = this.$wrapper.find("ul"); $ul.empty(); - $.each(wn.model.get("Workflow Transition", { - parent: this.frm.doctype, - state: state, - }), function(i, d) { + + $.each(wn.workflow.get_transitions(this.frm.doctype, state), function(i, d) { if(in_list(user_roles, d.allowed)) { d.icon = wn.model.get("Workflow State", {name:d.next_state})[0].icon; @@ -96,21 +127,16 @@ wn.ui.form.States = Class.extend({ .appendTo($ul); } }); - + // disable the button if user cannot change state - this.$wrapper.find('.btn').attr('disabled', $ul.find("li").length ? false : true); + this.$wrapper.find('.btn:first') + .attr('disabled', $ul.find("li").length ? false : true); }, set_default_state: function() { - var d = wn.model.get("Workflow Document State", { - parent: this.frm.doctype, - idx: 1 - }); - - if(d && d.length) { - this.frm.set_value_in_locals(this.frm.doctype, this.frm.docname, - this.state_fieldname, d[0].state); - refresh_field(this.state_fieldname); + var default_state = wn.workflow.get_default_state(this.frm.doctype); + if(default_state) { + this.frm.set_value(this.state_fieldname, default_state); } }, @@ -125,19 +151,12 @@ wn.ui.form.States = Class.extend({ var me = this; $(this.$wrapper).on("click", "[data-action]", function() { var action = $(this).attr("data-action"); - var next_state = wn.model.get("Workflow Transition", { - parent: me.frm.doctype, - state: me.frm.doc[me.state_fieldname], - action: action, - })[0].next_state; + var next_state = wn.workflow.get_next_state(me.frm.doc, + me.frm.doc[me.state_fieldname], action); me.frm.doc[me.state_fieldname] = next_state; - var new_state = wn.model.get("Workflow Document State", { - parent: me.frm.doctype, - state: next_state - })[0]; - + var new_state = wn.workflow.get_document_state(me.frm.doctype, next_state); var new_docstatus = new_state.doc_status; // update field and value diff --git a/public/js/wn/model/meta.js b/public/js/wn/model/meta.js index 3527e6d3e3..53635dccba 100644 --- a/public/js/wn/model/meta.js +++ b/public/js/wn/model/meta.js @@ -105,9 +105,4 @@ $.extend(wn.meta, { } }, - get_state_fieldname: function(doctype) { - var wf = wn.model.get("Workflow", {document_type: doctype}); - return wf.length ? wf[0].workflow_state_field : null; - }, - }); \ No newline at end of file diff --git a/public/js/wn/model/perm.js b/public/js/wn/model/perm.js index 47ab763017..dac3917b2e 100644 --- a/public/js/wn/model/perm.js +++ b/public/js/wn/model/perm.js @@ -40,7 +40,7 @@ $.extend(wn.perm, { return perms[doctype][level][type]; }, - get_perm: function(doctype, dn, ignore_submit) { + get_perm: function(doctype, dn) { var perm = [[0,0],]; if(in_list(user_roles, 'Administrator')) perm[0][READ] = 1;