Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

12 лет назад
12 лет назад
11 лет назад
7 лет назад
11 лет назад
11 лет назад
11 лет назад
6 лет назад
11 лет назад
11 лет назад
12 лет назад
11 лет назад
11 лет назад
11 лет назад
7 лет назад
6 лет назад
11 лет назад
12 лет назад
7 лет назад
11 лет назад
7 лет назад
11 лет назад
11 лет назад
11 лет назад
12 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
7 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # Copyright (c) 2015, Frappe 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. import json
  7. import csv
  8. import six
  9. import requests
  10. from six import StringIO, text_type, string_types
  11. from frappe.utils import encode, cstr, cint, flt, comma_or
  12. def read_csv_content_from_uploaded_file(ignore_encoding=False):
  13. if getattr(frappe, "uploaded_file", None):
  14. with open(frappe.uploaded_file, "r") as upfile:
  15. fcontent = upfile.read()
  16. else:
  17. _file = frappe.new_doc("File")
  18. fcontent = _file.get_uploaded_content()
  19. return read_csv_content(fcontent, ignore_encoding)
  20. def read_csv_content_from_attached_file(doc):
  21. fileid = frappe.get_all("File", fields = ["name"], filters = {"attached_to_doctype": doc.doctype,
  22. "attached_to_name":doc.name}, order_by="creation desc")
  23. if fileid : fileid = fileid[0].name
  24. if not fileid:
  25. msgprint(_("File not attached"))
  26. raise Exception
  27. try:
  28. _file = frappe.get_doc("File", fileid)
  29. fcontent = _file.get_content()
  30. return read_csv_content(fcontent, frappe.form_dict.get('ignore_encoding_errors'))
  31. except Exception:
  32. frappe.throw(_("Unable to open attached file. Did you export it as CSV?"), title=_('Invalid CSV Format'))
  33. def read_csv_content(fcontent, ignore_encoding=False):
  34. rows = []
  35. if not isinstance(fcontent, text_type):
  36. decoded = False
  37. for encoding in ["utf-8", "windows-1250", "windows-1252"]:
  38. try:
  39. fcontent = text_type(fcontent, encoding)
  40. decoded = True
  41. break
  42. except UnicodeDecodeError:
  43. continue
  44. if not decoded:
  45. frappe.msgprint(_("Unknown file encoding. Tried utf-8, windows-1250, windows-1252."), raise_exception=True)
  46. fcontent = fcontent.encode("utf-8")
  47. content = [ ]
  48. for line in fcontent.splitlines(True):
  49. if six.PY2:
  50. content.append(line)
  51. else:
  52. content.append(frappe.safe_decode(line))
  53. try:
  54. rows = []
  55. for row in csv.reader(content):
  56. r = []
  57. for val in row:
  58. # decode everything
  59. val = val.strip()
  60. if val=="":
  61. # reason: in maraidb strict config, one cannot have blank strings for non string datatypes
  62. r.append(None)
  63. else:
  64. r.append(val)
  65. rows.append(r)
  66. return rows
  67. except Exception:
  68. frappe.msgprint(_("Not a valid Comma Separated Value (CSV File)"))
  69. raise
  70. @frappe.whitelist()
  71. def send_csv_to_client(args):
  72. if isinstance(args, string_types):
  73. args = json.loads(args)
  74. args = frappe._dict(args)
  75. frappe.response["result"] = cstr(to_csv(args.data))
  76. frappe.response["doctype"] = args.filename
  77. frappe.response["type"] = "csv"
  78. def to_csv(data):
  79. writer = UnicodeWriter()
  80. for row in data:
  81. writer.writerow(row)
  82. return writer.getvalue()
  83. def build_csv_response(data, filename):
  84. frappe.response["result"] = cstr(to_csv(data))
  85. frappe.response["doctype"] = filename
  86. frappe.response["type"] = "csv"
  87. class UnicodeWriter:
  88. def __init__(self, encoding="utf-8"):
  89. self.encoding = encoding
  90. self.queue = StringIO()
  91. self.writer = csv.writer(self.queue, quoting=csv.QUOTE_NONNUMERIC)
  92. def writerow(self, row):
  93. if six.PY2:
  94. row = encode(row, self.encoding)
  95. self.writer.writerow(row)
  96. def getvalue(self):
  97. return self.queue.getvalue()
  98. def check_record(d):
  99. """check for mandatory, select options, dates. these should ideally be in doclist"""
  100. from frappe.utils.dateutils import parse_date
  101. doc = frappe.get_doc(d)
  102. for key in d:
  103. docfield = doc.meta.get_field(key)
  104. val = d[key]
  105. if docfield:
  106. if docfield.reqd and (val=='' or val==None):
  107. frappe.msgprint(_("{0} is required").format(docfield.label), raise_exception=1)
  108. if docfield.fieldtype=='Select' and val and docfield.options:
  109. if val not in docfield.options.split('\n'):
  110. frappe.throw(_("{0} must be one of {1}").format(_(docfield.label), comma_or(docfield.options.split("\n"))))
  111. if val and docfield.fieldtype=='Date':
  112. d[key] = parse_date(val)
  113. elif val and docfield.fieldtype in ["Int", "Check"]:
  114. d[key] = cint(val)
  115. elif val and docfield.fieldtype in ["Currency", "Float", "Percent"]:
  116. d[key] = flt(val)
  117. def import_doc(d, doctype, overwrite, row_idx, submit=False, ignore_links=False):
  118. """import main (non child) document"""
  119. if d.get("name") and frappe.db.exists(doctype, d['name']):
  120. if overwrite:
  121. doc = frappe.get_doc(doctype, d['name'])
  122. doc.flags.ignore_links = ignore_links
  123. doc.update(d)
  124. if d.get("docstatus") == 1:
  125. doc.update_after_submit()
  126. elif d.get("docstatus") == 0 and submit:
  127. doc.submit()
  128. else:
  129. doc.save()
  130. return 'Updated row (#%d) %s' % (row_idx + 1, getlink(doctype, d['name']))
  131. else:
  132. return 'Ignored row (#%d) %s (exists)' % (row_idx + 1,
  133. getlink(doctype, d['name']))
  134. else:
  135. doc = frappe.get_doc(d)
  136. doc.flags.ignore_links = ignore_links
  137. doc.insert()
  138. if submit:
  139. doc.submit()
  140. return 'Inserted row (#%d) %s' % (row_idx + 1, getlink(doctype,
  141. doc.get('name')))
  142. def getlink(doctype, name):
  143. return '<a href="/app/Form/%(doctype)s/%(name)s">%(name)s</a>' % locals()
  144. def get_csv_content_from_google_sheets(url):
  145. # https://docs.google.com/spreadsheets/d/{sheetid}}/edit#gid={gid}
  146. validate_google_sheets_url(url)
  147. # get gid, defaults to first sheet
  148. if "gid=" in url:
  149. gid = url.rsplit('gid=', 1)[1]
  150. else:
  151. gid = 0
  152. # remove /edit path
  153. url = url.rsplit('/edit', 1)[0]
  154. # add /export path,
  155. url = url + '/export?format=csv&gid={0}'.format(gid)
  156. headers = {
  157. 'Accept': 'text/csv'
  158. }
  159. response = requests.get(url, headers=headers)
  160. if response.ok:
  161. # if it returns html, it couldn't find the CSV content
  162. # because of invalid url or no access
  163. if response.text.strip().endswith('</html>'):
  164. frappe.throw(
  165. _('Google Sheets URL is invalid or not publicly accessible.'),
  166. title=_("Invalid URL")
  167. )
  168. return response.content
  169. elif response.status_code == 400:
  170. frappe.throw(_('Google Sheets URL must end with "gid={number}". Copy and paste the URL from the browser address bar and try again.'),
  171. title=_("Incorrect URL"))
  172. else:
  173. response.raise_for_status()
  174. def validate_google_sheets_url(url):
  175. if "docs.google.com/spreadsheets" not in url:
  176. frappe.throw(
  177. _('"{0}" is not a valid Google Sheets URL').format(url),
  178. title=_("Invalid URL"),
  179. )