1+ # -*- coding: utf-8 -*-
12# Copyright (c) 2019, Dolores Juliana Fdez Martin
23# License: GNU General Public License v3. See license.txt
34#
1819
1920from __future__ import unicode_literals
2021import frappe , ast
22+ from frappe import _
2123from frappe .utils .xlsxutils import read_xlsx_file_from_attached_file
2224from frappe .utils .csvutils import read_csv_content
2325import six
26+ from six import text_type , string_types
2427from datetime import date , datetime
28+ from frappe .utils import nowdate
29+ from frappe .utils .dateutils import parse_date
30+ from frappe .utils import cint , cstr , flt , getdate , get_datetime , get_url , get_url_to_form
2531from xml .etree import ElementTree as ET
32+ import copy
33+
34+ def force_to_unicode (text ):
35+ if text == None : text = " "
36+ resp = text .encode ('ascii' , 'ignore' ).decode ('ascii' )
37+ return resp
2638
2739def loaddata (self , method = None ):
2840 ext_rows = readfile (file_url = self .import_file , data_format = self .data_format )
@@ -36,7 +48,7 @@ def loaddata(self, method=None):
3648 numrecords = addrecords (name = self .name , datarows = datarows )
3749 message = str (numrecords ) + ' records loaded in the DocType ' + self .name
3850 frappe .publish_realtime ('msgprint' , message )
39-
51+
4052def reloaddata (self , method = None ):
4153 ext_rows = readfile (file_url = self .import_file , data_format = self .data_format )
4254 row_stop = 0 if self .row_end == 0 else self .row_start + self .row_end - 1
@@ -105,6 +117,8 @@ def analyzedata(row_labels, row_start, ext_rows, row_stop=None, newdata=False, n
105117 xrow = 0
106118 tt = []
107119 labels = []
120+ tmp_list = []
121+ fields = []
108122 lengths = []
109123 datatypes = []
110124 datamandatory = []
@@ -117,19 +131,36 @@ def analyzedata(row_labels, row_start, ext_rows, row_stop=None, newdata=False, n
117131 continue
118132 if row_stop and row_stop > 0 and xrow > row_stop :
119133 break
134+ # Row empty?
135+ if columns > 0 :
136+ rowempty = 1
137+ i = 0
138+ for cell in row :
139+ if i >= columns : break
140+ if cell and str (cell ).strip () != "" :
141+ rowempty = 0
142+ break
143+ i += 1
144+ if rowempty == 1 : continue
145+
120146 tmp_list = []
121147 i = 0
122148 for cell in row :
149+ # Label empty END
150+ if columns == 0 and (cell == None or cell == "" ): break
151+ if columns > 0 and i >= columns : break
152+
123153 if isinstance (cell , six .string_types ):
124154 if columns == 0 :
125- tmp_list .append (cell .replace ('"' ,'' ))
155+ tmp_list .append (cell .replace ('"' ,'' ). replace ( '.' , '' ). replace ( ',' , '' ) )
126156 else : tmp_list .append (cell .strip ().replace ('"' ,'' ).encode ('utf8' ))
127- else : tmp_list .append (cell )
157+ else :
158+ tmp_list .append (cell )
128159 if newdata and columns > 0 and i <= columns :
129160 x = 0
130161 if isinstance (cell , six .string_types ): x = len (cell )
131162 lengths [i ] = max ( x , lengths [i ])
132- if datatypes [i ] == "Data " :
163+ if datatypes [i ] == "PTE " :
133164 if lengths [i ] > 140 :
134165 datatypes [i ] = "Small Text"
135166 else :
@@ -138,32 +169,49 @@ def analyzedata(row_labels, row_start, ext_rows, row_stop=None, newdata=False, n
138169 if isinstance (cell , float ): datatypes [i ] = "Float"
139170 if isinstance (cell , datetime ): datatypes [i ] = "Datetime"
140171 if isinstance (cell , date ): datatypes [i ] = "Date"
172+ if isinstance (cell , str ): datatypes [i ] = "Data"
141173 else :
142174 if cell and cell != "" and cell != None and cell != 0 and cell != "0" :
175+ if lengths [i ] > 140 : datatypes [i ] = "Small Text"
143176 if datatypes [i ] == "Int" and not isinstance (cell , int ) and not isinstance (cell , long ): datatypes [i ] = "Data"
144177 if datatypes [i ] == "Float" and not isinstance (cell , float ): datatypes [i ] = "Data"
145178 if datatypes [i ] == "Date" and not isinstance (cell , date ): datatypes [i ] = "Data"
146179 if datatypes [i ] == "Datetime" and not isinstance (cell , datetime ): datatypes [i ] = "Data"
147180 if not cell or cell == "" or cell == None :
148181 if datamandatory [i ] == 1 : datamandatory [i ] = 0
149- if datatypes [i ] == "Data" and datamandatory [i ] == 1 :
182+ if datatypes [i ] == "Data" and datamandatory [i ] == 1 and isinstance ( cell , str ):
150183 if not cell .strip () in datavalues [i ]:
151184 datavalues [i ].append (cell .strip ())
152185 i += 1
153186 if xrow == row_labels :
154- labels = tmp_list
155- columns = len (labels )
156187 fields = tmp_list
188+ columns = len (tmp_list )
189+ labels = copy .deepcopy (tmp_list )
157190 i = 1
158191 while i <= columns :
159192 lengths .append (0 )
160- datatypes .append ("Data " )
193+ datatypes .append ("PTE " )
161194 datamandatory .append (1 )
162195 datavalues .append ([])
163196 j = i - 1
197+ labels [j ] = force_to_unicode (labels [j ])
198+ fields [j ] = force_to_unicode (fields [j ])
164199 fields [j ] = str (fields [j ]).lower ().replace (" " , "_" )
200+ if fields [j ] == "_" :
201+ fields [j ] = "column_" + str (i )
202+ labels [j ] = "Column " + str (i )
165203 i += 1
166204 datarows .append (fields )
205+ # template diferent
206+ if not newdata :
207+ meta = frappe .get_meta (name )
208+ i = 1
209+ while i <= columns :
210+ j = i - 1
211+ df = meta .get_field (fields [j ])
212+ if not df :
213+ frappe .throw (_ ("The fields of the file you are trying to load do not correspond to the fields in the initial template file" ))
214+ i += 1
167215 else :
168216 datarows .append (tmp_list )
169217 if newdata :
@@ -177,6 +225,7 @@ def analyzedata(row_labels, row_start, ext_rows, row_stop=None, newdata=False, n
177225 datavalues [i ] = listdv
178226 else :
179227 datavalues [i ] = ""
228+ if datatypes [i ] == "PTE" : datatypes [i ] = "Data"
180229 i += 1
181230 adddoctype (name , module , fields , labels , datatypes , datamandatory , datavalues )
182231 return datarows
@@ -189,6 +238,7 @@ def adddoctype(name, module, fields, labels, datatypes, datamandatory, datavalue
189238 "name" : name ,
190239 "quick_entry" : 0 ,
191240 "custom" : 1 })
241+
192242 i = 0
193243 for cell in labels :
194244 doc_field = frappe .get_doc ({
@@ -203,6 +253,19 @@ def adddoctype(name, module, fields, labels, datatypes, datamandatory, datavalue
203253 "in_list_view" : 1 if i < 3 else 0 })
204254 doc .append ("fields" , doc_field )
205255 i += 1
256+
257+ doc_field = frappe .get_doc ({
258+ "doctype" : "DocField" ,
259+ "label" : "Row Original" ,
260+ "fieldtype" : "Text Editor" ,
261+ "fieldname" : "row_original" ,
262+ "reqd" : 0 ,
263+ "in_standard_filter" : 0 ,
264+ "search_index" : 0 ,
265+ "options" : "" ,
266+ "in_list_view" : 0 ,
267+ "hidden" : 1 })
268+ doc .append ("fields" , doc_field )
206269
207270 if roles == None :
208271 roles = ["System Manager" , "Administrator" ]
@@ -214,7 +277,9 @@ def adddoctype(name, module, fields, labels, datatypes, datamandatory, datavalue
214277 doc .insert (ignore_permissions = True )
215278
216279def addrecords (name , datarows , limit = 65000 ):
280+ meta = frappe .get_meta (name )
217281 columns = 0
282+ x = 0
218283 j = 0
219284 for row in datarows :
220285 if j >= limit : break
@@ -226,10 +291,126 @@ def addrecords(name, datarows, limit=65000):
226291 i = 0
227292 for cell in row :
228293 if i >= columns : break
294+ df = meta .get_field (fields [i ])
295+ fieldtype = df .fieldtype if df else "Data"
296+ if fieldtype in ("Int" , "Check" ):
297+ cell = cint (cell )
298+ elif fieldtype in ("Float" , "Currency" , "Percent" ):
299+ cell = flt (cell )
300+ elif fieldtype == "Date" :
301+ if cell and isinstance (cell , datetime ):
302+ cell = str (cell )
303+ if cell and isinstance (cell , string_types ):
304+ cell = getdate (parse_date (cell ))
305+ elif fieldtype == "Datetime" :
306+ if cell :
307+ if " " in cell :
308+ _date , _time = cell .split ()
309+ else :
310+ _date , _time = cell , '00:00:00'
311+ _date = parse_date (cell )
312+ cell = get_datetime (_date + " " + _time )
313+ else :
314+ cell = None
315+ elif fieldtype in ("Link" , "Dynamic Link" , "Data" ) and cell :
316+ cell = cstr (cell )
317+
229318 datadoc .setdefault (fields [i ], cell )
230319 i += 1
320+
321+ row_original = str (datadoc )
322+ xduplicates = frappe .get_list (name , filters = {'row_original' : row_original }, fields = ['name' ])
323+ j += 1
324+ if len (xduplicates ) > 0 :
325+ x += 1
326+ continue
327+ datadoc = conversionrules (datadoc )
328+ datadoc .setdefault ("row_original" , row_original )
231329 doc = frappe .get_doc (datadoc )
232330 doc .insert (ignore_permissions = True )
233- j += 1
234- return j
331+ return j - x
332+
333+ def conversionrules (doc , conversion_type = 'During loading' ):
334+ rules = frappe .get_all ("Conversion Rules" ,
335+ filters = {"reference_doctype" : doc ['doctype' ], "conversion_type" : conversion_type },
336+ fields = ["origin_field" , "action" , "receiver_field" ],
337+ order_by = 'execution_order' )
338+ for rule in rules :
339+ x = doc .get (rule .origin_field )
340+ y = executeaction (x , rule .action )
341+ if doc [rule .receiver_field ]: doc [rule .receiver_field ] = y
342+ else : doc .setdefault (rule .receiver_field , y )
343+ return doc
344+
345+ def executeaction (x , action , param1 = None , param2 = None ):
346+ if not x or x == None : return x
347+ xact = ['Convert to Uppercase' ,'Convert to Lowercase' ,'Convert First Letter to Uppercase' ,
348+ 'Remove White Character from Beginning and End' ,'Replace character or string (All)' ,
349+ 'Replace character or string (the First one)' ,'Replace character or string (the Last one)' ]
350+ i = xact .index (action )
351+ if i == 0 : return x .upper ()
352+ if i == 1 : return x .lower ()
353+ if i == 2 : return (x [0 ].upper () + x [1 :].lower ())
354+ if i == 3 : return x .strip ()
355+ if i == 4 and param1 != None and param2 != None : return x .replace (param1 , param2 )
356+ if i == 5 and param1 != None and param2 != None : return x .replace (param1 , param2 , 1 )
357+
358+ return x
235359
360+ def changedoctype (self , method = None ):
361+ if not frappe .db .exists ('DocType' , self .reference_doctype ):
362+ return
363+ if not frappe .db .table_exists (self .name ) and not self .docfield :
364+ return
365+ allfields = frappe .get_list ('Change DocField' , filters = {'parent' : self .name }, fields = "*" )
366+ keydata = ["label" ,"fieldtype" ,"reqd" ,"search_index" ,"in_list_view" ,"in_standard_filter" ,"options" ,"default" ,"length" ,"in_global_search" ,"allow_in_quick_entry" ,"bold" ,"description" ]
367+ for onefield in allfields :
368+ docname = frappe .get_list ('DocField' ,
369+ filters = {'parent' : self .reference_doctype , 'fieldname' : onefield .fieldname },
370+ fields = ["name" ])
371+ doc = frappe .get_doc ('DocField' , docname [0 ]['name' ])
372+ for onekey in keydata :
373+ if doc .get (onekey ) != onefield .get (onekey ):
374+ setattr (doc ,onekey ,onefield .get (onekey ))
375+ doc .save ()
376+
377+ def doctype_query (doctype , txt , searchfield , start , page_len , filters , as_dict = False ):
378+ return frappe .db .sql ("""select eds.name
379+ from `tabExt Data Source` eds
380+ INNER JOIN tabDocType dt on eds.name = dt.name
381+ """ ,{
382+ "today" : nowdate (),
383+ "txt" : "%%%s%%" % txt ,
384+ "_txt" : txt .replace ("%" , "" ),
385+ "start" : start ,
386+ "page_len" : page_len
387+ }, as_dict = as_dict )
388+
389+ @frappe .whitelist ()
390+ def deletedata (doctype ):
391+ numrecords = frappe .db .count (doctype )
392+ if not numrecords or numrecords == 0 :
393+ frappe .throw (_ ("{0} is empty contains {1} records." ).format (doctype ,numrecords ))
394+ if not frappe .db .exists ('DocType' , doctype ):
395+ frappe .throw (_ ("{0} is not a doctype of the database." ).format (doctype ))
396+ if not frappe .db .exists ('Ext Data Source' , doctype ):
397+ frappe .throw (_ ("{0} is not a External Data." ).format (doctype ))
398+
399+ il = frappe .get_all (doctype , fields = ['name' ])
400+ failed = []
401+ i = 0
402+ for dd in il :
403+ d = dd .name
404+ try :
405+ frappe .delete_doc (doctype , d )
406+ if numrecords >= 5 :
407+ frappe .publish_realtime ("progress" ,
408+ dict (progress = [i + 1 , numrecords ], title = _ ('Deleting {0}' ).format (doctype ), description = d ),
409+ user = frappe .session .user )
410+ i += 1
411+ except Exception :
412+ failed .append (d )
413+
414+ message = str (numrecords - len (failed )) + ' records loaded in the DocType ' + doctype
415+ frappe .publish_realtime ('msgprint' , message )
416+ return failed
0 commit comments