FormMeta, Form Load, refactored client side Model and Meta - #478
This commit is contained in:
parent
ae2fc7ada2
commit
d5d9c8c563
41 changed files with 548 additions and 513 deletions
|
|
@ -96,9 +96,9 @@ def init(site, sites_path=None):
|
|||
local.site_path = os.path.join(sites_path, site)
|
||||
local.message_log = []
|
||||
local.debug_log = []
|
||||
local.response = _dict({})
|
||||
local.lang = "en"
|
||||
local.request_method = request.method if request else None
|
||||
local.response = _dict({"docs":[]})
|
||||
local.conf = _dict(get_site_config())
|
||||
local.initialised = True
|
||||
local.flags = _dict({})
|
||||
|
|
@ -115,6 +115,15 @@ def init(site, sites_path=None):
|
|||
|
||||
setup_module_map()
|
||||
|
||||
def connect(site=None, db_name=None):
|
||||
from database import Database
|
||||
if site:
|
||||
init(site)
|
||||
local.db = Database(user=db_name or local.conf.db_name)
|
||||
local.form_dict = _dict()
|
||||
local.session = _dict()
|
||||
set_user("Administrator")
|
||||
|
||||
def get_site_config(sites_path=None, site_path=None):
|
||||
config = {}
|
||||
|
||||
|
|
@ -200,16 +209,6 @@ def throw(msg, exc=ValidationError):
|
|||
def create_folder(path):
|
||||
if not os.path.exists(path): os.makedirs(path)
|
||||
|
||||
def connect(site=None, db_name=None):
|
||||
from database import Database
|
||||
if site:
|
||||
init(site)
|
||||
local.db = Database(user=db_name or local.conf.db_name)
|
||||
local.response = _dict()
|
||||
local.form_dict = _dict()
|
||||
local.session = _dict()
|
||||
set_user("Administrator")
|
||||
|
||||
def set_user(username):
|
||||
from frappe.utils.user import User
|
||||
local.session["user"] = username
|
||||
|
|
|
|||
|
|
@ -65,9 +65,6 @@ def get_bootinfo():
|
|||
for method in hooks.boot_session or []:
|
||||
frappe.get_attr(method)(bootinfo)
|
||||
|
||||
from frappe.model.utils import compress
|
||||
bootinfo['docs'] = compress(bootinfo['docs'])
|
||||
|
||||
if bootinfo.lang:
|
||||
bootinfo.lang = unicode(bootinfo.lang)
|
||||
|
||||
|
|
@ -138,10 +135,10 @@ def add_home_page(bootinfo, doclist):
|
|||
home_page = frappe.get_application_home_page(frappe.session.user)
|
||||
|
||||
try:
|
||||
page_doclist = frappe.widgets.page.get(home_page)
|
||||
page = frappe.widgets.page.get(home_page)
|
||||
except (frappe.DoesNotExistError, frappe.PermissionError), e:
|
||||
page_doclist = frappe.widgets.page.get('desktop')
|
||||
|
||||
bootinfo['home_page_html'] = page_doclist[0].content
|
||||
bootinfo['home_page'] = page_doclist[0].name
|
||||
doclist += page_doclist
|
||||
frappe.message_log.pop()
|
||||
page = frappe.widgets.page.get('desktop')
|
||||
|
||||
bootinfo['home_page'] = page.name
|
||||
doclist.append(page)
|
||||
|
|
|
|||
|
|
@ -9,23 +9,20 @@ import os
|
|||
|
||||
from frappe.utils import now, cint
|
||||
from frappe.model import no_value_fields
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc=None, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
class DocType(Document):
|
||||
def validate(self):
|
||||
if not frappe.conf.get("developer_mode"):
|
||||
frappe.throw("Not in Developer Mode! Set in site_config.json")
|
||||
for c in [".", "/", "#", "&", "=", ":", "'", '"']:
|
||||
if c in self.doc.name:
|
||||
if c in self.name:
|
||||
frappe.msgprint(c + " not allowed in name", raise_exception=1)
|
||||
self.validate_series()
|
||||
self.scrub_field_names()
|
||||
self.validate_title_field()
|
||||
validate_fields(self.doclist.get({"doctype":"DocField"}))
|
||||
validate_permissions(self.doclist.get({"doctype":"DocPerm"}))
|
||||
validate_fields(self.get("fields"))
|
||||
validate_permissions(self.get("permissions"))
|
||||
self.make_amendable()
|
||||
self.check_link_replacement_error()
|
||||
|
||||
|
|
@ -33,14 +30,14 @@ class DocType:
|
|||
if frappe.flags.in_import:
|
||||
return
|
||||
parent_list = frappe.db.sql("""SELECT parent
|
||||
from tabDocField where fieldtype="Table" and options=%s""", self.doc.name)
|
||||
from tabDocField where fieldtype="Table" and options=%s""", self.name)
|
||||
for p in parent_list:
|
||||
frappe.db.sql('UPDATE tabDocType SET modified=%s WHERE `name`=%s', (now(), p[0]))
|
||||
|
||||
def scrub_field_names(self):
|
||||
restricted = ('name','parent','idx','owner','creation','modified','modified_by',
|
||||
'parentfield','parenttype',"file_list")
|
||||
for d in self.doclist:
|
||||
for d in self.get("fields"):
|
||||
if d.parent and d.fieldtype:
|
||||
if (not d.fieldname):
|
||||
if d.label:
|
||||
|
|
@ -52,16 +49,16 @@ class DocType:
|
|||
|
||||
|
||||
def validate_title_field(self):
|
||||
if self.doc.title_field and \
|
||||
self.doc.title_field not in [d.fieldname for d in self.doclist.get({"doctype":"DocField"})]:
|
||||
if self.title_field and \
|
||||
self.title_field not in [d.fieldname for d in self.get("fields")]:
|
||||
frappe.throw(_("Title field must be a valid fieldname"))
|
||||
|
||||
def validate_series(self, autoname=None, name=None):
|
||||
if not autoname: autoname = self.doc.autoname
|
||||
if not name: name = self.doc.name
|
||||
if not autoname: autoname = self.autoname
|
||||
if not name: name = self.name
|
||||
|
||||
if not autoname and self.doclist.get({"fieldname":"naming_series"}):
|
||||
self.doc.autoname = "naming_series:"
|
||||
if not autoname and self.get("fields", {"fieldname":"naming_series"}):
|
||||
self.autoname = "naming_series:"
|
||||
|
||||
if autoname and (not autoname.startswith('field:')) and (not autoname.startswith('eval:')) \
|
||||
and (not autoname=='Prompt') and (not autoname.startswith('naming_series:')):
|
||||
|
|
@ -72,10 +69,10 @@ class DocType:
|
|||
|
||||
def on_update(self):
|
||||
from frappe.model.db_schema import updatedb
|
||||
updatedb(self.doc.name)
|
||||
updatedb(self.name)
|
||||
|
||||
self.change_modified_of_parent()
|
||||
make_module_and_roles(self.doclist)
|
||||
make_module_and_roles(self)
|
||||
|
||||
from frappe import conf
|
||||
if (not frappe.flags.in_import) and conf.get('developer_mode') or 0:
|
||||
|
|
@ -83,53 +80,53 @@ class DocType:
|
|||
self.make_controller_template()
|
||||
|
||||
# update index
|
||||
if not self.doc.custom:
|
||||
if not self.custom:
|
||||
from frappe.model.code import load_doctype_module
|
||||
module = load_doctype_module( self.doc.name, self.doc.module)
|
||||
module = load_doctype_module( self.name, self.module)
|
||||
if hasattr(module, "on_doctype_update"):
|
||||
module.on_doctype_update()
|
||||
frappe.clear_cache(doctype=self.doc.name)
|
||||
frappe.clear_cache(doctype=self.name)
|
||||
|
||||
def check_link_replacement_error(self):
|
||||
for d in self.doclist.get({"doctype":"DocField", "fieldtype":"Select"}):
|
||||
for d in self.get("fields", {"fieldtype":"Select"}):
|
||||
if (frappe.db.get_value("DocField", d.name, "options") or "").startswith("link:") \
|
||||
and not d.options.startswith("link:"):
|
||||
frappe.msgprint("link: type Select fields are getting replaced. Please check for %s" % d.label,
|
||||
raise_exception=True)
|
||||
|
||||
def on_trash(self):
|
||||
frappe.db.sql("delete from `tabCustom Field` where dt = %s", self.doc.name)
|
||||
frappe.db.sql("delete from `tabCustom Script` where dt = %s", self.doc.name)
|
||||
frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", self.doc.name)
|
||||
frappe.db.sql("delete from `tabReport` where ref_doctype=%s", self.doc.name)
|
||||
frappe.db.sql("delete from `tabCustom Field` where dt = %s", self.name)
|
||||
frappe.db.sql("delete from `tabCustom Script` where dt = %s", self.name)
|
||||
frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", self.name)
|
||||
frappe.db.sql("delete from `tabReport` where ref_doctype=%s", self.name)
|
||||
|
||||
def before_rename(self, old, new, merge=False):
|
||||
if merge:
|
||||
frappe.throw(_("DocType can not be merged"))
|
||||
|
||||
def after_rename(self, old, new, merge=False):
|
||||
if self.doc.issingle:
|
||||
if self.issingle:
|
||||
frappe.db.sql("""update tabSingles set doctype=%s where doctype=%s""", (new, old))
|
||||
else:
|
||||
frappe.db.sql("rename table `tab%s` to `tab%s`" % (old, new))
|
||||
|
||||
def export_doc(self):
|
||||
from frappe.modules.export_file import export_to_files
|
||||
export_to_files(record_list=[['DocType', self.doc.name]])
|
||||
export_to_files(record_list=[['DocType', self.name]])
|
||||
|
||||
def import_doc(self):
|
||||
from frappe.modules.import_module import import_from_files
|
||||
import_from_files(record_list=[[self.doc.module, 'doctype', self.doc.name]])
|
||||
import_from_files(record_list=[[self.module, 'doctype', self.name]])
|
||||
|
||||
def make_controller_template(self):
|
||||
from frappe.modules import get_doc_path, get_module_path, scrub
|
||||
|
||||
pypath = os.path.join(get_doc_path(self.doc.module,
|
||||
self.doc.doctype, self.doc.name), scrub(self.doc.name) + '.py')
|
||||
pypath = os.path.join(get_doc_path(self.module,
|
||||
self.doctype, self.name), scrub(self.name) + '.py')
|
||||
|
||||
if not os.path.exists(pypath):
|
||||
# get app publisher for copyright
|
||||
app = frappe.local.module_app[frappe.scrub(self.doc.module)]
|
||||
app = frappe.local.module_app[frappe.scrub(self.module)]
|
||||
if not app:
|
||||
frappe.throw("App not found!")
|
||||
app_publisher = frappe.get_hooks(hook="app_publisher", app_name=app)[0]
|
||||
|
|
@ -143,23 +140,22 @@ class DocType:
|
|||
"""
|
||||
if is_submittable is set, add amended_from docfields
|
||||
"""
|
||||
if self.doc.is_submittable:
|
||||
if self.is_submittable:
|
||||
if not frappe.db.sql("""select name from tabDocField
|
||||
where fieldname = 'amended_from' and parent = %s""", self.doc.name):
|
||||
new = self.doc.addchild('fields', 'DocField', self.doclist)
|
||||
new.label = 'Amended From'
|
||||
new.fieldtype = 'Link'
|
||||
new.fieldname = 'amended_from'
|
||||
new.options = self.doc.name
|
||||
new.permlevel = 0
|
||||
new.read_only = 1
|
||||
new.print_hide = 1
|
||||
new.no_copy = 1
|
||||
new.idx = self.get_max_idx() + 1
|
||||
where fieldname = 'amended_from' and parent = %s""", self.name):
|
||||
self.append("fields", {
|
||||
"label": "Amended From",
|
||||
"fieldtype": "Link",
|
||||
"fieldname": "amended_from",
|
||||
"options": self.name,
|
||||
"read_only": 1,
|
||||
"print_hide": 1,
|
||||
"no_copy": 1
|
||||
})
|
||||
|
||||
def get_max_idx(self):
|
||||
max_idx = frappe.db.sql("""select max(idx) from `tabDocField` where parent = %s""",
|
||||
self.doc.name)
|
||||
self.name)
|
||||
return max_idx and max_idx[0][0] or 0
|
||||
|
||||
def validate_fields_for_doctype(doctype):
|
||||
|
|
@ -329,14 +325,14 @@ def validate_permissions(permissions, for_remove=False):
|
|||
check_level_zero_is_set(d)
|
||||
remove_rights_for_single(d)
|
||||
|
||||
def make_module_and_roles(doclist, perm_doctype="DocPerm"):
|
||||
def make_module_and_roles(doc, perm_fieldname="permissions"):
|
||||
try:
|
||||
if not frappe.db.exists("Module Def", doclist[0].module):
|
||||
m = frappe.bean({"doctype": "Module Def", "module_name": doclist[0].module})
|
||||
if not frappe.db.exists("Module Def", doc.module):
|
||||
m = frappe.bean({"doctype": "Module Def", "module_name": doc.module})
|
||||
m.insert()
|
||||
|
||||
default_roles = ["Administrator", "Guest", "All"]
|
||||
roles = [p.role for p in doclist.get({"doctype": perm_doctype})] + default_roles
|
||||
roles = [p.role for p in doc.get(permissions)] + default_roles
|
||||
|
||||
for role in list(set(roles)):
|
||||
if not frappe.db.exists("Role", role):
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d,dl
|
||||
|
||||
class Page(Document):
|
||||
def autoname(self):
|
||||
"""
|
||||
Creates a url friendly name for this page.
|
||||
|
|
@ -15,17 +13,17 @@ class DocType:
|
|||
it will add name-1, name-2 etc.
|
||||
"""
|
||||
from frappe.utils import cint
|
||||
if (self.doc.name and self.doc.name.startswith('New Page')) or not self.doc.name:
|
||||
self.doc.name = self.doc.page_name.lower().replace('"','').replace("'",'').\
|
||||
if (self.name and self.name.startswith('New Page')) or not self.name:
|
||||
self.name = self.page_name.lower().replace('"','').replace("'",'').\
|
||||
replace(' ', '-')[:20]
|
||||
if frappe.db.exists('Page',self.doc.name):
|
||||
if frappe.db.exists('Page',self.name):
|
||||
cnt = frappe.db.sql("""select name from tabPage
|
||||
where name like "%s-%%" order by name desc limit 1""" % self.doc.name)
|
||||
where name like "%s-%%" order by name desc limit 1""" % self.name)
|
||||
if cnt:
|
||||
cnt = cint(cnt[0][0].split('-')[-1]) + 1
|
||||
else:
|
||||
cnt = 1
|
||||
self.doc.name += '-' + str(cnt)
|
||||
self.name += '-' + str(cnt)
|
||||
|
||||
# export
|
||||
def on_update(self):
|
||||
|
|
@ -35,16 +33,16 @@ class DocType:
|
|||
"""
|
||||
from frappe import conf
|
||||
from frappe.core.doctype.doctype.doctype import make_module_and_roles
|
||||
make_module_and_roles(self.doclist, "Page Role")
|
||||
make_module_and_roles(self, "roles")
|
||||
|
||||
if not frappe.flags.in_import and getattr(conf,'developer_mode', 0) and self.doc.standard=='Yes':
|
||||
if not frappe.flags.in_import and getattr(conf,'developer_mode', 0) and self.standard=='Yes':
|
||||
from frappe.modules.export_file import export_to_files
|
||||
from frappe.modules import get_module_path, scrub
|
||||
import os
|
||||
export_to_files(record_list=[['Page', self.doc.name]])
|
||||
export_to_files(record_list=[['Page', self.name]])
|
||||
|
||||
# write files
|
||||
path = os.path.join(get_module_path(self.doc.module), 'page', scrub(self.doc.name), scrub(self.doc.name))
|
||||
path = os.path.join(get_module_path(self.module), 'page', scrub(self.name), scrub(self.name))
|
||||
|
||||
# js
|
||||
if not os.path.exists(path + '.js'):
|
||||
|
|
@ -55,35 +53,39 @@ class DocType:
|
|||
title: '%s',
|
||||
single_column: true
|
||||
});
|
||||
}""" % (self.doc.name, self.doc.title))
|
||||
}""" % (self.name, self.title))
|
||||
|
||||
def get_from_files(self):
|
||||
"""
|
||||
Loads page info from files in module
|
||||
"""
|
||||
def as_dict(self):
|
||||
d = super(Page, self).as_dict()
|
||||
for key in ("script", "style", "content"):
|
||||
d[key] = self.get(key)
|
||||
return d
|
||||
|
||||
def load_assets(self):
|
||||
from frappe.modules import get_module_path, scrub
|
||||
import os
|
||||
|
||||
path = os.path.join(get_module_path(self.doc.module), 'page', scrub(self.doc.name))
|
||||
|
||||
path = os.path.join(get_module_path(self.module), 'page', scrub(self.name))
|
||||
|
||||
# script
|
||||
fpath = os.path.join(path, scrub(self.doc.name) + '.js')
|
||||
fpath = os.path.join(path, scrub(self.name) + '.js')
|
||||
if os.path.exists(fpath):
|
||||
with open(fpath, 'r') as f:
|
||||
self.doc.script = f.read()
|
||||
self.script = f.read()
|
||||
|
||||
# css
|
||||
fpath = os.path.join(path, scrub(self.doc.name) + '.css')
|
||||
fpath = os.path.join(path, scrub(self.name) + '.css')
|
||||
if os.path.exists(fpath):
|
||||
with open(fpath, 'r') as f:
|
||||
self.doc.style = f.read()
|
||||
self.style = f.read()
|
||||
|
||||
# html
|
||||
fpath = os.path.join(path, scrub(self.doc.name) + '.html')
|
||||
fpath = os.path.join(path, scrub(self.name) + '.html')
|
||||
if os.path.exists(fpath):
|
||||
with open(fpath, 'r') as f:
|
||||
self.doc.content = f.read()
|
||||
self.content = f.read()
|
||||
|
||||
if frappe.lang != 'en':
|
||||
from frappe.translate import get_lang_js
|
||||
self.doc.script += get_lang_js("page", self.doc.name)
|
||||
self.script += get_lang_js("page", self.name)
|
||||
|
||||
|
|
@ -151,8 +151,7 @@ frappe.RoleEditor = Class.extend({
|
|||
.each(function(i, checkbox) { checkbox.checked = false; });
|
||||
|
||||
// set user roles as checked
|
||||
$.each(frappe.model.get("UserRole", {parent: cur_frm.doc.name,
|
||||
parentfield: "user_roles"}), function(i, user_role) {
|
||||
$.each((cur_frm.doc.user_roles || []), function(i, user_role) {
|
||||
var checkbox = $(me.wrapper)
|
||||
.find('[data-user-role="'+user_role.role+'"] input[type="checkbox"]').get(0);
|
||||
if(checkbox) checkbox.checked = true;
|
||||
|
|
@ -163,8 +162,7 @@ frappe.RoleEditor = Class.extend({
|
|||
var existing_roles_map = {};
|
||||
var existing_roles_list = [];
|
||||
|
||||
$.each(frappe.model.get("UserRole", {parent: cur_frm.doc.name,
|
||||
parentfield: "user_roles"}), function(i, user_role) {
|
||||
$.each((cur_frm.doc.user_roles || []), function(i, user_role) {
|
||||
existing_roles_map[user_role.role] = user_role.name;
|
||||
existing_roles_list.push(user_role.role);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,11 +20,9 @@ frappe.core.Workflow = frappe.ui.form.Controller.extend({
|
|||
}
|
||||
},
|
||||
update_field_options: function() {
|
||||
var fields = $.map(frappe.model.get("DocField", {
|
||||
parent: this.frm.doc.document_type,
|
||||
fieldtype: ["not in", frappe.model.no_value_type]
|
||||
}),
|
||||
function(d) { return d.fieldname; });
|
||||
var fields = $.map(frappe.model.get_doc("DocType", this.frm.doc.document_type).fields, function(d) {
|
||||
return frappe.model.no_value_type.indexOf(d.fieldtype)===-1 ? d.fieldname : null;
|
||||
})
|
||||
frappe.meta.get_docfield("Workflow Document State", "update_field", this.frm.doc.name).options
|
||||
= [""].concat(fields);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,17 +428,15 @@ frappe.PermissionEngine = Class.extend({
|
|||
});
|
||||
},
|
||||
get_user_fields: function(doctype) {
|
||||
var user_fields = frappe.model.get("DocField", {parent:doctype,
|
||||
fieldtype:"Link", options:"User"});
|
||||
|
||||
user_fields = user_fields.concat(frappe.model.get("DocField", {parent:doctype,
|
||||
fieldtype:"Select", link_doctype:"User"}))
|
||||
|
||||
var user_fields = frappe.model.get_children("DocType", doctype, "fields", {fieldtype:"Link", options:"User"})
|
||||
user_fields = user_fields.concat(frappe.model.get_children("DocType", doctype, "fields",
|
||||
{fieldtype:"Select", link_doctype:"User"}))
|
||||
|
||||
return user_fields
|
||||
},
|
||||
get_link_fields: function(doctype) {
|
||||
return link_fields = frappe.model.get("DocField", {parent:doctype,
|
||||
fieldtype:"Link", options:["not in", ["User", '[Select]']]});
|
||||
return frappe.model.get_children("DocType", doctype, "fields",
|
||||
{fieldtype:"Link", options:["not in", ["User", '[Select]']]});
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ def handle():
|
|||
|
||||
if cmd!='login':
|
||||
execute_cmd(cmd)
|
||||
|
||||
|
||||
return build_response("json")
|
||||
|
||||
def execute_cmd(cmd):
|
||||
|
|
|
|||
|
|
@ -110,6 +110,16 @@ class BaseDocument(object):
|
|||
|
||||
return self._valid_columns
|
||||
|
||||
def as_dict(self):
|
||||
doc = self.get_valid_dict()
|
||||
doc["doctype"] = self.doctype
|
||||
for df in self.get_table_fields():
|
||||
doc[df.fieldname] = [d.as_dict() for d in (self.get(df.fieldname) or [])]
|
||||
return doc
|
||||
|
||||
def get_table_fields(self):
|
||||
return self.meta.get('fields', {"fieldtype":"Table"})
|
||||
|
||||
def get_table_field_doctype(self, fieldname):
|
||||
return self.meta.get("fields", {"fieldname":fieldname})[0].options
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ def get_obj(dt = None, dn = None, doc=None, doclist=None, with_children = 0):
|
|||
def get_server_obj(doc, doclist = [], basedoctype = ''):
|
||||
# for test
|
||||
module = get_doctype_module(doc.doctype)
|
||||
classname = doc.doctype.replace(" ", "")
|
||||
return load_doctype_module(doc.doctype, module).DocType(doc, doclist)
|
||||
|
||||
def run_server_obj(server_obj, method_name, arg=None):
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ def clear_cache(doctype=None):
|
|||
def clear_single(dt):
|
||||
frappe.cache().delete_value(cache_name(dt, False))
|
||||
frappe.cache().delete_value(cache_name(dt, True))
|
||||
frappe.cache().delete_value("meta:" + dt)
|
||||
frappe.cache().delete_value("form_meta:" + dt)
|
||||
|
||||
if doctype_cache and (dt in doctype_cache):
|
||||
del doctype_cache[dt]
|
||||
|
|
|
|||
|
|
@ -16,15 +16,20 @@ def get_doc(arg1, arg2=None):
|
|||
doctype = arg1
|
||||
else:
|
||||
doctype = arg1.get("doctype")
|
||||
|
||||
|
||||
controller = get_controller(doctype)
|
||||
if controller:
|
||||
return controller(arg1, arg2)
|
||||
|
||||
return Document(arg1, arg2)
|
||||
|
||||
def get_controller(doctype):
|
||||
module = load_doctype_module(doctype)
|
||||
classname = doctype.replace(" ", "")
|
||||
if hasattr(module, classname):
|
||||
_class = getattr(module, classname)
|
||||
if issubclass(_class, Document):
|
||||
return getattr(module, classname)(arg1, arg2)
|
||||
|
||||
return Document(arg1, arg2)
|
||||
return getattr(module, classname)
|
||||
|
||||
class Document(BaseDocument):
|
||||
def __init__(self, arg1, arg2=None):
|
||||
|
|
@ -59,6 +64,9 @@ class Document(BaseDocument):
|
|||
|
||||
else:
|
||||
d = frappe.db.get_value(self.doctype, self.name, "*", as_dict=1)
|
||||
if not d:
|
||||
frappe.throw("{}: {}, {}".format(_("Not Found"),
|
||||
self.doctype, self.name), frappe.DoesNotExistError)
|
||||
self.update(d, valid_columns = d.keys())
|
||||
|
||||
for df in self.get_table_fields():
|
||||
|
|
@ -70,9 +78,6 @@ class Document(BaseDocument):
|
|||
else:
|
||||
self.set(df.fieldname, [])
|
||||
|
||||
def get_table_fields(self):
|
||||
return self.meta.get('fields', {"fieldtype":"Table"})
|
||||
|
||||
def has_permission(self, permtype):
|
||||
if getattr(self, "_ignore_permissions", False):
|
||||
return True
|
||||
|
|
@ -293,23 +298,10 @@ class Document(BaseDocument):
|
|||
|
||||
def run_method(self, method, *args, **kwargs):
|
||||
"""run standard triggers, plus those in frappe"""
|
||||
def add_to_response(out, new_response):
|
||||
if isinstance(new_response, dict):
|
||||
out.update(new_response)
|
||||
|
||||
if hasattr(self, method):
|
||||
add_to_response(frappe.local.response,
|
||||
getattr(self, method)(*args, **kwargs))
|
||||
|
||||
args = [self, method] + list(args or [])
|
||||
|
||||
for handler in frappe.get_hooks("bean_event:" + self.doctype + ":" + method) \
|
||||
+ frappe.get_hooks("bean_event:*:" + method):
|
||||
add_to_response(frappe.local.response,
|
||||
frappe.call(frappe.get_attr(handler), *args, **kwargs))
|
||||
|
||||
return frappe.local.response
|
||||
|
||||
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
|
||||
return Document.hook(fn)(self, *args, **kwargs)
|
||||
|
||||
def run_before_save_methods(self):
|
||||
if self._action=="save":
|
||||
self.run_method("validate")
|
||||
|
|
@ -332,3 +324,31 @@ class Document(BaseDocument):
|
|||
self.run_method("on_cancel")
|
||||
elif self._action=="update_after_submit":
|
||||
self.run_method("on_update_after_submit")
|
||||
|
||||
@staticmethod
|
||||
def hook(f):
|
||||
def add_to_response(new_response):
|
||||
if isinstance(new_response, dict):
|
||||
frappe.local.response.update(new_response)
|
||||
|
||||
def compose(fn, *hooks):
|
||||
def runner(self, method, *args, **kwargs):
|
||||
add_to_response(fn(self, *args, **kwargs))
|
||||
for f in hooks:
|
||||
add_to_response(f(self, method, *args, **kwargs))
|
||||
return frappe.local.response
|
||||
|
||||
return runner
|
||||
|
||||
def composer(self, *args, **kwargs):
|
||||
hooks = []
|
||||
method = f.__name__
|
||||
for handler in frappe.get_hooks("bean_event:" + self.doctype + ":" + method) \
|
||||
+ frappe.get_hooks("bean_event:*:" + method):
|
||||
hooks.append(frappe.getattr(handler))
|
||||
|
||||
composed = compose(f, *hooks)
|
||||
return composed(self, method, *args, **kwargs)
|
||||
|
||||
return composer
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ from frappe.model.document import Document
|
|||
######
|
||||
|
||||
def get_meta(doctype, cached=True):
|
||||
# TODO: cache to be cleared
|
||||
|
||||
if cached:
|
||||
if doctype not in frappe.local.meta:
|
||||
frappe.local.meta[doctype] = frappe.cache().get_value("meta:" + doctype, lambda: Meta(doctype))
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@
|
|||
|
||||
"public/js/frappe/model/model.js",
|
||||
"public/js/frappe/model/meta.js",
|
||||
"public/js/frappe/model/doclist.js",
|
||||
"public/js/frappe/model/sync.js",
|
||||
"public/js/frappe/model/create_new.js",
|
||||
"public/js/frappe/model/perm.js",
|
||||
|
|
@ -135,6 +134,7 @@
|
|||
"public/js/frappe/form/toolbar.js",
|
||||
"public/js/frappe/form/infobar.js",
|
||||
"public/js/frappe/form/dashboard.js",
|
||||
"public/js/frappe/form/save.js",
|
||||
"public/js/frappe/form/script_manager.js",
|
||||
"public/js/frappe/form/control.js",
|
||||
"public/js/frappe/form/link_selector.js",
|
||||
|
|
|
|||
|
|
@ -980,8 +980,9 @@ frappe.ui.form.ControlTable = frappe.ui.form.Control.extend({
|
|||
this._super();
|
||||
|
||||
// add title if prev field is not column / section heading or html
|
||||
var prev_fieldtype = frappe.model.get("DocField",
|
||||
{parent: this.frm.doctype, idx: this.df.idx-1})[0].fieldtype;
|
||||
var prev_fieldtype = frappe.model.get_children("DocType", this.frm.doctype, "fields",
|
||||
{idx: this.df.idx-1});
|
||||
prev_fieldtype = prev_fieldtype ? prev_fieldtype[0].fieldtype : "";
|
||||
|
||||
if(["Column Break", "Section Break", "HTML"].indexOf(prev_fieldtype)===-1) {
|
||||
$("<label>" + this.df.label + "<label>").appendTo(this.wrapper);
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ frappe.form.formatters = {
|
|||
return "<pre>" + (value==null ? "" : $("<div>").text(value).html()) + "</pre>"
|
||||
},
|
||||
WorkflowState: function(value) {
|
||||
workflow_state = frappe.model.get("Workflow State", value)[0];
|
||||
workflow_state = frappe.model.get_doc("Workflow State", value);
|
||||
if(workflow_state) {
|
||||
return repl("<span class='label label-%(style)s' \
|
||||
data-workflow-state='%(value)s'\
|
||||
|
|
|
|||
|
|
@ -118,11 +118,7 @@ frappe.ui.form.Grid = Class.extend({
|
|||
});
|
||||
},
|
||||
get_data: function() {
|
||||
var data = frappe.model.get(this.df.options, {
|
||||
"parenttype": this.frm.doctype,
|
||||
"parentfield": this.df.fieldname,
|
||||
"parent": this.frm.docname
|
||||
});
|
||||
var data = this.frm.doc[this.df.fieldname] || [];
|
||||
data.sort(function(a, b) { return a.idx - b.idx});
|
||||
return data;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
// for license information please see license.txt
|
||||
|
||||
frappe.provide("frappe.ui.form")
|
||||
frappe.provide("frappe.ui.form");
|
||||
|
||||
frappe.ui.form.LinkedWith = Class.extend({
|
||||
init: function(opts) {
|
||||
|
|
|
|||
|
|
@ -1,45 +1,38 @@
|
|||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.provide("frappe.model");
|
||||
frappe.model.DocList = Class.extend({
|
||||
init: function(doctype, name) {
|
||||
this.doctype = doctype; this.name = name;
|
||||
this.doclist = frappe.model.get_doclist(this.doctype, this.name);
|
||||
this.doc = this.doclist[0];
|
||||
},
|
||||
|
||||
save: function(action, callback, btn) {
|
||||
this.check_name();
|
||||
if(this.check_mandatory()) {
|
||||
var me = this;
|
||||
this._call({
|
||||
frappe.provide("frappe.ui.form");
|
||||
|
||||
frappe.ui.form.save = function(frm, action, callback, btn) {
|
||||
var save = function() {
|
||||
check_name();
|
||||
if(check_mandatory()) {
|
||||
_call({
|
||||
method: "frappe.widgets.form.save.savedocs",
|
||||
args: { docs: frappe.model.compress(this.doclist), action:action},
|
||||
args: { docs: frm.doc, action:action},
|
||||
callback: function(r) {
|
||||
$(document).trigger("save", me.doc);
|
||||
$(document).trigger("save", frm.doc);
|
||||
callback(r);
|
||||
},
|
||||
btn: btn
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
cancel: function(callback, btn) {
|
||||
var me = this;
|
||||
this._call({
|
||||
var cancel = function() {
|
||||
_call({
|
||||
method: "frappe.widgets.form.save.cancel",
|
||||
args: { doctype: this.doctype, name: this.name },
|
||||
args: { doctype: frm.doc.doctype, name: frm.doc.name },
|
||||
callback: function(r) {
|
||||
$(document).trigger("save", frappe.model.get_doc(me.doctype, me.name));
|
||||
$(document).trigger("save", frm.doc);
|
||||
callback(r);
|
||||
},
|
||||
btn: btn
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
check_name: function() {
|
||||
var doc = this.doclist[0];
|
||||
var check_name = function() {
|
||||
var doc = frm.doc;
|
||||
var meta = locals.DocType[doc.doctype];
|
||||
if(doc.__islocal && (meta && meta.autoname
|
||||
&& meta.autoname.toLowerCase()=='prompt')) {
|
||||
|
|
@ -51,23 +44,22 @@ frappe.model.DocList = Class.extend({
|
|||
throw "name required";
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
check_mandatory: function() {
|
||||
var me = this;
|
||||
var check_mandatory = function() {
|
||||
var has_errors = false;
|
||||
this.scroll_set = false;
|
||||
frm.scroll_set = false;
|
||||
|
||||
if(this.doc.docstatus==2) return true; // don't check for cancel
|
||||
if(frm.doc.docstatus==2) return true; // don't check for cancel
|
||||
|
||||
$.each(this.doclist, function(i, doc) {
|
||||
$.each(frm.model.get_all_docs(frm.doc), function(i, doc) {
|
||||
|
||||
var error_fields = [];
|
||||
|
||||
$.each(frappe.meta.docfield_list[doc.doctype] || [], function(i, docfield) {
|
||||
if(docfield.fieldname) {
|
||||
var df = frappe.meta.get_docfield(doc.doctype,
|
||||
docfield.fieldname, me.doclist[0].name);
|
||||
docfield.fieldname, frm.doc.name);
|
||||
|
||||
if(df.reqd && !frappe.model.has_value(doc.doctype, doc.name, df.fieldname)) {
|
||||
has_errors = true;
|
||||
|
|
@ -87,17 +79,17 @@ frappe.model.DocList = Class.extend({
|
|||
});
|
||||
|
||||
return !has_errors;
|
||||
},
|
||||
};
|
||||
|
||||
scroll_to: function(fieldname) {
|
||||
var scroll_to = function(fieldname) {
|
||||
var f = cur_frm.fields_dict[fieldname];
|
||||
if(f) {
|
||||
$(document).scrollTop($(f.wrapper).offset().top - 100);
|
||||
}
|
||||
this.scroll_set = true;
|
||||
},
|
||||
frm.scroll_set = true;
|
||||
};
|
||||
|
||||
_call: function(opts) {
|
||||
var _call = function(opts) {
|
||||
// opts = {
|
||||
// method: "some server method",
|
||||
// args: {args to be passed},
|
||||
|
|
@ -114,5 +106,11 @@ frappe.model.DocList = Class.extend({
|
|||
opts.callback && opts.callback(r);
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if(action==="cancel") {
|
||||
cancel();
|
||||
} else {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ frappe.ui.form.ScriptManager = Class.extend({
|
|||
}
|
||||
},
|
||||
copy_from_first_row: function(parentfield, current_row, fieldnames) {
|
||||
var doclist = frappe.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name, {parentfield: parentfield});
|
||||
var doclist = this.frm.doc[parentfield];
|
||||
if(doclist.length===1 || doclist[0]===current_row) return;
|
||||
|
||||
$.each(fieldnames, function(i, fieldname) {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ frappe.ui.form.States = Class.extend({
|
|||
// show current state on the button
|
||||
this.workflow_button.find(".state-text").text(state);
|
||||
|
||||
var state_doc = frappe.model.get("Workflow State", {name:state})[0];
|
||||
var state_doc = frappe.model.get_doc("Workflow State", state);
|
||||
|
||||
if (state_doc) {
|
||||
// set the icon
|
||||
|
|
@ -109,7 +109,7 @@ frappe.ui.form.States = Class.extend({
|
|||
|
||||
$.each(frappe.workflow.get_transitions(this.frm.doctype, state), function(i, d) {
|
||||
if(in_list(user_roles, d.allowed)) {
|
||||
d.icon = frappe.model.get("Workflow State", {name:d.next_state})[0].icon;
|
||||
d.icon = frappe.model.get("Workflow State", d.next_state).icon;
|
||||
|
||||
$(repl('<li><a href="#" data-action="%(action)s">\
|
||||
<i class="icon icon-%(icon)s"></i> %(action)s</a></li>', d))
|
||||
|
|
|
|||
|
|
@ -122,20 +122,36 @@ $.extend(frappe.model, {
|
|||
return d;
|
||||
},
|
||||
|
||||
copy_doc: function(dt, dn, from_amend) {
|
||||
copy_doc: function(doc, from_amend) {
|
||||
var no_copy_list = ['name','amended_from','amendment_date','cancel_reason'];
|
||||
var newdoc = frappe.model.get_new_doc(dt);
|
||||
var newdoc = frappe.model.get_new_doc(doc.doctype);
|
||||
|
||||
for(var key in locals[dt][dn]) {
|
||||
for(var key in doc) {
|
||||
// dont copy name and blank fields
|
||||
var df = frappe.meta.get_docfield(dt, key);
|
||||
var df = frappe.meta.get_docfield(doc.doctype, 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];
|
||||
value = doc[key];
|
||||
if(df.fieldtype==="Table") {
|
||||
newdoc[key] = [];
|
||||
$.each(value || [], function(i, d) {
|
||||
newdoc[key].push(frappe.model.copy_doc(d, from_amend))
|
||||
})
|
||||
} else {
|
||||
newdoc[key] = doc[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newdoc.__islocal = 1;
|
||||
newdoc.docstatus = 0;
|
||||
newdoc.owner = user;
|
||||
newdoc.creation = '';
|
||||
newdoc.modified_by = user;
|
||||
newdoc.modified = '';
|
||||
|
||||
return newdoc;
|
||||
},
|
||||
|
||||
|
|
@ -167,7 +183,7 @@ $.extend(frappe.model, {
|
|||
method: opts.method,
|
||||
args: {
|
||||
"source_name": opts.source_name,
|
||||
"target_doclist": frappe.model.get_doclist(cur_frm.doc.doctype, cur_frm.doc.name)
|
||||
"target_doclist": cur_frm.doc
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@ frappe.provide('frappe.meta.doctypes');
|
|||
frappe.provide("frappe.meta.precision_map");
|
||||
|
||||
$.extend(frappe.meta, {
|
||||
sync: function(doc) {
|
||||
$.each(doc.fields, function(i, df) {
|
||||
frappe.meta.add_field(df);
|
||||
})
|
||||
frappe.meta.sync_messages(doc);
|
||||
},
|
||||
|
||||
// build docfield_map and docfield_list
|
||||
add_field: function(df) {
|
||||
frappe.provide('frappe.meta.docfield_map.' + df.parent);
|
||||
|
|
@ -84,8 +91,8 @@ $.extend(frappe.meta, {
|
|||
},
|
||||
|
||||
get_parentfield: function(parent_dt, child_dt) {
|
||||
var df = frappe.model.get("DocField", {parent:parent_dt, fieldtype:"Table",
|
||||
options:child_dt})
|
||||
var df = (frappe.model.get_doc("DocType", parent_dt).fields || []).filter(function(d)
|
||||
{ return d.fieldtype==="Table" && options===child_dt })
|
||||
if(!df.length)
|
||||
throw "parentfield not found for " + parent_dt + ", " + child_dt;
|
||||
return df[0].fieldname;
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ $.extend(frappe.model, {
|
|||
} else {
|
||||
var cached_timestamp = null;
|
||||
if(localStorage["_doctype:" + doctype]) {
|
||||
var cached_doclist = JSON.parse(localStorage["_doctype:" + doctype]);
|
||||
cached_timestamp = cached_doclist[0].modified;
|
||||
var cached_doc = JSON.parse(localStorage["_doctype:" + doctype]);
|
||||
cached_timestamp = cached_doc.modified;
|
||||
}
|
||||
return frappe.call({
|
||||
method:'frappe.widgets.form.load.getdoctype',
|
||||
|
|
@ -64,7 +64,7 @@ $.extend(frappe.model, {
|
|||
return;
|
||||
}
|
||||
if(r.message=="use_cache") {
|
||||
frappe.model.sync(cached_doclist);
|
||||
frappe.model.sync(cached_doc);
|
||||
} else {
|
||||
localStorage["_doctype:" + doctype] = JSON.stringify(r.docs);
|
||||
}
|
||||
|
|
@ -206,10 +206,10 @@ $.extend(frappe.model, {
|
|||
},
|
||||
|
||||
get: function(doctype, filters) {
|
||||
var src = locals[doctype] || locals[":" + doctype] || [];
|
||||
if($.isEmptyObject(src))
|
||||
var docsdict = locals[doctype] || locals[":" + doctype] || [];
|
||||
if($.isEmptyObject(docsdict))
|
||||
return [];
|
||||
return frappe.utils.filter_dict(src, filters);
|
||||
return frappe.utils.filter_dict(docsdict, filters);
|
||||
},
|
||||
|
||||
get_value: function(doctype, filters, fieldname) {
|
||||
|
|
@ -277,55 +277,16 @@ $.extend(frappe.model, {
|
|||
return locals[doctype] ? locals[doctype][name] : null;
|
||||
},
|
||||
|
||||
get_doclist: function(doctype, name, filters) {
|
||||
var doclist = [];
|
||||
if(!locals[doctype])
|
||||
return doclist;
|
||||
|
||||
doclist[0] = locals[doctype][name];
|
||||
|
||||
$.each(frappe.model.get("DocField", {parent:doctype, fieldtype:"Table"}),
|
||||
function(i, table_field) {
|
||||
var child_doclist = frappe.model.get(table_field.options, {
|
||||
parent:name, parenttype: doctype,
|
||||
parentfield: table_field.fieldname});
|
||||
|
||||
if($.isArray(child_doclist)) {
|
||||
child_doclist.sort(function(a, b) { return a.idx - b.idx; });
|
||||
doclist = doclist.concat(child_doclist);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if(filters) {
|
||||
doclist = frappe.utils.filter_dict(doclist, filters);
|
||||
}
|
||||
|
||||
return doclist;
|
||||
},
|
||||
|
||||
get_children: function(doctype, parent, parentfield, parenttype) {
|
||||
if(parenttype) {
|
||||
var l = frappe.model.get(doctype, {parent:parent,
|
||||
parentfield:parentfield, parenttype:parenttype});
|
||||
get_children: function(doctype, parent, parentfield, filters) {
|
||||
if($.isPlainObject(parentfield)) {
|
||||
var doc = doctype;
|
||||
var filters = parentfield;
|
||||
var parentfield = parent;
|
||||
return frappe.utils.filter_dict((doc[parentfield] || []), filters);
|
||||
} else {
|
||||
var l = frappe.model.get(doctype, {parent:parent,
|
||||
parentfield:parentfield});
|
||||
return frappe.utils.filter_dict((frappe.model.get_doc(doctype, parent)[parentfield] || []), filters);
|
||||
}
|
||||
|
||||
if(l.length) {
|
||||
l.sort(function(a,b) { return flt(a.idx) - flt(b.idx) });
|
||||
|
||||
// renumber
|
||||
$.each(l, function(i, v) { v.idx = i+1; }); // for chrome bugs ???
|
||||
}
|
||||
return l;
|
||||
},
|
||||
|
||||
clear_doclist: function(doctype, name) {
|
||||
$.each(frappe.model.get_doclist(doctype, name), function(i, d) {
|
||||
if(d) frappe.model.clear_doc(d.doctype, d.name);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
clear_table: function(doctype, parenttype, parent, parentfield) {
|
||||
|
|
@ -337,7 +298,7 @@ $.extend(frappe.model, {
|
|||
},
|
||||
|
||||
remove_from_locals: function(doctype, name) {
|
||||
this.clear_doclist(doctype, name);
|
||||
this.clear_doc(doctype, name);
|
||||
if(frappe.views.formview[doctype]) {
|
||||
delete frappe.views.formview[doctype].frm.opendocs[name];
|
||||
}
|
||||
|
|
@ -358,13 +319,14 @@ $.extend(frappe.model, {
|
|||
|
||||
get_no_copy_list: function(doctype) {
|
||||
var no_copy_list = ['name','amended_from','amendment_date','cancel_reason'];
|
||||
$.each(frappe.model.get("DocField", {parent:doctype}), function(i, df) {
|
||||
|
||||
$.each(frappe.model.get_doc("DocType", doctype).fields || [], function(i, df) {
|
||||
if(cint(df.no_copy)) no_copy_list.push(df.fieldname);
|
||||
})
|
||||
return no_copy_list;
|
||||
},
|
||||
|
||||
// args: source (doclist), target (doctype), table_map, field_map, callback
|
||||
// args: source (doc), target (doc), table_map, field_map, callback
|
||||
map: function(args) {
|
||||
frappe.model.with_doctype(args.target, function() {
|
||||
var map_info = frappe.model.map_info[args.target]
|
||||
|
|
@ -436,7 +398,7 @@ $.extend(frappe.model, {
|
|||
},
|
||||
callback: function(r, rt) {
|
||||
if(!r.exc) {
|
||||
frappe.model.clear_doclist(doctype, docname);
|
||||
frappe.model.clear_doc(doctype, docname);
|
||||
if(frappe.ui.toolbar.recent)
|
||||
frappe.ui.toolbar.recent.remove(doctype, docname);
|
||||
if(callback) callback(r,rt);
|
||||
|
|
@ -499,9 +461,20 @@ $.extend(frappe.model, {
|
|||
frappe.throw(frappe._("Please specify") + ": " +
|
||||
frappe._(frappe.meta.get_label(doc.doctype, fieldname, doc.parent || doc.name)));
|
||||
}
|
||||
},
|
||||
|
||||
get_all_docs: function(doc) {
|
||||
var all = [doc];
|
||||
for(key in doc) {
|
||||
if($.isArray(doc[key])) {
|
||||
$.each(doc[key], function(i, d) {
|
||||
all.push(d);
|
||||
});
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}
|
||||
});
|
||||
|
||||
// legacy
|
||||
getchildren = frappe.model.get_children
|
||||
make_doclist = frappe.model.get_doclist
|
||||
|
|
|
|||
|
|
@ -38,17 +38,9 @@ $.extend(frappe.perm, {
|
|||
var perm = [{read: 0}];
|
||||
|
||||
var meta = frappe.model.get_doc("DocType", doctype);
|
||||
|
||||
if(!meta) {
|
||||
return perm;
|
||||
} else if(meta.istable) {
|
||||
// if a child table, use permissions of parent form
|
||||
var parent_df = frappe.model.get("DocField", {fieldtype: "Table", options: doctype});
|
||||
if(parent_df.length) {
|
||||
if(docname) {
|
||||
docname = frappe.model.get_doc(doctype, docname).parent;
|
||||
}
|
||||
doctype = parent_df[0].parent;
|
||||
}
|
||||
}
|
||||
|
||||
if(user==="Administrator" || user_roles.indexOf("Administrator")!==-1) {
|
||||
|
|
@ -60,7 +52,7 @@ $.extend(frappe.perm, {
|
|||
return perm;
|
||||
}
|
||||
|
||||
var docperms = frappe.model.get("DocPerm", {parent: doctype});
|
||||
var docperms = frappe.model.get_doc("DocType", doctype).permissions || [];
|
||||
$.each(docperms, function(i, p) {
|
||||
// if user has this role
|
||||
if(user_roles.indexOf(p.role)!==-1) {
|
||||
|
|
|
|||
|
|
@ -5,35 +5,21 @@ $.extend(frappe.model, {
|
|||
docinfo: {},
|
||||
sync: function(r) {
|
||||
/* docs:
|
||||
extract doclist, docinfo (attachments, comments, assignments)
|
||||
extract docs, docinfo (attachments, comments, assignments)
|
||||
from incoming request and set in `locals` and `frappe.model.docinfo`
|
||||
*/
|
||||
|
||||
if(!r.docs && !r.docinfo) r = {docs:r};
|
||||
|
||||
if(r.docs) {
|
||||
var doclist = r.docs;
|
||||
if(doclist._kl)
|
||||
doclist = frappe.model.expand(doclist);
|
||||
|
||||
if(doclist && doclist.length)
|
||||
frappe.model.clear_doclist(doclist[0].doctype, doclist[0].name)
|
||||
|
||||
var last_parent_name = null;
|
||||
var dirty = [];
|
||||
$.each(doclist, function(i, d) {
|
||||
|
||||
$.each(r.docs, function(i, d) {
|
||||
if(!d.name && d.__islocal) { // get name (local if required)
|
||||
frappe.model.clear_doc(d)
|
||||
d.name = frappe.model.get_new_name(d.doctype);
|
||||
frappe.provide("frappe.model.docinfo." + d.doctype + "." + d.name);
|
||||
if(!d.parenttype)
|
||||
last_parent_name = d.name;
|
||||
|
||||
if(dirty.indexOf(d.parenttype || d.doctype)===-1) dirty.push(d.parenttype || d.doctype);
|
||||
}
|
||||
|
||||
// set parent for subsequent orphans
|
||||
if(d.parenttype && !d.parent && d.__islocal) {
|
||||
d.parent = last_parent_name;
|
||||
}
|
||||
|
||||
if(!locals[d.doctype])
|
||||
|
|
@ -41,14 +27,15 @@ $.extend(frappe.model, {
|
|||
|
||||
locals[d.doctype][d.name] = d;
|
||||
d.__last_sync_on = new Date();
|
||||
|
||||
if(d.doctype==="DocType") {
|
||||
frappe.meta.sync(d);
|
||||
}
|
||||
|
||||
if(cur_frm && cur_frm.doctype==d.doctype && cur_frm.docname==d.name) {
|
||||
cur_frm.doc = d;
|
||||
}
|
||||
|
||||
if(d.doctype=='DocField') frappe.meta.add_field(d);
|
||||
if(d.doctype=='DocType') frappe.meta.sync_messages(d);
|
||||
|
||||
if(d.localname) {
|
||||
frappe.model.new_names[d.localname] = d.name;
|
||||
$(document).trigger('rename', [d.doctype, d.localname, d.name]);
|
||||
|
|
@ -66,10 +53,10 @@ $.extend(frappe.model, {
|
|||
|
||||
}
|
||||
|
||||
// set docinfo
|
||||
// set docinfo (comments, assign, attachments)
|
||||
if(r.docinfo) {
|
||||
if(doclist) {
|
||||
var doc = doclist[0];
|
||||
if(r.docs) {
|
||||
var doc = r.docs[0];
|
||||
} else {
|
||||
var doc = cur_frm.doc;
|
||||
}
|
||||
|
|
@ -78,68 +65,7 @@ $.extend(frappe.model, {
|
|||
frappe.model.docinfo[doc.doctype][doc.name] = r.docinfo;
|
||||
}
|
||||
|
||||
return doclist;
|
||||
return r.docs;
|
||||
},
|
||||
|
||||
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 all_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', '_comments'];
|
||||
|
||||
for(key in frappe.meta.docfield_map[doctype]) { // all other values
|
||||
if(!in_list(key_list, key)
|
||||
&& !in_list(frappe.model.no_value_type, frappe.meta.docfield_map[doctype][key].fieldtype)
|
||||
&& !frappe.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(!all_keys[doc.doctype]) {
|
||||
all_keys[doc.doctype] = get_key_list(doc.doctype);
|
||||
// doctype must be first
|
||||
}
|
||||
|
||||
var row = []
|
||||
var key_list = all_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':all_keys});
|
||||
}
|
||||
});
|
||||
|
||||
// legacy
|
||||
compress_doclist = frappe.model.compress;
|
||||
|
|
@ -23,31 +23,19 @@ frappe.workflow = {
|
|||
},
|
||||
get_default_state: function(doctype) {
|
||||
frappe.workflow.setup(doctype);
|
||||
return frappe.model.get("Workflow Document State", {
|
||||
parent: frappe.workflow.workflows[doctype].name,
|
||||
idx: 1
|
||||
})[0].state;
|
||||
return frappe.workflow.workflows[doctype].workflow_document_states[0].state;
|
||||
},
|
||||
get_transitions: function(doctype, state) {
|
||||
frappe.workflow.setup(doctype);
|
||||
return frappe.model.get("Workflow Transition", {
|
||||
parent: frappe.workflow.workflows[doctype].name,
|
||||
state: state
|
||||
});
|
||||
return frappe.model.get_children(frappe.workflow.workflows[doctype], "workflow_transitions", {state:state});
|
||||
},
|
||||
get_document_state: function(doctype, state) {
|
||||
frappe.workflow.setup(doctype);
|
||||
return frappe.model.get("Workflow Document State", {
|
||||
parent: frappe.workflow.workflows[doctype].name,
|
||||
state: state
|
||||
})[0];
|
||||
return frappe.model.get_children(frappe.workflow.workflows[doctype], "workflow_document_states", {state:state})[0];
|
||||
},
|
||||
get_next_state: function(doctype, state, action) {
|
||||
return frappe.model.get("Workflow Transition", {
|
||||
parent: frappe.workflow.workflows[doctype].name,
|
||||
state: state,
|
||||
action: action
|
||||
})[0].next_state;
|
||||
return frappe.model.get_children(frappe.workflow.workflows[doctype], "workflow_transitions", {
|
||||
state:state, action:action})[0].next_state;
|
||||
},
|
||||
is_read_only: function(doctype, name) {
|
||||
var state_fieldname = frappe.workflow.get_state_fieldname(doctype);
|
||||
|
|
@ -60,13 +48,7 @@ frappe.workflow = {
|
|||
var state = locals[doctype][name][state_fieldname] ||
|
||||
frappe.workflow.get_default_state(doctype);
|
||||
|
||||
var workflow_doc_state = frappe.model.get("Workflow Document State",
|
||||
{
|
||||
parent: frappe.workflow.workflows[doctype].name,
|
||||
state: state
|
||||
});
|
||||
var allow_edit = workflow_doc_state.length ?
|
||||
workflow_doc_state[0].allow_edit : null;
|
||||
var allow_edit = state ? frappe.workflow.get_document_state(doctype, state).allow_edit : null;
|
||||
|
||||
if(user_roles.indexOf(allow_edit)==-1) {
|
||||
return true;
|
||||
|
|
@ -75,8 +57,8 @@ frappe.workflow = {
|
|||
return false;
|
||||
},
|
||||
get_update_fields: function(doctype) {
|
||||
var update_fields = $.unique($.map(frappe.model.get("Workflow Document State",
|
||||
{parent:frappe.workflow.workflows[doctype].name}), function(d) {
|
||||
var update_fields = $.unique($.map(frappe.workflow.workflows[doctype].workflow_document_states || [],
|
||||
function(d) {
|
||||
return d.update_field;
|
||||
}));
|
||||
return update_fields;
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ frappe.call = function(opts) {
|
|||
} else if(opts.doc) {
|
||||
$.extend(args, {
|
||||
cmd: "runserverobj",
|
||||
docs: frappe.model.compress(frappe.model.get_doclist(opts.doc.doctype,
|
||||
opts.doc.name)),
|
||||
docs: frappe.model.get_doc(opts.doc.doctype, opts.doc.name),
|
||||
method: opts.method,
|
||||
args: opts.args,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -337,13 +337,13 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
d.hide();
|
||||
var doclist = r.message;
|
||||
var doc = r.message;
|
||||
$.each(me.dataView.getItems(), function(i, item) {
|
||||
if (item.name === doclist[0].name) {
|
||||
var new_item = $.extend({}, item, doclist[0]);
|
||||
$.each(doclist, function(i, doc) {
|
||||
if(item[doc.doctype + ":name"]===doc.name) {
|
||||
$.each(doc, function(k, v) {
|
||||
if (item.name === doc.name) {
|
||||
var new_item = $.extend({}, item);
|
||||
$.each(frappe.model.get_all_docs(doc), function(i, d) {
|
||||
if(item[d.doctype + ":name"]===d.name) {
|
||||
$.each(d, function(k, v) {
|
||||
if(frappe.model.std_fields_list.indexOf(k)===-1) {
|
||||
new_item[k] = v;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@
|
|||
get_server_fields = function(method, arg, table_field, doc, dt, dn, allow_edit, call_back) {
|
||||
frappe.dom.freeze();
|
||||
return $c('runserverobj',
|
||||
args={'method':method,
|
||||
'docs':frappe.model.compress(make_doclist(doc.doctype, doc.name)),
|
||||
'arg':arg
|
||||
},
|
||||
args={'method': method, 'docs': doc, 'arg': arg },
|
||||
function(r, rt) {
|
||||
frappe.dom.unfreeze();
|
||||
if (r.message) {
|
||||
|
|
@ -125,10 +122,6 @@ _f.Frm.prototype.get_doc = function() {
|
|||
return locals[this.doctype][this.docname];
|
||||
}
|
||||
|
||||
_f.Frm.prototype.get_doclist = function(filters) {
|
||||
return frappe.model.get_doclist(this.doctype, this.docname, filters);
|
||||
}
|
||||
|
||||
_f.Frm.prototype.field_map = function(fnames, fn) {
|
||||
if(typeof fnames==='string') {
|
||||
if(fnames == '*') {
|
||||
|
|
@ -170,7 +163,7 @@ _f.Frm.prototype.toggle_display = function(fnames, show) {
|
|||
}
|
||||
|
||||
_f.Frm.prototype.call_server = function(method, args, callback) {
|
||||
return $c_obj(cur_frm.get_doclist(), method, args, callback);
|
||||
return $c_obj(cur_frm.doc, method, args, callback);
|
||||
}
|
||||
|
||||
_f.Frm.prototype.get_files = function() {
|
||||
|
|
|
|||
|
|
@ -548,13 +548,11 @@ _f.Frm.prototype.setnewdoc = function() {
|
|||
_f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) {
|
||||
var me = this;
|
||||
if(this.docname) {
|
||||
// make doc list
|
||||
var doclist = frappe.model.compress(make_doclist(this.doctype, this.docname));
|
||||
// send to run
|
||||
if(callingfield)
|
||||
$(callingfield.input).set_working();
|
||||
|
||||
return $c('runserverobj', {'docs':doclist, 'method':scriptname },
|
||||
return $c('runserverobj', {'docs':this.doc, 'method':scriptname },
|
||||
function(r, rtxt) {
|
||||
// run refresh
|
||||
if(onrefresh)
|
||||
|
|
@ -577,45 +575,10 @@ _f.Frm.prototype.copy_doc = function(onload, from_amend) {
|
|||
return;
|
||||
}
|
||||
|
||||
var dn = this.docname;
|
||||
// copy parent
|
||||
var newdoc = frappe.model.copy_doc(this.doctype, dn, from_amend);
|
||||
var newdoc = frappe.model.copy_doc(this.doc, from_amend);
|
||||
|
||||
newdoc.idx = null;
|
||||
|
||||
// copy chidren
|
||||
var dl = make_doclist(this.doctype, dn);
|
||||
|
||||
// table fields dict - for no_copy check
|
||||
var tf_dict = {};
|
||||
|
||||
for(var d in dl) {
|
||||
d1 = dl[d];
|
||||
|
||||
// get tabel field
|
||||
if(d1.parentfield && !tf_dict[d1.parentfield]) {
|
||||
tf_dict[d1.parentfield] = frappe.meta.get_docfield(d1.parenttype, d1.parentfield);
|
||||
}
|
||||
|
||||
if(d1.parent==dn && cint(tf_dict[d1.parentfield].no_copy)!=1) {
|
||||
var ch = frappe.model.copy_doc(d1.doctype, d1.name, from_amend);
|
||||
ch.parent = newdoc.name;
|
||||
ch.docstatus = 0;
|
||||
ch.owner = user;
|
||||
ch.creation = '';
|
||||
ch.modified_by = user;
|
||||
ch.modified = '';
|
||||
}
|
||||
}
|
||||
|
||||
newdoc.__islocal = 1;
|
||||
newdoc.docstatus = 0;
|
||||
newdoc.owner = user;
|
||||
newdoc.creation = '';
|
||||
newdoc.modified_by = user;
|
||||
newdoc.modified = '';
|
||||
|
||||
if(onload)onload(newdoc);
|
||||
|
||||
loaddoc(newdoc.doctype, newdoc.name);
|
||||
}
|
||||
|
||||
|
|
@ -651,19 +614,15 @@ _f.Frm.prototype._save = function(save_action, callback, btn, on_error) {
|
|||
scroll(0, 0);
|
||||
|
||||
// validate
|
||||
if(save_action!="Cancel") {
|
||||
validated = true;
|
||||
this.script_manager.trigger("validate");
|
||||
if(!validated) {
|
||||
if(on_error)
|
||||
on_error();
|
||||
return;
|
||||
}
|
||||
validated = true;
|
||||
this.script_manager.trigger("validate");
|
||||
if(!validated) {
|
||||
if(on_error)
|
||||
on_error();
|
||||
return;
|
||||
}
|
||||
|
||||
var doclist = new frappe.model.DocList(this.doctype, this.docname);
|
||||
|
||||
doclist.save(save_action || "Save", function(r) {
|
||||
|
||||
var after_save = function(r) {
|
||||
if(!r.exc) {
|
||||
me.refresh();
|
||||
} else {
|
||||
|
|
@ -680,7 +639,9 @@ _f.Frm.prototype._save = function(save_action, callback, btn, on_error) {
|
|||
}
|
||||
frappe._from_link = null;
|
||||
}
|
||||
}, btn);
|
||||
}
|
||||
|
||||
frappe.ui.form.save(this, save_action || "Save", after_save, btn);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -713,14 +674,16 @@ _f.Frm.prototype.savecancel = function(btn, on_error) {
|
|||
on_error();
|
||||
return;
|
||||
}
|
||||
|
||||
var doclist = new frappe.model.DocList(me.doctype, me.docname);
|
||||
doclist.cancel(function(r) {
|
||||
|
||||
var after_cancel = function(r) {
|
||||
if(!r.exc) {
|
||||
me.refresh();
|
||||
me.script_manager.trigger("after_cancel");
|
||||
} else {
|
||||
on_error();
|
||||
}
|
||||
}, btn, on_error);
|
||||
}
|
||||
frappe.ui.form.save(this, "cancel", after_cancel, btn);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function $c(command, args, callback, error, no_spinner, freeze_msg, btn) {
|
|||
}
|
||||
|
||||
// For calling an object
|
||||
function $c_obj(doclist, method, arg, callback, no_spinner, freeze_msg, btn) {
|
||||
function $c_obj(doc, method, arg, callback, no_spinner, freeze_msg, btn) {
|
||||
if(arg && typeof arg!='string') arg = JSON.stringify(arg);
|
||||
|
||||
args = {
|
||||
|
|
@ -22,10 +22,11 @@ function $c_obj(doclist, method, arg, callback, no_spinner, freeze_msg, btn) {
|
|||
method: method
|
||||
};
|
||||
|
||||
if(typeof doclist=='string')
|
||||
args.doctype = doclist;
|
||||
else
|
||||
args.docs = frappe.model.compress(doclist)
|
||||
if(typeof doc=='string') {
|
||||
args.doctype = doc;
|
||||
} else {
|
||||
args.docs = doc
|
||||
}
|
||||
|
||||
return frappe.request.call({
|
||||
args: args,
|
||||
|
|
@ -53,7 +54,7 @@ function $c_page(module, page, method, arg, callback, no_spinner, freeze_msg, bt
|
|||
}
|
||||
|
||||
// For calling an for output as csv
|
||||
function $c_obj_csv(doclist, method, arg) {
|
||||
function $c_obj_csv(doc, method, arg) {
|
||||
// single
|
||||
|
||||
var args = {}
|
||||
|
|
@ -62,10 +63,10 @@ function $c_obj_csv(doclist, method, arg) {
|
|||
args.method = method;
|
||||
args.arg = arg;
|
||||
|
||||
if(doclist.substr)
|
||||
args.doctype = doclist;
|
||||
if(doc.substr)
|
||||
args.doctype = doc;
|
||||
else
|
||||
args.docs = frappe.model.compress(doclist);
|
||||
args.docs = doc;
|
||||
|
||||
// open
|
||||
open_url_post(frappe.request.url, args);
|
||||
|
|
|
|||
|
|
@ -120,5 +120,6 @@ class TestDocument(unittest.TestCase):
|
|||
d.starts_on = "2014-01-01"
|
||||
d.ends_on = "2013-01-01"
|
||||
self.assertRaises(frappe.ValidationError, d.validate)
|
||||
self.assertRaises(frappe.ValidationError, d.run_method, "validate")
|
||||
self.assertRaises(frappe.ValidationError, d.save)
|
||||
|
||||
|
|
|
|||
16
frappe/tests/test_form_load.py
Normal file
16
frappe/tests/test_form_load.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
import frappe, unittest
|
||||
from frappe.widgets.form.meta import get_meta
|
||||
from frappe.widgets.form.load import getdoctype, getdoc
|
||||
|
||||
class TestFormLoad(unittest.TestCase):
|
||||
def test_load(self):
|
||||
getdoctype("DocType")
|
||||
self.assertEquals(frappe.response.docs[0].name, "DocType")
|
||||
self.assertTrue(frappe.response.docs[0].get("__js"))
|
||||
|
||||
frappe.response.docs = []
|
||||
d = getdoctype("Event")
|
||||
self.assertTrue(frappe.response.docs[0].get("__calendar_js"))
|
||||
|
|
@ -9,7 +9,8 @@ import mimetypes
|
|||
import os
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.doc import Document
|
||||
import frappe.model.doc
|
||||
import frappe.model.document
|
||||
import frappe.utils
|
||||
import frappe.sessions
|
||||
import frappe.model.utils
|
||||
|
|
@ -28,6 +29,9 @@ def report_error(status_code):
|
|||
return response
|
||||
|
||||
def build_response(response_type=None):
|
||||
if "docs" in frappe.local.response and not frappe.local.response.docs:
|
||||
del frappe.local.response["docs"]
|
||||
|
||||
response_type_map = {
|
||||
'csv': as_csv,
|
||||
'download': as_raw,
|
||||
|
|
@ -54,7 +58,6 @@ def as_raw():
|
|||
|
||||
def as_json():
|
||||
make_logs()
|
||||
cleanup_docs()
|
||||
response = Response()
|
||||
response.headers["Content-Type"] = "application/json; charset: utf-8"
|
||||
response = gzip(json.dumps(frappe.local.response, default=json_handler, separators=(',',':')),
|
||||
|
|
@ -68,14 +71,11 @@ def make_logs():
|
|||
frappe.response['exc'] = json.dumps([frappe.utils.cstr(d) for d in frappe.local.error_log])
|
||||
|
||||
if frappe.local.message_log:
|
||||
frappe.response['_server_messages'] = json.dumps([frappe.utils.cstr(d) for d in frappe.local.message_log])
|
||||
frappe.response['_server_messages'] = json.dumps([frappe.utils.cstr(d) for
|
||||
d in frappe.local.message_log])
|
||||
|
||||
if frappe.debug_log and frappe.conf.get("logging") or False:
|
||||
frappe.response['_debug_messages'] = json.dumps(frappe.local.debug_log)
|
||||
|
||||
def cleanup_docs():
|
||||
if frappe.response.get('docs') and type(frappe.response['docs'])!=dict:
|
||||
frappe.response['docs'] = frappe.model.utils.compress(frappe.response['docs'])
|
||||
|
||||
def gzip(data, response):
|
||||
data = data.encode('utf-8')
|
||||
|
|
@ -107,8 +107,10 @@ def json_handler(obj):
|
|||
return unicode(obj)
|
||||
elif isinstance(obj, LocalProxy):
|
||||
return unicode(obj)
|
||||
elif isinstance(obj, Document):
|
||||
elif isinstance(obj, frappe.model.doc.Document):
|
||||
return obj.fields
|
||||
elif isinstance(obj, frappe.model.document.Document):
|
||||
return obj.as_dict()
|
||||
else:
|
||||
raise TypeError, """Object of type %s with value of %s is not JSON serializable""" % \
|
||||
(type(obj), repr(obj))
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ cur_frm.cscript.refresh = function(doc) {
|
|||
if(!doc.__islocal && doc.published) {
|
||||
if(!doc.email_sent) {
|
||||
cur_frm.add_custom_button('Email Subscribers', function() {
|
||||
$c_obj(make_doclist(doc.doctype, doc.name), 'send_emails', '', function(r) {
|
||||
$c_obj(doc, 'send_emails', '', function(r) {
|
||||
cur_frm.refresh();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
|||
import frappe, json
|
||||
import frappe.model.doc
|
||||
import frappe.utils
|
||||
import frappe.widgets.form.meta
|
||||
|
||||
@frappe.whitelist()
|
||||
def getdoc(doctype, name, user=None):
|
||||
|
|
@ -13,8 +14,6 @@ def getdoc(doctype, name, user=None):
|
|||
Requries "doctype", "name" as form variables.
|
||||
Will also call the "onload" method on the document.
|
||||
"""
|
||||
|
||||
import frappe
|
||||
|
||||
if not (doctype and name):
|
||||
raise Exception, 'doctype and name required!'
|
||||
|
|
@ -26,14 +25,12 @@ def getdoc(doctype, name, user=None):
|
|||
return []
|
||||
|
||||
try:
|
||||
bean = frappe.bean(doctype, name)
|
||||
bean.run_method("onload")
|
||||
doc = frappe.get_doc(doctype, name)
|
||||
doc.run_method("onload")
|
||||
|
||||
if not bean.has_read_perm():
|
||||
if not doc.has_permission("read"):
|
||||
raise frappe.PermissionError
|
||||
|
||||
doclist = bean.doclist
|
||||
|
||||
# add file list
|
||||
get_docinfo(doctype, name)
|
||||
|
||||
|
|
@ -42,35 +39,38 @@ def getdoc(doctype, name, user=None):
|
|||
frappe.msgprint('Did not load.')
|
||||
raise
|
||||
|
||||
if bean and not name.startswith('_'):
|
||||
if doc and not name.startswith('_'):
|
||||
frappe.user.update_recent(doctype, name)
|
||||
|
||||
frappe.response['docs'] = doclist
|
||||
frappe.response.docs.append(doc)
|
||||
|
||||
@frappe.whitelist()
|
||||
def getdoctype(doctype, with_parent=False, cached_timestamp=None):
|
||||
"""load doctype"""
|
||||
import frappe.model.doctype
|
||||
import frappe.model.meta
|
||||
|
||||
doclist = []
|
||||
|
||||
docs = []
|
||||
# with parent (called from report builder)
|
||||
if with_parent:
|
||||
parent_dt = frappe.model.meta.get_parent_dt(doctype)
|
||||
if parent_dt:
|
||||
doclist = frappe.model.doctype.get(parent_dt, processed=True)
|
||||
docs = get_meta_bundle(parent_dt)
|
||||
frappe.response['parent_dt'] = parent_dt
|
||||
|
||||
if not doclist:
|
||||
doclist = frappe.model.doctype.get(doctype, processed=True)
|
||||
if not docs:
|
||||
docs = get_meta_bundle(doctype)
|
||||
|
||||
frappe.response['restrictions'] = get_restrictions(doclist)
|
||||
frappe.response['restrictions'] = get_restrictions(docs[0])
|
||||
|
||||
if cached_timestamp and doclist[0].modified==cached_timestamp:
|
||||
if cached_timestamp and docs[0].modified==cached_timestamp:
|
||||
return "use_cache"
|
||||
|
||||
frappe.response['docs'] = doclist
|
||||
frappe.response.docs.extend(docs)
|
||||
|
||||
def get_meta_bundle(doctype):
|
||||
bundle = [frappe.widgets.form.meta.get_meta(doctype)]
|
||||
for df in bundle[0].get_table_fields():
|
||||
bundle.append(frappe.widgets.form.meta.get_meta(df.options))
|
||||
return bundle
|
||||
|
||||
def get_docinfo(doctype, name):
|
||||
frappe.response["docinfo"] = {
|
||||
|
|
|
|||
157
frappe/widgets/form/meta.py
Normal file
157
frappe/widgets/form/meta.py
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
# metadata
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, os
|
||||
from frappe.utils import cstr, cint
|
||||
from frappe.model.meta import Meta
|
||||
from frappe.modules import scrub, get_module_path
|
||||
from frappe.model.workflow import get_workflow_name
|
||||
|
||||
######
|
||||
|
||||
def get_meta(doctype, cached=True):
|
||||
if cached:
|
||||
meta = frappe.cache().get_value("form_meta:" + doctype, lambda: FormMeta(doctype))
|
||||
else:
|
||||
meta = FormMeta(doctype)
|
||||
|
||||
if frappe.local.lang != 'en':
|
||||
meta.set("__messages", frappe.get_lang_dict("doctype", doctype))
|
||||
|
||||
return meta
|
||||
|
||||
class FormMeta(Meta):
|
||||
def __init__(self, doctype):
|
||||
super(FormMeta, self).__init__(doctype)
|
||||
self.load_assets()
|
||||
|
||||
def load_assets(self):
|
||||
self.expand_selects()
|
||||
self.add_search_fields()
|
||||
|
||||
if not self.istable:
|
||||
self.add_linked_with()
|
||||
self.add_code()
|
||||
self.load_print_formats()
|
||||
self.load_workflows()
|
||||
|
||||
def as_dict(self):
|
||||
d = super(FormMeta, self).as_dict()
|
||||
for k in ("__js", "__css", "__list_js", "__calendar_js", "__map_js", "__linked_with", "__messages"):
|
||||
d[k] = self.get(k)
|
||||
|
||||
for i, df in enumerate(d.get("fields")):
|
||||
for k in ("link_doctype", "search_fields"):
|
||||
df[k] = self.get("fields")[i].get(k)
|
||||
|
||||
return d
|
||||
|
||||
def add_code(self):
|
||||
path = os.path.join(get_module_path(self.module), 'doctype', scrub(self.name))
|
||||
def _get_path(fname):
|
||||
return os.path.join(path, scrub(fname))
|
||||
|
||||
self._add_code(_get_path(self.name + '.js'), '__js')
|
||||
self._add_code(_get_path(self.name + '.css'), "__css")
|
||||
self._add_code(_get_path(self.name + '_list.js'), '__list_js')
|
||||
self._add_code(_get_path(self.name + '_calendar.js'), '__calendar_js')
|
||||
self._add_code(_get_path(self.name + '_map.js'), '__map_js')
|
||||
|
||||
self.add_custom_script()
|
||||
self.add_code_via_hook("doctype_js", "__js")
|
||||
|
||||
def _add_code(self, path, fieldname):
|
||||
js = frappe.read_file(path)
|
||||
if js:
|
||||
self.set(fieldname, (self.get(fieldname) or "") + "\n\n" + render_jinja(js))
|
||||
|
||||
def add_code_via_hook(self, hook, fieldname):
|
||||
hook = "{}:{}".format(hook, self.name)
|
||||
for app_name in frappe.get_installed_apps():
|
||||
for file in frappe.get_hooks(hook, app_name=app_name):
|
||||
path = frappe.get_app_path(app_name, *file.strip("/").split("/"))
|
||||
self._add_code(path, fieldname)
|
||||
|
||||
def add_custom_script(self):
|
||||
"""embed all require files"""
|
||||
# custom script
|
||||
custom = frappe.db.get_value("Custom Script", {"dt": self.name,
|
||||
"script_type": "Client"}, "script") or ""
|
||||
|
||||
self.set("__js", (self.get('__js') or '') + "\n\n" + custom)
|
||||
|
||||
def render_jinja(content):
|
||||
if "{% include" in content:
|
||||
content = frappe.get_jenv().from_string(content).render()
|
||||
return content
|
||||
|
||||
def expand_selects(self):
|
||||
for df in self.get("fields", {"fieldtype": "Select"}):
|
||||
if df.options and df.options.startswith("link:"):
|
||||
df.link_doctype = df.options.split("\n")[0][5:]
|
||||
df.options = '\n'.join([''] + [o.name for o in frappe.db.sql("""select
|
||||
name from `tab%s` where docstatus<2 order by name asc""" % df.link_doctype, as_dict=1)])
|
||||
|
||||
def add_search_fields(self):
|
||||
"""add search fields found in the doctypes indicated by link fields' options"""
|
||||
for df in self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}):
|
||||
if df.options:
|
||||
search_fields = frappe.get_meta(df.options).search_fields
|
||||
if search_fields:
|
||||
df.search_fields = map(lambda sf: sf.strip(), search_fields.split(","))
|
||||
|
||||
def add_linked_with(self):
|
||||
"""add list of doctypes this doctype is 'linked' with"""
|
||||
links = frappe.db.sql("""select parent, fieldname from tabDocField
|
||||
where (fieldtype="Link" and options=%s)
|
||||
or (fieldtype="Select" and options=%s)""", (self.name, "link:"+ self.name))
|
||||
links += frappe.db.sql("""select dt as parent, fieldname from `tabCustom Field`
|
||||
where (fieldtype="Link" and options=%s)
|
||||
or (fieldtype="Select" and options=%s)""", (self.name, "link:"+ self.name))
|
||||
|
||||
links = dict(links)
|
||||
|
||||
if not links:
|
||||
return {}
|
||||
|
||||
ret = {}
|
||||
|
||||
for dt in links:
|
||||
ret[dt] = { "fieldname": links[dt] }
|
||||
|
||||
for grand_parent, options in frappe.db.sql("""select parent, options from tabDocField
|
||||
where fieldtype="Table"
|
||||
and options in (select name from tabDocType
|
||||
where istable=1 and name in (%s))""" % ", ".join(["%s"] * len(links)) ,tuple(links)):
|
||||
|
||||
ret[grand_parent] = {"child_doctype": options, "fieldname": links[options] }
|
||||
if options in ret:
|
||||
del ret[options]
|
||||
|
||||
self.set("__linked_with", ret)
|
||||
|
||||
def load_print_formats(self):
|
||||
frappe.response.docs.extend(frappe.db.sql("""select * FROM `tabPrint Format`
|
||||
WHERE doc_type=%s AND docstatus<2""", (self.name,), as_dict=1, update={"doctype":"Print Format"}))
|
||||
|
||||
def load_workflows(self):
|
||||
# get active workflow
|
||||
workflow_name = get_workflow_name(self.name)
|
||||
|
||||
if workflow_name and frappe.db.exists("Workflow", workflow_name):
|
||||
workflow = frappe.get_doc("Workflow", workflow_name)
|
||||
frappe.response.docs.append(workflow)
|
||||
|
||||
for d in workflow.get("workflow_document_states"):
|
||||
frappe.response.docs.append(frappe.get_doc("Workflow State", d.state))
|
||||
|
||||
|
||||
def render_jinja(content):
|
||||
if "{% include" in content:
|
||||
content = frappe.get_jenv().from_string(content).render()
|
||||
return content
|
||||
|
||||
|
||||
|
|
@ -20,8 +20,6 @@ def runserverobj():
|
|||
dt = frappe.form_dict.get('doctype')
|
||||
dn = frappe.form_dict.get('docname')
|
||||
|
||||
frappe.response["docs"] = []
|
||||
|
||||
if dt: # not called from a doctype (from a page)
|
||||
if not dn: dn = dt # single
|
||||
so = frappe.model.code.get_obj(dt, dn)
|
||||
|
|
|
|||
|
|
@ -112,8 +112,6 @@ def get_linked_docs(doctype, name, metadata_loaded=None):
|
|||
results[dt] = ret
|
||||
|
||||
if not dt in metadata_loaded:
|
||||
if not "docs" in frappe.local.response:
|
||||
frappe.local.response.docs = []
|
||||
frappe.local.response.docs += linkmeta
|
||||
|
||||
return results
|
||||
|
|
@ -11,14 +11,14 @@ def get(name):
|
|||
"""
|
||||
Return the :term:`doclist` of the `Page` specified by `name`
|
||||
"""
|
||||
page = frappe.bean("Page", name)
|
||||
if has_permission(page.doclist):
|
||||
page.run_method("get_from_files")
|
||||
return page.doclist
|
||||
page = frappe.get_doc('Page', name)
|
||||
if has_permission(page):
|
||||
page.load_assets()
|
||||
return page
|
||||
else:
|
||||
frappe.response['403'] = 1
|
||||
raise frappe.PermissionError, 'No read permission for Page %s' % \
|
||||
(page.doclist[0].title or name,)
|
||||
(page.title or name)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def getpage():
|
||||
|
|
@ -26,24 +26,19 @@ def getpage():
|
|||
Load the page from `frappe.form` and send it via `frappe.response`
|
||||
"""
|
||||
page = frappe.form_dict.get('name')
|
||||
doclist = get(page)
|
||||
doc = get(page)
|
||||
|
||||
if has_permission(doclist):
|
||||
# load translations
|
||||
if frappe.lang != "en":
|
||||
frappe.response["__messages"] = frappe.get_lang_dict("page", page)
|
||||
# load translations
|
||||
if frappe.lang != "en":
|
||||
frappe.response["__messages"] = frappe.get_lang_dict("page", page)
|
||||
|
||||
frappe.response['docs'] = doclist
|
||||
else:
|
||||
frappe.response['403'] = 1
|
||||
raise frappe.PermissionError, 'No read permission for Page %s' % \
|
||||
(doclist[0].title or page, )
|
||||
|
||||
def has_permission(page_doclist):
|
||||
frappe.response.docs.append(doc)
|
||||
|
||||
def has_permission(page):
|
||||
if frappe.user.name == "Administrator" or "System Manager" in frappe.user.get_roles():
|
||||
return True
|
||||
|
||||
page_roles = [d.role for d in page_doclist if d.fields.get("doctype")=="Page Role"]
|
||||
page_roles = [d.role for d in page.get("roles")]
|
||||
if page_roles:
|
||||
if frappe.session.user == "Guest" and "Guest" not in page_roles:
|
||||
return False
|
||||
|
|
@ -51,7 +46,7 @@ def has_permission(page_doclist):
|
|||
# check if roles match
|
||||
return False
|
||||
|
||||
if not frappe.has_permission("Page", ptype="read", refdoc=page_doclist[0].name):
|
||||
if not frappe.has_permission("Page", ptype="read", doc=page):
|
||||
# check if there are any restrictions
|
||||
return False
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue