Issues (1588)

myems-api/excelexporters/metertrend.py (3 issues)

1
import base64
2
from core.utilities import get_translation
3
import os
4
import re
5
import uuid
6
import openpyxl.utils.cell as format_cell
7
from openpyxl import Workbook
8
from openpyxl.chart import LineChart, Reference
9
from openpyxl.drawing.image import Image
10
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
11
from core.utilities import round2
12
13
########################################################################################################################
14
# PROCEDURES
15
# Step 1: Validate the report data
16
# Step 2: Generate excel file
17
# Step 3: Encode the excel file bytes to Base64
18
########################################################################################################################
19
20
21 View Code Duplication
def export(result,
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
22
           name,
23
           reporting_start_datetime_local,
24
           reporting_end_datetime_local,
25
           period_type,
26
           language):
27
    ####################################################################################################################
28
    # Step 1: Validate the report data
29
    ####################################################################################################################
30
    if result is None:
31
        return None
32
33
    ####################################################################################################################
34
    # Step 2: Generate excel file from the report data
35
    ####################################################################################################################
36
    filename = generate_excel(result,
37
                              name,
38
                              reporting_start_datetime_local,
39
                              reporting_end_datetime_local,
40
                              period_type,
41
                              language)
42
43
    ####################################################################################################################
44
    # Step 3: Encode the excel file to Base64
45
    ####################################################################################################################
46
    binary_file_data = b''
47
    try:
48
        with open(filename, 'rb') as binary_file:
49
            binary_file_data = binary_file.read()
50
    except IOError as ex:
51
        print(str(ex))
52
53
    # Base64 encode the bytes
54
    base64_encoded_data = base64.b64encode(binary_file_data)
55
    # get the Base64 encoded data using human-readable characters.
56
    base64_message = base64_encoded_data.decode('utf-8')
57
    # delete the file from server
58
    try:
59
        os.remove(filename)
60
    except NotImplementedError as ex:
61
        print(str(ex))
62
    return base64_message
63
64
65
def generate_excel(report,
66
                   name,
67
                   reporting_start_datetime_local,
68
                   reporting_end_datetime_local,
69
                   period_type,
70
                   language):
71
72
    trans = get_translation(language)
73
    trans.install()
74
    _ = trans.gettext
75
76
    wb = Workbook()
77
    ws = wb.active
78
    ws.title = "MeterTrend"
79
80
    # Row height
81
    ws.row_dimensions[1].height = 102
82
    for i in range(2, 8):
83
        ws.row_dimensions[i].height = 42
84
85
    # Col width
86
    ws.column_dimensions['A'].width = 1.5
87
88
    ws.column_dimensions['B'].width = 25.0
89
90
    for i in range(ord('C'), ord('V')):
91
        ws.column_dimensions[chr(i)].width = 15.0
92
93
    # Font
94
    name_font = Font(name='Arial', size=15, bold=True)
95
    title_font = Font(name='Arial', size=15, bold=True)
96
97
    table_fill = PatternFill(fill_type='solid', fgColor='90ee90')
98
    f_border = Border(left=Side(border_style='medium'),
99
                      right=Side(border_style='medium'),
100
                      bottom=Side(border_style='medium'),
101
                      top=Side(border_style='medium')
102
                      )
103
    b_border = Border(
104
        bottom=Side(border_style='medium'),
105
    )
106
107
    b_c_alignment = Alignment(vertical='bottom',
108
                              horizontal='center',
109
                              text_rotation=0,
110
                              wrap_text=True,
111
                              shrink_to_fit=False,
112
                              indent=0)
113
    c_c_alignment = Alignment(vertical='center',
114
                              horizontal='center',
115
                              text_rotation=0,
116
                              wrap_text=True,
117
                              shrink_to_fit=False,
118
                              indent=0)
119
    b_r_alignment = Alignment(vertical='bottom',
120
                              horizontal='right',
121
                              text_rotation=0,
122
                              wrap_text=True,
123
                              shrink_to_fit=False,
124
                              indent=0)
125
126
    # Img
127
    img = Image("excelexporters/myems.png")
128
    ws.add_image(img, 'A1')
129
130
    # Title
131
    ws['B3'].alignment = b_r_alignment
132
    ws['B3'] = _('Name') + ':'
133
    ws['C3'].border = b_border
134
    ws['C3'].alignment = b_c_alignment
135
    ws['C3'] = name
136
137
    ws['B4'].alignment = b_r_alignment
138
    ws['B4'] = _('Reporting Start Datetime') + ':'
139
    ws['C4'].border = b_border
140
    ws['C4'].alignment = b_c_alignment
141
    ws['C4'] = reporting_start_datetime_local
142
143
    ws['B5'].alignment = b_r_alignment
144
    ws['B5'] = _('Reporting End Datetime') + ':'
145
    ws['C5'].border = b_border
146
    ws['C5'].alignment = b_c_alignment
147
    ws['C5'] = reporting_end_datetime_local
148
149
    if "reporting_period" not in report.keys() or \
150
            "names" not in report['reporting_period'].keys() or len(report['reporting_period']['names']) == 0:
151
        filename = str(uuid.uuid4()) + '.xlsx'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable str does not seem to be defined.
Loading history...
152
        wb.save(filename)
153
154
        return filename
155
    ####################################################################################################################
156
    # First: Trend
157
    # 6: title
158
    # 7: table title
159
    # 8~ table_data
160
    ####################################################################################################################
161
    has_data_flag = True
162
    report['reporting_period'] = report['reporting_period']
163
    if "names" not in report['reporting_period'].keys() or \
164
            report['reporting_period']['names'] is None or \
165
            len(report['reporting_period']['names']) == 0:
166
        has_data_flag = False
167
168
    if "timestamps" not in report['reporting_period'].keys() or \
169
            report['reporting_period']['timestamps'] is None or \
170
            len(report['reporting_period']['timestamps']) == 0:
171
        has_data_flag = False
172
173
    if "values" not in report['reporting_period'].keys() or \
174
            report['reporting_period']['values'] is None or \
175
            len(report['reporting_period']['values']) == 0:
176
        has_data_flag = False
177
178
    ca_len = len(report['reporting_period']['names'])
179
    times = report['reporting_period']['timestamps']
180
    category = report['meter']['energy_category_name']
181
    parameters_names_len = len(report['parameters']['names'])
182
    parameters_data = report['parameters']
183
    parameters_parameters_datas_len = 0
184
    for i in range(0, parameters_names_len):
185
        if len(parameters_data['timestamps'][i]) == 0:
186
            continue
187
        parameters_parameters_datas_len += 1
188
    start_detail_data_row_num = 9 + (parameters_parameters_datas_len + ca_len) * 6
189
    if has_data_flag:
190
        time = times[0]
191
        for time in times:
192
            if len(time) > 0:
193
                break
194
        has_data = False
195
        current_sheet_parameters_row_number = 7
196
        for i in range(8, len(time) + 6 + ca_len * 6 + len(category) * 6 + 2):
197
            ws.row_dimensions[i].height = 42
198
        if len(time) > 0:
199
            has_data = True
200
            current_sheet_parameters_row_number = 7 + ca_len * 6
201
        if has_data:
202
203
            max_row = start_detail_data_row_num + len(time)
204
            ws['B6'].font = title_font
205
            ws['B6'] = name + ' ' + _('Trend')
206
207
            ws.row_dimensions[start_detail_data_row_num - 1].height = 60
208
            ws['B' + str(start_detail_data_row_num - 1)].fill = table_fill
209
            ws['B' + str(start_detail_data_row_num - 1)].font = title_font
210
            ws['B' + str(start_detail_data_row_num - 1)].border = f_border
211
            ws['B' + str(start_detail_data_row_num - 1)].alignment = c_c_alignment
212
            ws['B' + str(start_detail_data_row_num - 1)] = _('Datetime')
213
214
            for i in range(0, len(time)):
215
                col = 'B'
216
                row = str(start_detail_data_row_num + i)
217
                ws[col + row].font = title_font
218
                ws[col + row].alignment = c_c_alignment
219
                ws[col + row] = time[i]
220
                ws[col + row].border = f_border
221
222
            for i in range(0, ca_len):
223
                # 38 title
224
                col = format_cell.get_column_letter(3 + i)
225
226
                ws[col + str(start_detail_data_row_num - 1)].fill = table_fill
227
                ws[col + str(start_detail_data_row_num - 1)].font = title_font
228
                ws[col + str(start_detail_data_row_num - 1)].alignment = c_c_alignment
229
                ws[col + str(start_detail_data_row_num - 1)] = report['reporting_period']['names'][i]
230
                ws[col + str(start_detail_data_row_num - 1)].border = f_border
231
232
                for j in range(0, len(time)):
233
234
                    row = str(start_detail_data_row_num + j)
235
                    ws[col + row].font = title_font
236
                    ws[col + row].alignment = c_c_alignment
237
                    try:
238
                        ws[col + row] = round2(report['reporting_period']['values'][i][j], 3) if \
239
                            len(report['reporting_period']['values'][i]) > 0 and \
240
                            len(report['reporting_period']['values'][i]) > j and \
241
                            report['reporting_period']['values'][i][j] is not None else ''
242
                    except Exception as e:
243
                        print('error 1 in excelexporters\\metertrend: ' + str(e))
244
245
                    ws[col + row].border = f_border
246
            # line
247
            # 39~: line
248
                line = LineChart()
249
                line.title = report['reporting_period']['names'][i]
250
                labels = Reference(ws, min_col=2, min_row=start_detail_data_row_num, max_row=max_row-1)
251
                line_data = Reference(ws, min_col=3 + i, min_row=start_detail_data_row_num+1, max_row=max_row-1)
252
                line.add_data(line_data, titles_from_data=True)
253
                line.set_categories(labels)
254
                line_data.smooth = True
255
                line.x_axis.crosses = 'min'
256
                line.height = 8.25
257
                line.width = 36
258
                chart_col = chr(ord('B'))
259
                chart_cell = chart_col + str(7 + 6*i)
260
261
                ws.add_chart(line, chart_cell)
262
263
    ####################################################################################################################
264
    # 12 is the starting line number of the last line chart in the report period
265
    if 'parameters' not in report.keys() or \
266
            report['parameters'] is None or \
267
            'names' not in report['parameters'].keys() or \
268
            report['parameters']['names'] is None or \
269
            len(report['parameters']['names']) == 0 or \
270
            'timestamps' not in report['parameters'].keys() or \
271
            report['parameters']['timestamps'] is None or \
272
            len(report['parameters']['timestamps']) == 0 or \
273
            'values' not in report['parameters'].keys() or \
274
            report['parameters']['values'] is None or \
275
            len(report['parameters']['values']) == 0 or \
276
            timestamps_data_all_equal_0(report['parameters']['timestamps']):
277
        pass
278
    else:
279
280
        ################################################################################################################
281
        # new worksheet
282
        ################################################################################################################
283
284
        parameters_data = report['parameters']
285
286
        parameters_names_len = len(parameters_data['names'])
287
288
        file_name = (re.sub(r'[^A-Z]', '', ws.title))+'_'
289
        parameters_ws = wb.create_sheet(file_name + _('Parameters'))
290
291
        parameters_timestamps_data_max_len = \
292
            get_parameters_timestamps_lists_max_len(list(parameters_data['timestamps']))
293
294
        # Row height
295
        parameters_ws.row_dimensions[1].height = 102
296
        for i in range(2, 7 + 1):
297
            parameters_ws.row_dimensions[i].height = 42
298
299
        for i in range(8, parameters_timestamps_data_max_len + 10):
300
            parameters_ws.row_dimensions[i].height = 60
301
302
        # Col width
303
        parameters_ws.column_dimensions['A'].width = 1.5
304
305
        parameters_ws.column_dimensions['B'].width = 25.0
306
307
        for i in range(3, 12 + parameters_names_len * 3):
308
            parameters_ws.column_dimensions[format_cell.get_column_letter(i)].width = 15.0
309
310
        # Img
311
        img = Image("excelexporters/myems.png")
312
        parameters_ws.add_image(img, 'A1')
313
314
        # Title
315
        parameters_ws['B3'].alignment = b_r_alignment
316
        parameters_ws['B3'] = _('Name') + ':'
317
        parameters_ws['C3'].border = b_border
318
        parameters_ws['C3'].alignment = b_c_alignment
319
        parameters_ws['C3'] = name
320
321
        parameters_ws['B4'].alignment = b_r_alignment
322
        parameters_ws['B4'] = _('Reporting Start Datetime') + ':'
323
        parameters_ws['C4'].border = b_border
324
        parameters_ws['C4'].alignment = b_c_alignment
325
        parameters_ws['C4'] = reporting_start_datetime_local
326
327
        parameters_ws['B5'].alignment = b_r_alignment
328
        parameters_ws['B5'] = _('Reporting End Datetime') + ':'
329
        parameters_ws['C5'].border = b_border
330
        parameters_ws['C5'].alignment = b_c_alignment
331
        parameters_ws['C5'] = reporting_end_datetime_local
332
333
        parameters_ws_current_row_number = 6
334
335
        parameters_ws['B' + str(parameters_ws_current_row_number)].font = title_font
336
        parameters_ws['B' + str(parameters_ws_current_row_number)] = name + ' ' + _('Parameters')
337
338
        parameters_ws_current_row_number += 1
339
340
        parameters_table_start_row_number = parameters_ws_current_row_number
341
342
        parameters_ws.row_dimensions[parameters_ws_current_row_number].height = 80
343
344
        parameters_ws_current_row_number += 1
345
346
        table_current_col_number = 2
347
348
        for i in range(0, parameters_names_len):
349
350
            if len(parameters_data['timestamps'][i]) == 0:
351
                continue
352
353
            col = format_cell.get_column_letter(table_current_col_number)
354
355
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
356
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
357
358
            col = format_cell.get_column_letter(table_current_col_number + 1)
359
360
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
361
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
362
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].font = name_font
363
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].alignment = c_c_alignment
364
            parameters_ws[col + str(parameters_ws_current_row_number - 1)] = parameters_data['names'][i]
365
366
            table_current_row_number = parameters_ws_current_row_number
367
368
            for j, value in enumerate(list(parameters_data['timestamps'][i])):
369
                col = format_cell.get_column_letter(table_current_col_number)
370
371
                parameters_ws[col + str(table_current_row_number)].border = f_border
372
                parameters_ws[col + str(table_current_row_number)].font = title_font
373
                parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
374
                parameters_ws[col + str(table_current_row_number)] = value
375
376
                col = format_cell.get_column_letter(table_current_col_number + 1)
377
378
                parameters_ws[col + str(table_current_row_number)].border = f_border
379
                parameters_ws[col + str(table_current_row_number)].font = title_font
380
                parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
381
                try:
382
                    parameters_ws[col + str(table_current_row_number)] = round2(parameters_data['values'][i][j], 2)
383
                except Exception as e:
384
                    print('error 2 in excelexporters\\metertrend: ' + str(e))
385
                
386
                table_current_row_number += 1
387
388
            table_current_col_number = table_current_col_number + 3
389
390
        ################################################################################################################
391
        # parameters chart and parameters table
392
        ################################################################################################################
393
394
        ws['B' + str(current_sheet_parameters_row_number)].font = title_font
0 ignored issues
show
The variable current_sheet_parameters_row_number does not seem to be defined in case has_data_flag on line 189 is False. Are you sure this can never be the case?
Loading history...
395
        ws['B' + str(current_sheet_parameters_row_number)] = name + ' ' + _('Parameters')
396
397
        current_sheet_parameters_row_number += 1
398
399
        chart_start_row_number = current_sheet_parameters_row_number
400
401
        col_index = 0
402
403
        for i in range(0, parameters_names_len):
404
405
            if len(parameters_data['timestamps'][i]) == 0:
406
                continue
407
408
            line = LineChart()
409
            data_col = 3 + col_index * 3
410
            labels_col = 2 + col_index * 3
411
            col_index += 1
412
            line.title = _('Parameters') + ' - ' + \
413
                parameters_ws.cell(row=parameters_table_start_row_number, column=data_col).value
414
            labels = Reference(parameters_ws, min_col=labels_col, min_row=parameters_table_start_row_number + 1,
415
                               max_row=(len(parameters_data['timestamps'][i]) + parameters_table_start_row_number))
416
            line_data = Reference(parameters_ws, min_col=data_col, min_row=parameters_table_start_row_number,
417
                                  max_row=(len(parameters_data['timestamps'][i]) + parameters_table_start_row_number))
418
            line.add_data(line_data, titles_from_data=True)
419
            line.set_categories(labels)
420
            line_data = line.series[0]
421
            line_data.marker.symbol = "auto"
422
            line_data.smooth = True
423
            line.x_axis.crosses = 'min'
424
            line.height = 8.25
425
            line.width = 24
426
            chart_col = 'B'
427
            chart_cell = chart_col + str(chart_start_row_number)
428
            chart_start_row_number += 6
429
            ws.add_chart(line, chart_cell)
430
431
        current_sheet_parameters_row_number = chart_start_row_number
432
433
        current_sheet_parameters_row_number += 1
434
435
    filename = str(uuid.uuid4()) + '.xlsx'
436
    wb.save(filename)
437
438
    return filename
439
440
441
def timestamps_data_all_equal_0(lists):
442
    for i, value in enumerate(list(lists)):
443
        if len(value) > 0:
444
            return False
445
446
    return True
447
448
449
def get_parameters_timestamps_lists_max_len(parameters_timestamps_lists):
450
    max_len = 0
451
    for i, value in enumerate(list(parameters_timestamps_lists)):
452
        if len(value) > max_len:
453
            max_len = len(value)
454
455
    return max_len
456
457
458
def timestamps_data_not_equal_0(lists):
459
    number = 0
460
    for i, value in enumerate(list(lists)):
461
        if len(value) > 0:
462
            number += 1
463
    return number
464