You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

611 line
18 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe, sys
  5. from frappe import _
  6. from frappe.utils import cint, flt, now, cstr, strip_html, getdate, get_datetime, to_timedelta
  7. from frappe.model import default_fields
  8. from frappe.model.naming import set_new_name
  9. from frappe.modules import load_doctype_module
  10. from frappe.model import display_fieldtypes
  11. _classes = {}
  12. def get_controller(doctype):
  13. """Returns the **class** object of the given DocType.
  14. For `custom` type, returns `frappe.model.document.Document`.
  15. :param doctype: DocType name as string."""
  16. from frappe.model.document import Document
  17. if not doctype in _classes:
  18. module_name, custom = frappe.db.get_value("DocType", doctype, ["module", "custom"]) \
  19. or ["Core", False]
  20. if custom:
  21. _class = Document
  22. else:
  23. module = load_doctype_module(doctype, module_name)
  24. classname = doctype.replace(" ", "").replace("-", "")
  25. if hasattr(module, classname):
  26. _class = getattr(module, classname)
  27. if issubclass(_class, BaseDocument):
  28. _class = getattr(module, classname)
  29. else:
  30. raise ImportError, doctype
  31. else:
  32. raise ImportError, doctype
  33. _classes[doctype] = _class
  34. return _classes[doctype]
  35. class BaseDocument(object):
  36. ignore_in_getter = ("doctype", "_meta", "meta", "_table_fields", "_valid_columns")
  37. def __init__(self, d):
  38. self.update(d)
  39. self.dont_update_if_missing = []
  40. if hasattr(self, "__setup__"):
  41. self.__setup__()
  42. @property
  43. def meta(self):
  44. if not hasattr(self, "_meta"):
  45. self._meta = frappe.get_meta(self.doctype)
  46. return self._meta
  47. def update(self, d):
  48. if "doctype" in d:
  49. self.set("doctype", d.get("doctype"))
  50. # first set default field values of base document
  51. for key in default_fields:
  52. if key in d:
  53. self.set(key, d.get(key))
  54. for key, value in d.iteritems():
  55. self.set(key, value)
  56. return self
  57. def update_if_missing(self, d):
  58. if isinstance(d, BaseDocument):
  59. d = d.get_valid_dict()
  60. if "doctype" in d:
  61. self.set("doctype", d.get("doctype"))
  62. for key, value in d.iteritems():
  63. # dont_update_if_missing is a list of fieldnames, for which, you don't want to set default value
  64. if (self.get(key) is None) and (value is not None) and (key not in self.dont_update_if_missing):
  65. self.set(key, value)
  66. def get_db_value(self, key):
  67. return frappe.db.get_value(self.doctype, self.name, key)
  68. def get(self, key=None, filters=None, limit=None, default=None):
  69. if key:
  70. if isinstance(key, dict):
  71. return _filter(self.get_all_children(), key, limit=limit)
  72. if filters:
  73. if isinstance(filters, dict):
  74. value = _filter(self.__dict__.get(key, []), filters, limit=limit)
  75. else:
  76. default = filters
  77. filters = None
  78. value = self.__dict__.get(key, default)
  79. else:
  80. value = self.__dict__.get(key, default)
  81. if value is None and key not in self.ignore_in_getter \
  82. and key in (d.fieldname for d in self.meta.get_table_fields()):
  83. self.set(key, [])
  84. value = self.__dict__.get(key)
  85. return value
  86. else:
  87. return self.__dict__
  88. def getone(self, key, filters=None):
  89. return self.get(key, filters=filters, limit=1)[0]
  90. def set(self, key, value, as_value=False):
  91. if isinstance(value, list) and not as_value:
  92. self.__dict__[key] = []
  93. self.extend(key, value)
  94. else:
  95. self.__dict__[key] = value
  96. def delete_key(self, key):
  97. if key in self.__dict__:
  98. del self.__dict__[key]
  99. def append(self, key, value=None):
  100. if value==None:
  101. value={}
  102. if isinstance(value, (dict, BaseDocument)):
  103. if not self.__dict__.get(key):
  104. self.__dict__[key] = []
  105. value = self._init_child(value, key)
  106. self.__dict__[key].append(value)
  107. # reference parent document
  108. value.parent_doc = self
  109. return value
  110. else:
  111. raise ValueError, "Document attached to child table must be a dict or BaseDocument, not " + str(type(value))[1:-1]
  112. def extend(self, key, value):
  113. if isinstance(value, list):
  114. for v in value:
  115. self.append(key, v)
  116. else:
  117. raise ValueError
  118. def remove(self, doc):
  119. self.get(doc.parentfield).remove(doc)
  120. def _init_child(self, value, key):
  121. if not self.doctype:
  122. return value
  123. if not isinstance(value, BaseDocument):
  124. if "doctype" not in value:
  125. value["doctype"] = self.get_table_field_doctype(key)
  126. if not value["doctype"]:
  127. raise AttributeError, key
  128. value = get_controller(value["doctype"])(value)
  129. value.init_valid_columns()
  130. value.parent = self.name
  131. value.parenttype = self.doctype
  132. value.parentfield = key
  133. if value.docstatus is None:
  134. value.docstatus = 0
  135. if not getattr(value, "idx", None):
  136. value.idx = len(self.get(key) or []) + 1
  137. if not getattr(value, "name", None):
  138. value.__dict__['__islocal'] = 1
  139. return value
  140. def get_valid_dict(self):
  141. d = {}
  142. for fieldname in self.meta.get_valid_columns():
  143. d[fieldname] = self.get(fieldname)
  144. df = self.meta.get_field(fieldname)
  145. if df:
  146. if df.fieldtype=="Check" and not isinstance(d[fieldname], int):
  147. d[fieldname] = cint(d[fieldname])
  148. elif df.fieldtype in ("Datetime", "Date") and d[fieldname]=="":
  149. d[fieldname] = None
  150. elif df.get("unique") and cstr(d[fieldname]).strip()=="":
  151. # unique empty field should be set to None
  152. d[fieldname] = None
  153. return d
  154. def init_valid_columns(self):
  155. for key in default_fields:
  156. if key not in self.__dict__:
  157. self.__dict__[key] = None
  158. for key in self.get_valid_columns():
  159. if key not in self.__dict__:
  160. self.__dict__[key] = None
  161. def get_valid_columns(self):
  162. if self.doctype not in frappe.local.valid_columns:
  163. if self.doctype in ("DocField", "DocPerm") and self.parent in ("DocType", "DocField", "DocPerm"):
  164. from frappe.model.meta import get_table_columns
  165. valid = get_table_columns(self.doctype)
  166. else:
  167. valid = self.meta.get_valid_columns()
  168. frappe.local.valid_columns[self.doctype] = valid
  169. return frappe.local.valid_columns[self.doctype]
  170. def is_new(self):
  171. return self.get("__islocal")
  172. def as_dict(self, no_nulls=False, no_default_fields=False):
  173. doc = self.get_valid_dict()
  174. doc["doctype"] = self.doctype
  175. for df in self.meta.get_table_fields():
  176. children = self.get(df.fieldname) or []
  177. doc[df.fieldname] = [d.as_dict(no_nulls=no_nulls) for d in children]
  178. if no_nulls:
  179. for k in doc.keys():
  180. if doc[k] is None:
  181. del doc[k]
  182. if no_default_fields:
  183. for k in doc.keys():
  184. if k in default_fields:
  185. del doc[k]
  186. for key in ("_user_tags", "__islocal", "__onload", "_starred_by"):
  187. if self.get(key):
  188. doc[key] = self.get(key)
  189. return frappe._dict(doc)
  190. def as_json(self):
  191. return frappe.as_json(self.as_dict())
  192. def get_table_field_doctype(self, fieldname):
  193. return self.meta.get_field(fieldname).options
  194. def get_parentfield_of_doctype(self, doctype):
  195. fieldname = [df.fieldname for df in self.meta.get_table_fields() if df.options==doctype]
  196. return fieldname[0] if fieldname else None
  197. def db_insert(self):
  198. """INSERT the document (with valid columns) in the database."""
  199. if not self.name:
  200. # name will be set by document class in most cases
  201. set_new_name(self)
  202. d = self.get_valid_dict()
  203. columns = d.keys()
  204. try:
  205. frappe.db.sql("""insert into `tab{doctype}`
  206. ({columns}) values ({values})""".format(
  207. doctype = self.doctype,
  208. columns = ", ".join(["`"+c+"`" for c in columns]),
  209. values = ", ".join(["%s"] * len(columns))
  210. ), d.values())
  211. except Exception, e:
  212. if e.args[0]==1062:
  213. if "PRIMARY" in cstr(e.args[1]):
  214. if self.meta.autoname=="hash":
  215. # hash collision? try again
  216. self.name = None
  217. self.db_insert()
  218. return
  219. type, value, traceback = sys.exc_info()
  220. frappe.msgprint(_("Duplicate name {0} {1}").format(self.doctype, self.name))
  221. raise frappe.DuplicateEntryError, (self.doctype, self.name, e), traceback
  222. elif "Duplicate" in cstr(e.args[1]):
  223. # unique constraint
  224. self.show_unique_validation_message(e)
  225. else:
  226. raise
  227. else:
  228. raise
  229. self.set("__islocal", False)
  230. def db_update(self):
  231. if self.get("__islocal") or not self.name:
  232. self.db_insert()
  233. return
  234. d = self.get_valid_dict()
  235. columns = d.keys()
  236. try:
  237. frappe.db.sql("""update `tab{doctype}`
  238. set {values} where name=%s""".format(
  239. doctype = self.doctype,
  240. values = ", ".join(["`"+c+"`=%s" for c in columns])
  241. ), d.values() + [d.get("name")])
  242. except Exception, e:
  243. if e.args[0]==1062 and "Duplicate" in cstr(e.args[1]):
  244. self.show_unique_validation_message(e)
  245. else:
  246. raise
  247. def show_unique_validation_message(self, e):
  248. type, value, traceback = sys.exc_info()
  249. fieldname = str(e).split("'")[-2]
  250. label = fieldname if fieldname.startswith("unique_") else self.meta.get_label(fieldname)
  251. frappe.msgprint(_("{0} must be unique".format(label)))
  252. raise frappe.UniqueValidationError, (self.doctype, self.name, e), traceback
  253. def db_set(self, fieldname, value, update_modified=True):
  254. self.set(fieldname, value)
  255. self.set("modified", now())
  256. self.set("modified_by", frappe.session.user)
  257. frappe.db.set_value(self.doctype, self.name, fieldname, value,
  258. self.modified, self.modified_by, update_modified=update_modified)
  259. def _fix_numeric_types(self):
  260. for df in self.meta.get("fields"):
  261. if df.fieldtype == "Check":
  262. self.set(df.fieldname, cint(self.get(df.fieldname)))
  263. elif self.get(df.fieldname) is not None:
  264. if df.fieldtype == "Int":
  265. self.set(df.fieldname, cint(self.get(df.fieldname)))
  266. elif df.fieldtype in ("Float", "Currency", "Percent"):
  267. self.set(df.fieldname, flt(self.get(df.fieldname)))
  268. if self.docstatus is not None:
  269. self.docstatus = cint(self.docstatus)
  270. def _get_missing_mandatory_fields(self):
  271. """Get mandatory fields that do not have any values"""
  272. def get_msg(df):
  273. if df.fieldtype == "Table":
  274. return "{}: {}: {}".format(_("Error"), _("Data missing in table"), _(df.label))
  275. elif self.parentfield:
  276. return "{}: {} #{}: {}: {}".format(_("Error"), _("Row"), self.idx,
  277. _("Value missing for"), _(df.label))
  278. else:
  279. return "{}: {}: {}".format(_("Error"), _("Value missing for"), _(df.label))
  280. missing = []
  281. for df in self.meta.get("fields", {"reqd": 1}):
  282. if self.get(df.fieldname) in (None, []) or not strip_html(cstr(self.get(df.fieldname))).strip():
  283. missing.append((df.fieldname, get_msg(df)))
  284. return missing
  285. def get_invalid_links(self, is_submittable=False):
  286. def get_msg(df, docname):
  287. if self.parentfield:
  288. return "{} #{}: {}: {}".format(_("Row"), self.idx, _(df.label), docname)
  289. else:
  290. return "{}: {}".format(_(df.label), docname)
  291. invalid_links = []
  292. cancelled_links = []
  293. for df in self.meta.get_link_fields() + self.meta.get("fields",
  294. {"fieldtype":"Dynamic Link"}):
  295. docname = self.get(df.fieldname)
  296. if docname:
  297. if df.fieldtype=="Link":
  298. doctype = df.options
  299. if not doctype:
  300. frappe.throw(_("Options not set for link field {0}").format(df.fieldname))
  301. else:
  302. doctype = self.get(df.options)
  303. if not doctype:
  304. frappe.throw(_("{0} must be set first").format(self.meta.get_label(df.options)))
  305. # MySQL is case insensitive. Preserve case of the original docname in the Link Field.
  306. value = frappe.db.get_value(doctype, docname, "name", cache=True)
  307. setattr(self, df.fieldname, value)
  308. if not value:
  309. invalid_links.append((df.fieldname, docname, get_msg(df, docname)))
  310. elif (df.fieldname != "amended_from"
  311. and (is_submittable or self.meta.is_submittable) and frappe.get_meta(doctype).is_submittable
  312. and cint(frappe.db.get_value(doctype, docname, "docstatus"))==2):
  313. cancelled_links.append((df.fieldname, docname, get_msg(df, docname)))
  314. return invalid_links, cancelled_links
  315. def _validate_selects(self):
  316. if frappe.flags.in_import:
  317. return
  318. for df in self.meta.get_select_fields():
  319. if df.fieldname=="naming_series" or not (self.get(df.fieldname) and df.options):
  320. continue
  321. options = (df.options or "").split("\n")
  322. # if only empty options
  323. if not filter(None, options):
  324. continue
  325. # strip and set
  326. self.set(df.fieldname, cstr(self.get(df.fieldname)).strip())
  327. value = self.get(df.fieldname)
  328. if value not in options and not (frappe.flags.in_test and value.startswith("_T-")):
  329. # show an elaborate message
  330. prefix = _("Row #{0}:").format(self.idx) if self.get("parentfield") else ""
  331. label = _(self.meta.get_label(df.fieldname))
  332. comma_options = '", "'.join(_(each) for each in options)
  333. frappe.throw(_('{0} {1} cannot be "{2}". It should be one of "{3}"').format(prefix, label,
  334. value, comma_options))
  335. def _validate_constants(self):
  336. if frappe.flags.in_import or self.is_new():
  337. return
  338. constants = [d.fieldname for d in self.meta.get("fields", {"set_only_once": 1})]
  339. if constants:
  340. values = frappe.db.get_value(self.doctype, self.name, constants, as_dict=True)
  341. for fieldname in constants:
  342. if self.get(fieldname) != values.get(fieldname):
  343. frappe.throw(_("Value cannot be changed for {0}").format(self.meta.get_label(fieldname)),
  344. frappe.CannotChangeConstantError)
  345. def _validate_update_after_submit(self):
  346. db_values = frappe.db.get_value(self.doctype, self.name, "*", as_dict=True)
  347. for key, db_value in db_values.iteritems():
  348. df = self.meta.get_field(key)
  349. if df and not df.allow_on_submit and (self.get(key) or db_value):
  350. self_value = self.get_value(key)
  351. if self_value != db_value:
  352. frappe.throw(_("Not allowed to change {0} after submission").format(df.label),
  353. frappe.UpdateAfterSubmitError)
  354. def precision(self, fieldname, parentfield=None):
  355. """Returns float precision for a particular field (or get global default).
  356. :param fieldname: Fieldname for which precision is required.
  357. :param parentfield: If fieldname is in child table."""
  358. from frappe.model.meta import get_field_precision
  359. if parentfield and not isinstance(parentfield, basestring):
  360. parentfield = parentfield.parentfield
  361. cache_key = parentfield or "main"
  362. if not hasattr(self, "_precision"):
  363. self._precision = frappe._dict()
  364. if cache_key not in self._precision:
  365. self._precision[cache_key] = frappe._dict()
  366. if fieldname not in self._precision[cache_key]:
  367. self._precision[cache_key][fieldname] = None
  368. doctype = self.meta.get_field(parentfield).options if parentfield else self.doctype
  369. df = frappe.get_meta(doctype).get_field(fieldname)
  370. if df.fieldtype in ("Currency", "Float", "Percent"):
  371. self._precision[cache_key][fieldname] = get_field_precision(df, self)
  372. return self._precision[cache_key][fieldname]
  373. def get_formatted(self, fieldname, doc=None, currency=None, absolute_value=False):
  374. from frappe.utils.formatters import format_value
  375. df = self.meta.get_field(fieldname)
  376. if not df and fieldname in default_fields:
  377. from frappe.model.meta import get_default_df
  378. df = get_default_df(fieldname)
  379. val = self.get(fieldname)
  380. if absolute_value and isinstance(val, (int, float)):
  381. val = abs(self.get(fieldname))
  382. return format_value(val, df=df, doc=doc or self, currency=currency)
  383. def is_print_hide(self, fieldname, df=None, for_print=True):
  384. """Returns true if fieldname is to be hidden for print.
  385. Print Hide can be set via the Print Format Builder or in the controller as a list
  386. of hidden fields. Example
  387. class MyDoc(Document):
  388. def __setup__(self):
  389. self.print_hide = ["field1", "field2"]
  390. :param fieldname: Fieldname to be checked if hidden.
  391. """
  392. meta_df = self.meta.get_field(fieldname)
  393. if meta_df and meta_df.get("__print_hide"):
  394. return True
  395. if df:
  396. return df.print_hide
  397. if meta_df:
  398. return meta_df.print_hide
  399. def in_format_data(self, fieldname):
  400. """Returns True if shown via Print Format::`format_data` property.
  401. Called from within standard print format."""
  402. doc = getattr(self, "parent_doc", self)
  403. if hasattr(doc, "format_data_map"):
  404. return fieldname in doc.format_data_map
  405. else:
  406. return True
  407. def reset_values_if_no_permlevel_access(self, has_access_to, high_permlevel_fields):
  408. """If the user does not have permissions at permlevel > 0, then reset the values to original / default"""
  409. to_reset = []
  410. for df in high_permlevel_fields:
  411. if df.permlevel not in has_access_to and df.fieldtype not in display_fieldtypes:
  412. to_reset.append(df)
  413. if to_reset:
  414. if self.is_new():
  415. # if new, set default value
  416. ref_doc = frappe.new_doc(self.doctype)
  417. else:
  418. # get values from old doc
  419. if self.parent:
  420. self.parent_doc.get_latest()
  421. ref_doc = [d for d in self.parent_doc.get(self.parentfield) if d.name == self.name][0]
  422. else:
  423. ref_doc = self.get_latest()
  424. for df in to_reset:
  425. self.set(df.fieldname, ref_doc.get(df.fieldname))
  426. def get_value(self, fieldname):
  427. df = self.meta.get_field(fieldname)
  428. val = self.get(fieldname)
  429. return self.cast(val, df)
  430. def cast(self, val, df):
  431. if df.fieldtype in ("Currency", "Float", "Percent"):
  432. val = flt(val)
  433. elif df.fieldtype in ("Int", "Check"):
  434. val = cint(val)
  435. elif df.fieldtype in ("Data", "Text", "Small Text", "Long Text",
  436. "Text Editor", "Select", "Link", "Dynamic Link"):
  437. val = cstr(val)
  438. elif df.fieldtype == "Date":
  439. val = getdate(val)
  440. elif df.fieldtype == "Datetime":
  441. val = get_datetime(val)
  442. elif df.fieldtype == "Time":
  443. val = to_timedelta(val)
  444. return val
  445. def _extract_images_from_text_editor(self):
  446. from frappe.utils.file_manager import extract_images_from_doc
  447. if self.doctype != "DocType":
  448. for df in self.meta.get("fields", {"fieldtype":"Text Editor"}):
  449. extract_images_from_doc(self, df.fieldname)
  450. def _filter(data, filters, limit=None):
  451. """pass filters as:
  452. {"key": "val", "key": ["!=", "val"],
  453. "key": ["in", "val"], "key": ["not in", "val"], "key": "^val",
  454. "key" : True (exists), "key": False (does not exist) }"""
  455. out = []
  456. for d in data:
  457. add = True
  458. for f in filters:
  459. fval = filters[f]
  460. if fval is True:
  461. fval = ("not None", fval)
  462. elif fval is False:
  463. fval = ("None", fval)
  464. elif not isinstance(fval, (tuple, list)):
  465. if isinstance(fval, basestring) and fval.startswith("^"):
  466. fval = ("^", fval[1:])
  467. else:
  468. fval = ("=", fval)
  469. if not frappe.compare(getattr(d, f, None), fval[0], fval[1]):
  470. add = False
  471. break
  472. if add:
  473. out.append(d)
  474. if limit and (len(out)-1)==limit:
  475. break
  476. return out