@@ -26,9 +26,6 @@ import webnotes | |||
from webnotes.utils import now, cint | |||
msgprint = webnotes.msgprint | |||
class DocType: | |||
def __init__(self, doc=None, doclist=[]): | |||
self.doc = doc | |||
@@ -68,6 +65,9 @@ class DocType: | |||
msgprint('<b>Series already in use:</b> The series "%s" is already used in "%s"' % (prefix, used_in[0][0]), raise_exception=1) | |||
def validate(self): | |||
for c in [".", "/", "#", "&", "=", ":", "'", '"']: | |||
if c in self.name: | |||
webnotes.msgprint(c + " not allowed in name", raise_exception=1) | |||
self.validate_series() | |||
self.scrub_field_names() | |||
validate_fields(filter(lambda d: d.doctype=="DocField", self.doclist)) | |||
@@ -182,7 +182,7 @@ def validate_fields_for_doctype(doctype): | |||
def validate_fields(fields): | |||
def check_illegal_characters(fieldname): | |||
for c in ['.', ',', ' ', '-', '&', '%', '=', '"', "'", '*', '$', | |||
'(', ')', '[', ']']: | |||
'(', ')', '[', ']', '/']: | |||
if c in fieldname: | |||
webnotes.msgprint("'%s' not allowed in fieldname (%s)" % (c, fieldname)) | |||
@@ -54,13 +54,10 @@ | |||
"lib/public/js/wn/provide.js", | |||
"lib/public/js/wn/assets.js", | |||
"lib/public/js/wn/dom.js", | |||
"lib/public/js/wn/model.js", | |||
"lib/public/js/wn/perm.js", | |||
"lib/public/js/wn/meta.js", | |||
"lib/public/js/wn/misc/user.js", | |||
"lib/public/js/wn/misc/utils.js", | |||
"lib/public/js/lib/public/json2.js", | |||
"lib/public/js/wn/router.js", | |||
"lib/public/js/wn/ui/messages.js", | |||
"lib/public/js/wn/ui/listing.js", | |||
"lib/public/js/wn/views/container.js", | |||
@@ -79,8 +76,6 @@ | |||
"lib/public/js/wn/ui/button.js", | |||
"lib/public/js/legacy/widgets/dialog.js", | |||
"lib/public/js/legacy/webpage/loaders.js", | |||
"lib/public/js/legacy/model/local_data.js", | |||
"lib/public/js/legacy/model/doclist.js", | |||
"lib/public/js/wn/app.js" | |||
] | |||
}, | |||
@@ -98,6 +93,13 @@ | |||
"lib/public/js/lib/tiny_mce_3.5.7/jquery.tinymce.js:concat", | |||
"lib/public/js/lib/mousetrap.min.js", | |||
"lib/public/js/wn/router.js", | |||
"lib/public/js/wn/model/model.js", | |||
"lib/public/js/wn/model/doclist.js", | |||
"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/misc/tools.js", | |||
"lib/public/js/legacy/utils/printElement.js", | |||
"lib/public/js/legacy/widgets/form/fields.js", | |||
@@ -10,6 +10,8 @@ wn.provide('_r'); | |||
wn.provide('_c'); | |||
wn.provide('_e'); | |||
wn.provide('_startup_data') | |||
wn.provide('locals') | |||
wn.provide('locals.DocType') | |||
// setup custom binding for history | |||
wn.settings.no_history = 1; | |||
@@ -52,6 +54,4 @@ var FILTER_SEP = '\1'; | |||
var frms={}; | |||
var cur_frm=null; | |||
var pscript = {}; | |||
var validated = true; | |||
var validation_message = ''; | |||
var tinymce_loaded = null; |
@@ -1,175 +0,0 @@ | |||
// 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. | |||
// | |||
function compress_doclist(list) { | |||
var kl = {}; var vl = []; var flx = {}; | |||
for(var i=0; i<list.length;i++) { | |||
var o = list[i]; | |||
var fl = []; | |||
if(!kl[o.doctype]) { // make key only once # doctype must be first | |||
var tfl = ['doctype', 'name', 'docstatus', 'owner', 'parent', 'parentfield', 'parenttype', | |||
'idx', 'creation', 'modified', 'modified_by', '__islocal', '__newname', '__modified', | |||
'_user_tags', '__temp']; | |||
var fl = [].concat(tfl); | |||
for(key in wn.meta.docfield_map[o.doctype]) { // all other values | |||
if(!in_list(fl, key) | |||
&& !in_list(no_value_fields, wn.meta.docfield_map[o.doctype][key].fieldtype) | |||
&& !wn.meta.docfield_map[o.doctype][key].no_column) { | |||
fl[fl.length] = key; // save value list | |||
tfl[tfl.length] = key //.replace(/'/g, "\\'").replace(/\n/g, "\\n"); | |||
} | |||
} | |||
flx[o.doctype] = fl; | |||
kl[o.doctype] = tfl | |||
} | |||
var nl = []; | |||
var fl = flx[o.doctype]; | |||
// check all | |||
for(var j=0;j<fl.length;j++) { | |||
var v = o[fl[j]]; | |||
nl.push(v); | |||
} | |||
vl.push(nl); | |||
} | |||
return JSON.stringify({'_vl':vl, '_kl':kl}); | |||
} | |||
function expand_doclist(docs) { | |||
var l = []; | |||
for(var i=0;i<docs._vl.length;i++) | |||
l[l.length] = zip(docs._kl[docs._vl[i][0]], docs._vl[i]); | |||
return l; | |||
} | |||
function zip(k,v) { | |||
var obj = {}; | |||
for(var i=0;i<k.length;i++) { | |||
obj[k[i]] = v[i]; | |||
} | |||
return obj; | |||
} | |||
function save_doclist(dt, dn, save_action, onsave, onerr, btn) { | |||
var doc = locals[dt][dn]; | |||
var doctype = locals['DocType'][dt]; | |||
var tmplist = []; | |||
// make doc list | |||
var doclist = make_doclist(dt, dn, 1); | |||
var all_reqd_ok = true; | |||
if(save_action!='Cancel') { | |||
for(var n in doclist) { | |||
// type / mandatory checking | |||
var reqd_ok = check_required(doclist[n].doctype, doclist[n].name, doclist[0].doctype); | |||
if(doclist[n].docstatus+''!='2' && all_reqd_ok) // if not deleted | |||
all_reqd_ok = reqd_ok; | |||
} | |||
} | |||
// mandatory not filled | |||
if(!all_reqd_ok) { | |||
onerr() | |||
return; | |||
} | |||
var _save = function() { | |||
//console.log(compress_doclist(doclist)); | |||
btn && $(btn).attr("disabled", true); | |||
$c('webnotes.widgets.form.save.savedocs', {'docs':compress_doclist(doclist), 'docname':dn, 'action': save_action, 'user':user }, | |||
function(r) { | |||
btn && $(btn).attr("disabled", false); | |||
if(r.saved) { | |||
if(onsave)onsave(r); | |||
} else { | |||
if(onerr)onerr(r); | |||
} | |||
}, function() { | |||
// | |||
},0,(f ? 'Saving...' : '') | |||
); | |||
} | |||
// ask for name | |||
if(doc.__islocal && (doctype && doctype.autoname && doctype.autoname.toLowerCase()=='prompt')) { | |||
var newname = prompt('Enter the name of the new '+ dt, ''); | |||
if(newname) { | |||
doc.__newname = strip(newname); _save(); | |||
} else { | |||
msgprint('Not Saved'); onerr(); | |||
} | |||
} else { | |||
_save(); | |||
} | |||
} | |||
function check_required(dt, dn, parent_dt) { | |||
var doc = locals[dt][dn]; | |||
if(doc.docstatus>1)return true; | |||
var fl = wn.meta.docfield_list[dt]; | |||
if(!fl)return true; // no doctype loaded | |||
var all_clear = true; | |||
var errfld = []; | |||
for(var i=0;i<fl.length;i++) { | |||
var key = fl[i].fieldname; | |||
var df = wn.meta.get_docfield(dt, key, dn); | |||
var has_value = wn.model.has_value(dt, dn, key); | |||
if(df.reqd && !has_value) { | |||
errfld[errfld.length] = df.label; | |||
// Bring to front "Section" | |||
if(cur_frm) { | |||
// show as red | |||
var f = cur_frm.fields_dict[df.fieldname]; | |||
if(f) { | |||
// in form | |||
f.df.has_error = true; | |||
f.refresh_label_icon && f.refresh_label_icon(); | |||
if(all_clear && f.wrapper) { | |||
$(document).scrollTop($(f.wrapper).offset().top - 100); | |||
} | |||
if(f.df.hidden) { | |||
msgprint('Oops, field "'+ f.df.label+'" is both hidden and mandatory. \ | |||
Please contact your admin for help.'); | |||
} | |||
} | |||
} | |||
if(all_clear)all_clear = false; | |||
} | |||
} | |||
if(errfld.length)msgprint('<b>Mandatory fields required in '+ | |||
(doc.parenttype ? (wn.meta.docfield_map[doc.parenttype][doc.parentfield].label + ' (Table)') : | |||
doc.doctype) + ':</b>\n' + errfld.join('\n')); | |||
return all_clear; | |||
} |
@@ -1,288 +0,0 @@ | |||
// 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. | |||
// | |||
// Local DB | |||
//----------- | |||
var locals = {'DocType':{}}; | |||
var LocalDB={}; | |||
var READ = 0; var WRITE = 1; var CREATE = 2; var SUBMIT = 3; var CANCEL = 4; var AMEND = 5; | |||
LocalDB.getchildren = function(child_dt, parent, parentfield, parenttype) { | |||
var l = []; | |||
for(var key in locals[child_dt]) { | |||
var d = locals[child_dt][key]; | |||
if((d.parent == parent)&&(d.parentfield == parentfield)) { | |||
if(parenttype) { | |||
if(d.parenttype==parenttype)l.push(d); | |||
} else { // ignore for now | |||
l.push(d); | |||
} | |||
} | |||
} | |||
l.sort(function(a,b){return (cint(a.idx)-cint(b.idx))}); return l; | |||
} | |||
// Add Doc | |||
// ====================================================================================== | |||
LocalDB.add=function(dt, dn) { | |||
if(!locals[dt]) locals[dt] = {}; if(locals[dt][dn]) delete locals[dt][dn]; | |||
locals[dt][dn] = {'name':dn, 'doctype':dt, 'docstatus':0}; | |||
return locals[dt][dn]; | |||
} | |||
// Delete Doc | |||
// ====================================================================================== | |||
LocalDB.delete_doc=function(dt, dn) { | |||
var doc = get_local(dt, dn); | |||
if(!doc) return; | |||
for(var ndt in locals) { // all doctypes | |||
if(locals[ndt]) { | |||
for(var ndn in locals[ndt]) { | |||
var doc = locals[ndt][ndn]; | |||
if(doc && doc.parenttype==dt && (doc.parent==dn||doc.__oldparent==dn)) { | |||
delete locals[ndt][ndn]; | |||
} | |||
} | |||
} | |||
} | |||
delete locals[dt][dn]; | |||
} | |||
function get_local(dt, dn) { return locals[dt] ? locals[dt][dn] : null; } | |||
// Sync Records from Server | |||
// ====================================================================================== | |||
LocalDB.sync = function(list) { | |||
if(keys(list._kl)) | |||
list = expand_doclist(list); | |||
if(list.length) { | |||
LocalDB.clear_locals(list[0].doctype, list[0].name); | |||
} else { | |||
return; | |||
} | |||
for(var i=0;i<list.length;i++) { | |||
var d = list[i]; | |||
if(!d.name) // get name (local if required) | |||
d.name = LocalDB.get_localname(d.doctype); | |||
LocalDB.add(d.doctype, d.name); | |||
locals[d.doctype][d.name] = d; | |||
// reset cur_frm.doc (as new doc is loaded from the server) | |||
if(cur_frm && cur_frm.doctype==d.doctype && cur_frm.docname==d.name) { | |||
cur_frm.doc = d; | |||
} | |||
if(d.doctype=='DocField') | |||
wn.meta.add_field(d); | |||
if(d.localname) { | |||
wn.model.new_names[d.localname] = d.name; | |||
$(document).trigger('rename', [d.doctype, d.localname, d.name]); | |||
delete locals[d.doctype][d.localname]; | |||
} | |||
} | |||
} | |||
LocalDB.clear_locals = function(dt, dn) { | |||
var doclist = make_doclist(dt, dn, 1); | |||
// console.dir(['in clear', doclist]); | |||
$.each(doclist, function(i, v) { | |||
v && delete locals[v.doctype][v.name]; | |||
}); | |||
} | |||
// Get Local Name | |||
// ====================================================================================== | |||
local_name_idx = {}; | |||
LocalDB.get_localname=function(doctype) { | |||
if(!local_name_idx[doctype]) local_name_idx[doctype] = 1; | |||
var n = 'New '+ get_doctype_label(doctype) + ' ' + local_name_idx[doctype]; | |||
local_name_idx[doctype]++; | |||
return n; | |||
} | |||
// Create Local Doc | |||
// ====================================================================================== | |||
LocalDB.set_default_values = function(doc) { | |||
var doctype = doc.doctype; | |||
var docfields = wn.meta.docfield_list[doctype]; | |||
if(!docfields) { | |||
return; | |||
} | |||
var fields_to_refresh = []; | |||
for(var fid=0;fid<docfields.length;fid++) { | |||
var f = docfields[fid]; | |||
if(!in_list(no_value_fields, f.fieldtype) && doc[f.fieldname]==null) { | |||
var v = LocalDB.get_default_value(f.fieldname, f.fieldtype, f['default']); | |||
if(v) { | |||
doc[f.fieldname] = v; | |||
fields_to_refresh.push(f.fieldname); | |||
} | |||
} | |||
} | |||
return fields_to_refresh; | |||
} | |||
// ====================================================================================== | |||
LocalDB.create = function(doctype, n) { | |||
if(!n) n = LocalDB.get_localname(doctype); | |||
var doc = LocalDB.add(doctype, n) | |||
doc.__islocal=1; doc.owner = user; | |||
LocalDB.set_default_values(doc); | |||
return n; | |||
} | |||
// ====================================================================================== | |||
LocalDB.delete_record = function(dt, dn) { | |||
delete locals[dt][dn]; | |||
} | |||
// ====================================================================================== | |||
LocalDB.get_default_value = function(fn, ft, df) { | |||
if(df=='_Login' || df=='__user') | |||
return user; | |||
else if(df=='_Full Name') | |||
return user_fullname; | |||
else if(ft=='Date'&& (df=='Today' || df=='__today')) { | |||
return get_today(); } | |||
else if(df) | |||
return df; | |||
else if(user_defaults[fn]) | |||
return user_defaults[fn][0]; | |||
else if(sys_defaults[fn]) | |||
return sys_defaults[fn]; | |||
} | |||
// ====================================================================================== | |||
LocalDB.add_child = function(doc, childtype, parentfield) { | |||
// create row doc | |||
var n = LocalDB.create(childtype); | |||
var d = locals[childtype][n]; | |||
d.parent = doc.name; | |||
d.parentfield = parentfield; | |||
d.parenttype = doc.doctype; | |||
return d; | |||
} | |||
// ====================================================================================== | |||
LocalDB.no_copy_list = ['amended_from','amendment_date','cancel_reason']; | |||
LocalDB.copy=function(dt, dn, from_amend) { | |||
var newdoc = LocalDB.create(dt); | |||
for(var key in locals[dt][dn]) { | |||
// dont copy name and blank fields | |||
var df = wn.meta.get_docfield(dt, key); | |||
if(key!=='name' && key.substr(0,2)!='__' && | |||
!(df && ((!from_amend && cint(df.no_copy)==1) || in_list(LocalDB.no_copy_list, df.fieldname)))) { | |||
locals[dt][newdoc][key] = locals[dt][dn][key]; | |||
} | |||
} | |||
return locals[dt][newdoc]; | |||
} | |||
// ====================================================================================== | |||
function make_doclist(dt, dn) { | |||
if(!locals[dt]) { return []; } | |||
var dl = []; | |||
dl[0] = locals[dt][dn]; | |||
// get children | |||
for(var ndt in locals) { // all doctypes | |||
if(locals[ndt]) { | |||
for(var ndn in locals[ndt]) { | |||
var doc = locals[ndt][ndn]; | |||
if(doc && doc.parenttype==dt && doc.parent==dn) { | |||
dl.push(doc) | |||
} | |||
} | |||
} | |||
} | |||
return dl; | |||
} | |||
// Meta Data | |||
// ====================================================================================== | |||
var Meta={}; | |||
var local_dt = {}; | |||
// Make Unique Copy of DocType for each record for client scripting | |||
Meta.make_local_dt = function(dt, dn) { | |||
var dl = make_doclist('DocType', dt); | |||
if(!local_dt[dt]) local_dt[dt]={}; | |||
if(!local_dt[dt][dn]) local_dt[dt][dn]={}; | |||
for(var i=0;i<dl.length;i++) { | |||
var d = dl[i]; | |||
if(d.doctype=='DocField') { | |||
var key = d.fieldname ? d.fieldname : d.label; | |||
local_dt[dt][dn][key] = copy_dict(d); | |||
local_dt[dt][dn][key].__copy = true; | |||
} | |||
} | |||
} | |||
Meta.set_field_property=function(fn, key, val, doc) { | |||
if(!doc && (cur_frm.doc))doc = cur_frm.doc; | |||
try{ | |||
local_dt[doc.doctype][doc.name][fn][key] = val; | |||
refresh_field(fn); | |||
} catch(e) { | |||
alert("Client Script Error: Unknown values for " + doc.name + ',' + fn +'.'+ key +'='+ val); | |||
} | |||
} | |||
Meta.get_field = function(dt, fn, dn) { | |||
try { | |||
return local_dt[dt][dn][fn]; | |||
} catch(e) { | |||
return null; | |||
} | |||
} | |||
// Get Dt label | |||
// ====================================================================================== | |||
function get_doctype_label(dt) { | |||
return dt | |||
} | |||
function get_label_doctype(label) { | |||
return label | |||
} | |||
// Global methods for API | |||
// ====================================================================================== | |||
var getchildren = LocalDB.getchildren; | |||
var createLocal = LocalDB.create; |
@@ -44,7 +44,7 @@ function $c_obj(doclist, method, arg, callback, no_spinner, freeze_msg, btn) { | |||
if(typeof doclist=='string') | |||
args.doctype = doclist; | |||
else | |||
args.docs = compress_doclist(doclist) | |||
args.docs = wn.model.compress(doclist) | |||
wn.request.call({ | |||
args: args, | |||
@@ -84,7 +84,7 @@ function $c_obj_csv(doclist, method, arg) { | |||
if(doclist.substr) | |||
args.doctype = doclist; | |||
else | |||
args.docs = compress_doclist(doclist); | |||
args.docs = wn.model.compress(doclist); | |||
// open | |||
open_url_post(wn.request.url, args); | |||
@@ -28,7 +28,6 @@ function loadreport(dt, rep_name, onload) { | |||
} | |||
function loaddoc(doctype, name, onload) { | |||
//doctype = get_label_doctype(doctype); | |||
wn.model.with_doctype(doctype, function() { | |||
if(locals.DocType[doctype].in_dialog) { | |||
_f.edit_record(doctype, name); | |||
@@ -40,10 +39,9 @@ function loaddoc(doctype, name, onload) { | |||
var load_doc = loaddoc; | |||
function new_doc(doctype, in_form) { | |||
doctype = get_label_doctype(doctype); | |||
wn.model.with_doctype(doctype, function() { | |||
if(!in_form && locals.DocType[doctype].in_dialog) { | |||
var new_name = LocalDB.create(doctype); | |||
var new_name = wn.model.make_new_doc_and_get_name(doctype); | |||
_f.edit_record(doctype, new_name); | |||
} else { | |||
wn.views.formview.create(doctype); | |||
@@ -74,7 +74,7 @@ function makeselector() { | |||
} | |||
d.style = 'Search'; | |||
if(d.input) { d.input = null; sel_type = null; } | |||
d.sel_type = get_label_doctype(dt); | |||
d.sel_type = dt; | |||
d.set_title('Quick Search for ' + dt); | |||
} | |||
@@ -44,7 +44,7 @@ get_server_fields = function(method, arg, table_field, doc, dt, dn, allow_edit, | |||
if(!allow_edit) wn.dom.freeze(); | |||
$c('runserverobj', | |||
args={'method':method, | |||
'docs':compress_doclist(make_doclist(doc.doctype, doc.name)), | |||
'docs':wn.model.compress(make_doclist(doc.doctype, doc.name)), | |||
'arg':arg | |||
}, | |||
function(r, rt) { | |||
@@ -127,7 +127,7 @@ set_field_permlevel = function(n, level) { | |||
} | |||
toggle_field = function(n, hidden) { | |||
var df = Meta.get_field(cur_frm.doctype, n, cur_frm.docname); | |||
var df = wn.meta.get_docfield(cur_frm.doctype, n, cur_frm.docname); | |||
if(df) { | |||
df.hidden = hidden; | |||
refresh_field(n); | |||
@@ -759,8 +759,8 @@ LinkField.prototype.validate_link = function(val, from_selector) { | |||
me.run_trigger(); | |||
} else { | |||
var astr = ''; | |||
if(in_list(profile.can_create, me.df.options)) astr = repl('<br><br><span class="link_type" onclick="newdoc(\'%(dt)s\')">Click here</span> to create a new %(dtl)s', {dt:me.df.options, dtl:get_doctype_label(me.df.options)}) | |||
msgprint(repl('error:<b>%(val)s</b> is not a valid %(dt)s.<br><br>You must first create a new %(dt)s <b>%(val)s</b> and then select its value. To find an existing %(dt)s, click on the magnifying glass next to the field.%(add)s', {val:me.txt.value, dt:get_doctype_label(me.df.options), add:astr})); | |||
if(in_list(profile.can_create, me.df.options)) astr = repl('<br><br><span class="link_type" onclick="newdoc(\'%(dt)s\')">Click here</span> to create a new %(dtl)s', {dt:me.df.options, dtl:wn._(me.df.options)}) | |||
msgprint(repl('error:<b>%(val)s</b> is not a valid %(dt)s.<br><br>You must first create a new %(dt)s <b>%(val)s</b> and then select its value. To find an existing %(dt)s, click on the magnifying glass next to the field.%(add)s', {val:me.txt.value, dt:wn._(me.df.options), add:astr})); | |||
me.txt.value = ''; | |||
me.set(''); | |||
} | |||
@@ -46,6 +46,7 @@ _f.Frm = function(doctype, parent, in_form) { | |||
this.docname = ''; | |||
this.doctype = doctype; | |||
this.display = 0; | |||
this.refresh_if_stale_for = 600; | |||
var me = this; | |||
this.is_editable = {}; | |||
@@ -215,7 +216,7 @@ _f.Frm.prototype.print_doc = function() { | |||
_f.Frm.prototype.email_doc = function(message) { | |||
new wn.views.CommunicationComposer({ | |||
doc: this.doc, | |||
subject: get_doctype_label(this.meta.name) + ': ' + this.docname, | |||
subject: wn._(this.meta.name) + ': ' + this.docname, | |||
recipients: this.doc.email || this.doc.email_id || this.doc.contact_email, | |||
attach_document_print: true, | |||
message: message, | |||
@@ -237,7 +238,7 @@ _f.Frm.prototype.rename_notify = function(dt, old, name) { | |||
if(this.docname == old) | |||
this.docname = name; | |||
else | |||
return; // thats it, not for children! | |||
return; | |||
// editable | |||
this.is_editable[name] = this.is_editable[old]; | |||
@@ -245,9 +246,9 @@ _f.Frm.prototype.rename_notify = function(dt, old, name) { | |||
// cleanup | |||
if(this && this.opendocs[old]) { | |||
// local doctype copy | |||
local_dt[dt][name] = local_dt[dt][old]; | |||
local_dt[dt][old] = null; | |||
// delete docfield copy | |||
wn.meta.docfield_copy[dt][name] = wn.meta.docfield_copy[dt][old]; | |||
delete wn.meta.docfield_copy[dt][old]; | |||
} | |||
delete this.opendocs[old]; | |||
@@ -260,19 +261,16 @@ _f.Frm.prototype.rename_notify = function(dt, old, name) { | |||
// SETUP | |||
_f.Frm.prototype.setup_meta = function(doctype) { | |||
this.meta = get_local('DocType',this.doctype); | |||
this.meta = wn.model.get_doc('DocType',this.doctype); | |||
this.perm = wn.perm.get_perm(this.doctype); // for create | |||
if(this.meta.istable) { this.meta.in_dialog = 1 } | |||
this.setup_print(); | |||
} | |||
_f.Frm.prototype.setup_sidebar = function() { | |||
this.sidebar = new wn.widgets.form.sidebar.Sidebar(this); | |||
} | |||
_f.Frm.prototype.setup_footer = function() { | |||
var me = this; | |||
@@ -372,7 +370,6 @@ _f.Frm.prototype.setup_fields_std = function() { | |||
} | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.add_custom_button = function(label, fn, icon) { | |||
this.frm_head.appframe.add_button(label, fn, icon); | |||
} | |||
@@ -380,8 +377,6 @@ _f.Frm.prototype.clear_custom_buttons = function() { | |||
this.frm_head.refresh_toolbar() | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) { | |||
if(!this.fetch_dict[link_field]) { | |||
this.fetch_dict[link_field] = {'columns':[], 'fields':[]} | |||
@@ -390,8 +385,6 @@ _f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) { | |||
this.fetch_dict[link_field].fields.push(tar_field); | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.setup_client_script = function() { | |||
// setup client obj | |||
@@ -400,8 +393,6 @@ _f.Frm.prototype.setup_client_script = function() { | |||
} | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.refresh_print_layout = function() { | |||
$ds(this.print_wrapper); | |||
$dh(this.page_layout.wrapper); | |||
@@ -432,8 +423,6 @@ _f.Frm.prototype.refresh_print_layout = function() { | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.show_the_frm = function() { | |||
// show the dialog | |||
if(this.meta.in_dialog && !this.parent.dialog.display) { | |||
@@ -443,38 +432,15 @@ _f.Frm.prototype.show_the_frm = function() { | |||
} | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.set_print_heading = function(txt) { | |||
this.pformat[cur_frm.docname] = txt; | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.defocus_rest = function() { | |||
// deselect others | |||
if(_f.cur_grid_cell) _f.cur_grid_cell.grid.cell_deselect(); | |||
} | |||
// -------- Permissions ------- | |||
// Returns global permissions, at all levels | |||
// ====================================================================================== | |||
_f.Frm.prototype.get_doc_perms = function() { | |||
var p = [0,0,0,0,0,0]; | |||
for(var i=0; i<this.perm.length; i++) { | |||
if(this.perm[i]) { | |||
if(this.perm[i][READ]) p[READ] = 1; | |||
if(this.perm[i][WRITE]) p[WRITE] = 1; | |||
if(this.perm[i][SUBMIT]) p[SUBMIT] = 1; | |||
if(this.perm[i][CANCEL]) p[CANCEL] = 1; | |||
if(this.perm[i][AMEND]) p[AMEND] = 1; | |||
} | |||
} | |||
return p; | |||
} | |||
// refresh | |||
// ====================================================================================== | |||
_f.Frm.prototype.refresh_header = function() { | |||
// set title | |||
// main title | |||
@@ -493,8 +459,6 @@ _f.Frm.prototype.refresh_header = function() { | |||
wn.ui.toolbar.recent.add(this.doctype, this.docname, 1); | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.check_doc_perm = function() { | |||
// get perm | |||
var dt = this.parent_doctype?this.parent_doctype : this.doctype; | |||
@@ -516,8 +480,6 @@ _f.Frm.prototype.check_doc_perm = function() { | |||
return 1 | |||
} | |||
// -------------------------------------------------------------------------------------- | |||
_f.Frm.prototype.refresh = function(docname) { | |||
// record switch | |||
if(docname) { | |||
@@ -535,15 +497,20 @@ _f.Frm.prototype.refresh = function(docname) { | |||
// check permissions | |||
if(!this.check_doc_perm()) return; | |||
// set the doc | |||
this.doc = wn.model.get_doc(this.doctype, this.docname); | |||
// check if doctype is already open | |||
if (!this.opendocs[this.docname]) { | |||
this.check_doctype_conflict(this.docname); | |||
} else { | |||
if((new Date() - this.doc.__last_sync_on) / 1000 > this.refresh_if_stale_for) { | |||
this.reload_doc(); | |||
return; | |||
} | |||
} | |||
// set the doc | |||
this.doc = get_local(this.doctype, this.docname); | |||
// do setup | |||
if(!this.setup_done) this.setup(); | |||
@@ -621,13 +588,11 @@ _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.in_dialog || this.in_form) | |||
&& this.doc.docstatus==0 && !this.meta.istable && this.get_doc_perms()[WRITE] | |||
&& this.doc.docstatus==0 && !this.meta.istable && this.perm[0][WRITE] | |||
&& (this.fields && this.fields.length > 7)) { | |||
f.show_save(); | |||
} else { | |||
@@ -755,18 +720,14 @@ _f.Frm.prototype.setnewdoc = function(docname) { | |||
return; | |||
} | |||
//if(!this.meta) | |||
// this.setup_meta(); | |||
// make a copy of the doctype for client script settings | |||
// each record will have its own client script | |||
Meta.make_local_dt(this.doctype,docname); | |||
wn.meta.make_docfield_copy_for(this.doctype,docname); | |||
this.docname = docname; | |||
var me = this; | |||
var viewname = docname; | |||
if(this.meta.issingle) viewname = this.doctype; | |||
var viewname = this.meta.issingle ? this.doctype : docname; | |||
// Client Script | |||
this.runclientscript('onload', this.doctype, this.docname); | |||
@@ -788,82 +749,12 @@ _f.Frm.prototype.show_doc = function(dn) { | |||
this.refresh(dn); | |||
} | |||
// ====================================================================================== | |||
var validated; // bad design :( | |||
_f.Frm.prototype.save = function(save_action, callback, btn) { | |||
// removes focus from a field before save, | |||
// so that its change event gets triggered before saving | |||
$(document.activeElement).blur(); | |||
//alert(save_action); | |||
if(!save_action) { | |||
if(cint(this.doc.docstatus) > 0) return; | |||
save_action = 'Save'; | |||
} | |||
if(save_action=='Submit') { | |||
locals[this.doctype][this.docname].submitted_on = dateutil.full_str(); | |||
locals[this.doctype][this.docname].submitted_by = user; | |||
} | |||
if(save_action=='Trash') { | |||
var reason = prompt('Reason for trash (mandatory)', ''); | |||
if(!strip(reason)) { | |||
msgprint('Reason is mandatory, not trashed'); | |||
return; | |||
} | |||
locals[this.doctype][this.docname].trash_reason = reason; | |||
} | |||
// run validations | |||
if(save_action=='Cancel') { | |||
var reason = prompt('Reason for cancellation (mandatory)', ''); | |||
if(!strip(reason)) { | |||
msgprint('Reason is mandatory, not cancelled'); | |||
return; | |||
} | |||
locals[this.doctype][this.docname].cancel_reason = reason; | |||
locals[this.doctype][this.docname].cancelled_on = dateutil.full_str(); | |||
locals[this.doctype][this.docname].cancelled_by = user; | |||
} else if(save_action=='Update') { | |||
// no validation for update | |||
} else { // no validation for cancellation | |||
validated = true; | |||
if(this.cscript.validate) | |||
this.runclientscript('validate'); | |||
if(!validated) { | |||
return 'Error'; | |||
} | |||
} | |||
var onsave = function(r) { | |||
if(!me.meta.istable && r) { | |||
me.refresh(r.docname); | |||
} | |||
callback && callback(r) | |||
} | |||
var me = this; | |||
var onerr = function(r) { | |||
var doc = locals[me.doctype][me.docname]; | |||
onsave(r); | |||
} | |||
if(this.docname && validated) { | |||
// scroll to top | |||
scroll(0, 0); | |||
return save_doclist(this.doctype, this.docname, save_action, onsave, onerr, btn); | |||
} | |||
} | |||
_f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) { | |||
var me = this; | |||
if(this.docname) { | |||
// make doc list | |||
var doclist = compress_doclist(make_doclist(this.doctype, this.docname)); | |||
var doclist = wn.model.compress(make_doclist(this.doctype, this.docname)); | |||
// send to run | |||
if(callingfield) | |||
$(callingfield.input).set_working(); | |||
@@ -906,7 +797,7 @@ _f.Frm.prototype.runclientscript = function(caller, cdt, cdn) { | |||
if(caller && caller.toLowerCase()=='setup') { | |||
var doctype = get_local('DocType', this.doctype); | |||
var doctype = wn.model.get_doc('DocType', this.doctype); | |||
// js | |||
var cs = doctype.__js || (doctype.client_script_core + doctype.client_script); | |||
@@ -941,7 +832,7 @@ _f.Frm.prototype.copy_doc = function(onload, from_amend) { | |||
var dn = this.docname; | |||
// copy parent | |||
var newdoc = LocalDB.copy(this.doctype, dn, from_amend); | |||
var newdoc = wn.model.copy_doc(this.doctype, dn, from_amend); | |||
// do not copy attachments | |||
if(this.meta.allow_attach && newdoc.file_list && !from_amend) | |||
@@ -962,7 +853,7 @@ _f.Frm.prototype.copy_doc = function(onload, from_amend) { | |||
} | |||
if(d1.parent==dn && cint(tf_dict[d1.parentfield].no_copy)!=1) { | |||
var ch = LocalDB.copy(d1.doctype, d1.name, from_amend); | |||
var ch = wn.model.copy_doc(d1.doctype, d1.name, from_amend); | |||
ch.parent = newdoc.name; | |||
ch.docstatus = 0; | |||
ch.owner = user; | |||
@@ -1003,6 +894,31 @@ _f.Frm.prototype.reload_doc = function() { | |||
} | |||
} | |||
var validated; | |||
_f.Frm.prototype.save = function(save_action, callback, btn) { | |||
$(document.activeElement).blur(); | |||
var me = this; | |||
var doclist = new wn.model.DocList(this.doctype, this.docname); | |||
// validate | |||
if(save_action!="Cancel") { | |||
validated = true; | |||
if(this.cscript.validate) | |||
this.runclientscript('validate'); | |||
if(!validated) { | |||
return; | |||
} | |||
} | |||
doclist.save(save_action || "Save", function(r) { | |||
if(!r.exc) { | |||
me.refresh(); | |||
} | |||
callback && callback(r); | |||
}, btn); | |||
} | |||
_f.Frm.prototype.savesubmit = function(btn) { | |||
var me = this; | |||
wn.confirm("Permanently Submit "+this.docname+"?", function() { | |||
@@ -1017,7 +933,10 @@ _f.Frm.prototype.savesubmit = function(btn) { | |||
_f.Frm.prototype.savecancel = function(btn) { | |||
var me = this; | |||
wn.confirm("Permanently Cancel "+this.docname+"?", function() { | |||
me.save('Cancel', null, btn); | |||
var doclist = new wn.model.DocList(me.doctype, me.docname); | |||
doclist.cancel(function(r) { | |||
if(!r.exc) me.refresh(); | |||
}, btn); | |||
}); | |||
} | |||
@@ -158,7 +158,7 @@ _f.FormGrid.prototype.insert_row = function() { | |||
_f.FormGrid.prototype.new_row_doc = function() { | |||
// create row doc | |||
var n = LocalDB.create(this.doctype); | |||
var n = wn.model.make_new_doc_and_get_name(this.doctype); | |||
var d = locals[this.doctype][n]; | |||
d.parent = this.field.frm.docname; | |||
d.parentfield = this.field.df.fieldname; | |||
@@ -220,7 +220,7 @@ _f.FormGrid.prototype.check_selected = function() { | |||
_f.FormGrid.prototype.delete_row = function(dt, dn) { | |||
if(dt && dn) { | |||
LocalDB.delete_record(dt, dn); | |||
wn.model.clear_doc(dt, dn); | |||
this.refresh(); | |||
} else { | |||
if(!this.check_selected()) return; | |||
@@ -230,7 +230,7 @@ _f.FormGrid.prototype.delete_row = function(dt, dn) { | |||
var ci = _f.cur_grid_cell.cellIndex; | |||
var ri = _f.cur_grid_cell.row.rowIndex; | |||
LocalDB.delete_record(this.doctype, r.docname); | |||
wn.model.clear_doc(this.doctype, r.docname); | |||
this.refresh(); | |||
if(ri < (this.tab.rows.length-1)) | |||
@@ -80,7 +80,7 @@ _f.FrmHeader = Class.extend({ | |||
this.$w.find('.avatar img').centerImage(); | |||
}, | |||
refresh_labels: function() { | |||
cur_frm.doc = get_local(cur_frm.doc.doctype, cur_frm.doc.name); | |||
cur_frm.doc = wn.model.get_doc(cur_frm.doc.doctype, cur_frm.doc.name); | |||
var labinfo = { | |||
0: ['Saved', 'label-success'], | |||
1: ['Submitted', 'label-info'], | |||
@@ -121,7 +121,7 @@ _f.FrmHeader = Class.extend({ | |||
} | |||
this.appframe.clear_buttons(); | |||
var p = cur_frm.get_doc_perms(); | |||
var p = cur_frm.perm[0]; | |||
// Edit | |||
if(cur_frm.meta.read_only_onload && !cur_frm.doc.__islocal) { | |||
@@ -452,7 +452,7 @@ $.extend(_p, { | |||
} | |||
} | |||
// if not, just have doctype has heading | |||
h1.innerHTML = val ? val : get_doctype_label(doctype); | |||
h1.innerHTML = val ? val : wn._(doctype); | |||
} | |||
var h2_style = { | |||
@@ -132,7 +132,7 @@ _r.ReportBuilder = function(parent, doctype, onload) { | |||
$ds(me.wrapper); | |||
// reset main title | |||
this.set_main_title('Report: ' + get_doctype_label(me.doctype)); | |||
this.set_main_title('Report: ' + wn._(me.doctype)); | |||
if(my_onload)my_onload(me); | |||
} | |||
@@ -156,7 +156,7 @@ _r.ReportBuilder.prototype.make_tabs = function() { | |||
_r.ReportBuilder.prototype.make_body = function() { | |||
this.set_main_title('Report: ' + get_doctype_label(this.doctype)); | |||
this.set_main_title('Report: ' + wn._(this.doctype)); | |||
var me = this; | |||
this.make_save_criteria(); | |||
@@ -204,7 +204,7 @@ _r.ReportBuilder.prototype.save_criteria = function(save_as) { | |||
if(!criteria_name) | |||
return; | |||
var dn = createLocal('Search Criteria'); | |||
var dn = wn.model.make_new_doc_and_get_name('Search Criteria'); | |||
var doc = locals['Search Criteria'][dn]; | |||
doc.criteria_name = criteria_name; | |||
@@ -243,12 +243,7 @@ _r.ReportBuilder.prototype.save_criteria = function(save_as) { | |||
me.sc_dict[criteria_name] = r.main_doc_name; | |||
me.set_criteria_sel(criteria_name); | |||
} | |||
//if(this.current_loaded && overwrite) { | |||
// msgprint('Filters and Columns Synchronized. You must also "Save" the Search Criteria to update'); | |||
// loaddoc('Search Criteria', this.sc_dict[this.current_loaded]); | |||
//} else { | |||
save_doclist(doc.doctype, doc.name, 'Save', fn); // server-side save | |||
//} | |||
new wn.model.DocList(doc.doctype, doc.name).save("Save", fn); | |||
} | |||
// ------------------------------------------------------------------------------------- | |||
@@ -292,7 +287,7 @@ _r.ReportBuilder.prototype.clear_criteria = function() { | |||
this.set_sort_options(); | |||
this.set_main_title('Report: ' + get_doctype_label(this.doctype)); | |||
this.set_main_title('Report: ' + wn._(this.doctype)); | |||
this.current_loaded = null; | |||
this.customized_filters = null; | |||
@@ -503,10 +498,10 @@ _r.ReportBuilder.prototype.setup_dt_filters_and_cols = function(fl, dt) { | |||
// set section headings | |||
var lab = $a(me.filter_area,'div','filter_dt_head'); | |||
lab.innerHTML = 'Filters for ' + get_doctype_label(dt); | |||
lab.innerHTML = 'Filters for ' + wn._(dt); | |||
var lab = $a(me.picker_area,'div','builder_dt_head'); | |||
lab.innerHTML = 'Select columns for ' + get_doctype_label(dt); | |||
lab.innerHTML = 'Select columns for ' + wn._(dt); | |||
// get fields | |||
var dt_fields = wn.meta.docfield_list[dt]; | |||
@@ -678,7 +673,7 @@ _r.ReportBuilder.prototype.make_datatable = function() { | |||
// get search criteria | |||
if(me.current_loaded && me.sc_dict[me.current_loaded]) { | |||
var sc = get_local('Search Criteria', me.sc_dict[me.current_loaded]); | |||
var sc = wn.model.get_doc('Search Criteria', me.sc_dict[me.current_loaded]); | |||
} | |||
if(sc) me.dt.search_criteria = sc; | |||
@@ -1221,7 +1216,7 @@ _r.ReportColumnPicker.prototype.set_options = function(s, l) { | |||
for(var i=0; i<l.length; i++) { | |||
var v = l[i].df.parent + '.' + l[i].df.label; | |||
var v_label = get_doctype_label(l[i].df.parent) + '.' + l[i].df.label; | |||
var v_label = wn._(l[i].df.parent) + '.' + l[i].df.label; | |||
var o = new Option (v_label, v, false, false); | |||
o.field = l[i]; | |||
if(o.field.is_selected) o.selected = 1; | |||
@@ -36,7 +36,8 @@ wn.widgets.form.sidebar.Comments = function(parent, sidebar, doctype, docname) { | |||
this.refresh_latest_comment = function() { | |||
var wrapper = cur_frm.page_layout.body; | |||
if(!$(wrapper).find(".latest-comment").length) { | |||
$('<div class="latest-comment alert alert-info" style="margin-top:20px;">').prependTo(wrapper); | |||
$('<div class="latest-comment alert alert-info" style="margin-top:20px; display: none;">') | |||
.prependTo(wrapper); | |||
} | |||
var comment_list = wn.widgets.form.comments.comment_list[me.docname]; | |||
if(comment_list) { | |||
@@ -21,6 +21,7 @@ | |||
// | |||
wn.provide('wn.meta.docfield_map'); | |||
wn.provide('wn.meta.docfield_copy'); | |||
wn.provide('wn.meta.docfield_list'); | |||
wn.provide('wn.meta.doctypes'); | |||
wn.provide("wn.meta.precision_map"); | |||
@@ -43,9 +44,21 @@ $.extend(wn.meta, { | |||
wn.meta.docfield_list[df.parent].push(df); | |||
}, | |||
make_docfield_copy_for: function(doctype, docname) { | |||
var c = wn.meta.docfield_copy; | |||
if(!c[doctype]) | |||
c[doctype] = {}; | |||
if(!c[doctype][docname]) | |||
c[doctype][docname] = {}; | |||
$.each(wn.meta.docfield_list[doctype], function(i, df) { | |||
c[doctype][docname][df.fieldname || df.label] = copy_dict(df); | |||
}) | |||
}, | |||
get_docfield: function(dt, fn, dn) { | |||
if(dn && local_dt[dt] && local_dt[dt][dn]){ | |||
return local_dt[dt][dn][fn]; | |||
if(dn && wn.meta.docfield_copy[dt] && wn.meta.docfield_copy[dt][dn]){ | |||
return wn.meta.docfield_copy[dt][dn][fn]; | |||
} else { | |||
return wn.meta.docfield_map[dt][fn]; | |||
} | |||
@@ -85,4 +98,11 @@ $.extend(wn.meta, { | |||
return wn.meta.precision_map[doctype]; | |||
}, | |||
sync_messages: function(doc) { | |||
if(doc.__messages) { | |||
$.extend(wn._messages, doc.__messages); | |||
} | |||
}, | |||
}); |
@@ -0,0 +1,99 @@ | |||
wn.provide("wn.model"); | |||
$.extend(wn.model, { | |||
new_names: {}, | |||
new_name_count: {}, | |||
get_new_doc: function(doctype) { | |||
wn.provide("locals." + doctype); | |||
var doc = { | |||
docstatus: 0, | |||
doctype: doctype, | |||
name: wn.model.get_new_name(doctype), | |||
__islocal: 1, | |||
owner: user | |||
}; | |||
wn.model.set_default_values(doc); | |||
locals[doctype][doc.name] = doc; | |||
return doc; | |||
}, | |||
make_new_doc_and_get_name: function(doctype) { | |||
return wn.model.get_new_doc(doctype).name; | |||
}, | |||
get_new_name: function(doctype) { | |||
var cnt = wn.model.new_name_count | |||
if(!cnt[doctype]) | |||
cnt[doctype] = 0; | |||
cnt[doctype]++; | |||
return 'New '+ doctype + ' ' + cnt[doctype]; | |||
}, | |||
set_default_values: function(doc) { | |||
var doctype = doc.doctype; | |||
var docfields = wn.meta.docfield_list[doctype] || []; | |||
var updated = []; | |||
for(var fid=0;fid<docfields.length;fid++) { | |||
var f = docfields[fid]; | |||
if(!in_list(no_value_fields, f.fieldtype) && doc[f.fieldname]==null) { | |||
var v = wn.model.get_default_value(f); | |||
if(v) { | |||
doc[f.fieldname] = v; | |||
updated.push(f.fieldname); | |||
} | |||
} | |||
} | |||
return updated; | |||
}, | |||
get_default_value: function(df) { | |||
var def_vals = { | |||
"_Login": user, | |||
"__user": user, | |||
"Today": dateutil.get_today(), | |||
"__today": dateutil.get_today(), | |||
"Now": dateutil.get_cur_time() | |||
} | |||
if(def_vals[df["default"]]) | |||
return def_vals[df["default"]]; | |||
else if(df["default"]) | |||
return df["default"]; | |||
else if(user_defaults[df.fieldname]) | |||
return user_defaults[df.fieldname][0]; | |||
else if(sys_defaults[df.fieldname]) | |||
return sys_defaults[df.fieldname]; | |||
}, | |||
add_child: function(doc, childtype, parentfield) { | |||
// create row doc | |||
var d = wn.model.get_new_doc(childtype); | |||
$.extend(d, { | |||
parent: doc.name, | |||
parentfield: parentfield, | |||
parenttype: doc.doctype, | |||
idx: getchildren(childtype, d.parent, d.parentfield, d.parenttype).length | |||
}); | |||
return d; | |||
}, | |||
copy_doc: function(dt, dn, from_amend) { | |||
var no_copy_list = ['name','amended_from','amendment_date','cancel_reason']; | |||
var newdoc = wn.model.get_new_doc(dt); | |||
for(var key in locals[dt][dn]) { | |||
// dont copy name and blank fields | |||
var df = wn.meta.get_docfield(dt, key); | |||
if(key.substr(0,2)!='__' | |||
&& !in_list(no_copy_list, key) | |||
&& !(df && (!from_amend && cint(df.no_copy)==1))) { | |||
newdoc[key] = locals[dt][dn][key]; | |||
} | |||
} | |||
return newdoc; | |||
}, | |||
}) |
@@ -0,0 +1,129 @@ | |||
// 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.provide("wn.model"); | |||
wn.model.DocList = Class.extend({ | |||
init: function(doctype, name) { | |||
this.doctype = doctype; this.name = name; | |||
this.doclist = wn.model.get_doclist(this.doctype, this.name); | |||
this.doc = this.doclist[0]; | |||
}, | |||
save: function(action, callback, btn) { | |||
this.check_name(); | |||
if(this.check_mandatory()) { | |||
this._call({ | |||
method: "webnotes.widgets.form.save.savedocs", | |||
args: { docs: wn.model.compress(this.doclist), action:action}, | |||
callback: callback, | |||
btn: btn | |||
}); | |||
} | |||
}, | |||
cancel: function(callback, btn) { | |||
this._call({ | |||
method: "webnotes.widgets.form.save.cancel", | |||
args: { doctype: this.doctype, name: this.name }, | |||
callback: callback, | |||
btn: btn | |||
}); | |||
}, | |||
check_name: function() { | |||
var doc = this.doclist[0]; | |||
var doctype = doc.doctype; | |||
if(doc.__islocal && (doctype && doctype.autoname | |||
&& doctype.autoname.toLowerCase()=='prompt')) { | |||
var newname = prompt('Enter the name of the new '+ dt, ''); | |||
if(newname) { | |||
doc.__newname = strip(newname); | |||
} else { | |||
msgprint("Name is required."); | |||
throw "name required"; | |||
} | |||
} | |||
}, | |||
check_mandatory: function() { | |||
var me = this; | |||
var has_errors = false; | |||
this.scroll_set = false; | |||
if(this.doc.docstatus==2) return true; // don't check for cancel | |||
$.each(this.doclist, function(i, doc) { | |||
var error_fields = []; | |||
$.each(wn.meta.docfield_list[doc.doctype], function(i, docfield) { | |||
if(!docfield.fieldname.std_field) { | |||
var df = wn.meta.get_docfield(doc.doctype, | |||
docfield.fieldname, me.doclist[0].name); | |||
if(df.reqd && !wn.model.has_value(doc.doctype, doc.name, df.fieldname)) { | |||
has_errors = true; | |||
error_fields[error_fields.length] = df.label; | |||
// scroll to field | |||
if(!me.scroll_set) | |||
me.scroll_to(doc.parentfield || df.fieldname); | |||
} | |||
} | |||
}); | |||
if(error_fields.length) | |||
msgprint('<b>Mandatory fields required in '+ (doc.parenttype | |||
? (wn.meta.docfield_map[doc.parenttype][doc.parentfield].label + ' (Table)') | |||
: doc.doctype) + ':</b>\n' + error_fields.join('\n')); | |||
}); | |||
return !has_errors; | |||
}, | |||
scroll_to: function(fieldname) { | |||
var f = cur_frm.fields_dict[fieldname]; | |||
if(f) { | |||
$(document).scrollTop($(f.wrapper).offset().top - 100); | |||
} | |||
this.scroll_set = true; | |||
}, | |||
_call: function(opts) { | |||
// opts = { | |||
// method: "some server method", | |||
// args: {args to be passed}, | |||
// callback: callback, | |||
// btn: btn | |||
// } | |||
$(opts.btn).attr("disabled", true); | |||
wn.call({ | |||
freeze: true, | |||
method: opts.method, | |||
args: opts.args, | |||
callback: function(r) { | |||
$(opts.btn).attr("disabled", false); | |||
opts.callback && opts.callback(r); | |||
} | |||
}) | |||
}, | |||
}); |
@@ -22,7 +22,7 @@ | |||
wn.provide('wn.model'); | |||
wn.model = { | |||
$.extend(wn.model, { | |||
no_value_type: ['Section Break', 'Column Break', 'HTML', 'Table', | |||
'Button', 'Image'], | |||
@@ -85,7 +85,7 @@ wn.model = { | |||
}); | |||
} | |||
}, | |||
get_server_module_name: function(doctype) { | |||
var dt = wn.model.scrub(doctype) | |||
return wn.model.scrub(locals.DocType[doctype].module) | |||
@@ -136,6 +136,10 @@ wn.model = { | |||
return wn.utils.filter_dict(locals[doctype], filters); | |||
}, | |||
get_doc: function(doctype, name) { | |||
return locals[doctype] ? locals[doctype][name] : null; | |||
}, | |||
get_doclist: function(doctype, name, filters) { | |||
var doclist = []; | |||
if(!locals[doctype]) | |||
@@ -159,6 +163,47 @@ wn.model = { | |||
return doclist; | |||
}, | |||
get_children: function(child_dt, parent, parentfield, parenttype) { | |||
if(parenttype) { | |||
var l = wn.model.get(child_dt, {parent:parent, | |||
parentfield:parentfield, parenttype:parenttype}); | |||
} else { | |||
var l = wn.model.get(child_dt, {parent:parent, | |||
parentfield:parentfield}); | |||
} | |||
l.sort(function(a,b) { return cint(a.idx) - cint(b.idx) }); | |||
$.each(l, function(i, v) { v.idx = i+1; }); // for chrome bugs ??? | |||
return l; | |||
}, | |||
clear_doclist: function(doctype, name) { | |||
$.each(wn.model.get_doclist(doctype, name), function(i, d) { | |||
if(d) wn.model.clear_doc(d.doctype, d.name); | |||
}); | |||
}, | |||
clear_doc: function(doctype, name) { | |||
delete locals[doctype][name]; | |||
}, | |||
copy_doc: function(dt, dn, from_amend) { | |||
var no_copy_list = ['name','amended_from','amendment_date','cancel_reason']; | |||
var newdoc = wn.model.get_new_doc(dt); | |||
for(var key in locals[dt][dn]) { | |||
// dont copy name and blank fields | |||
var df = wn.meta.get_docfield(dt, key); | |||
if(key.substr(0,2)!='__' | |||
&& !in_list(no_copy_list, key) | |||
&& !(df && (!from_amend && cint(df.no_copy)==1))) { | |||
newdoc[key] = locals[dt][dn][key]; | |||
} | |||
} | |||
return newdoc; | |||
}, | |||
delete_doc: function(doctype, docname, callback) { | |||
wn.confirm("Permanently delete "+ docname + "?", function() { | |||
@@ -170,7 +215,7 @@ wn.model = { | |||
}, | |||
callback: function(r, rt) { | |||
if(!r.exc) { | |||
LocalDB.delete_doc(doctype, docname); | |||
wn.model.clear_doclist(doctype, docname); | |||
if(wn.ui.toolbar.recent) | |||
wn.ui.toolbar.recent.remove(doctype, docname); | |||
if(callback) callback(r,rt); | |||
@@ -215,4 +260,8 @@ wn.model = { | |||
}); | |||
d.show(); | |||
} | |||
} | |||
}); | |||
// legacy | |||
getchildren = wn.model.get_children | |||
make_doclist = wn.model.get_doclist |
@@ -0,0 +1,117 @@ | |||
// 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. | |||
// | |||
$.extend(wn.model, { | |||
sync: function(doclist, sync_in) { | |||
if(!sync_in) | |||
sync_in = locals; | |||
if(doclist._kl) | |||
doclist = wn.model.expand(doclist); | |||
if(doclist && sync_in==locals) | |||
wn.model.clear_doclist(doclist[0].doctype, doclist[0].name) | |||
$.each(doclist, function(i, d) { | |||
if(!d.name) // get name (local if required) | |||
d.name = wn.model.get_new_name(d.doctype); | |||
if(!sync_in[d.doctype]) | |||
sync_in[d.doctype] = {}; | |||
sync_in[d.doctype][d.name] = d; | |||
d.__last_sync_on = new Date(); | |||
if(cur_frm && cur_frm.doctype==d.doctype && cur_frm.docname==d.name) { | |||
cur_frm.doc = d; | |||
} | |||
if(d.doctype=='DocField') wn.meta.add_field(d); | |||
if(d.doctype=='DocType') wn.meta.sync_messages(d); | |||
if(d.localname) { | |||
wn.model.new_names[d.localname] = d.name; | |||
$(document).trigger('rename', [d.doctype, d.localname, d.name]); | |||
delete sync_in[d.doctype][d.localname]; | |||
} | |||
}); | |||
}, | |||
expand: function(data) { | |||
function zip(k,v) { | |||
var obj = {}; | |||
for(var i=0;i<k.length;i++) { | |||
obj[k[i]] = v[i]; | |||
} | |||
return obj; | |||
} | |||
var l = []; | |||
for(var i=0;i<data._vl.length;i++) { | |||
l.push(zip(data._kl[data._vl[i][0]], data._vl[i])); | |||
} | |||
return l; | |||
}, | |||
compress: function(doclist) { | |||
var keys = {}; var values = []; | |||
function get_key_list(doctype) { | |||
// valid standard keys | |||
var key_list = ['doctype', 'name', 'docstatus', 'owner', 'parent', | |||
'parentfield', 'parenttype', 'idx', 'creation', 'modified', | |||
'modified_by', '__islocal', '__newname', '__modified', | |||
'_user_tags', '__temp']; | |||
for(key in wn.meta.docfield_map[doctype]) { // all other values | |||
if(!in_list(key_list, key) | |||
&& !in_list(no_value_fields, wn.meta.docfield_map[doctype][key].fieldtype) | |||
&& !wn.meta.docfield_map[doctype][key].no_column) { | |||
key_list[key_list.length] = key | |||
} | |||
} | |||
return key_list; | |||
} | |||
for(var i=0; i<doclist.length;i++) { | |||
var doc = doclist[i]; | |||
// make keys | |||
if(!keys[doc.doctype]) { | |||
keys[doc.doctype] = get_key_list(doc.doctype); | |||
// doctype must be first | |||
} | |||
var row = [] | |||
var key_list = keys[doc.doctype]; | |||
// make data rows | |||
for(var j=0;j<key_list.length;j++) { | |||
row.push(doc[key_list[j]]); | |||
} | |||
values.push(row); | |||
} | |||
return JSON.stringify({'_vl':values, '_kl':keys}); | |||
} | |||
}); |
@@ -40,5 +40,6 @@ wn._ = function(txt) { | |||
return txt; | |||
} | |||
wn.provide('wn.settings'); | |||
wn.provide('wn.ui'); | |||
wn.provide("locals"); | |||
wn.provide("wn.settings"); | |||
wn.provide("wn.ui"); |
@@ -87,7 +87,7 @@ wn.request.cleanup = function(opts, r) { | |||
// sync docs | |||
if(r.docs) { | |||
LocalDB.sync(r.docs); | |||
wn.model.sync(r.docs); | |||
} | |||
wn.last_response = r; | |||
@@ -148,7 +148,7 @@ wn.call = function(opts) { | |||
} else if(opts.doc) { | |||
$.extend(args, { | |||
cmd: "runserverobj", | |||
docs: compress_doclist(wn.model.get_doclist(opts.doc.doctype, | |||
docs: wn.model.compress(wn.model.get_doclist(opts.doc.doctype, | |||
opts.doc.name)), | |||
method: opts.method, | |||
args: opts.args, | |||
@@ -65,7 +65,7 @@ wn.ui.Listing = Class.extend({ | |||
if(wn.boot.profile.can_create.indexOf(this.opts.new_doctype)==-1) { | |||
this.opts.new_doctype = null; | |||
} else { | |||
this.opts.new_doctype = get_doctype_label(this.opts.new_doctype); | |||
this.opts.new_doctype = wn._(this.opts.new_doctype); | |||
} | |||
} | |||
if(!this.opts.no_result_message) { | |||
@@ -10,7 +10,7 @@ wn.ui.set_user_background = function(src) { | |||
wn.ui.themes = { | |||
"Default": { | |||
sidebar: "#f2f2f2", | |||
titlebar: "#dfdfdf", | |||
titlebar: "#d2d2d2", | |||
toolbar: "#e9e9e9" | |||
}, | |||
Desert: { | |||
@@ -82,7 +82,7 @@ wn.ui.toolbar.SelectorDialog = Class.extend({ | |||
set_values: function(lst) { | |||
// convert to labels | |||
for(var i=0;i<lst.length;i++) | |||
lst[i]=get_doctype_label(lst[i]); | |||
lst[i]=wn._(lst[i]); | |||
// set values | |||
var sel = this.dialog.fields_dict.doctype.input; | |||
@@ -45,7 +45,7 @@ wn.views.doclistview.show = function(doctype) { | |||
wn.views.DocListView = wn.ui.Listing.extend({ | |||
init: function(doctype) { | |||
this.doctype = doctype; | |||
this.label = get_doctype_label(doctype); | |||
this.label = wn._(doctype); | |||
this.label = (this.label.toLowerCase().substr(-4) == 'list') ? | |||
this.label : (this.label + ' List'); | |||
this.make_page(); | |||
@@ -15,7 +15,7 @@ wn.views.formview = { | |||
if(!(locals[dt] && locals[dt][dn])) { | |||
if(dn && dn.substr(0,4)=="New ") { | |||
var new_name = LocalDB.create(dt); | |||
var new_name = wn.model.make_new_doc_and_get_name(dt); | |||
wn.views.formview.show(dt, new_name); | |||
return; | |||
} else { | |||
@@ -33,7 +33,7 @@ wn.views.formview = { | |||
}) | |||
}, | |||
create: function(dt) { | |||
var new_name = LocalDB.create(dt); | |||
var new_name = wn.model.make_new_doc_and_get_name(dt); | |||
wn.set_route('Form', dt, new_name); | |||
} | |||
} |
@@ -23,7 +23,6 @@ | |||
wn.views.reportview = { | |||
show: function(dt, rep_name) { | |||
wn.require('js/report-legacy.js'); | |||
dt = get_label_doctype(dt); | |||
if(!_r.rb_con) { | |||
// first load | |||
@@ -286,7 +286,7 @@ def doclist(lst=None): | |||
from webnotes.model.doclist import DocList | |||
return DocList(lst) | |||
def model_wrapper(doctype, name=None): | |||
def model_wrapper(doctype=None, name=None): | |||
from webnotes.model.wrapper import ModelWrapper | |||
return ModelWrapper(doctype, name) | |||
@@ -80,6 +80,10 @@ def save_uploaded(): | |||
return None, fname | |||
def save_url(file_url): | |||
if not (file_url.startswith("http://") or file_url.startswith("https://")): | |||
webnotes.msgprint("URL must start with 'http://' or 'https://'") | |||
return None, None | |||
f = webnotes.doc("File Data") | |||
f.file_url = file_url | |||
f.file_name = file_url.split('/')[-1] | |||
@@ -93,7 +97,7 @@ def get_uploaded_content(): | |||
webnotes.uploaded_filename, webnotes.uploaded_content = i.filename, i.file.read() | |||
return webnotes.uploaded_filename, webnotes.uploaded_content | |||
else: | |||
webnotes.msgprint('No File'); | |||
webnotes.msgprint('No File') | |||
return None, None | |||
def save_file(fname, content, module=None): | |||
@@ -23,6 +23,7 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
import webnotes.model.doc | |||
import webnotes.utils | |||
@webnotes.whitelist() | |||
def getdoc(): | |||
@@ -25,32 +25,40 @@ import webnotes | |||
@webnotes.whitelist() | |||
def savedocs(): | |||
"""save / submit / cancel / update doclist""" | |||
"""save / submit / update doclist""" | |||
try: | |||
from webnotes.model.wrapper import ModelWrapper | |||
form = webnotes.form_dict | |||
doclist = ModelWrapper() | |||
doclist.from_compressed(form.get('docs'), form.get('docname')) | |||
doclist = webnotes.model_wrapper() | |||
doclist.from_compressed(webnotes.form_dict.docs, webnotes.form_dict.docname) | |||
# action | |||
action = form.get('action') | |||
action = webnotes.form_dict.action | |||
if action=='Update': action='update_after_submit' | |||
getattr(doclist, action.lower())() | |||
# update recent documents | |||
webnotes.user.update_recent(doclist.doc.doctype, doclist.doc.name) | |||
send_updated_docs(doclist) | |||
# send updated docs | |||
webnotes.response['saved'] = '1' | |||
webnotes.response['main_doc_name'] = doclist.doc.name | |||
webnotes.response['doctype'] = doclist.doc.doctype | |||
webnotes.response['docname'] = doclist.doc.name | |||
webnotes.response['docs'] = [doclist.doc] + doclist.children | |||
except Exception, e: | |||
webnotes.msgprint(webnotes._('Did not save')) | |||
webnotes.errprint(webnotes.utils.getTraceback()) | |||
raise e | |||
@webnotes.whitelist() | |||
def cancel(doctype=None, name=None): | |||
"""cancel a doclist""" | |||
try: | |||
doclist = webnotes.model_wrapper(doctype, name) | |||
doclist.cancel() | |||
send_updated_docs(doclist) | |||
except Exception, e: | |||
webnotes.msgprint('Did not save') | |||
webnotes.errprint(webnotes.utils.getTraceback()) | |||
webnotes.msgprint(webnotes._("Did not cancel")) | |||
raise e | |||
def send_updated_docs(doclist): | |||
webnotes.response['main_doc_name'] = doclist.doc.name | |||
webnotes.response['doctype'] = doclist.doc.doctype | |||
webnotes.response['docname'] = doclist.doc.name | |||
webnotes.response['docs'] = [doclist.doc] + doclist.children |