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.
 
 
 
 
 
 

1022 rivejä
31 KiB

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