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.
 
 
 
 
 
 

281 rivejä
7.5 KiB

  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe
  5. from frappe import _, msgprint
  6. from frappe.utils import cint, flt, cstr, now
  7. from frappe.model import default_fields
  8. from frappe.model.naming import set_new_name
  9. class BaseDocument(object):
  10. ignore_in_getter = ("doctype", "_meta", "meta", "_table_fields", "_valid_columns")
  11. def __init__(self, d):
  12. self.update(d)
  13. @property
  14. def meta(self):
  15. if not hasattr(self, "_meta"):
  16. self._meta = frappe.get_meta(self.doctype)
  17. return self._meta
  18. def update(self, d):
  19. if "doctype" in d:
  20. self.set("doctype", d.get("doctype"))
  21. for key, value in d.iteritems():
  22. self.set(key, value)
  23. def update_if_missing(self, d):
  24. if isinstance(d, BaseDocument):
  25. d = d.get_valid_dict()
  26. if "doctype" in d:
  27. self.set("doctype", d.get("doctype"))
  28. for key, value in d.iteritems():
  29. if self.get(key) is None:
  30. self.set(key, value)
  31. def get_db_value(self, key):
  32. return frappe.db.get_value(self.doctype, self.name, key)
  33. def get(self, key=None, filters=None, limit=None, default=None):
  34. if key:
  35. if isinstance(key, dict):
  36. return _filter(self.get_all_children(), key, limit=limit)
  37. if filters:
  38. if isinstance(filters, dict):
  39. value = _filter(self.__dict__.get(key), filters, limit=limit)
  40. else:
  41. default = filters
  42. filters = None
  43. value = self.__dict__.get(key, default)
  44. else:
  45. value = self.__dict__.get(key, default)
  46. if value is None and key not in self.ignore_in_getter \
  47. and key in (d.fieldname for d in self.meta.get_table_fields()):
  48. self.set(key, [])
  49. value = self.__dict__.get(key)
  50. return value
  51. else:
  52. return self.__dict__
  53. def getone(self, key, filters=None):
  54. return self.get(key, filters=filters, limit=1)[0]
  55. def set(self, key, value):
  56. if isinstance(value, list):
  57. self.__dict__[key] = []
  58. self.extend(key, value)
  59. else:
  60. self.__dict__[key] = value
  61. def append(self, key, value=None):
  62. if value==None:
  63. value={}
  64. if isinstance(value, (dict, BaseDocument)):
  65. if not self.__dict__.get(key):
  66. self.__dict__[key] = []
  67. value = self._init_child(value, key)
  68. self.__dict__[key].append(value)
  69. return value
  70. else:
  71. raise ValueError
  72. def extend(self, key, value):
  73. if isinstance(value, list):
  74. for v in value:
  75. self.append(key, v)
  76. else:
  77. raise ValueError
  78. def remove(self, doc):
  79. self.get(doc.parentfield).remove(doc)
  80. def _init_child(self, value, key):
  81. if not self.doctype:
  82. return value
  83. if not isinstance(value, BaseDocument):
  84. if "doctype" not in value:
  85. value["doctype"] = self.get_table_field_doctype(key)
  86. if not value["doctype"]:
  87. raise AttributeError, key
  88. value = BaseDocument(value)
  89. value.init_valid_columns()
  90. value.parent = self.name
  91. value.parenttype = self.doctype
  92. value.parentfield = key
  93. if not getattr(value, "idx", None):
  94. value.idx = len(self.get(key) or []) + 1
  95. return value
  96. def get_valid_dict(self):
  97. d = {}
  98. for fieldname in self.meta.get_valid_columns():
  99. d[fieldname] = self.get(fieldname)
  100. return d
  101. def init_valid_columns(self):
  102. for key in default_fields:
  103. if key not in self.__dict__:
  104. self.__dict__[key] = None
  105. if getattr(self, "_metaclass", False) or self.doctype in ("DocType", "DocField", "DocPerm"):
  106. valid = frappe.db.get_table_columns(self.doctype)
  107. else:
  108. valid = self.meta.get_valid_columns()
  109. for key in valid:
  110. if key not in self.__dict__:
  111. self.__dict__[key] = None
  112. def is_new(self):
  113. return self.get("__islocal")
  114. def as_dict(self):
  115. doc = self.get_valid_dict()
  116. doc["doctype"] = self.doctype
  117. for df in self.meta.get_table_fields():
  118. children = self.get(df.fieldname) or []
  119. doc[df.fieldname] = [d.as_dict() for d in children]
  120. return doc
  121. def get_table_field_doctype(self, fieldname):
  122. return self.meta.get_field(fieldname).options
  123. def get_parentfield_of_doctype(self, doctype):
  124. fieldname = [df.fieldname for df in self.meta.get_table_fields() if df.options==doctype]
  125. return fieldname[0] if fieldname else None
  126. def db_insert(self):
  127. set_new_name(self)
  128. d = self.get_valid_dict()
  129. columns = d.keys()
  130. frappe.db.sql("""insert into `tab{doctype}`
  131. ({columns}) values ({values})""".format(
  132. doctype = self.doctype,
  133. columns = ", ".join(["`"+c+"`" for c in columns]),
  134. values = ", ".join(["%s"] * len(columns))
  135. ), d.values())
  136. self.set("__islocal", False)
  137. def db_update(self):
  138. if self.get("__islocal") or not self.name:
  139. self.db_insert()
  140. return
  141. d = self.get_valid_dict()
  142. columns = d.keys()
  143. frappe.db.sql("""update `tab{doctype}`
  144. set {values} where name=%s""".format(
  145. doctype = self.doctype,
  146. values = ", ".join(["`"+c+"`=%s" for c in columns])
  147. ), d.values() + [d.get("name")])
  148. def _fix_numeric_types(self):
  149. for df in self.meta.get("fields"):
  150. if df.fieldtype in ("Int", "Check"):
  151. self.set(df.fieldname, cint(self.get(df.fieldname)))
  152. elif df.fieldtype in ("Float", "Currency"):
  153. self.set(df.fieldname, flt(self.get(df.fieldname)))
  154. if self.docstatus is not None:
  155. self.docstatus = cint(self.docstatus)
  156. def _get_missing_mandatory_fields(self):
  157. """Get mandatory fields that do not have any values"""
  158. def get_msg(df):
  159. if df.fieldtype == "Table":
  160. return "{}: {}: {}".format(_("Error"), _("Data missing in table"), _(df.label))
  161. elif self.parentfield:
  162. return "{}: {} #{}: {}: {}".format(_("Error"), _("Row"), self.idx,
  163. _("Value missing for"), _(df.label))
  164. else:
  165. return "{}: {}: {}".format(_("Error"), _("Value missing for"), _(df.label))
  166. missing = []
  167. for df in self.meta.get("fields", {"reqd": 1}):
  168. if self.get(df.fieldname) in (None, []):
  169. missing.append((df.fieldname, get_msg(df)))
  170. return missing
  171. def get_invalid_links(self):
  172. def get_msg(df, docname):
  173. if self.parentfield:
  174. return "{} #{}: {}: {}".format(_("Row"), self.idx, _(df.label), docname)
  175. else:
  176. return "{}: {}".format(_(df.label), docname)
  177. invalid_links = []
  178. for df in self.meta.get_link_fields():
  179. doctype = df.options
  180. if not doctype:
  181. frappe.throw("Options not set for link field: {}".format(df.fieldname))
  182. elif doctype.lower().startswith("link:"):
  183. doctype = doctype[5:]
  184. docname = self.get(df.fieldname)
  185. if docname and not frappe.db.get_value(doctype, docname):
  186. invalid_links.append((df.fieldname, docname, get_msg(df, docname)))
  187. return invalid_links
  188. def _validate_constants(self):
  189. if frappe.flags.in_import:
  190. return
  191. constants = [d.fieldname for d in self.meta.get("fields", {"set_only_once": 1})]
  192. if constants:
  193. values = frappe.db.get_value(self.doctype, self.name, constants, as_dict=True)
  194. for fieldname in constants:
  195. if self.get(fieldname) != values.get(fieldname):
  196. frappe.throw("{0}: {1}".format(_("Value cannot be changed for"),
  197. _(self.meta.get_label(fieldname))),
  198. frappe.CannotChangeConstantError)
  199. def _filter(data, filters, limit=None):
  200. """pass filters as:
  201. {"key": "val", "key": ["!=", "val"],
  202. "key": ["in", "val"], "key": ["not in", "val"], "key": "^val",
  203. "key" : True (exists), "key": False (does not exist) }"""
  204. out = []
  205. for d in data:
  206. add = True
  207. for f in filters:
  208. fval = filters[f]
  209. if fval is True:
  210. fval = ("not None", fval)
  211. elif fval is False:
  212. fval = ("None", fval)
  213. elif not isinstance(fval, (tuple, list)):
  214. if isinstance(fval, basestring) and fval.startswith("^"):
  215. fval = ("^", fval[1:])
  216. else:
  217. fval = ("=", fval)
  218. if not frappe.compare(getattr(d, f, None), fval[0], fval[1]):
  219. add = False
  220. break
  221. if add:
  222. out.append(d)
  223. if limit and (len(out)-1)==limit:
  224. break
  225. return out