Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

235 Zeilen
6.4 KiB

  1. import requests
  2. import json
  3. import frappe
  4. class AuthError(Exception):
  5. pass
  6. class FrappeException(Exception):
  7. pass
  8. class FrappeClient(object):
  9. def __init__(self, url, username, password, verify=True):
  10. self.verify = verify
  11. self.session = requests.session()
  12. self.url = url
  13. self.login(username, password)
  14. def __enter__(self):
  15. return self
  16. def __exit__(self, *args, **kwargs):
  17. self.logout()
  18. def login(self, username, password):
  19. r = self.session.post(self.url, data={
  20. 'cmd': 'login',
  21. 'usr': username,
  22. 'pwd': password
  23. }, verify=self.verify)
  24. if r.status_code==200 and r.json().get('message') == "Logged In":
  25. return r.json()
  26. else:
  27. raise AuthError
  28. def logout(self):
  29. self.session.get(self.url, params={
  30. 'cmd': 'logout',
  31. }, verify=self.verify)
  32. def get_list(self, doctype, fields='"*"', filters=None, limit_start=0, limit_page_length=0):
  33. """Returns list of records of a particular type"""
  34. if not isinstance(fields, basestring):
  35. fields = json.dumps(fields)
  36. params = {
  37. "fields": fields,
  38. }
  39. if filters:
  40. params["filters"] = json.dumps(filters)
  41. if limit_page_length:
  42. params["limit_start"] = limit_start
  43. params["limit_page_length"] = limit_page_length
  44. res = self.session.get(self.url + "/api/resource/" + doctype, params=params, verify=self.verify)
  45. return self.post_process(res)
  46. def insert(self, doc):
  47. res = self.session.post(self.url + "/api/resource/" + doc.get("doctype"),
  48. data={"data":frappe.as_json(doc)}, verify=self.verify)
  49. return self.post_process(res)
  50. def update(self, doc):
  51. url = self.url + "/api/resource/" + doc.get("doctype") + "/" + doc.get("name")
  52. res = self.session.put(url, data={"data":frappe.as_json(doc)}, verify=self.verify)
  53. return self.post_process(res)
  54. def bulk_update(self, docs):
  55. return self.post_request({
  56. "cmd": "frappe.client.bulk_update",
  57. "docs": frappe.as_json(docs)
  58. })
  59. def delete(self, doctype, name):
  60. return self.post_request({
  61. "cmd": "frappe.model.delete_doc",
  62. "doctype": doctype,
  63. "name": name
  64. })
  65. def submit(self, doclist):
  66. return self.post_request({
  67. "cmd": "frappe.client.submit",
  68. "doclist": frappe.as_json(doclist)
  69. })
  70. def get_value(self, doctype, fieldname=None, filters=None):
  71. return self.get_request({
  72. "cmd": "frappe.client.get_value",
  73. "doctype": doctype,
  74. "fieldname": fieldname or "name",
  75. "filters": frappe.as_json(filters)
  76. })
  77. def set_value(self, doctype, docname, fieldname, value):
  78. return self.post_request({
  79. "cmd": "frappe.client.set_value",
  80. "doctype": doctype,
  81. "name": docname,
  82. "fieldname": fieldname,
  83. "value": value
  84. })
  85. def cancel(self, doctype, name):
  86. return self.post_request({
  87. "cmd": "frappe.client.cancel",
  88. "doctype": doctype,
  89. "name": name
  90. })
  91. def get_doc(self, doctype, name="", filters=None, fields=None):
  92. params = {}
  93. if filters:
  94. params["filters"] = json.dumps(filters)
  95. if fields:
  96. params["fields"] = json.dumps(fields)
  97. res = self.session.get(self.url + "/api/resource/" + doctype + "/" + name,
  98. params=params, verify=self.verify)
  99. return self.post_process(res)
  100. def rename_doc(self, doctype, old_name, new_name):
  101. params = {
  102. "cmd": "frappe.client.rename_doc",
  103. "doctype": doctype,
  104. "old_name": old_name,
  105. "new_name": new_name
  106. }
  107. return self.post_request(params)
  108. def migrate_doctype(self, doctype, filters=None, update=None, verbose=1, exclude=None, preprocess=None):
  109. """Migrate records from another doctype"""
  110. meta = frappe.get_meta(doctype)
  111. tables = {}
  112. for df in meta.get_table_fields():
  113. if verbose: print "getting " + df.options
  114. tables[df.fieldname] = self.get_list(df.options, limit_page_length=999999)
  115. # get links
  116. if verbose: print "getting " + doctype
  117. docs = self.get_list(doctype, limit_page_length=999999, filters=filters)
  118. # build - attach children to parents
  119. if tables:
  120. docs = [frappe._dict(doc) for doc in docs]
  121. docs_map = dict((doc.name, doc) for doc in docs)
  122. for fieldname in tables:
  123. for child in tables[fieldname]:
  124. child = frappe._dict(child)
  125. if child.parent in docs_map:
  126. docs_map[child.parent].setdefault(fieldname, []).append(child)
  127. if verbose: print "inserting " + doctype
  128. for doc in docs:
  129. if exclude and doc["name"] in exclude:
  130. continue
  131. if preprocess:
  132. preprocess(doc)
  133. if not doc.get("owner"):
  134. doc["owner"] = "Administrator"
  135. if doctype != "User" and not frappe.db.exists("User", doc.get("owner")):
  136. frappe.get_doc({"doctype": "User", "email": doc.get("owner"),
  137. "first_name": doc.get("owner").split("@")[0] }).insert()
  138. if update:
  139. doc.update(update)
  140. doc["doctype"] = doctype
  141. new_doc = frappe.get_doc(doc)
  142. new_doc.insert()
  143. if not meta.istable:
  144. if doctype != "Communication":
  145. self.migrate_doctype("Communication", {"reference_doctype": doctype, "reference_name": doc["name"]},
  146. update={"reference_name": new_doc.name}, verbose=0)
  147. if doctype != "File":
  148. self.migrate_doctype("File", {"attached_to_doctype": doctype,
  149. "attached_to_name": doc["name"]}, update={"attached_to_name": new_doc.name}, verbose=0)
  150. def migrate_single(self, doctype):
  151. doc = self.get_doc(doctype, doctype)
  152. doc = frappe.get_doc(doc)
  153. # change modified so that there is no error
  154. doc.modified = frappe.db.get_single_value(doctype, "modified")
  155. frappe.get_doc(doc).insert()
  156. def get_api(self, method, params={}):
  157. res = self.session.get(self.url + "/api/method/" + method + "/",
  158. params=params, verify=self.verify)
  159. return self.post_process(res)
  160. def post_api(self, method, params={}):
  161. res = self.session.post(self.url + "/api/method/" + method + "/",
  162. params=params, verify=self.verify)
  163. return self.post_process(res)
  164. def get_request(self, params):
  165. res = self.session.get(self.url, params=self.preprocess(params), verify=self.verify)
  166. res = self.post_process(res)
  167. return res
  168. def post_request(self, data):
  169. res = self.session.post(self.url, data=self.preprocess(data), verify=self.verify)
  170. res = self.post_process(res)
  171. return res
  172. def preprocess(self, params):
  173. """convert dicts, lists to json"""
  174. for key, value in params.iteritems():
  175. if isinstance(value, (dict, list)):
  176. params[key] = json.dumps(value)
  177. return params
  178. def post_process(self, response):
  179. try:
  180. rjson = response.json()
  181. except ValueError:
  182. print response.text
  183. raise
  184. if rjson and ("exc" in rjson) and rjson["exc"]:
  185. raise FrappeException(rjson["exc"])
  186. if 'message' in rjson:
  187. return rjson['message']
  188. elif 'data' in rjson:
  189. return rjson['data']
  190. else:
  191. return None