Skip to content

Commit 493d942

Browse files
rootroot
authored andcommitted
Version 1.1.0
1 parent cd01a6a commit 493d942

40 files changed

+3697
-40
lines changed

pibiapp/config/desktop.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,13 @@ def get_data():
1919
"type": "module",
2020
"label": _("External Data"),
2121
"hidden": 1
22-
}
22+
},
23+
{
24+
"module_name": "Redash",
25+
"color": "grey",
26+
"icon": "octicon octicon-pulse",
27+
"type": "module",
28+
"label": _("Redash"),
29+
"hidden": 1
30+
}
2331
]

pibiapp/config/external_data.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ def get_data():
1111
"name": "Ext Data Source",
1212
"description": _("Load files as new doctype of Frappe"),
1313
},
14+
{
15+
"type": "doctype",
16+
"name": "Change DocType Empty",
17+
"description": _("Change the fields of an external data DocType while it is empty"),
18+
},
1419
{
1520
"type": "doctype",
1621
"name": "Successive loads",

pibiapp/config/redash.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import unicode_literals
2+
from frappe import _
3+
4+
def get_data():
5+
return [
6+
{
7+
"label": _("Dashboards"),
8+
"items": [
9+
{
10+
"type": "doctype",
11+
"name": "Redash Business Intelligence",
12+
"description": _("It shows the dashboards designed in Redash and enabled in Frappe"),
13+
}
14+
]
15+
},
16+
{
17+
"label": _("Settings"),
18+
"items": [
19+
{
20+
"type": "doctype",
21+
"name": "Redash Dashboards",
22+
"description": _("List of dashboards and viewing permissions"),
23+
}
24+
]
25+
}
26+
]

pibiapp/config/xlsdata.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

pibiapp/external_data/data_manage.py

Lines changed: 191 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
# Copyright (c) 2019, Dolores Juliana Fdez Martin
23
# License: GNU General Public License v3. See license.txt
34
#
@@ -18,11 +19,22 @@
1819

1920
from __future__ import unicode_literals
2021
import frappe, ast
22+
from frappe import _
2123
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
2224
from frappe.utils.csvutils import read_csv_content
2325
import six
26+
from six import text_type, string_types
2427
from 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
2531
from 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

2739
def 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+
4052
def 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

216279
def 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

pibiapp/external_data/doctype/change_docfield/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)