@@ -68,7 +68,7 @@ wn.RoleEditor = Class.extend({ | |||||
for(var i in this.roles) { | for(var i in this.roles) { | ||||
$(this.wrapper).append(repl('<div class="user-role" \ | $(this.wrapper).append(repl('<div class="user-role" \ | ||||
data-user-role="%(role)s">\ | data-user-role="%(role)s">\ | ||||
<input type="checkbox"> \ | |||||
<input type="checkbox" style="margin-top:0px;"> \ | |||||
<a href="#">%(role)s</a>\ | <a href="#">%(role)s</a>\ | ||||
</div>', {role: this.roles[i]})); | </div>', {role: this.roles[i]})); | ||||
} | } | ||||
@@ -3,17 +3,29 @@ wn.provide("wn.core") | |||||
wn.core.Workflow = wn.ui.form.Controller.extend({ | wn.core.Workflow = wn.ui.form.Controller.extend({ | ||||
refresh: function(doc) { | refresh: function(doc) { | ||||
this.frm.set_intro(""); | 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; | |||||
} | } | ||||
}); | }); | ||||
@@ -4,7 +4,7 @@ | |||||
"docstatus": 0, | "docstatus": 0, | ||||
"creation": "2012-12-28 10:49:56", | "creation": "2012-12-28 10:49:56", | ||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"modified": "2012-12-28 11:37:31" | |||||
"modified": "2012-12-28 14:06:23" | |||||
}, | }, | ||||
{ | { | ||||
"istable": 1, | "istable": 1, | ||||
@@ -18,7 +18,6 @@ | |||||
"name": "__common__", | "name": "__common__", | ||||
"parent": "Workflow Document State", | "parent": "Workflow Document State", | ||||
"doctype": "DocField", | "doctype": "DocField", | ||||
"width": "200px", | |||||
"parenttype": "DocType", | "parenttype": "DocType", | ||||
"permlevel": 0, | "permlevel": 0, | ||||
"parentfield": "fields" | "parentfield": "fields" | ||||
@@ -30,29 +29,45 @@ | |||||
{ | { | ||||
"doctype": "DocField", | "doctype": "DocField", | ||||
"label": "State", | "label": "State", | ||||
"width": "160px", | |||||
"fieldname": "state", | "fieldname": "state", | ||||
"fieldtype": "Link", | "fieldtype": "Link", | ||||
"reqd": 1, | "reqd": 1, | ||||
"options": "Workflow State" | "options": "Workflow State" | ||||
}, | }, | ||||
{ | |||||
"doctype": "DocField", | |||||
"label": "Allow Edit", | |||||
"fieldname": "allow_edit", | |||||
"fieldtype": "Link", | |||||
"reqd": 0, | |||||
"options": "Role" | |||||
}, | |||||
{ | { | ||||
"doctype": "DocField", | "doctype": "DocField", | ||||
"label": "Doc Status", | "label": "Doc Status", | ||||
"width": "80px", | |||||
"fieldname": "doc_status", | "fieldname": "doc_status", | ||||
"fieldtype": "Select", | "fieldtype": "Select", | ||||
"options": "0\n1\n2" | "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", | "doctype": "DocField", | ||||
"label": "Message", | "label": "Message", | ||||
"width": "160px", | |||||
"fieldname": "message", | "fieldname": "message", | ||||
"fieldtype": "Text", | "fieldtype": "Text", | ||||
"reqd": 0 | "reqd": 0 | ||||
@@ -153,6 +153,7 @@ | |||||
"lib/public/js/legacy/wn/widgets/form/assign_to.js", | "lib/public/js/legacy/wn/widgets/form/assign_to.js", | ||||
"lib/public/js/wn/form/attachments.js", | "lib/public/js/wn/form/attachments.js", | ||||
"lib/public/js/wn/form/linked_with.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/wn/print/print_table.js", | ||||
'lib/public/js/lib/jquery/jquery.ui.interactions.min.js', | 'lib/public/js/lib/jquery/jquery.ui.interactions.min.js', | ||||
@@ -185,6 +185,11 @@ _f.Frm.prototype.setup_std_layout = function() { | |||||
this.setup_sidebar(); | this.setup_sidebar(); | ||||
} | } | ||||
// state | |||||
this.states = new wn.ui.form.States({ | |||||
frm: this | |||||
}); | |||||
// watermark | // watermark | ||||
$('<div style="font-size: 21px; color: #aaa; float: right;\ | $('<div style="font-size: 21px; color: #aaa; float: right;\ | ||||
margin-top: -5px; margin-right: -5px; z-index: 5;">' | margin-top: -5px; margin-right: -5px; z-index: 5;">' | ||||
@@ -805,34 +810,36 @@ _f.Frm.prototype.runclientscript = function(caller, cdt, cdn) { | |||||
validated = false; | validated = false; | ||||
console.log(e); | console.log(e); | ||||
} | } | ||||
if(caller && caller.toLowerCase()=='setup') { | 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<elist.length;i=i+2) { | |||||
this.cstring[strip(elist[i])] = elist[i+1]; | |||||
} | |||||
// 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<elist.length;i=i+2) { | |||||
this.cstring[strip(elist[i])] = elist[i+1]; | |||||
} | } | ||||
} | } | ||||
return ret; | |||||
} | } | ||||
_f.Frm.prototype.copy_doc = function(onload, from_amend) { | _f.Frm.prototype.copy_doc = function(onload, from_amend) { | ||||
@@ -39,6 +39,7 @@ wn.PageLayout = function(args) { | |||||
this.main = $a(this.wrapper, 'div', 'layout-main-section'); | this.main = $a(this.wrapper, 'div', 'layout-main-section'); | ||||
this.sidebar_area = $a(this.wrapper, 'div', 'layout-side-section'); | this.sidebar_area = $a(this.wrapper, 'div', 'layout-side-section'); | ||||
$a(this.wrapper, 'div', '', {clear:'both'}); | $a(this.wrapper, 'div', '', {clear:'both'}); | ||||
this.body_header = $a(this.main, 'div'); | |||||
this.body = $a(this.main, 'div'); | this.body = $a(this.main, 'div'); | ||||
this.footer = $a(this.main, 'div'); | this.footer = $a(this.main, 'div'); | ||||
if(this.heading) { | if(this.heading) { | ||||
@@ -0,0 +1,168 @@ | |||||
// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com) | |||||
// | |||||
// MIT License (MIT) | |||||
// | |||||
// Permission is hereby granted, free of charge, to any person obtaining a | |||||
// copy of this software and associated documentation files (the "Software"), | |||||
// to deal in the Software without restriction, including without limitation | |||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||||
// and/or sell copies of the Software, and to permit persons to whom the | |||||
// Software is furnished to do so, subject to the following conditions: | |||||
// | |||||
// The above copyright notice and this permission notice shall be included in | |||||
// all copies or substantial portions of the Software. | |||||
// | |||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |||||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | |||||
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
// | |||||
wn.ui.form.States = Class.extend({ | |||||
init: function(opts) { | |||||
$.extend(this, opts); | |||||
this.state_fieldname = wn.meta.get_state_fieldname(this.frm.doctype); | |||||
this.make(); | |||||
this.bind_action(); | |||||
var me = this; | |||||
$(this.frm.wrapper).bind("render_complete", function() { | |||||
me.refresh(); | |||||
}) | |||||
}, | |||||
make: function() { | |||||
this.$wrapper = $('<div class="states" style="margin-bottom: 11px; height: 26px;">\ | |||||
<div class="btn-group">\ | |||||
<button class="btn dropdown-toggle" data-toggle="dropdown">\ | |||||
<i class="icon-small"></i> <span class="state-text"></span> <span class="caret"></span></button>\ | |||||
<ul class="dropdown-menu">\ | |||||
</ul>\ | |||||
</div>\ | |||||
</div>').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('<li><a href="#" data-action="%(action)s">\ | |||||
<i class="icon icon-%(icon)s"></i> %(action)s</a></li>', 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; | |||||
}) | |||||
} | |||||
}); |
@@ -16,7 +16,17 @@ wn.utils = { | |||||
} | } | ||||
$.each(dict, function(i, d) { | $.each(dict, function(i, d) { | ||||
for(key in filters) { | 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); | ret.push(d); | ||||
}); | }); | ||||
@@ -104,5 +104,10 @@ $.extend(wn.meta, { | |||||
$.extend(wn._messages, doc.__messages); | $.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; | |||||
}, | |||||
}); | }); |