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.
 
 
 
 
 
 

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