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.

import_docs.py 16 KiB

14 年之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. import webnotes
  2. def import_docs(docs = []):
  3. from webnotes.model.doc import Document
  4. import webnotes.model.code
  5. doc_list = {}
  6. created_docs = []
  7. already_exists = []
  8. out, tmp ="", ""
  9. for d in docs:
  10. cur_doc = Document(fielddata = d)
  11. if not cur_doc.parent in already_exists: # parent should not exist
  12. try:
  13. cur_doc.save(1)
  14. out += "Created: " + cur_doc.name + "\n"
  15. created_docs.append(cur_doc)
  16. # make in groups
  17. if cur_doc.parent:
  18. if not doc_list.has_key(cur_doc.parent):
  19. doc_list[cur_doc.parent] = []
  20. doc_list[cur_doc.parent].append(cur_doc)
  21. except Exception, e:
  22. out += "Creation Warning/Error: " + cur_doc.name + " :"+ str(e) + "\n"
  23. already_exists.append(cur_doc.name)
  24. # Run scripts for main docs
  25. for m in created_docs:
  26. if doc_list.has_key(m.name):
  27. tmp = webnotes.model.code.run_server_obj(webnotes.model.code.get_server_obj(m, doc_list.get(m.name, [])),'on_update')
  28. # update database (in case of DocType)
  29. if m.doctype=='DocType':
  30. import webnotes.model.doctype
  31. try: webnotes.model.doctype.update_doctype(doc_list.get(m.name, []))
  32. except: pass
  33. out += 'Executed: '+ str(m.name) + ', Err:' + str(tmp) + "\n"
  34. return out
  35. #======================================================================================================================================
  36. import webnotes
  37. import webnotes.utils
  38. sql = webnotes.conn.sql
  39. flt = webnotes.utils.flt
  40. cint = webnotes.utils.cint
  41. cstr = webnotes.utils.cstr
  42. class CSVImport:
  43. def __init__(self):
  44. self.msg = []
  45. self.csv_data = None
  46. self.import_date_format = None
  47. def validate_doctype(self, dt_list):
  48. cl, tables, self.dt_list, self.prompt_autoname_flag = 0, [t[0] for t in sql("show tables")], [], 0
  49. self.msg.append('<p><b>Identifying Documents</b></p>')
  50. dtd = sql("select name, istable, autoname from `tabDocType` where name = '%s' " % dt_list[0])
  51. if dtd and dtd[0][0]:
  52. self.msg.append('<div style="color: GREEN">Identified Document: ' + dt_list[0] + '</div>')
  53. self.dt_list.append(dt_list[0])
  54. if dtd[0][2] and 'Prompt' in dtd[0][2]: self.prompt_autoname_flag = 1
  55. if flt(dtd[0][1]):
  56. res1 = sql("select parent, fieldname from tabDocField where options='%s' and fieldtype='Table' and docstatus!=2" % self.dt_list[0])
  57. if res1 and res1[0][0] == dt_list[1]:
  58. self.msg.append('<div style="color: GREEN">Identified Document: ' + dt_list[1] + '</div>')
  59. self.dt_list.append(dt_list[1])
  60. else :
  61. self.msg.append('<div style="color:RED"> Error: At Row 1, Column 2 => %s is not a valid Document </div>' % dt_list[1])
  62. self.validate_success = 0
  63. if res1 and res1[0][1] == dt_list[2]:
  64. self.msg.append('<div style="color: GREEN" >Identified Document Fieldname: ' + dt_list[2] + '</div>')
  65. self.dt_list.append(dt_list[2])
  66. else :
  67. self.msg.append('<div style="color:RED"> Error: At Row 1, Column 3 => %s is not a valid Fieldname </div>' % dt_list[2])
  68. self.validate_success = 0
  69. elif dt_list[1]:
  70. self.msg.append('<div style="color:RED"> Error: At Row 1, Column 1 => %s is not a Table. </div>' % dt_list[0])
  71. self.validate_success = 0
  72. else:
  73. self.msg.append('<div style="color:RED"> Error: At Row 1, Column 1 => %s is not a valid Document </div>' % dt_list[0])
  74. self.validate_success = 0
  75. def validate_fields(self, lb_list):
  76. self.msg.append('<p><b>Checking fieldnames for %s</b></p>' % self.dt_list[0])
  77. if len(self.dt_list) > 1 and self.overwrite:
  78. self.msg.append('<div style="color:RED"> Error: Overwrite is not possible for Document %s </div>' % self.dt_list[0])
  79. self.validate_success = 0
  80. return
  81. elif self.overwrite and 'Name' != lb_list[0]:
  82. self.msg.append('<div style="color:RED"> Error : At Row 4 and Column 1: To Overwrite fieldname should be Name </div>')
  83. self.validate_success = 0
  84. return
  85. # labelnames
  86. res = self.validate_success and [d[0] for d in sql("select label from tabDocField where parent='%s' and docstatus!=2 and ifnull(hidden,'') in ('',0)" % self.dt_list[0])] or []
  87. if len(self.dt_list) > 1 and self.dt_list[1]:
  88. self.fields.append('parent')
  89. lb_list.pop(lb_list.index(self.dt_list[1]))
  90. dtd = sql("select autoname from `tabDocType` where name = '%s' " % self.dt_list[0])[0][0]
  91. if self.prompt_autoname_flag or self.overwrite:
  92. self.fields.append('name')
  93. res.append('Name')
  94. lb_list.pop(lb_list.index('Name'))
  95. cl = 1
  96. for l in lb_list:
  97. try:
  98. if l:
  99. if not (l in res):
  100. self.msg.append('<div style="color: RED">Error : At Row 4 and Column %s Field %s is not present in %s</div>' % (cl, l, self.dt_list[0]))
  101. self.validate_success = 0
  102. # this condition is for child doctype
  103. else: self.fields.append(sql("select fieldname from tabDocField where parent ='%s' and label = '%s' and ifnull(fieldname,'') !='' " % (self.dt_list[0], l))[0][0] or '')
  104. except Exception, e:
  105. self.msg.append('<div style="color: RED"> At Row 4 and Column %s : =>ERROR: %s </div>' % ( cl, e))
  106. self.validate_success = 0
  107. cl = cl + 1
  108. if not self.overwrite:
  109. # get_reqd_fields
  110. reqd_list = [d[0] for d in sql("select label from `tabDocField` where parent = '%s' and ifnull(reqd,'') not in ('', 0) and docstatus !=2" % self.dt_list[0]) if d[0] not in lb_list] or []
  111. # Check if Reqd field not present in self.fields
  112. if reqd_list:
  113. self.msg.append('<div style="color: RED"> Error : At Row 4 Mandatory Fields %s of Document %s are Required. </div>' %(reqd_list , self.dt_list[0]))
  114. self.validate_success = 0
  115. if self.validate_success:
  116. self.msg.append('<div style="color: GREEN">Fields OK for %s</div>' % self.dt_list[0])
  117. def validate_headers(self):
  118. self.validate_doctype(self.doctype_data)
  119. if self.validate_success:
  120. self.validate_fields(self.labels)
  121. # Date parsing
  122. # --------------------------------------------------------------------
  123. def parse_date(self, r, c, d):
  124. out = ''
  125. try:
  126. if self.import_date_format=='yyyy-mm-dd':
  127. tmpd = d.split('-')
  128. if len(tmpd)==3:
  129. out = tmpd[0] + '-'+tmpd[1] + '-' + tmpd[2]
  130. elif d and self.import_date_format=='dd-mm-yyyy':
  131. tmpd = d.split('-')
  132. if len(tmpd)==3:
  133. out = tmpd[2]+'-'+tmpd[1]+'-'+tmpd[0]
  134. elif d and self.import_date_format=='mm/dd/yyyy':
  135. tmpd = d.split('/')
  136. if len(tmpd)==3:
  137. out = tmpd[2]+'-'+tmpd[0]+'-'+tmpd[1]
  138. elif d and self.import_date_format=='mm/dd/yy':
  139. tmpd = d.split('/')
  140. if len(tmpd)==3:
  141. out = '20'+tmpd[2]+'-'+tmpd[0]+'-'+tmpd[1]
  142. elif d and self.import_date_format=='dd/mm/yyyy':
  143. tmpd = d.split('/')
  144. if len(tmpd)==3:
  145. out = tmpd[2]+'-'+tmpd[1]+'-'+tmpd[0]
  146. elif d and self.import_date_format=='dd/mm/yy':
  147. tmpd = d.split('/')
  148. if len(tmpd)==3:
  149. out = '20'+tmpd[2]+'-'+tmpd[1]+'-'+tmpd[0]
  150. if len(tmpd) != 3:
  151. self.msg.append('<div style="color: RED"> At Row %s and Column %s : => Date Format selected as %s does not match with Date Format in File</div>' % (r, c, str(self.import_date_format)))
  152. self.validate_success = 0
  153. else:
  154. import datetime
  155. dt = out.split('-')
  156. datetime.date(int(dt[0]),int(dt[1]), int(dt[2]))
  157. except Exception, e:
  158. self.msg.append('<div style="color: RED"> At Row %s and Column %s : =>ERROR: %s </div>' % (r, c, e))
  159. self.validate_success = 0
  160. self.msg.append(out)
  161. return out
  162. def check_select_link_data(self, r, c, f, d, s = '', l = ''):
  163. from webnotes.model.doctype import get_field_property
  164. options = ''
  165. try:
  166. if d and f:
  167. dt = get_field_property(self.dt_list[0], f, 'options')
  168. lbl = get_field_property(self.dt_list[0], f, 'label')
  169. if dt:
  170. options = l and dt and [n[0] for n in sql("select name from `tab%s` " % (('link:' in dt and dt[5:]) or dt))] or s and dt.split('\n') or ''
  171. if options and d not in options :
  172. msg = '<div style="color: RED">At Row ' + str(r) + ' and Column ' + str(c)+ ' : => Data "' + str(d) + '" in field ['+ str(lbl) +'] Not Found in '
  173. msg = msg.__add__( s and str( 'Select Options [' +str(dt.replace('\n', ',')) +']' ) or str('Master ' + str('link:' in dt and dt[5:] or dt)))
  174. msg = msg.__add__('</div>\n')
  175. self.msg.append(msg)
  176. self.validate_success = 0
  177. except Exception, e:
  178. self.msg.append('<div style="color: RED"> ERROR: %s </div>' % (str(webnotes.utils.getTraceback())))
  179. self.validate_success = 0
  180. return d
  181. def get_field_type_list(self):
  182. # get_date_fields
  183. date_list = [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and fieldtype='Date' and docstatus !=2" % self.dt_list[0])]
  184. # get_link_fields
  185. link_list = [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and ((fieldtype='Link' and ifnull(options,'') != '') or (fieldtype='Select' and ifnull(options,'') like '%%link:%%')) and docstatus !=2 " % self.dt_list[0])]
  186. # get_select_fileds
  187. select_list = [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and fieldtype='Select' and ifnull(options,'') not like '%%link:%%' and docstatus !=2" % self.dt_list[0])]
  188. # get_reqd_fields
  189. reqd_list = self.overwrite and ['name'] or [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and ifnull(reqd,'') not in ('', 0) and docstatus !=2" % self.dt_list[0])]
  190. if len(self.dt_list)> 1 and 'parent' not in reqd_list: reqd_list.append('parent')
  191. if self.prompt_autoname_flag and 'name' not in reqd_list: reqd_list.append('name')
  192. return date_list, link_list, select_list, reqd_list
  193. def validate_data(self):
  194. self.msg.append('<p><b>Checking Data for %s</b></p>' % self.dt_list[0])
  195. date_list, link_list, select_list, reqd_list = self.get_field_type_list()
  196. # load data
  197. row = 5
  198. for d in self.data:
  199. self.validate_success, fd, col = 1, {}, 1
  200. self.msg.append('<p><b>Checking Row %s </b></p>' % (row))
  201. for i in range(len(d)):
  202. if i < len(self.fields):
  203. f = self.fields[i]
  204. try:
  205. # Check Reqd Fields
  206. if (f in reqd_list) and not d[i]:
  207. self.msg.append('<div style="color: RED">Error: At Row %s and Column %s, Field %s is Mandatory.</div>' % (row, col, f))
  208. self.validate_success = 0
  209. # Check Date Fields
  210. if d[i] and f and f in date_list : fd[f] = self.parse_date(row, col, d[i])
  211. # Check Link Fields
  212. elif d[i] and f in link_list:
  213. fd[f] = self.check_select_link_data(row, col, f, d[i], l='Link')
  214. # Check Select Fields
  215. elif d[i] and f in select_list:
  216. fd[f] = self.check_select_link_data(row, col, f, d[i], s= 'Select')
  217. # Need To Perform Check For Other Data Type Too
  218. else: fd[f] = d[i]
  219. except Exception:
  220. self.msg.append('<div style="color: RED"> ERROR: %sData:%s and %s and %s and %s</div>' % (str(webnotes.utils.getTraceback()) + '\n', str(d), str(f), str(date_list), str(link_list)))
  221. self.validate_success = 0
  222. elif d[i]:
  223. self.validate_success = 0
  224. self.msg.append('<div style="color: RED">At Row %s and Column %s</div>' % (row,col))
  225. self.msg.append('<div style="color: ORANGE">Ignored</div>')
  226. col = col + 1
  227. if self.validate_success:
  228. self.msg.append('<div style="color: GREEN">At Row %s and Column %s, Data Verification Completed </div>' % (row,col))
  229. self.update_data(fd,row)
  230. row = row + 1
  231. def update_data(self, fd, row):
  232. # load metadata
  233. from webnotes.model.doc import Document
  234. cur_doc = Document(fielddata = fd)
  235. cur_doc.doctype, cur_doc.parenttype, cur_doc.parentfield = self.dt_list[0], len(self.dt_list) > 1 and self.dt_list[1] or '', len(self.dt_list) > 1 and self.dt_list[2] or ''
  236. obj = ''
  237. webnotes.message_log = []
  238. # save the document
  239. try:
  240. if webnotes.conn.in_transaction:
  241. sql("COMMIT")
  242. sql("START TRANSACTION")
  243. if cur_doc.name and webnotes.conn.exists(self.dt_list[0], cur_doc.name):
  244. if self.overwrite:
  245. cur_doc.save()
  246. obj = webnotes.model.code.get_obj(cur_doc.parent and cur_doc.parent_type or cur_doc.doctype, cur_doc.parent or cur_doc.name, with_children = 1)
  247. self.msg.append('<div style="color: ORANGE">Row %s => Over-written: %s</div>' % (row, cur_doc.name))
  248. else:
  249. self.msg.append('<div style="color: ORANGE">Row %s => Ignored: %s</div>' % (row, cur_doc.name))
  250. else:
  251. if cur_doc.parent and webnotes.conn.exists(cur_doc.parenttype, cur_doc.parent) or not cur_doc.parent:
  252. cur_doc.save(1)
  253. obj = webnotes.model.code.get_obj(cur_doc.parent and cur_doc.parenttype or cur_doc.doctype, cur_doc.parent or cur_doc.name, with_children = 1)
  254. self.msg.append('<div style="color: GREEN">Row %s => Created: %s</div>' % (row, cur_doc.name))
  255. else:
  256. self.msg.append('<div style="color: RED">Row %s => Invalid %s : %s</div>' % (row, cur_doc.parenttype, cur_doc.parent))
  257. except Exception:
  258. self.msg.append('<div style="color: RED"> Validation: %s</div>' % str(webnotes.utils.getTraceback()))
  259. try:
  260. if obj:
  261. if hasattr(obj, 'validate') : obj.validate()
  262. if hasattr(obj, 'on_update') : obj.on_update()
  263. if hasattr(obj, 'on_submit') : obj.on_submit()
  264. sql("COMMIT")
  265. except Exception:
  266. sql("ROLLBACK")
  267. self.msg.append('<div style="color: RED"> Validation Error: %s</div>' % str((webnotes.message_log and webnotes.message_log[0]) or webnotes.utils.getTraceback()))
  268. self.msg.append('<div style="color: RED"> Did not import</div>')
  269. # do import
  270. # --------------------------------------------------------------------
  271. def import_csv(self, csv_data, import_date_format = 'yyyy-mm-dd', overwrite = 0):
  272. import csv
  273. self.validate_success, self.csv_data = 1, self.convert_csv_data_into_list(csv.reader(csv_data.splitlines()))
  274. self.import_date_format, self.overwrite = import_date_format, overwrite
  275. if len(self.csv_data) > 4:
  276. self.doctype_data, self.labels, self.data = self.csv_data[0][:4], self.csv_data[3], self.csv_data[4:]
  277. self.fields = []
  278. import webnotes.model.code
  279. from webnotes.model.doc import Document
  280. sql = webnotes.conn.sql
  281. self.validate_headers()
  282. if self.validate_success:
  283. self.validate_data()
  284. else:
  285. self.msg.append('<p><b>No data entered in file.</b></p>')
  286. return '\n'.join(self.msg)
  287. def convert_csv_data_into_list(self,csv_data):
  288. st_list = []
  289. for s in csv_data:
  290. st_list.append([d.strip() for d in s])
  291. return st_list
  292. # Get Template method
  293. # -----------------------------------------------------------------
  294. def get_template():
  295. import webnotes.model
  296. from webnotes.utils import getCSVelement
  297. form = webnotes.form
  298. sql = webnotes.conn.sql
  299. # get form values
  300. dt = form.getvalue('dt')
  301. overwrite = cint(form.getvalue('overwrite')) or 0
  302. pt, pf = '', ''
  303. tmp_lbl, tmp_ml = [],[]
  304. # is table?
  305. dtd = sql("select istable, autoname from tabDocType where name='%s'" % dt)
  306. if dtd and dtd[0][0]:
  307. res1 = sql("select parent, fieldname from tabDocField where options='%s' and fieldtype='Table' and docstatus!=2" % dt)
  308. if res1:
  309. pt, pf = res1[0][0], res1[0][1]
  310. # line 1
  311. dset = []
  312. if pt and pf:
  313. lbl, ml = [pt], ['[Mandatory]']
  314. line1 = '%s,%s,%s' % (getCSVelement(dt), getCSVelement(pt), getCSVelement(pf))
  315. line2 = ',,,,,,Please fill valid %(p)s No in %(p)s column.' % {'p':getCSVelement(pt)}
  316. else:
  317. if dtd[0][1]=='Prompt' or overwrite:
  318. lbl, ml= ['Name'], ['[Mandatory][Special Characters are not allowed]']
  319. else:
  320. lbl, ml= [], []
  321. line1 = '%s' % getCSVelement(dt)
  322. line2 = (overwrite and ',,,,,,Please fill valid %(d)s No in %(n)s' % {'d':dt,'n': 'Name'}) or ',,'
  323. # Help on Line
  324. line1 = line1 + ',,,Please fill columns which are Mandatory., Please do not modify the structure'
  325. # fieldnames
  326. res = sql("select fieldname, fieldtype, label, reqd, hidden from tabDocField where parent='%s' and docstatus!=2" % dt)
  327. for r in res:
  328. # restrict trash_reason field, hidden and required fields
  329. if not r[1] in webnotes.model.no_value_fields and r[0] != 'trash_reason' and not r[4] and not r[3]:
  330. tmp_lbl.append(getCSVelement(r[2]))
  331. tmp_ml.append('')
  332. # restrict trash_reason field and hidden fields and add Mandatory indicator for required fields
  333. elif not r[1] in webnotes.model.no_value_fields and r[0] != 'trash_reason' and not r[4] and r[3]:
  334. lbl.append(getCSVelement(r[2]))
  335. ml.append(getCSVelement('[Mandatory]'))
  336. dset.append(line1)
  337. dset.append(line2)
  338. dset.append(','.join(ml + tmp_ml))
  339. dset.append(','.join(lbl + tmp_lbl))
  340. txt = '\n'.join(dset)
  341. webnotes.response['result'] = txt
  342. webnotes.response['type'] = 'csv'
  343. webnotes.response['doctype'] = dt