We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Auto Email Report CSV Format Broken
When downloading (or sending) an auto email report with format "CSV" the following error occurs:

```
raceback (most recent call last):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/app.py", line 66, in application
    response = frappe.api.handle()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/api.py", line 56, in handle
    return frappe.handler.handle()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 21, in handle
    data = execute_cmd(cmd)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 56, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 1007, in call
    return fn(*args, **newargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/auto_email_report/auto_email_report.py", line 153, in download
    data = auto_email_report.get_report_content()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/auto_email_report/auto_email_report.py", line 61, in get_report_content
    filters = self.filters, as_dict=True)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/core/doctype/report/report.py", line 152, in get_data
    order_by = _format(self.ref_doctype, 'modified') + ' desc'
TypeError: _format() takes exactly 1 argument (2 given)
```

We're using the latest frappe 11.0.3-beta.21.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `frappe/core/doctype/report/report.py`
Content:
```
1 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2 # MIT License. See license.txt
3 
4 from __future__ import unicode_literals
5 import frappe
6 import json
7 from frappe import _
8 import frappe.desk.query_report
9 from frappe.utils import cint
10 from frappe.model.document import Document
11 from frappe.modules.export_file import export_to_files
12 from frappe.modules import make_boilerplate
13 from frappe.core.doctype.page.page import delete_custom_role
14 from frappe.core.doctype.custom_role.custom_role import get_custom_allowed_roles
15 from six import iteritems
16 
17 
18 class Report(Document):
19 	def validate(self):
20 		"""only administrator can save standard report"""
21 		if not self.module:
22 			self.module = frappe.db.get_value("DocType", self.ref_doctype, "module")
23 
24 		if not self.is_standard:
25 			self.is_standard = "No"
26 			if frappe.session.user=="Administrator" and getattr(frappe.local.conf, 'developer_mode',0)==1:
27 				self.is_standard = "Yes"
28 
29 		if self.is_standard == "No" and frappe.db.get_value("Report", self.name, "is_standard") == "Yes":
30 			frappe.throw(_("Cannot edit a standard report. Please duplicate and create a new report"))
31 
32 		if self.is_standard == "Yes" and frappe.session.user!="Administrator":
33 			frappe.throw(_("Only Administrator can save a standard report. Please rename and save."))
34 
35 		if self.report_type in ("Query Report", "Script Report") \
36 			and frappe.session.user!="Administrator":
37 			frappe.throw(_("Only Administrator allowed to create Query / Script Reports"))
38 
39 		if self.report_type == "Report Builder":
40 			self.update_report_json()
41 
42 	def before_insert(self):
43 		self.set_doctype_roles()
44 
45 	def on_update(self):
46 		self.export_doc()
47 
48 	def on_trash(self):
49 		delete_custom_role('report', self.name)
50 
51 	def set_doctype_roles(self):
52 		if not self.get('roles') and self.is_standard == 'No':
53 			meta = frappe.get_meta(self.ref_doctype)
54 			roles = [{'role': d.role} for d in meta.permissions if d.permlevel==0]
55 			self.set('roles', roles)
56 
57 	def is_permitted(self):
58 		"""Returns true if Has Role is not set or the user is allowed."""
59 		from frappe.utils import has_common
60 
61 		allowed = [d.role for d in frappe.get_all("Has Role", fields=["role"],
62 			filters={"parent": self.name})]
63 
64 		custom_roles = get_custom_allowed_roles('report', self.name)
65 		allowed.extend(custom_roles)
66 
67 		if not allowed:
68 			return True
69 
70 		roles = frappe.get_roles()
71 
72 		if has_common(roles, allowed):
73 			return True
74 
75 	def update_report_json(self):
76 		if not self.json:
77 			self.json = '{}'
78 
79 		if self.json:
80 			data = json.loads(self.json)
81 			data["add_total_row"] = self.add_total_row
82 			self.json = json.dumps(data)
83 
84 	def export_doc(self):
85 		if frappe.flags.in_import:
86 			return
87 
88 		if self.is_standard == 'Yes' and (frappe.local.conf.get('developer_mode') or 0) == 1:
89 			export_to_files(record_list=[['Report', self.name]],
90 				record_module=self.module, create_init=True)
91 
92 			self.create_report_py()
93 
94 	def create_report_py(self):
95 		if self.report_type == "Script Report":
96 			make_boilerplate("controller.py", self, {"name": self.name})
97 			make_boilerplate("controller.js", self, {"name": self.name})
98 
99 	def get_data(self, filters=None, limit=None, user=None, as_dict=False):
100 		columns = []
101 		out = []
102 
103 		if self.report_type in ('Query Report', 'Script Report'):
104 			# query and script reports
105 			data = frappe.desk.query_report.run(self.name, filters=filters, user=user)
106 			for d in data.get('columns'):
107 				if isinstance(d, dict):
108 					col = frappe._dict(d)
109 					if not col.fieldname:
110 						col.fieldname = col.label
111 					columns.append(col)
112 				else:
113 					fieldtype, options = "Data", None
114 					parts = d.split(':')
115 					if len(parts) > 1:
116 						if parts[1]:
117 							fieldtype, options = parts[1], None
118 							if fieldtype and '/' in fieldtype:
119 								fieldtype, options = fieldtype.split('/')
120 
121 					columns.append(frappe._dict(label=parts[0], fieldtype=fieldtype, fieldname=parts[0]))
122 
123 			out += data.get('result')
124 		else:
125 			# standard report
126 			params = json.loads(self.json)
127 
128 			if params.get('columns'):
129 				columns = params.get('columns')
130 			else:
131 				columns = [['name', self.ref_doctype]]
132 				for df in frappe.get_meta(self.ref_doctype).fields:
133 					if df.in_list_view:
134 						columns.append([df.fieldname, self.ref_doctype])
135 
136 			_filters = params.get('filters') or []
137 
138 			if filters:
139 				for key, value in iteritems(filters):
140 					condition, _value = '=', value
141 					if isinstance(value, (list, tuple)):
142 						condition, _value = value
143 					_filters.append([key, condition, _value])
144 
145 			def _format(parts):
146 				# sort by is saved as DocType.fieldname, covert it to sql
147 				return '`tab{0}`.`{1}`'.format(*parts)
148 
149 			if params.get('sort_by'):
150 				order_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order')
151 			else:
152 				order_by = _format(self.ref_doctype, 'modified') + ' desc'
153 
154 			if params.get('sort_by_next'):
155 				order_by += ', ' + _format(params.get('sort_by_next').split('.')) + ' ' + params.get('sort_order_next')
156 
157 			result = frappe.get_list(self.ref_doctype,
158 				fields = [_format([c[1], c[0]]) for c in columns],
159 				filters=_filters,
160 				order_by = order_by,
161 				as_list=True,
162 				limit=limit,
163 				user=user)
164 
165 			_columns = []
166 			for column in columns:
167 				meta = frappe.get_meta(column[1])
168 				field = [meta.get_field(column[0]) or frappe._dict(label=meta.get_label(column[0]), fieldname=column[0])]
169 				_columns.extend(field)
170 			columns = _columns
171 
172 			out = out + [list(d) for d in result]
173 
174 		if as_dict:
175 			data = []
176 			for row in out:
177 				if isinstance(row, (list, tuple)):
178 					_row = frappe._dict()
179 					for i, val in enumerate(row):
180 						_row[columns[i].get('fieldname')] = val
181 				elif isinstance(row, dict):
182 					# no need to convert from dict to dict
183 					_row = frappe._dict(row)
184 				data.append(_row)
185 		else:
186 			data = out
187 		return columns, data
188 
189 
190 	@Document.whitelist
191 	def toggle_disable(self, disable):
192 		self.db_set("disabled", cint(disable))
193
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -127,6 +127,8 @@
 
 			if params.get('columns'):
 				columns = params.get('columns')
+			elif params.get('fields'):
+				columns = params.get('fields')
 			else:
 				columns = [['name', self.ref_doctype]]
 				for df in frappe.get_meta(self.ref_doctype).fields:
@@ -149,7 +151,7 @@
 			if params.get('sort_by'):
 				order_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order')
 			else:
-				order_by = _format(self.ref_doctype, 'modified') + ' desc'
+				order_by = _format([self.ref_doctype, 'modified']) + ' desc'
 
 			if params.get('sort_by_next'):
 				order_by += ', ' + _format(params.get('sort_by_next').split('.')) + ' ' + params.get('sort_order_next')

{"golden_diff": "diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py\n--- a/frappe/core/doctype/report/report.py\n+++ b/frappe/core/doctype/report/report.py\n@@ -127,6 +127,8 @@\n \n \t\t\tif params.get('columns'):\n \t\t\t\tcolumns = params.get('columns')\n+\t\t\telif params.get('fields'):\n+\t\t\t\tcolumns = params.get('fields')\n \t\t\telse:\n \t\t\t\tcolumns = [['name', self.ref_doctype]]\n \t\t\t\tfor df in frappe.get_meta(self.ref_doctype).fields:\n@@ -149,7 +151,7 @@\n \t\t\tif params.get('sort_by'):\n \t\t\t\torder_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order')\n \t\t\telse:\n-\t\t\t\torder_by = _format(self.ref_doctype, 'modified') + ' desc'\n+\t\t\t\torder_by = _format([self.ref_doctype, 'modified']) + ' desc'\n \n \t\t\tif params.get('sort_by_next'):\n \t\t\t\torder_by += ', ' + _format(params.get('sort_by_next').split('.')) + ' ' + params.get('sort_order_next')\n", "issue": "Auto Email Report CSV Format Broken\nWhen downloading (or sending) an auto email report with format \"CSV\" the following error occurs:\r\n\r\n```\r\nraceback (most recent call last):\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/app.py\", line 66, in application\r\n    response = frappe.api.handle()\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/api.py\", line 56, in handle\r\n    return frappe.handler.handle()\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/handler.py\", line 21, in handle\r\n    data = execute_cmd(cmd)\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/handler.py\", line 56, in execute_cmd\r\n    return frappe.call(method, **frappe.form_dict)\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py\", line 1007, in call\r\n    return fn(*args, **newargs)\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/auto_email_report/auto_email_report.py\", line 153, in download\r\n    data = auto_email_report.get_report_content()\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/email/doctype/auto_email_report/auto_email_report.py\", line 61, in get_report_content\r\n    filters = self.filters, as_dict=True)\r\n  File \"/home/frappe/frappe-bench/apps/frappe/frappe/core/doctype/report/report.py\", line 152, in get_data\r\n    order_by = _format(self.ref_doctype, 'modified') + ' desc'\r\nTypeError: _format() takes exactly 1 argument (2 given)\r\n```\r\n\r\nWe're using the latest frappe 11.0.3-beta.21.\n", "before_files": [{"content": "# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n# MIT License. See license.txt\n\nfrom __future__ import unicode_literals\nimport frappe\nimport json\nfrom frappe import _\nimport frappe.desk.query_report\nfrom frappe.utils import cint\nfrom frappe.model.document import Document\nfrom frappe.modules.export_file import export_to_files\nfrom frappe.modules import make_boilerplate\nfrom frappe.core.doctype.page.page import delete_custom_role\nfrom frappe.core.doctype.custom_role.custom_role import get_custom_allowed_roles\nfrom six import iteritems\n\n\nclass Report(Document):\n\tdef validate(self):\n\t\t\"\"\"only administrator can save standard report\"\"\"\n\t\tif not self.module:\n\t\t\tself.module = frappe.db.get_value(\"DocType\", self.ref_doctype, \"module\")\n\n\t\tif not self.is_standard:\n\t\t\tself.is_standard = \"No\"\n\t\t\tif frappe.session.user==\"Administrator\" and getattr(frappe.local.conf, 'developer_mode',0)==1:\n\t\t\t\tself.is_standard = \"Yes\"\n\n\t\tif self.is_standard == \"No\" and frappe.db.get_value(\"Report\", self.name, \"is_standard\") == \"Yes\":\n\t\t\tfrappe.throw(_(\"Cannot edit a standard report. Please duplicate and create a new report\"))\n\n\t\tif self.is_standard == \"Yes\" and frappe.session.user!=\"Administrator\":\n\t\t\tfrappe.throw(_(\"Only Administrator can save a standard report. Please rename and save.\"))\n\n\t\tif self.report_type in (\"Query Report\", \"Script Report\") \\\n\t\t\tand frappe.session.user!=\"Administrator\":\n\t\t\tfrappe.throw(_(\"Only Administrator allowed to create Query / Script Reports\"))\n\n\t\tif self.report_type == \"Report Builder\":\n\t\t\tself.update_report_json()\n\n\tdef before_insert(self):\n\t\tself.set_doctype_roles()\n\n\tdef on_update(self):\n\t\tself.export_doc()\n\n\tdef on_trash(self):\n\t\tdelete_custom_role('report', self.name)\n\n\tdef set_doctype_roles(self):\n\t\tif not self.get('roles') and self.is_standard == 'No':\n\t\t\tmeta = frappe.get_meta(self.ref_doctype)\n\t\t\troles = [{'role': d.role} for d in meta.permissions if d.permlevel==0]\n\t\t\tself.set('roles', roles)\n\n\tdef is_permitted(self):\n\t\t\"\"\"Returns true if Has Role is not set or the user is allowed.\"\"\"\n\t\tfrom frappe.utils import has_common\n\n\t\tallowed = [d.role for d in frappe.get_all(\"Has Role\", fields=[\"role\"],\n\t\t\tfilters={\"parent\": self.name})]\n\n\t\tcustom_roles = get_custom_allowed_roles('report', self.name)\n\t\tallowed.extend(custom_roles)\n\n\t\tif not allowed:\n\t\t\treturn True\n\n\t\troles = frappe.get_roles()\n\n\t\tif has_common(roles, allowed):\n\t\t\treturn True\n\n\tdef update_report_json(self):\n\t\tif not self.json:\n\t\t\tself.json = '{}'\n\n\t\tif self.json:\n\t\t\tdata = json.loads(self.json)\n\t\t\tdata[\"add_total_row\"] = self.add_total_row\n\t\t\tself.json = json.dumps(data)\n\n\tdef export_doc(self):\n\t\tif frappe.flags.in_import:\n\t\t\treturn\n\n\t\tif self.is_standard == 'Yes' and (frappe.local.conf.get('developer_mode') or 0) == 1:\n\t\t\texport_to_files(record_list=[['Report', self.name]],\n\t\t\t\trecord_module=self.module, create_init=True)\n\n\t\t\tself.create_report_py()\n\n\tdef create_report_py(self):\n\t\tif self.report_type == \"Script Report\":\n\t\t\tmake_boilerplate(\"controller.py\", self, {\"name\": self.name})\n\t\t\tmake_boilerplate(\"controller.js\", self, {\"name\": self.name})\n\n\tdef get_data(self, filters=None, limit=None, user=None, as_dict=False):\n\t\tcolumns = []\n\t\tout = []\n\n\t\tif self.report_type in ('Query Report', 'Script Report'):\n\t\t\t# query and script reports\n\t\t\tdata = frappe.desk.query_report.run(self.name, filters=filters, user=user)\n\t\t\tfor d in data.get('columns'):\n\t\t\t\tif isinstance(d, dict):\n\t\t\t\t\tcol = frappe._dict(d)\n\t\t\t\t\tif not col.fieldname:\n\t\t\t\t\t\tcol.fieldname = col.label\n\t\t\t\t\tcolumns.append(col)\n\t\t\t\telse:\n\t\t\t\t\tfieldtype, options = \"Data\", None\n\t\t\t\t\tparts = d.split(':')\n\t\t\t\t\tif len(parts) > 1:\n\t\t\t\t\t\tif parts[1]:\n\t\t\t\t\t\t\tfieldtype, options = parts[1], None\n\t\t\t\t\t\t\tif fieldtype and '/' in fieldtype:\n\t\t\t\t\t\t\t\tfieldtype, options = fieldtype.split('/')\n\n\t\t\t\t\tcolumns.append(frappe._dict(label=parts[0], fieldtype=fieldtype, fieldname=parts[0]))\n\n\t\t\tout += data.get('result')\n\t\telse:\n\t\t\t# standard report\n\t\t\tparams = json.loads(self.json)\n\n\t\t\tif params.get('columns'):\n\t\t\t\tcolumns = params.get('columns')\n\t\t\telse:\n\t\t\t\tcolumns = [['name', self.ref_doctype]]\n\t\t\t\tfor df in frappe.get_meta(self.ref_doctype).fields:\n\t\t\t\t\tif df.in_list_view:\n\t\t\t\t\t\tcolumns.append([df.fieldname, self.ref_doctype])\n\n\t\t\t_filters = params.get('filters') or []\n\n\t\t\tif filters:\n\t\t\t\tfor key, value in iteritems(filters):\n\t\t\t\t\tcondition, _value = '=', value\n\t\t\t\t\tif isinstance(value, (list, tuple)):\n\t\t\t\t\t\tcondition, _value = value\n\t\t\t\t\t_filters.append([key, condition, _value])\n\n\t\t\tdef _format(parts):\n\t\t\t\t# sort by is saved as DocType.fieldname, covert it to sql\n\t\t\t\treturn '`tab{0}`.`{1}`'.format(*parts)\n\n\t\t\tif params.get('sort_by'):\n\t\t\t\torder_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order')\n\t\t\telse:\n\t\t\t\torder_by = _format(self.ref_doctype, 'modified') + ' desc'\n\n\t\t\tif params.get('sort_by_next'):\n\t\t\t\torder_by += ', ' + _format(params.get('sort_by_next').split('.')) + ' ' + params.get('sort_order_next')\n\n\t\t\tresult = frappe.get_list(self.ref_doctype,\n\t\t\t\tfields = [_format([c[1], c[0]]) for c in columns],\n\t\t\t\tfilters=_filters,\n\t\t\t\torder_by = order_by,\n\t\t\t\tas_list=True,\n\t\t\t\tlimit=limit,\n\t\t\t\tuser=user)\n\n\t\t\t_columns = []\n\t\t\tfor column in columns:\n\t\t\t\tmeta = frappe.get_meta(column[1])\n\t\t\t\tfield = [meta.get_field(column[0]) or frappe._dict(label=meta.get_label(column[0]), fieldname=column[0])]\n\t\t\t\t_columns.extend(field)\n\t\t\tcolumns = _columns\n\n\t\t\tout = out + [list(d) for d in result]\n\n\t\tif as_dict:\n\t\t\tdata = []\n\t\t\tfor row in out:\n\t\t\t\tif isinstance(row, (list, tuple)):\n\t\t\t\t\t_row = frappe._dict()\n\t\t\t\t\tfor i, val in enumerate(row):\n\t\t\t\t\t\t_row[columns[i].get('fieldname')] = val\n\t\t\t\telif isinstance(row, dict):\n\t\t\t\t\t# no need to convert from dict to dict\n\t\t\t\t\t_row = frappe._dict(row)\n\t\t\t\tdata.append(_row)\n\t\telse:\n\t\t\tdata = out\n\t\treturn columns, data\n\n\n\t@Document.whitelist\n\tdef toggle_disable(self, disable):\n\t\tself.db_set(\"disabled\", cint(disable))\n", "path": "frappe/core/doctype/report/report.py"}], "after_files": [{"content": "# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n# MIT License. See license.txt\n\nfrom __future__ import unicode_literals\nimport frappe\nimport json\nfrom frappe import _\nimport frappe.desk.query_report\nfrom frappe.utils import cint\nfrom frappe.model.document import Document\nfrom frappe.modules.export_file import export_to_files\nfrom frappe.modules import make_boilerplate\nfrom frappe.core.doctype.page.page import delete_custom_role\nfrom frappe.core.doctype.custom_role.custom_role import get_custom_allowed_roles\nfrom six import iteritems\n\n\nclass Report(Document):\n\tdef validate(self):\n\t\t\"\"\"only administrator can save standard report\"\"\"\n\t\tif not self.module:\n\t\t\tself.module = frappe.db.get_value(\"DocType\", self.ref_doctype, \"module\")\n\n\t\tif not self.is_standard:\n\t\t\tself.is_standard = \"No\"\n\t\t\tif frappe.session.user==\"Administrator\" and getattr(frappe.local.conf, 'developer_mode',0)==1:\n\t\t\t\tself.is_standard = \"Yes\"\n\n\t\tif self.is_standard == \"No\" and frappe.db.get_value(\"Report\", self.name, \"is_standard\") == \"Yes\":\n\t\t\tfrappe.throw(_(\"Cannot edit a standard report. Please duplicate and create a new report\"))\n\n\t\tif self.is_standard == \"Yes\" and frappe.session.user!=\"Administrator\":\n\t\t\tfrappe.throw(_(\"Only Administrator can save a standard report. Please rename and save.\"))\n\n\t\tif self.report_type in (\"Query Report\", \"Script Report\") \\\n\t\t\tand frappe.session.user!=\"Administrator\":\n\t\t\tfrappe.throw(_(\"Only Administrator allowed to create Query / Script Reports\"))\n\n\t\tif self.report_type == \"Report Builder\":\n\t\t\tself.update_report_json()\n\n\tdef before_insert(self):\n\t\tself.set_doctype_roles()\n\n\tdef on_update(self):\n\t\tself.export_doc()\n\n\tdef on_trash(self):\n\t\tdelete_custom_role('report', self.name)\n\n\tdef set_doctype_roles(self):\n\t\tif not self.get('roles') and self.is_standard == 'No':\n\t\t\tmeta = frappe.get_meta(self.ref_doctype)\n\t\t\troles = [{'role': d.role} for d in meta.permissions if d.permlevel==0]\n\t\t\tself.set('roles', roles)\n\n\tdef is_permitted(self):\n\t\t\"\"\"Returns true if Has Role is not set or the user is allowed.\"\"\"\n\t\tfrom frappe.utils import has_common\n\n\t\tallowed = [d.role for d in frappe.get_all(\"Has Role\", fields=[\"role\"],\n\t\t\tfilters={\"parent\": self.name})]\n\n\t\tcustom_roles = get_custom_allowed_roles('report', self.name)\n\t\tallowed.extend(custom_roles)\n\n\t\tif not allowed:\n\t\t\treturn True\n\n\t\troles = frappe.get_roles()\n\n\t\tif has_common(roles, allowed):\n\t\t\treturn True\n\n\tdef update_report_json(self):\n\t\tif not self.json:\n\t\t\tself.json = '{}'\n\n\t\tif self.json:\n\t\t\tdata = json.loads(self.json)\n\t\t\tdata[\"add_total_row\"] = self.add_total_row\n\t\t\tself.json = json.dumps(data)\n\n\tdef export_doc(self):\n\t\tif frappe.flags.in_import:\n\t\t\treturn\n\n\t\tif self.is_standard == 'Yes' and (frappe.local.conf.get('developer_mode') or 0) == 1:\n\t\t\texport_to_files(record_list=[['Report', self.name]],\n\t\t\t\trecord_module=self.module, create_init=True)\n\n\t\t\tself.create_report_py()\n\n\tdef create_report_py(self):\n\t\tif self.report_type == \"Script Report\":\n\t\t\tmake_boilerplate(\"controller.py\", self, {\"name\": self.name})\n\t\t\tmake_boilerplate(\"controller.js\", self, {\"name\": self.name})\n\n\tdef get_data(self, filters=None, limit=None, user=None, as_dict=False):\n\t\tcolumns = []\n\t\tout = []\n\n\t\tif self.report_type in ('Query Report', 'Script Report'):\n\t\t\t# query and script reports\n\t\t\tdata = frappe.desk.query_report.run(self.name, filters=filters, user=user)\n\t\t\tfor d in data.get('columns'):\n\t\t\t\tif isinstance(d, dict):\n\t\t\t\t\tcol = frappe._dict(d)\n\t\t\t\t\tif not col.fieldname:\n\t\t\t\t\t\tcol.fieldname = col.label\n\t\t\t\t\tcolumns.append(col)\n\t\t\t\telse:\n\t\t\t\t\tfieldtype, options = \"Data\", None\n\t\t\t\t\tparts = d.split(':')\n\t\t\t\t\tif len(parts) > 1:\n\t\t\t\t\t\tif parts[1]:\n\t\t\t\t\t\t\tfieldtype, options = parts[1], None\n\t\t\t\t\t\t\tif fieldtype and '/' in fieldtype:\n\t\t\t\t\t\t\t\tfieldtype, options = fieldtype.split('/')\n\n\t\t\t\t\tcolumns.append(frappe._dict(label=parts[0], fieldtype=fieldtype, fieldname=parts[0]))\n\n\t\t\tout += data.get('result')\n\t\telse:\n\t\t\t# standard report\n\t\t\tparams = json.loads(self.json)\n\n\t\t\tif params.get('columns'):\n\t\t\t\tcolumns = params.get('columns')\n\t\t\telif params.get('fields'):\n\t\t\t\tcolumns = params.get('fields')\n\t\t\telse:\n\t\t\t\tcolumns = [['name', self.ref_doctype]]\n\t\t\t\tfor df in frappe.get_meta(self.ref_doctype).fields:\n\t\t\t\t\tif df.in_list_view:\n\t\t\t\t\t\tcolumns.append([df.fieldname, self.ref_doctype])\n\n\t\t\t_filters = params.get('filters') or []\n\n\t\t\tif filters:\n\t\t\t\tfor key, value in iteritems(filters):\n\t\t\t\t\tcondition, _value = '=', value\n\t\t\t\t\tif isinstance(value, (list, tuple)):\n\t\t\t\t\t\tcondition, _value = value\n\t\t\t\t\t_filters.append([key, condition, _value])\n\n\t\t\tdef _format(parts):\n\t\t\t\t# sort by is saved as DocType.fieldname, covert it to sql\n\t\t\t\treturn '`tab{0}`.`{1}`'.format(*parts)\n\n\t\t\tif params.get('sort_by'):\n\t\t\t\torder_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order')\n\t\t\telse:\n\t\t\t\torder_by = _format([self.ref_doctype, 'modified']) + ' desc'\n\n\t\t\tif params.get('sort_by_next'):\n\t\t\t\torder_by += ', ' + _format(params.get('sort_by_next').split('.')) + ' ' + params.get('sort_order_next')\n\n\t\t\tresult = frappe.get_list(self.ref_doctype,\n\t\t\t\tfields = [_format([c[1], c[0]]) for c in columns],\n\t\t\t\tfilters=_filters,\n\t\t\t\torder_by = order_by,\n\t\t\t\tas_list=True,\n\t\t\t\tlimit=limit,\n\t\t\t\tuser=user)\n\n\t\t\t_columns = []\n\t\t\tfor column in columns:\n\t\t\t\tmeta = frappe.get_meta(column[1])\n\t\t\t\tfield = [meta.get_field(column[0]) or frappe._dict(label=meta.get_label(column[0]), fieldname=column[0])]\n\t\t\t\t_columns.extend(field)\n\t\t\tcolumns = _columns\n\n\t\t\tout = out + [list(d) for d in result]\n\n\t\tif as_dict:\n\t\t\tdata = []\n\t\t\tfor row in out:\n\t\t\t\tif isinstance(row, (list, tuple)):\n\t\t\t\t\t_row = frappe._dict()\n\t\t\t\t\tfor i, val in enumerate(row):\n\t\t\t\t\t\t_row[columns[i].get('fieldname')] = val\n\t\t\t\telif isinstance(row, dict):\n\t\t\t\t\t# no need to convert from dict to dict\n\t\t\t\t\t_row = frappe._dict(row)\n\t\t\t\tdata.append(_row)\n\t\telse:\n\t\t\tdata = out\n\t\treturn columns, data\n\n\n\t@Document.whitelist\n\tdef toggle_disable(self, disable):\n\t\tself.db_set(\"disabled\", cint(disable))\n", "path": "frappe/core/doctype/report/report.py"}]}