您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

1009 行
30 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. from six import iteritems, string_types
  5. import frappe
  6. import datetime
  7. from frappe import _
  8. from frappe.model import default_fields, table_fields
  9. from frappe.model.naming import set_new_name
  10. from frappe.model.utils.link_count import notify_link_count
  11. from frappe.modules import load_doctype_module
  12. from frappe.model import display_fieldtypes
  13. from frappe.utils import (cint, flt, now, cstr, strip_html,
  14. sanitize_html, sanitize_email, cast_fieldtype)
  15. from frappe.utils.html_utils import unescape_html
  16. max_positive_value = {
  17. 'smallint': 2 ** 15,
  18. 'int': 2 ** 31,
  19. 'bigint': 2 ** 63
  20. }
  21. DOCTYPES_FOR_DOCTYPE = ('DocType', 'DocField', 'DocPerm', 'DocType Action', 'DocType Link')
  22. def get_controller(doctype):
  23. """Returns the **class** object of the given DocType.
  24. For `custom` type, returns `frappe.model.document.Document`.
  25. :param doctype: DocType name as string."""
  26. def _get_controller():
  27. from frappe.model.document import Document
  28. from frappe.utils.nestedset import NestedSet
  29. module_name, custom = frappe.db.get_value(
  30. "DocType", doctype, ("module", "custom"), cache=True
  31. ) or ["Core", False]
  32. if custom:
  33. if frappe.db.field_exists("DocType", "is_tree"):
  34. is_tree = frappe.db.get_value("DocType", doctype, "is_tree", cache=True)
  35. else:
  36. is_tree = False
  37. _class = NestedSet if is_tree else Document
  38. else:
  39. class_overrides = frappe.get_hooks('override_doctype_class')
  40. if class_overrides and class_overrides.get(doctype):
  41. import_path = class_overrides[doctype][-1]
  42. module_path, classname = import_path.rsplit('.', 1)
  43. module = frappe.get_module(module_path)
  44. if not hasattr(module, classname):
  45. raise ImportError('{0}: {1} does not exist in module {2}'.format(doctype, classname, module_path))
  46. else:
  47. module = load_doctype_module(doctype, module_name)
  48. classname = doctype.replace(" ", "").replace("-", "")
  49. if hasattr(module, classname):
  50. _class = getattr(module, classname)
  51. if issubclass(_class, BaseDocument):
  52. _class = getattr(module, classname)
  53. else:
  54. raise ImportError(doctype)
  55. else:
  56. raise ImportError(doctype)
  57. return _class
  58. if frappe.local.dev_server:
  59. return _get_controller()
  60. site_controllers = frappe.controllers.setdefault(frappe.local.site, {})
  61. if doctype not in site_controllers:
  62. site_controllers[doctype] = _get_controller()
  63. return site_controllers[doctype]
  64. class BaseDocument(object):
  65. ignore_in_getter = ("doctype", "_meta", "meta", "_table_fields", "_valid_columns")
  66. def __init__(self, d):
  67. self.update(d)
  68. self.dont_update_if_missing = []
  69. if hasattr(self, "__setup__"):
  70. self.__setup__()
  71. @property
  72. def meta(self):
  73. if not hasattr(self, "_meta"):
  74. self._meta = frappe.get_meta(self.doctype)
  75. return self._meta
  76. def update(self, d):
  77. """ Update multiple fields of a doctype using a dictionary of key-value pairs.
  78. Example:
  79. doc.update({
  80. "user": "admin",
  81. "balance": 42000
  82. })
  83. """
  84. if "doctype" in d:
  85. self.set("doctype", d.get("doctype"))
  86. # first set default field values of base document
  87. for key in default_fields:
  88. if key in d:
  89. self.set(key, d.get(key))
  90. for key, value in iteritems(d):
  91. self.set(key, value)
  92. return self
  93. def update_if_missing(self, d):
  94. if isinstance(d, BaseDocument):
  95. d = d.get_valid_dict()
  96. if "doctype" in d:
  97. self.set("doctype", d.get("doctype"))
  98. for key, value in iteritems(d):
  99. # dont_update_if_missing is a list of fieldnames, for which, you don't want to set default value
  100. if (self.get(key) is None) and (value is not None) and (key not in self.dont_update_if_missing):
  101. self.set(key, value)
  102. def get_db_value(self, key):
  103. return frappe.db.get_value(self.doctype, self.name, key)
  104. def get(self, key=None, filters=None, limit=None, default=None):
  105. if key:
  106. if isinstance(key, dict):
  107. return _filter(self.get_all_children(), key, limit=limit)
  108. if filters:
  109. if isinstance(filters, dict):
  110. value = _filter(self.__dict__.get(key, []), filters, limit=limit)
  111. else:
  112. default = filters
  113. filters = None
  114. value = self.__dict__.get(key, default)
  115. else:
  116. value = self.__dict__.get(key, default)
  117. if value is None and key not in self.ignore_in_getter \
  118. and key in (d.fieldname for d in self.meta.get_table_fields()):
  119. self.set(key, [])
  120. value = self.__dict__.get(key)
  121. return value
  122. else:
  123. return self.__dict__
  124. def getone(self, key, filters=None):
  125. return self.get(key, filters=filters, limit=1)[0]
  126. def set(self, key, value, as_value=False):
  127. if isinstance(value, list) and not as_value:
  128. self.__dict__[key] = []
  129. self.extend(key, value)
  130. else:
  131. self.__dict__[key] = value
  132. def delete_key(self, key):
  133. if key in self.__dict__:
  134. del self.__dict__[key]
  135. def append(self, key, value=None):
  136. """ Append an item to a child table.
  137. Example:
  138. doc.append("childtable", {
  139. "child_table_field": "value",
  140. "child_table_int_field": 0,
  141. ...
  142. })
  143. """
  144. if value==None:
  145. value={}
  146. if isinstance(value, (dict, BaseDocument)):
  147. if not self.__dict__.get(key):
  148. self.__dict__[key] = []
  149. value = self._init_child(value, key)
  150. self.__dict__[key].append(value)
  151. # reference parent document
  152. value.parent_doc = self
  153. return value
  154. else:
  155. # metaclasses may have arbitrary lists
  156. # which we can ignore
  157. if (getattr(self, '_metaclass', None)
  158. or self.__class__.__name__ in ('Meta', 'FormMeta', 'DocField')):
  159. return value
  160. raise ValueError(
  161. 'Document for field "{0}" attached to child table of "{1}" must be a dict or BaseDocument, not {2} ({3})'.format(key,
  162. self.name, str(type(value))[1:-1], value)
  163. )
  164. def extend(self, key, value):
  165. if isinstance(value, list):
  166. for v in value:
  167. self.append(key, v)
  168. else:
  169. raise ValueError
  170. def remove(self, doc):
  171. self.get(doc.parentfield).remove(doc)
  172. def _init_child(self, value, key):
  173. if not self.doctype:
  174. return value
  175. if not isinstance(value, BaseDocument):
  176. if "doctype" not in value or value['doctype'] is None:
  177. value["doctype"] = self.get_table_field_doctype(key)
  178. if not value["doctype"]:
  179. raise AttributeError(key)
  180. value = get_controller(value["doctype"])(value)
  181. value.init_valid_columns()
  182. value.parent = self.name
  183. value.parenttype = self.doctype
  184. value.parentfield = key
  185. if value.docstatus is None:
  186. value.docstatus = 0
  187. if not getattr(value, "idx", None):
  188. value.idx = len(self.get(key) or []) + 1
  189. if not getattr(value, "name", None):
  190. value.__dict__['__islocal'] = 1
  191. return value
  192. def get_valid_dict(self, sanitize=True, convert_dates_to_str=False, ignore_nulls = False):
  193. d = frappe._dict()
  194. for fieldname in self.meta.get_valid_columns():
  195. d[fieldname] = self.get(fieldname)
  196. # if no need for sanitization and value is None, continue
  197. if not sanitize and d[fieldname] is None:
  198. continue
  199. df = self.meta.get_field(fieldname)
  200. if df:
  201. if df.fieldtype=="Check":
  202. d[fieldname] = 1 if cint(d[fieldname]) else 0
  203. elif df.fieldtype=="Int" and not isinstance(d[fieldname], int):
  204. d[fieldname] = cint(d[fieldname])
  205. elif df.fieldtype in ("Currency", "Float", "Percent") and not isinstance(d[fieldname], float):
  206. d[fieldname] = flt(d[fieldname])
  207. elif df.fieldtype in ("Datetime", "Date", "Time") and d[fieldname]=="":
  208. d[fieldname] = None
  209. elif df.get("unique") and cstr(d[fieldname]).strip()=="":
  210. # unique empty field should be set to None
  211. d[fieldname] = None
  212. if isinstance(d[fieldname], list) and df.fieldtype not in table_fields:
  213. frappe.throw(_('Value for {0} cannot be a list').format(_(df.label)))
  214. if convert_dates_to_str and isinstance(d[fieldname], (datetime.datetime, datetime.time, datetime.timedelta)):
  215. d[fieldname] = str(d[fieldname])
  216. if d[fieldname] == None and ignore_nulls:
  217. del d[fieldname]
  218. return d
  219. def init_valid_columns(self):
  220. for key in default_fields:
  221. if key not in self.__dict__:
  222. self.__dict__[key] = None
  223. if key in ("idx", "docstatus") and self.__dict__[key] is None:
  224. self.__dict__[key] = 0
  225. for key in self.get_valid_columns():
  226. if key not in self.__dict__:
  227. self.__dict__[key] = None
  228. def get_valid_columns(self):
  229. if self.doctype not in frappe.local.valid_columns:
  230. if self.doctype in DOCTYPES_FOR_DOCTYPE:
  231. from frappe.model.meta import get_table_columns
  232. valid = get_table_columns(self.doctype)
  233. else:
  234. valid = self.meta.get_valid_columns()
  235. frappe.local.valid_columns[self.doctype] = valid
  236. return frappe.local.valid_columns[self.doctype]
  237. def is_new(self):
  238. return self.get("__islocal")
  239. def as_dict(self, no_nulls=False, no_default_fields=False, convert_dates_to_str=False):
  240. doc = self.get_valid_dict(convert_dates_to_str=convert_dates_to_str)
  241. doc["doctype"] = self.doctype
  242. for df in self.meta.get_table_fields():
  243. children = self.get(df.fieldname) or []
  244. doc[df.fieldname] = [d.as_dict(convert_dates_to_str=convert_dates_to_str, no_nulls=no_nulls) for d in children]
  245. if no_nulls:
  246. for k in list(doc):
  247. if doc[k] is None:
  248. del doc[k]
  249. if no_default_fields:
  250. for k in list(doc):
  251. if k in default_fields:
  252. del doc[k]
  253. for key in ("_user_tags", "__islocal", "__onload", "_liked_by", "__run_link_triggers", "__unsaved"):
  254. if self.get(key):
  255. doc[key] = self.get(key)
  256. return doc
  257. def as_json(self):
  258. return frappe.as_json(self.as_dict())
  259. def get_table_field_doctype(self, fieldname):
  260. try:
  261. return self.meta.get_field(fieldname).options
  262. except AttributeError:
  263. if self.doctype == 'DocType':
  264. return dict(links='DocType Link', actions='DocType Action').get(fieldname)
  265. raise
  266. def get_parentfield_of_doctype(self, doctype):
  267. fieldname = [df.fieldname for df in self.meta.get_table_fields() if df.options==doctype]
  268. return fieldname[0] if fieldname else None
  269. def db_insert(self):
  270. """INSERT the document (with valid columns) in the database."""
  271. if not self.name:
  272. # name will be set by document class in most cases
  273. set_new_name(self)
  274. if not self.creation:
  275. self.creation = self.modified = now()
  276. self.created_by = self.modified_by = frappe.session.user
  277. # if doctype is "DocType", don't insert null values as we don't know who is valid yet
  278. d = self.get_valid_dict(convert_dates_to_str=True, ignore_nulls = self.doctype in DOCTYPES_FOR_DOCTYPE)
  279. columns = list(d)
  280. try:
  281. frappe.db.sql("""INSERT INTO `tab{doctype}` ({columns})
  282. VALUES ({values})""".format(
  283. doctype = self.doctype,
  284. columns = ", ".join(["`"+c+"`" for c in columns]),
  285. values = ", ".join(["%s"] * len(columns))
  286. ), list(d.values()))
  287. except Exception as e:
  288. if frappe.db.is_primary_key_violation(e):
  289. if self.meta.autoname=="hash":
  290. # hash collision? try again
  291. frappe.flags.retry_count = (frappe.flags.retry_count or 0) + 1
  292. if frappe.flags.retry_count > 5 and not frappe.flags.in_test:
  293. raise
  294. self.name = None
  295. self.db_insert()
  296. return
  297. frappe.msgprint(_("{0} {1} already exists").format(self.doctype, frappe.bold(self.name)), title=_("Duplicate Name"), indicator="red")
  298. raise frappe.DuplicateEntryError(self.doctype, self.name, e)
  299. elif frappe.db.is_unique_key_violation(e):
  300. # unique constraint
  301. self.show_unique_validation_message(e)
  302. else:
  303. raise
  304. self.set("__islocal", False)
  305. def db_update(self):
  306. if self.get("__islocal") or not self.name:
  307. self.db_insert()
  308. return
  309. d = self.get_valid_dict(convert_dates_to_str=True, ignore_nulls = self.doctype in DOCTYPES_FOR_DOCTYPE)
  310. # don't update name, as case might've been changed
  311. name = d['name']
  312. del d['name']
  313. columns = list(d)
  314. try:
  315. frappe.db.sql("""UPDATE `tab{doctype}`
  316. SET {values} WHERE `name`=%s""".format(
  317. doctype = self.doctype,
  318. values = ", ".join(["`"+c+"`=%s" for c in columns])
  319. ), list(d.values()) + [name])
  320. except Exception as e:
  321. if frappe.db.is_unique_key_violation(e):
  322. self.show_unique_validation_message(e)
  323. else:
  324. raise
  325. def db_update_all(self):
  326. """Raw update parent + children
  327. DOES NOT VALIDATE AND CALL TRIGGERS"""
  328. self.db_update()
  329. for df in self.meta.get_table_fields():
  330. for doc in self.get(df.fieldname):
  331. doc.db_update()
  332. def show_unique_validation_message(self, e):
  333. if frappe.db.db_type != 'postgres':
  334. fieldname = str(e).split("'")[-2]
  335. label = None
  336. # MariaDB gives key_name in error. Extracting fieldname from key name
  337. try:
  338. fieldname = self.get_field_name_by_key_name(fieldname)
  339. except IndexError:
  340. pass
  341. label = self.get_label_from_fieldname(fieldname)
  342. frappe.msgprint(_("{0} must be unique").format(label or fieldname))
  343. # this is used to preserve traceback
  344. raise frappe.UniqueValidationError(self.doctype, self.name, e)
  345. def get_field_name_by_key_name(self, key_name):
  346. """MariaDB stores a mapping between `key_name` and `column_name`.
  347. This function returns the `column_name` associated with the `key_name` passed
  348. Args:
  349. key_name (str): The name of the database index.
  350. Raises:
  351. IndexError: If the key is not found in the table.
  352. Returns:
  353. str: The column name associated with the key.
  354. """
  355. return frappe.db.sql(f"""
  356. SHOW
  357. INDEX
  358. FROM
  359. `tab{self.doctype}`
  360. WHERE
  361. key_name=%s
  362. AND
  363. Non_unique=0
  364. """, key_name, as_dict=True)[0].get("Column_name")
  365. def get_label_from_fieldname(self, fieldname):
  366. """Returns the associated label for fieldname
  367. Args:
  368. fieldname (str): The fieldname in the DocType to use to pull the label.
  369. Returns:
  370. str: The label associated with the fieldname, if found, otherwise `None`.
  371. """
  372. df = self.meta.get_field(fieldname)
  373. if df:
  374. return df.label
  375. def update_modified(self):
  376. """Update modified timestamp"""
  377. self.set("modified", now())
  378. frappe.db.set_value(self.doctype, self.name, 'modified', self.modified, update_modified=False)
  379. def _fix_numeric_types(self):
  380. for df in self.meta.get("fields"):
  381. if df.fieldtype == "Check":
  382. self.set(df.fieldname, cint(self.get(df.fieldname)))
  383. elif self.get(df.fieldname) is not None:
  384. if df.fieldtype == "Int":
  385. self.set(df.fieldname, cint(self.get(df.fieldname)))
  386. elif df.fieldtype in ("Float", "Currency", "Percent"):
  387. self.set(df.fieldname, flt(self.get(df.fieldname)))
  388. if self.docstatus is not None:
  389. self.docstatus = cint(self.docstatus)
  390. def _get_missing_mandatory_fields(self):
  391. """Get mandatory fields that do not have any values"""
  392. def get_msg(df):
  393. if df.fieldtype in table_fields:
  394. return "{}: {}: {}".format(_("Error"), _("Data missing in table"), _(df.label))
  395. elif self.parentfield:
  396. return "{}: {} {} #{}: {}: {}".format(_("Error"), frappe.bold(_(self.doctype)),
  397. _("Row"), self.idx, _("Value missing for"), _(df.label))
  398. else:
  399. return _("Error: Value missing for {0}: {1}").format(_(df.parent), _(df.label))
  400. missing = []
  401. for df in self.meta.get("fields", {"reqd": ('=', 1)}):
  402. if self.get(df.fieldname) in (None, []) or not strip_html(cstr(self.get(df.fieldname))).strip():
  403. missing.append((df.fieldname, get_msg(df)))
  404. # check for missing parent and parenttype
  405. if self.meta.istable:
  406. for fieldname in ("parent", "parenttype"):
  407. if not self.get(fieldname):
  408. missing.append((fieldname, get_msg(frappe._dict(label=fieldname))))
  409. return missing
  410. def get_invalid_links(self, is_submittable=False):
  411. """Returns list of invalid links and also updates fetch values if not set"""
  412. def get_msg(df, docname):
  413. if self.parentfield:
  414. return "{} #{}: {}: {}".format(_("Row"), self.idx, _(df.label), docname)
  415. else:
  416. return "{}: {}".format(_(df.label), docname)
  417. invalid_links = []
  418. cancelled_links = []
  419. for df in (self.meta.get_link_fields()
  420. + self.meta.get("fields", {"fieldtype": ('=', "Dynamic Link")})):
  421. docname = self.get(df.fieldname)
  422. if docname:
  423. if df.fieldtype=="Link":
  424. doctype = df.options
  425. if not doctype:
  426. frappe.throw(_("Options not set for link field {0}").format(df.fieldname))
  427. else:
  428. doctype = self.get(df.options)
  429. if not doctype:
  430. frappe.throw(_("{0} must be set first").format(self.meta.get_label(df.options)))
  431. # MySQL is case insensitive. Preserve case of the original docname in the Link Field.
  432. # get a map of values ot fetch along with this link query
  433. # that are mapped as link_fieldname.source_fieldname in Options of
  434. # Readonly or Data or Text type fields
  435. fields_to_fetch = [
  436. _df for _df in self.meta.get_fields_to_fetch(df.fieldname)
  437. if
  438. not _df.get('fetch_if_empty')
  439. or (_df.get('fetch_if_empty') and not self.get(_df.fieldname))
  440. ]
  441. if not frappe.get_meta(doctype).get('is_virtual'):
  442. if not fields_to_fetch:
  443. # cache a single value type
  444. values = frappe._dict(name=frappe.db.get_value(doctype, docname,
  445. 'name', cache=True))
  446. else:
  447. values_to_fetch = ['name'] + [_df.fetch_from.split('.')[-1]
  448. for _df in fields_to_fetch]
  449. # don't cache if fetching other values too
  450. values = frappe.db.get_value(doctype, docname,
  451. values_to_fetch, as_dict=True)
  452. if frappe.get_meta(doctype).issingle:
  453. values.name = doctype
  454. if frappe.get_meta(doctype).get('is_virtual'):
  455. values = frappe.get_doc(doctype, docname)
  456. if values:
  457. setattr(self, df.fieldname, values.name)
  458. for _df in fields_to_fetch:
  459. if self.is_new() or self.docstatus != 1 or _df.allow_on_submit:
  460. self.set_fetch_from_value(doctype, _df, values)
  461. notify_link_count(doctype, docname)
  462. if not values.name:
  463. invalid_links.append((df.fieldname, docname, get_msg(df, docname)))
  464. elif (df.fieldname != "amended_from"
  465. and (is_submittable or self.meta.is_submittable) and frappe.get_meta(doctype).is_submittable
  466. and cint(frappe.db.get_value(doctype, docname, "docstatus"))==2):
  467. cancelled_links.append((df.fieldname, docname, get_msg(df, docname)))
  468. return invalid_links, cancelled_links
  469. def set_fetch_from_value(self, doctype, df, values):
  470. fetch_from_fieldname = df.fetch_from.split('.')[-1]
  471. value = values[fetch_from_fieldname]
  472. if df.fieldtype in ['Small Text', 'Text', 'Data']:
  473. if fetch_from_fieldname in default_fields:
  474. from frappe.model.meta import get_default_df
  475. fetch_from_df = get_default_df(fetch_from_fieldname)
  476. else:
  477. fetch_from_df = frappe.get_meta(doctype).get_field(fetch_from_fieldname)
  478. if not fetch_from_df:
  479. frappe.throw(
  480. _('Please check the value of "Fetch From" set for field {0}').format(frappe.bold(df.label)),
  481. title = _('Wrong Fetch From value')
  482. )
  483. fetch_from_ft = fetch_from_df.get('fieldtype')
  484. if fetch_from_ft == 'Text Editor' and value:
  485. value = unescape_html(strip_html(value))
  486. setattr(self, df.fieldname, value)
  487. def _validate_selects(self):
  488. if frappe.flags.in_import:
  489. return
  490. for df in self.meta.get_select_fields():
  491. if df.fieldname=="naming_series" or not (self.get(df.fieldname) and df.options):
  492. continue
  493. options = (df.options or "").split("\n")
  494. # if only empty options
  495. if not filter(None, options):
  496. continue
  497. # strip and set
  498. self.set(df.fieldname, cstr(self.get(df.fieldname)).strip())
  499. value = self.get(df.fieldname)
  500. if value not in options and not (frappe.flags.in_test and value.startswith("_T-")):
  501. # show an elaborate message
  502. prefix = _("Row #{0}:").format(self.idx) if self.get("parentfield") else ""
  503. label = _(self.meta.get_label(df.fieldname))
  504. comma_options = '", "'.join(_(each) for each in options)
  505. frappe.throw(_('{0} {1} cannot be "{2}". It should be one of "{3}"').format(prefix, label,
  506. value, comma_options))
  507. def _validate_data_fields(self):
  508. from frappe.core.doctype.user.user import STANDARD_USERS
  509. # data_field options defined in frappe.model.data_field_options
  510. for data_field in self.meta.get_data_fields():
  511. data = self.get(data_field.fieldname)
  512. data_field_options = data_field.get("options")
  513. old_fieldtype = data_field.get("oldfieldtype")
  514. if old_fieldtype and old_fieldtype != "Data":
  515. continue
  516. if data_field_options == "Email":
  517. if (self.owner in STANDARD_USERS) and (data in STANDARD_USERS):
  518. continue
  519. for email_address in frappe.utils.split_emails(data):
  520. frappe.utils.validate_email_address(email_address, throw=True)
  521. if data_field_options == "Name":
  522. frappe.utils.validate_name(data, throw=True)
  523. if data_field_options == "Phone":
  524. frappe.utils.validate_phone_number(data, throw=True)
  525. if data_field_options == "URL":
  526. if not data:
  527. continue
  528. frappe.utils.validate_url(data, throw=True)
  529. def _validate_constants(self):
  530. if frappe.flags.in_import or self.is_new() or self.flags.ignore_validate_constants:
  531. return
  532. constants = [d.fieldname for d in self.meta.get("fields", {"set_only_once": ('=',1)})]
  533. if constants:
  534. values = frappe.db.get_value(self.doctype, self.name, constants, as_dict=True)
  535. for fieldname in constants:
  536. df = self.meta.get_field(fieldname)
  537. # This conversion to string only when fieldtype is Date
  538. if df.fieldtype == 'Date' or df.fieldtype == 'Datetime':
  539. value = str(values.get(fieldname))
  540. else:
  541. value = values.get(fieldname)
  542. if self.get(fieldname) != value:
  543. frappe.throw(_("Value cannot be changed for {0}").format(self.meta.get_label(fieldname)),
  544. frappe.CannotChangeConstantError)
  545. def _validate_length(self):
  546. if frappe.flags.in_install:
  547. return
  548. if self.meta.issingle:
  549. # single doctype value type is mediumtext
  550. return
  551. type_map = frappe.db.type_map
  552. for fieldname, value in iteritems(self.get_valid_dict()):
  553. df = self.meta.get_field(fieldname)
  554. if not df or df.fieldtype == 'Check':
  555. # skip standard fields and Check fields
  556. continue
  557. column_type = type_map[df.fieldtype][0] or None
  558. if column_type == 'varchar':
  559. default_column_max_length = type_map[df.fieldtype][1] or None
  560. max_length = cint(df.get("length")) or cint(default_column_max_length)
  561. if len(cstr(value)) > max_length:
  562. self.throw_length_exceeded_error(df, max_length, value)
  563. elif column_type in ('int', 'bigint', 'smallint'):
  564. max_length = max_positive_value[column_type]
  565. if abs(cint(value)) > max_length:
  566. self.throw_length_exceeded_error(df, max_length, value)
  567. def throw_length_exceeded_error(self, df, max_length, value):
  568. if self.parentfield and self.idx:
  569. reference = _("{0}, Row {1}").format(_(self.doctype), self.idx)
  570. else:
  571. reference = "{0} {1}".format(_(self.doctype), self.name)
  572. frappe.throw(_("{0}: '{1}' ({3}) will get truncated, as max characters allowed is {2}")\
  573. .format(reference, _(df.label), max_length, value), frappe.CharacterLengthExceededError, title=_('Value too big'))
  574. def _validate_update_after_submit(self):
  575. # get the full doc with children
  576. db_values = frappe.get_doc(self.doctype, self.name).as_dict()
  577. for key in self.as_dict():
  578. df = self.meta.get_field(key)
  579. db_value = db_values.get(key)
  580. if df and not df.allow_on_submit and (self.get(key) or db_value):
  581. if df.fieldtype in table_fields:
  582. # just check if the table size has changed
  583. # individual fields will be checked in the loop for children
  584. self_value = len(self.get(key))
  585. db_value = len(db_value)
  586. else:
  587. self_value = self.get_value(key)
  588. if self_value != db_value:
  589. frappe.throw(_("Not allowed to change {0} after submission").format(df.label),
  590. frappe.UpdateAfterSubmitError)
  591. def _sanitize_content(self):
  592. """Sanitize HTML and Email in field values. Used to prevent XSS.
  593. - Ignore if 'Ignore XSS Filter' is checked or fieldtype is 'Code'
  594. """
  595. from bs4 import BeautifulSoup
  596. if frappe.flags.in_install:
  597. return
  598. for fieldname, value in self.get_valid_dict().items():
  599. if not value or not isinstance(value, string_types):
  600. continue
  601. value = frappe.as_unicode(value)
  602. if (u"<" not in value and u">" not in value):
  603. # doesn't look like html so no need
  604. continue
  605. elif "<!-- markdown -->" in value and not bool(BeautifulSoup(value, "html.parser").find()):
  606. # should be handled separately via the markdown converter function
  607. continue
  608. df = self.meta.get_field(fieldname)
  609. sanitized_value = value
  610. if df and (df.get("ignore_xss_filter")
  611. or (df.get("fieldtype") in ("Data", "Small Text", "Text") and df.get("options")=="Email")
  612. or df.get("fieldtype") in ("Attach", "Attach Image", "Barcode", "Code")
  613. # cancelled and submit but not update after submit should be ignored
  614. or self.docstatus==2
  615. or (self.docstatus==1 and not df.get("allow_on_submit"))):
  616. continue
  617. else:
  618. sanitized_value = sanitize_html(value, linkify=df and df.fieldtype=='Text Editor')
  619. self.set(fieldname, sanitized_value)
  620. def _save_passwords(self):
  621. """Save password field values in __Auth table"""
  622. from frappe.utils.password import set_encrypted_password, remove_encrypted_password
  623. if self.flags.ignore_save_passwords is True:
  624. return
  625. for df in self.meta.get('fields', {'fieldtype': ('=', 'Password')}):
  626. if self.flags.ignore_save_passwords and df.fieldname in self.flags.ignore_save_passwords: continue
  627. new_password = self.get(df.fieldname)
  628. if not new_password:
  629. remove_encrypted_password(self.doctype, self.name, df.fieldname)
  630. if new_password and not self.is_dummy_password(new_password):
  631. # is not a dummy password like '*****'
  632. set_encrypted_password(self.doctype, self.name, new_password, df.fieldname)
  633. # set dummy password like '*****'
  634. self.set(df.fieldname, '*'*len(new_password))
  635. def get_password(self, fieldname='password', raise_exception=True):
  636. from frappe.utils.password import get_decrypted_password
  637. if self.get(fieldname) and not self.is_dummy_password(self.get(fieldname)):
  638. return self.get(fieldname)
  639. return get_decrypted_password(self.doctype, self.name, fieldname, raise_exception=raise_exception)
  640. def is_dummy_password(self, pwd):
  641. return ''.join(set(pwd))=='*'
  642. def precision(self, fieldname, parentfield=None):
  643. """Returns float precision for a particular field (or get global default).
  644. :param fieldname: Fieldname for which precision is required.
  645. :param parentfield: If fieldname is in child table."""
  646. from frappe.model.meta import get_field_precision
  647. if parentfield and not isinstance(parentfield, string_types):
  648. parentfield = parentfield.parentfield
  649. cache_key = parentfield or "main"
  650. if not hasattr(self, "_precision"):
  651. self._precision = frappe._dict()
  652. if cache_key not in self._precision:
  653. self._precision[cache_key] = frappe._dict()
  654. if fieldname not in self._precision[cache_key]:
  655. self._precision[cache_key][fieldname] = None
  656. doctype = self.meta.get_field(parentfield).options if parentfield else self.doctype
  657. df = frappe.get_meta(doctype).get_field(fieldname)
  658. if df.fieldtype in ("Currency", "Float", "Percent"):
  659. self._precision[cache_key][fieldname] = get_field_precision(df, self)
  660. return self._precision[cache_key][fieldname]
  661. def get_formatted(self, fieldname, doc=None, currency=None, absolute_value=False, translated=False):
  662. from frappe.utils.formatters import format_value
  663. df = self.meta.get_field(fieldname)
  664. if not df and fieldname in default_fields:
  665. from frappe.model.meta import get_default_df
  666. df = get_default_df(fieldname)
  667. if not currency:
  668. currency = self.get(df.get("options"))
  669. if not frappe.db.exists('Currency', currency, cache=True):
  670. currency = None
  671. val = self.get(fieldname)
  672. if translated:
  673. val = _(val)
  674. if not doc:
  675. doc = getattr(self, "parent_doc", None) or self
  676. if (absolute_value or doc.get('absolute_value')) and isinstance(val, (int, float)):
  677. val = abs(self.get(fieldname))
  678. return format_value(val, df=df, doc=doc, currency=currency)
  679. def is_print_hide(self, fieldname, df=None, for_print=True):
  680. """Returns true if fieldname is to be hidden for print.
  681. Print Hide can be set via the Print Format Builder or in the controller as a list
  682. of hidden fields. Example
  683. class MyDoc(Document):
  684. def __setup__(self):
  685. self.print_hide = ["field1", "field2"]
  686. :param fieldname: Fieldname to be checked if hidden.
  687. """
  688. meta_df = self.meta.get_field(fieldname)
  689. if meta_df and meta_df.get("__print_hide"):
  690. return True
  691. print_hide = 0
  692. if self.get(fieldname)==0 and not self.meta.istable:
  693. print_hide = ( df and df.print_hide_if_no_value ) or ( meta_df and meta_df.print_hide_if_no_value )
  694. if not print_hide:
  695. if df and df.print_hide is not None:
  696. print_hide = df.print_hide
  697. elif meta_df:
  698. print_hide = meta_df.print_hide
  699. return print_hide
  700. def in_format_data(self, fieldname):
  701. """Returns True if shown via Print Format::`format_data` property.
  702. Called from within standard print format."""
  703. doc = getattr(self, "parent_doc", self)
  704. if hasattr(doc, "format_data_map"):
  705. return fieldname in doc.format_data_map
  706. else:
  707. return True
  708. def reset_values_if_no_permlevel_access(self, has_access_to, high_permlevel_fields):
  709. """If the user does not have permissions at permlevel > 0, then reset the values to original / default"""
  710. to_reset = []
  711. for df in high_permlevel_fields:
  712. if df.permlevel not in has_access_to and df.fieldtype not in display_fieldtypes:
  713. to_reset.append(df)
  714. if to_reset:
  715. if self.is_new():
  716. # if new, set default value
  717. ref_doc = frappe.new_doc(self.doctype)
  718. else:
  719. # get values from old doc
  720. if self.get('parent_doc'):
  721. parent_doc = self.parent_doc.get_latest()
  722. ref_doc = [d for d in parent_doc.get(self.parentfield) if d.name == self.name][0]
  723. else:
  724. ref_doc = self.get_latest()
  725. for df in to_reset:
  726. self.set(df.fieldname, ref_doc.get(df.fieldname))
  727. def get_value(self, fieldname):
  728. df = self.meta.get_field(fieldname)
  729. val = self.get(fieldname)
  730. return self.cast(val, df)
  731. def cast(self, value, df):
  732. return cast_fieldtype(df.fieldtype, value)
  733. def _extract_images_from_text_editor(self):
  734. from frappe.core.doctype.file.file import extract_images_from_doc
  735. if self.doctype != "DocType":
  736. for df in self.meta.get("fields", {"fieldtype": ('=', "Text Editor")}):
  737. extract_images_from_doc(self, df.fieldname)
  738. def _filter(data, filters, limit=None):
  739. """pass filters as:
  740. {"key": "val", "key": ["!=", "val"],
  741. "key": ["in", "val"], "key": ["not in", "val"], "key": "^val",
  742. "key" : True (exists), "key": False (does not exist) }"""
  743. out, _filters = [], {}
  744. if not data:
  745. return out
  746. # setup filters as tuples
  747. if filters:
  748. for f in filters:
  749. fval = filters[f]
  750. if not isinstance(fval, (tuple, list)):
  751. if fval is True:
  752. fval = ("not None", fval)
  753. elif fval is False:
  754. fval = ("None", fval)
  755. elif isinstance(fval, string_types) and fval.startswith("^"):
  756. fval = ("^", fval[1:])
  757. else:
  758. fval = ("=", fval)
  759. _filters[f] = fval
  760. for d in data:
  761. add = True
  762. for f, fval in iteritems(_filters):
  763. if not frappe.compare(getattr(d, f, None), fval[0], fval[1]):
  764. add = False
  765. break
  766. if add:
  767. out.append(d)
  768. if limit and (len(out)-1)==limit:
  769. break
  770. return out