Repository: frappe/frappe

Issue:
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 162-163: ordinal not in range(256)
### Information about bug

error when export

### Module

accounts

### Version

ERPNEXT -VERISON 15

### Installation method

docker

### Relevant log output / Stack trace / Full Error Message.

```shell
curl 'http://8.137.104.208/api/method/frappe.core.doctype.data_import.data_import.download_template' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
  -H 'Accept-Language: zh-CN,zh;q=0.9' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -H 'Cookie: sid=0b61e612f2b80213ff10d515ec85bffebc7a937e7bfc9f463eaa5802; system_user=yes; full_name=%E6%8C%AF%E5%AE%87%20%E5%BC%A0; user_id=uans3k%40foxmail.com; user_image=' \
  -H 'Origin: http://8.137.104.208' \
  -H 'Pragma: no-cache' \
  -H 'Referer: http://8.137.104.208/app/account' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36' \
  --data-raw 'doctype=Account&file_type=Excel&export_records=all&export_fields=%7B%22Account%22%3A%5B%22name%22%2C%22account_name%22%2C%22company%22%2C%22parent_account%22%5D%7D&export_filters=null&csrf_token=5c48ae60be34ba588e386b95dda0a2c65ae7e890877bb7868b977433' \
  --compressed \
  --insecure


Stack :
erp-backend-1       | [2023-11-25 09:07:39 +0000] [8] [ERROR] Error handling request /api/method/frappe.core.doctype.data_import.data_import.download_template
erp-backend-1       | Traceback (most recent call last):
erp-backend-1       |   File "/home/frappe/frappe-bench/env/lib/python3.11/site-packages/gunicorn/workers/gthread.py", line 282, in handle
erp-backend-1       |     keepalive = self.handle_request(req, conn)
erp-backend-1       |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erp-backend-1       |   File "/home/frappe/frappe-bench/env/lib/python3.11/site-packages/gunicorn/workers/gthread.py", line 340, in handle_request
erp-backend-1       |     resp.write(item)
erp-backend-1       |   File "/home/frappe/frappe-bench/env/lib/python3.11/site-packages/gunicorn/http/wsgi.py", line 326, in write
erp-backend-1       |     self.send_headers()
erp-backend-1       |   File "/home/frappe/frappe-bench/env/lib/python3.11/site-packages/gunicorn/http/wsgi.py", line 322, in send_headers
erp-backend-1       |     util.write(self.sock, util.to_bytestring(header_str, "latin-1"))
erp-backend-1       |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erp-backend-1       |   File "/home/frappe/frappe-bench/env/lib/python3.11/site-packages/gunicorn/util.py", line 580, in to_bytestring
erp-backend-1       |     return value.encode(encoding)
erp-backend-1       |            ^^^^^^^^^^^^^^^^^^^^^^
erp-backend-1       | UnicodeEncodeError: 'latin-1' codec can't encode characters in position 162-163: ordinal not in range(256)
```



Discussion:
I have the same problem in ERPNEXT  v15 with persian lang
Same problem 😒

Resolving patch:
diff --git a/frappe/utils/response.py b/frappe/utils/response.py
--- a/frappe/utils/response.py
+++ b/frappe/utils/response.py
@@ -7,7 +7,7 @@
 import mimetypes
 import os
 import sys
-from typing import TYPE_CHECKING, Literal
+from typing import TYPE_CHECKING
 from urllib.parse import quote
 
 import werkzeug.utils
@@ -92,6 +92,7 @@ def as_csv():
 	response = Response()
 	response.mimetype = "text/csv"
 	filename = f"{frappe.response['doctype']}.csv"
+	filename = filename.encode("utf-8").decode("unicode-escape", "ignore")
 	response.headers.add("Content-Disposition", "attachment", filename=filename)
 	response.data = frappe.response["result"]
 	return response
@@ -101,6 +102,7 @@ def as_txt():
 	response = Response()
 	response.mimetype = "text"
 	filename = f"{frappe.response['doctype']}.txt"
+	filename = filename.encode("utf-8").decode("unicode-escape", "ignore")
 	response.headers.add("Content-Disposition", "attachment", filename=filename)
 	response.data = frappe.response["result"]
 	return response
@@ -113,10 +115,11 @@ def as_raw():
 		or mimetypes.guess_type(frappe.response["filename"])[0]
 		or "application/unknown"
 	)
+	filename = frappe.response["filename"].encode("utf-8").decode("unicode-escape", "ignore")
 	response.headers.add(
 		"Content-Disposition",
 		frappe.response.get("display_content_as", "attachment"),
-		filename=frappe.response["filename"],
+		filename=filename,
 	)
 	response.data = frappe.response["filecontent"]
 	return response
@@ -138,7 +141,8 @@ def as_json():
 def as_pdf():
 	response = Response()
 	response.mimetype = "application/pdf"
-	response.headers.add("Content-Disposition", None, filename=frappe.response["filename"])
+	filename = frappe.response["filename"].encode("utf-8").decode("unicode-escape", "ignore")
+	response.headers.add("Content-Disposition", None, filename=filename)
 	response.data = frappe.response["filecontent"]
 	return response
 


Test patch: