From 3c69a805219b48a1b76d88de9f82450263c3a31c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 28 Dec 2012 14:57:25 +0530 Subject: [PATCH] integrated workflow in form --- core/doctype/profile/profile.js | 2 +- core/doctype/workflow/workflow.js | 32 ++-- .../workflow_document_state.txt | 35 ++-- public/build.json | 1 + public/js/legacy/widgets/form/form.js | 51 +++--- public/js/legacy/wn/page_layout.js | 1 + public/js/wn/form/states.js | 168 ++++++++++++++++++ public/js/wn/misc/utils.js | 12 +- public/js/wn/model/meta.js | 7 +- 9 files changed, 264 insertions(+), 45 deletions(-) create mode 100644 public/js/wn/form/states.js diff --git a/core/doctype/profile/profile.js b/core/doctype/profile/profile.js index 137747f48f..37a1a0be73 100644 --- a/core/doctype/profile/profile.js +++ b/core/doctype/profile/profile.js @@ -68,7 +68,7 @@ wn.RoleEditor = Class.extend({ for(var i in this.roles) { $(this.wrapper).append(repl('
\ - \ + \ %(role)s\
', {role: this.roles[i]})); } diff --git a/core/doctype/workflow/workflow.js b/core/doctype/workflow/workflow.js index c0ec3f72f9..006b06eac8 100644 --- a/core/doctype/workflow/workflow.js +++ b/core/doctype/workflow/workflow.js @@ -3,17 +3,29 @@ wn.provide("wn.core") wn.core.Workflow = wn.ui.form.Controller.extend({ refresh: function(doc) { this.frm.set_intro(""); - if(doc.is_custom=="No" && !in_list(user_roles, 'Administrator')) { - // make the document read-only - this.frm.perm[0][WRITE] = 0; - - this.frm.set_intro('Standard Workflow editable by Administrator only. \ - To edit workflow, copy this and create a new Custom workflow for this Document Type') - } else { - if(doc.is_active) { - this.frm.set_intro("This Workflow is active."); - } + if(doc.is_active) { + this.frm.set_intro("This Workflow is active."); + } + this.load_document_type(doc); + }, + document_type: function(doc) { + this.load_document_type(doc); + }, + load_document_type: function(doc) { + var me = this; + if(!locals.DocType[doc.document_type]) { + wn.model.with_doctype(doc.document_type, function() { + me.update_field_options(); + }); } + }, + update_field_options: function() { + var fields = $.map(wn.model.get("DocField", { + parent: this.frm.doc.document_type, + fieldtype: ["not in", wn.model.no_value_type] + }), + function(d) { return d.fieldname; }); + wn.meta.get_docfield("Workflow Document State", "update_field").options = fields; } }); diff --git a/core/doctype/workflow_document_state/workflow_document_state.txt b/core/doctype/workflow_document_state/workflow_document_state.txt index 8d7d57c1bc..b9891bfd5f 100644 --- a/core/doctype/workflow_document_state/workflow_document_state.txt +++ b/core/doctype/workflow_document_state/workflow_document_state.txt @@ -4,7 +4,7 @@ "docstatus": 0, "creation": "2012-12-28 10:49:56", "modified_by": "Administrator", - "modified": "2012-12-28 11:37:31" + "modified": "2012-12-28 14:06:23" }, { "istable": 1, @@ -18,7 +18,6 @@ "name": "__common__", "parent": "Workflow Document State", "doctype": "DocField", - "width": "200px", "parenttype": "DocType", "permlevel": 0, "parentfield": "fields" @@ -30,29 +29,45 @@ { "doctype": "DocField", "label": "State", + "width": "160px", "fieldname": "state", "fieldtype": "Link", "reqd": 1, "options": "Workflow State" }, - { - "doctype": "DocField", - "label": "Allow Edit", - "fieldname": "allow_edit", - "fieldtype": "Link", - "reqd": 0, - "options": "Role" - }, { "doctype": "DocField", "label": "Doc Status", + "width": "80px", "fieldname": "doc_status", "fieldtype": "Select", "options": "0\n1\n2" }, + { + "doctype": "DocField", + "label": "Update Field", + "fieldname": "update_field", + "fieldtype": "Select" + }, + { + "doctype": "DocField", + "label": "Update Value", + "fieldname": "update_value", + "fieldtype": "Data" + }, + { + "doctype": "DocField", + "label": "Only Allow Edit For", + "width": "160px", + "fieldname": "allow_edit", + "fieldtype": "Link", + "reqd": 1, + "options": "Role" + }, { "doctype": "DocField", "label": "Message", + "width": "160px", "fieldname": "message", "fieldtype": "Text", "reqd": 0 diff --git a/public/build.json b/public/build.json index f94af0d8c9..04888f72cc 100644 --- a/public/build.json +++ b/public/build.json @@ -153,6 +153,7 @@ "lib/public/js/legacy/wn/widgets/form/assign_to.js", "lib/public/js/wn/form/attachments.js", "lib/public/js/wn/form/linked_with.js", + "lib/public/js/wn/form/states.js", "lib/public/js/wn/print/print_table.js", 'lib/public/js/lib/jquery/jquery.ui.interactions.min.js', diff --git a/public/js/legacy/widgets/form/form.js b/public/js/legacy/widgets/form/form.js index 9cc7a61b31..167669ca79 100644 --- a/public/js/legacy/widgets/form/form.js +++ b/public/js/legacy/widgets/form/form.js @@ -185,6 +185,11 @@ _f.Frm.prototype.setup_std_layout = function() { this.setup_sidebar(); } + // state + this.states = new wn.ui.form.States({ + frm: this + }); + // watermark $('
' @@ -805,34 +810,36 @@ _f.Frm.prototype.runclientscript = function(caller, cdt, cdn) { validated = false; console.log(e); } - if(caller && caller.toLowerCase()=='setup') { + this.setup_client_js(); + } + return ret; +} - var doctype = wn.model.get_doc('DocType', this.doctype); - - // js - var cs = doctype.__js || (doctype.client_script_core + doctype.client_script); - if(cs) { - try { - var tmp = eval(cs); - } catch(e) { - console.log(e); - } +_f.Frm.prototype.setup_client_js = function(caller, cdt, cdn) { + var doctype = wn.model.get_doc('DocType', this.doctype); + + // js + var cs = doctype.__js || (doctype.client_script_core + doctype.client_script); + if(cs) { + try { + var tmp = eval(cs); + } catch(e) { + console.log(e); } + } - // css - if(doctype.__css) set_style(doctype.__css) - - // ---Client String---- - if(doctype.client_string) { // split client string - this.cstring = {}; - var elist = doctype.client_string.split('---'); - for(var i=1;i\ +
\ + \ + \ +
\ +
').appendTo(this.frm.page_layout.body_header); + }, + + refresh: function() { + // hide if its not yet saved + if(this.frm.doc.__islocal) { + this.set_default_state(); + this.$wrapper.toggle(false); + return; + } + this.$wrapper.toggle(true); + + // state text + var state = this.get_state(); + + if(state) { + // show current state on the button + this.$wrapper.find(".state-text").text(state); + + var state_doc = wn.model.get("Workflow State", {name:state})[0]; + + // set the icon + this.$wrapper.find('.icon-small').removeClass() + .addClass("icon-small icon-white") + .addClass("icon-" + state_doc.icon); + + // set the style + this.$wrapper.find(".btn").removeClass() + .addClass("btn btn-small dropdown-toggle") + .addClass("btn-" + state_doc.style.toLowerCase()); + + // show actions from that state + this.show_actions(state); + + // disable if not allowed + } else { + this.$wrapper.toggle(false); + } + }, + + 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) { + if(in_list(user_roles, d.allowed)) { + d.icon = wn.model.get("Workflow State", {name:d.next_state})[0].icon; + + $(repl('
  • \ + %(action)s
  • ', d)) + .appendTo($ul); + } + }); + + // disable the button if user cannot change state + this.$wrapper.find('.btn').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); + } + }, + + get_state: function() { + if(!this.frm.doc[this.state_fieldname]) { + this.set_default_state(); + } + return this.frm.doc[this.state_fieldname]; + }, + + bind_action: function() { + 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; + + 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_docstatus = new_state.doc_status; + + // update field and value + if(new_state.update_field) { + me.frm.set_value(new_state.update_field, new_state.update_value); + } + + if(new_docstatus==1 && me.frm.doc.docstatus==0) { + me.frm.savesubmit(); + } else if(new_docstatus==0 && me.frm.doc.docstatus==0) { + me.frm.save(); + } else if(new_docstatus==1 && me.frm.doc.docstatus==1) { + me.frm.saveupdate(); + } else if(new_docstatus==2 && me.frm.doc.docstatus==1) { + me.frm.savecancel(); + } else { + msgprint("Docstatus transition from " + me.frm.doc.docstatus + " to" + + new_docstatus + " is not allowed."); + return; + } + + // hide dropdown + $(this).parents(".dropdown-menu").prev().dropdown('toggle'); + + return false; + }) + } +}); \ No newline at end of file diff --git a/public/js/wn/misc/utils.js b/public/js/wn/misc/utils.js index 1e3b479bb1..1f3a2d87c5 100644 --- a/public/js/wn/misc/utils.js +++ b/public/js/wn/misc/utils.js @@ -16,7 +16,17 @@ wn.utils = { } $.each(dict, function(i, d) { for(key in filters) { - if(d[key]!=filters[key]) return; + if($.isArray(filters[key])) { + if(filters[key][0]=="in") { + if(filters[key][1].indexOf(d[key])==-1) + return; + } else if(filters[key][0]=="not in") { + if(filters[key][1].indexOf(d[key])!=-1) + return; + } + } else { + if(d[key]!=filters[key]) return; + } } ret.push(d); }); diff --git a/public/js/wn/model/meta.js b/public/js/wn/model/meta.js index 0cbf497414..3527e6d3e3 100644 --- a/public/js/wn/model/meta.js +++ b/public/js/wn/model/meta.js @@ -104,5 +104,10 @@ $.extend(wn.meta, { $.extend(wn._messages, doc.__messages); } }, - + + 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