Passed
Push — master ( 107ae9...7e7300 )
by Guangyu
12:14 queued 12s
created

excelexporters.storeenergyitem.generate_excel()   F

Complexity

Conditions 73

Size

Total Lines 737
Code Lines 560

Duplication

Lines 737
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 560
dl 737
loc 737
rs 0
c 0
b 0
f 0
cc 73
nop 8

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like excelexporters.storeenergyitem.generate_excel() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
import base64
2
import gettext
3
import os
4
import re
5
import uuid
6
7
import openpyxl.utils.cell as format_cell
8
from openpyxl import Workbook
9
from openpyxl.chart import PieChart, LineChart, Reference
10
from openpyxl.chart.label import DataLabelList
11
from openpyxl.drawing.image import Image
12
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
13
14
15
########################################################################################################################
16
# PROCEDURES
17
# Step 1: Validate the report data
18
# Step 2: Generate excel file
19
# Step 3: Encode the excel file to Base64
20
########################################################################################################################
21
22
23 View Code Duplication
def export(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
24
           name,
25
           base_period_start_datetime_local,
26
           base_period_end_datetime_local,
27
           reporting_start_datetime_local,
28
           reporting_end_datetime_local,
29
           period_type,
30
           language):
31
    ####################################################################################################################
32
    # Step 1: Validate the report data
33
    ####################################################################################################################
34
    if report is None:
35
        return None
36
37
    ####################################################################################################################
38
    # Step 2: Generate excel file from the report data
39
    ####################################################################################################################
40
    filename = generate_excel(report,
41
                              name,
42
                              base_period_start_datetime_local,
43
                              base_period_end_datetime_local,
44
                              reporting_start_datetime_local,
45
                              reporting_end_datetime_local,
46
                              period_type,
47
                              language)
48
    ####################################################################################################################
49
    # Step 3: Encode the excel file to Base64
50
    ####################################################################################################################
51
    binary_file_data = b''
52
    try:
53
        with open(filename, 'rb') as binary_file:
54
            binary_file_data = binary_file.read()
55
    except IOError as ex:
56
        print(str(ex))
57
58
    # Base64 encode the bytes
59
    base64_encoded_data = base64.b64encode(binary_file_data)
60
    # get the Base64 encoded data using human-readable characters.
61
    base64_message = base64_encoded_data.decode('utf-8')
62
    # delete the file from server
63
    try:
64
        os.remove(filename)
65
    except NotImplementedError as ex:
66
        print(str(ex))
67
    return base64_message
68
69
70 View Code Duplication
def generate_excel(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
71
                   name,
72
                   base_period_start_datetime_local,
73
                   base_period_end_datetime_local,
74
                   reporting_start_datetime_local,
75
                   reporting_end_datetime_local,
76
                   period_type,
77
                   language):
78
79
    locale_path = './i18n/'
80
    if language == 'zh_CN':
81
        trans = gettext.translation('myems', locale_path, languages=['zh_CN'])
82
    elif language == 'de':
83
        trans = gettext.translation('myems', locale_path, languages=['de'])
84
    elif language == 'en':
85
        trans = gettext.translation('myems', locale_path, languages=['en'])
86
    else:
87
        trans = gettext.translation('myems', locale_path, languages=['en'])
88
    trans.install()
89
    _ = trans.gettext
90
91
    wb = Workbook()
92
    ws = wb.active
93
    ws.title = "StoreEnergyItem"
94
95
    # Row height
96
    ws.row_dimensions[1].height = 102
97
    for i in range(2, 2000 + 1):
98
        ws.row_dimensions[i].height = 42
99
100
    # Col width
101
    ws.column_dimensions['A'].width = 1.5
102
103
    ws.column_dimensions['B'].width = 25.0
104
105
    for i in range(ord('C'), ord('Z')):
106
        ws.column_dimensions[chr(i)].width = 15.0
107
108
    # Font
109
    name_font = Font(name='Arial', size=15, bold=True)
110
    title_font = Font(name='Arial', size=15, bold=True)
111
112
    table_fill = PatternFill(fill_type='solid', fgColor='90ee90')
113
    f_border = Border(left=Side(border_style='medium'),
114
                      right=Side(border_style='medium'),
115
                      bottom=Side(border_style='medium'),
116
                      top=Side(border_style='medium')
117
                      )
118
    b_border = Border(
119
        bottom=Side(border_style='medium'),
120
    )
121
122
    b_c_alignment = Alignment(vertical='bottom',
123
                              horizontal='center',
124
                              text_rotation=0,
125
                              wrap_text=True,
126
                              shrink_to_fit=False,
127
                              indent=0)
128
    c_c_alignment = Alignment(vertical='center',
129
                              horizontal='center',
130
                              text_rotation=0,
131
                              wrap_text=True,
132
                              shrink_to_fit=False,
133
                              indent=0)
134
    b_r_alignment = Alignment(vertical='bottom',
135
                              horizontal='right',
136
                              text_rotation=0,
137
                              wrap_text=True,
138
                              shrink_to_fit=False,
139
                              indent=0)
140
    # Img
141
    img = Image("excelexporters/myems.png")
142
    ws.add_image(img, 'A1')
143
144
    # Title
145
    ws['B3'].alignment = b_r_alignment
146
    ws['B3'] = _('Name') + ':'
147
    ws['C3'].border = b_border
148
    ws['C3'].alignment = b_c_alignment
149
    ws['C3'] = name
150
151
    ws['D3'].alignment = b_r_alignment
152
    ws['D3'] = _('Period Type') + ':'
153
    ws['E3'].border = b_border
154
    ws['E3'].alignment = b_c_alignment
155
    ws['E3'] = period_type
156
157
    ws['B4'].alignment = b_r_alignment
158
    ws['B4'] = _('Reporting Start Datetime') + ':'
159
    ws['C4'].border = b_border
160
    ws['C4'].alignment = b_c_alignment
161
    ws['C4'] = reporting_start_datetime_local
162
163
    ws['D4'].alignment = b_r_alignment
164
    ws['D4'] = _('Reporting End Datetime') + ':'
165
    ws['E4'].border = b_border
166
    ws['E4'].alignment = b_c_alignment
167
    ws['E4'] = reporting_end_datetime_local
168
169
    is_base_period_timestamp_exists_flag = is_base_period_timestamp_exists(report['base_period'])
170
171
    if is_base_period_timestamp_exists_flag:
172
        ws['B5'].alignment = b_r_alignment
173
        ws['B5'] = _('Base Period Start Datetime') + ':'
174
        ws['C5'].border = b_border
175
        ws['C5'].alignment = b_c_alignment
176
        ws['C5'] = base_period_start_datetime_local
177
178
        ws['D5'].alignment = b_r_alignment
179
        ws['D5'] = _('Base Period End Datetime') + ':'
180
        ws['E5'].border = b_border
181
        ws['E5'].alignment = b_c_alignment
182
        ws['E5'] = base_period_end_datetime_local
183
184
    if "reporting_period" not in report.keys() or \
185
            "names" not in report['reporting_period'].keys() or len(report['reporting_period']['names']) == 0:
186
        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...
187
        wb.save(filename)
188
189
        return filename
190
191
    ####################################################################################################################
192
    current_row_number = 7
193
    reporting_period_data = report['reporting_period']
194
    if "names" not in reporting_period_data.keys() or \
195
            reporting_period_data['names'] is None or \
196
            len(reporting_period_data['names']) == 0:
197
        pass
198
    else:
199
        ws['B' + str(current_row_number)].font = title_font
200
        ws['B' + str(current_row_number)] = name + ' ' + _('Reporting Period Consumption')
201
202
        current_row_number += 1
203
204
        category = reporting_period_data['names']
205
        ca_len = len(category)
206
207
        ws.row_dimensions[current_row_number].height = 60
208
        ws['B' + str(current_row_number)].fill = table_fill
209
        ws['B' + str(current_row_number)].border = f_border
210
211
        col = 'C'
212
213
        for i in range(0, ca_len):
214
            ws[col + str(current_row_number)].fill = table_fill
215
            ws[col + str(current_row_number)].font = name_font
216
            ws[col + str(current_row_number)].alignment = c_c_alignment
217
            ws[col + str(current_row_number)].border = f_border
218
            ws[col + str(current_row_number)] = \
219
                reporting_period_data['names'][i] + " " + reporting_period_data['energy_category_names'][i] + \
220
                " (" + reporting_period_data['units'][i] + ")"
221
222
            col = chr(ord(col) + 1)
223
224
        current_row_number += 1
225
226
        ws['B' + str(current_row_number)].font = title_font
227
        ws['B' + str(current_row_number)].alignment = c_c_alignment
228
        ws['B' + str(current_row_number)].border = f_border
229
        ws['B' + str(current_row_number)] = _('Per Unit Area')
230
231
        col = 'C'
232
233
        for i in range(0, ca_len):
234
            ws[col + str(current_row_number)].font = name_font
235
            ws[col + str(current_row_number)].alignment = c_c_alignment
236
            ws[col + str(current_row_number)].border = f_border
237
            ws[col + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
238
239
            col = chr(ord(col) + 1)
240
241
        current_row_number += 1
242
243
        ws['B' + str(current_row_number)].font = title_font
244
        ws['B' + str(current_row_number)].alignment = c_c_alignment
245
        ws['B' + str(current_row_number)].border = f_border
246
        ws['B' + str(current_row_number)] = _('Per Unit Area')
247
248
        col = 'C'
249
250
        for i in range(0, ca_len):
251
            ws[col + str(current_row_number)].font = name_font
252
            ws[col + str(current_row_number)].alignment = c_c_alignment
253
            ws[col + str(current_row_number)].border = f_border
254
            ws[col + str(current_row_number)] = round(reporting_period_data['subtotals_per_unit_area'][i], 2)
255
256
            col = chr(ord(col) + 1)
257
258
        current_row_number += 1
259
260
        ws['B' + str(current_row_number)].font = title_font
261
        ws['B' + str(current_row_number)].alignment = c_c_alignment
262
        ws['B' + str(current_row_number)].border = f_border
263
        ws['B' + str(current_row_number)] = _('Increment Rate')
264
265
        col = 'C'
266
267
        for i in range(0, ca_len):
268
            ws[col + str(current_row_number)].font = name_font
269
            ws[col + str(current_row_number)].alignment = c_c_alignment
270
            ws[col + str(current_row_number)].border = f_border
271
            ws[col + str(current_row_number)] = str(
272
                round(reporting_period_data['increment_rates'][i] * 100, 2)) + '%' \
273
                if reporting_period_data['increment_rates'][i] is not None else '-'
274
275
            col = chr(ord(col) + 1)
276
277
        current_row_number += 2
278
279
        category_dict = group_by_category(reporting_period_data['energy_category_names'])
280
281
        for category_dict_name, category_dict_values in category_dict.items():
282
283
            ws['B' + str(current_row_number)].font = title_font
284
            ws['B' + str(current_row_number)] = name + ' ' + category_dict_name + ' ' + \
285
                '(' + reporting_period_data['units'][category_dict_values[0]] + ') by Energy Item'
286
287
            current_row_number += 1
288
            table_start_row_number = current_row_number
289
290
            ws['B' + str(current_row_number)].fill = table_fill
291
            ws['B' + str(current_row_number)].border = f_border
292
293
            ws['C' + str(current_row_number)].font = name_font
294
            ws['C' + str(current_row_number)].fill = table_fill
295
            ws['C' + str(current_row_number)].alignment = c_c_alignment
296
            ws['C' + str(current_row_number)].border = f_border
297
            ws['C' + str(current_row_number)] = _('Per Unit Area')
298
299
            current_row_number += 1
300
301
            for i in category_dict_values:
302
                ws['B' + str(current_row_number)].font = title_font
303
                ws['B' + str(current_row_number)].alignment = c_c_alignment
304
                ws['B' + str(current_row_number)].border = f_border
305
                ws['B' + str(current_row_number)] = \
306
                    reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
307
                ws['C' + str(current_row_number)].font = name_font
308
                ws['C' + str(current_row_number)].alignment = c_c_alignment
309
                ws['C' + str(current_row_number)].border = f_border
310
                ws['C' + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 3)
311
312
                current_row_number += 1
313
314
            table_end_row_number = current_row_number - 1
315
316
            pie = PieChart()
317
            pie.title = name + ' ' + category_dict_name + ' ' + \
318
                '(' + reporting_period_data['units'][category_dict_values[0]] + ') by Energy Item'
319
            labels = Reference(ws, min_col=2, min_row=table_start_row_number + 1, max_row=table_end_row_number)
320
            pie_data = Reference(ws, min_col=3, min_row=table_start_row_number, max_row=table_end_row_number)
321
            pie.add_data(pie_data, titles_from_data=True)
322
            pie.set_categories(labels)
323
            pie.height = 6.6
324
            pie.width = 9
325
            s1 = pie.series[0]
326
            s1.dLbls = DataLabelList()
327
            s1.dLbls.showCatName = False
328
            s1.dLbls.showVal = True
329
            s1.dLbls.showPercent = True
330
            ws.add_chart(pie, 'D' + str(table_start_row_number))
331
332
            if len(category_dict_values) < 4:
333
                current_row_number = current_row_number - len(category_dict_values) + 4
334
335
            current_row_number += 1
336
337
    ####################################################################################################################
338
    chart_start_row_number = current_row_number
339
340
    has_values_data = True
341
    has_timestamps_data = True
342
343
    if 'values' not in reporting_period_data.keys() or \
344
            reporting_period_data['values'] is None or \
345
            len(reporting_period_data['values']) == 0:
346
        has_values_data = False
347
348
    if 'timestamps' not in reporting_period_data.keys() or \
349
            reporting_period_data['timestamps'] is None or \
350
            len(reporting_period_data['timestamps']) == 0 or \
351
            len(reporting_period_data['timestamps'][0]) == 0:
352
        has_timestamps_data = False
353
354
    if not is_base_period_timestamp_exists_flag:
355
        if has_values_data and has_timestamps_data:
356
            ca_len = len(reporting_period_data['names'])
357
            time = reporting_period_data['timestamps'][0]
358
            real_timestamps_len = timestamps_data_not_equal_0(report['parameters']['timestamps'])
359
            ws['B' + str(current_row_number)].font = title_font
360
            ws['B' + str(current_row_number)] = name + ' ' + _('Detailed Data')
361
362
            current_row_number += 1
363
364
            chart_start_row_number = current_row_number
365
366
            # 1: Stand for blank line  2: Stand for title
367
            current_row_number += ca_len * 6 + real_timestamps_len * 6 + 1 + 2
368
            table_start_row_number = current_row_number
369
370
            ws.row_dimensions[current_row_number].height = 60
371
            ws['B' + str(current_row_number)].fill = table_fill
372
            ws['B' + str(current_row_number)].font = title_font
373
            ws['B' + str(current_row_number)].alignment = c_c_alignment
374
            ws['B' + str(current_row_number)].border = f_border
375
            ws['B' + str(current_row_number)] = _('Datetime')
376
377
            col = 'C'
378
379
            for i in range(0, ca_len):
380
                ws[col + str(current_row_number)].fill = table_fill
381
                ws[col + str(current_row_number)].font = title_font
382
                ws[col + str(current_row_number)].alignment = c_c_alignment
383
                ws[col + str(current_row_number)].border = f_border
384
                ws[col + str(current_row_number)] = \
385
                    reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
386
                col = chr(ord(col) + 1)
387
388
            current_row_number += 1
389
390
            for i in range(0, len(time)):
391
                ws['B' + str(current_row_number)].font = title_font
392
                ws['B' + str(current_row_number)].alignment = c_c_alignment
393
                ws['B' + str(current_row_number)].border = f_border
394
                ws['B' + str(current_row_number)] = time[i]
395
396
                col = 'C'
397
                for j in range(0, ca_len):
398
                    ws[col + str(current_row_number)].font = title_font
399
                    ws[col + str(current_row_number)].alignment = c_c_alignment
400
                    ws[col + str(current_row_number)].border = f_border
401
                    ws[col + str(current_row_number)] = round(reporting_period_data['values'][j][i], 2) \
402
                        if reporting_period_data['values'][j][i] is not None else 0.00
403
                    col = chr(ord(col) + 1)
404
405
                current_row_number += 1
406
407
            table_end_row_number = current_row_number - 1
408
409
            ws['B' + str(current_row_number)].font = title_font
410
            ws['B' + str(current_row_number)].alignment = c_c_alignment
411
            ws['B' + str(current_row_number)].border = f_border
412
            ws['B' + str(current_row_number)] = _('Subtotal')
413
414
            col = 'C'
415
416
            for i in range(0, ca_len):
417
                ws[col + str(current_row_number)].font = title_font
418
                ws[col + str(current_row_number)].alignment = c_c_alignment
419
                ws[col + str(current_row_number)].border = f_border
420
                ws[col + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
421
                col = chr(ord(col) + 1)
422
423
            current_row_number += 2
424
425
            for i in range(0, ca_len):
426
                line = LineChart()
427
                line.title = _('Reporting Period Consumption') + ' - ' \
428
                    + reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
429
                labels = Reference(ws, min_col=2,
430
                                   min_row=table_start_row_number + 1,
431
                                   max_row=table_end_row_number)
432
                reporting_line_data = Reference(ws, min_col=3 + i,
433
                                                min_row=table_start_row_number,
434
                                                max_row=table_end_row_number)
435
                line.add_data(reporting_line_data, titles_from_data=True)
436
                line.set_categories(labels)
437
                reporting_line_data = line.series[0]
438
                reporting_line_data.marker.symbol = "circle"
439
                reporting_line_data.smooth = True
440
                line.x_axis.crosses = 'min'
441
                line.height = 8.25
442
                line.width = 24
443
                line.dLbls = DataLabelList()
444
                line.dLbls.dLblPos = 't'
445
                line.dLbls.showVal = True
446
                line.dLbls.showPercent = False
447
                chart_col = 'B'
448
                chart_cell = chart_col + str(chart_start_row_number)
449
                chart_start_row_number += 6
450
                ws.add_chart(line, chart_cell)
451
452
    else:
453
        if has_values_data and has_timestamps_data:
454
            base_period_data = report['base_period']
455
            reporting_period_data = report['reporting_period']
456
            base_period_timestamps = base_period_data['timestamps']
457
            reporting_period_timestamps = reporting_period_data['timestamps']
458
            # Tip:
459
            #     base_period_data['names'] == reporting_period_data['names']
460
            #     base_period_data['units'] == reporting_period_data['units']
461
            base_period_data_ca_len = len(base_period_data['names'])
462
            reporting_period_data_ca_len = len(reporting_period_data['names'])
463
            real_timestamps_len = timestamps_data_not_equal_0(report['parameters']['timestamps'])
464
            ws['B' + str(current_row_number)].font = title_font
465
            ws['B' + str(current_row_number)] = name + ' ' + _('Detailed Data')
466
            current_row_number += 1
467
468
            chart_start_row_number = current_row_number
469
470
            # 1: Stand for blank line  2: Stand for title
471
            current_row_number += reporting_period_data_ca_len * 6 + real_timestamps_len * 6 + 1 + 2
472
            table_start_row_number = current_row_number
473
474
            ws.row_dimensions[current_row_number].height = 60
475
            current_col_number = 2
476
            col = format_cell.get_column_letter(current_col_number)
477
            ws[col + str(current_row_number)].fill = table_fill
478
            ws[col + str(current_row_number)].font = title_font
479
            ws[col + str(current_row_number)].alignment = c_c_alignment
480
            ws[col + str(current_row_number)].border = f_border
481
            ws[col + str(current_row_number)] = _('Base Period') + " - " + _('Datetime')
482
483
            for i in range(0, base_period_data_ca_len):
484
                current_col_number += 1
485
                col = format_cell.get_column_letter(current_col_number)
486
487
                ws[col + str(current_row_number)].fill = table_fill
488
                ws[col + str(current_row_number)].font = title_font
489
                ws[col + str(current_row_number)].alignment = c_c_alignment
490
                ws[col + str(current_row_number)] = _('Base Period') + " - " + base_period_data['names'][i] + \
491
                    " (" + base_period_data['units'][i] + ")"
492
                ws[col + str(current_row_number)].border = f_border
493
494
            current_col_number += 1
495
            col = format_cell.get_column_letter(current_col_number)
496
497
            ws[col + str(current_row_number)].fill = table_fill
498
            ws[col + str(current_row_number)].font = title_font
499
            ws[col + str(current_row_number)].border = f_border
500
            ws[col + str(current_row_number)].alignment = c_c_alignment
501
            ws[col + str(current_row_number)] = _('Reporting Period') + " - " + _('Datetime')
502
503
            for i in range(0, reporting_period_data_ca_len):
504
                current_col_number += 1
505
                col = format_cell.get_column_letter(current_col_number)
506
                ws[col + str(current_row_number)].fill = table_fill
507
                ws[col + str(current_row_number)].font = title_font
508
                ws[col + str(current_row_number)].alignment = c_c_alignment
509
                ws[col + str(current_row_number)] = _('Reporting Period') + " - " \
510
                    + reporting_period_data['names'][i] + " (" + \
511
                    reporting_period_data['units'][i] + ")"
512
                ws[col + str(current_row_number)].border = f_border
513
514
            current_row_number += 1
515
516
            max_timestamps_len = len(base_period_timestamps[0]) \
517
                if len(base_period_timestamps[0]) >= len(reporting_period_timestamps[0]) \
518
                else len(reporting_period_timestamps[0])
519
520
            for i in range(0, max_timestamps_len):
521
                current_col_number = 2
522
                col = format_cell.get_column_letter(current_col_number)
523
                ws[col + str(current_row_number)].font = title_font
524
                ws[col + str(current_row_number)].alignment = c_c_alignment
525
                ws[col + str(current_row_number)] = base_period_timestamps[0][i] \
526
                    if i < len(base_period_timestamps[0]) else None
527
                ws[col + str(current_row_number)].border = f_border
528
529
                for j in range(0, base_period_data_ca_len):
530
                    current_col_number += 1
531
                    col = format_cell.get_column_letter(current_col_number)
532
533
                    ws[col + str(current_row_number)].font = title_font
534
                    ws[col + str(current_row_number)].alignment = c_c_alignment
535
                    ws[col + str(current_row_number)] = round(base_period_data['values'][j][i], 2) \
536
                        if i < len(base_period_data['values'][j]) else None
537
                    ws[col + str(current_row_number)].border = f_border
538
                current_col_number += 1
539
                col = format_cell.get_column_letter(current_col_number)
540
541
                ws[col + str(current_row_number)].font = title_font
542
                ws[col + str(current_row_number)].alignment = c_c_alignment
543
                ws[col + str(current_row_number)] = reporting_period_timestamps[0][i] \
544
                    if i < len(reporting_period_timestamps[0]) else None
545
                ws[col + str(current_row_number)].border = f_border
546
547
                for j in range(0, reporting_period_data_ca_len):
548
                    current_col_number += 1
549
                    col = format_cell.get_column_letter(current_col_number)
550
551
                    ws[col + str(current_row_number)].font = title_font
552
                    ws[col + str(current_row_number)].alignment = c_c_alignment
553
                    ws[col + str(current_row_number)] = round(reporting_period_data['values'][j][i], 2) \
554
                        if i < len(reporting_period_data['values'][j]) else None
555
                    ws[col + str(current_row_number)].border = f_border
556
557
                current_row_number += 1
558
559
            current_col_number = 2
560
            col = format_cell.get_column_letter(current_col_number)
561
562
            ws[col + str(current_row_number)].font = title_font
563
            ws[col + str(current_row_number)].alignment = c_c_alignment
564
            ws[col + str(current_row_number)] = _('Subtotal')
565
            ws[col + str(current_row_number)].border = f_border
566
567
            for i in range(0, base_period_data_ca_len):
568
                current_col_number += 1
569
                col = format_cell.get_column_letter(current_col_number)
570
                ws[col + str(current_row_number)].font = title_font
571
                ws[col + str(current_row_number)].alignment = c_c_alignment
572
                ws[col + str(current_row_number)] = round(base_period_data['subtotals'][i], 2)
573
                ws[col + str(current_row_number)].border = f_border
574
575
            current_col_number += 1
576
            col = format_cell.get_column_letter(current_col_number)
577
578
            ws[col + str(current_row_number)].font = title_font
579
            ws[col + str(current_row_number)].alignment = c_c_alignment
580
            ws[col + str(current_row_number)] = _('Subtotal')
581
            ws[col + str(current_row_number)].border = f_border
582
583
            for i in range(0, reporting_period_data_ca_len):
584
                current_col_number += 1
585
                col = format_cell.get_column_letter(current_col_number)
586
                ws[col + str(current_row_number)].font = title_font
587
                ws[col + str(current_row_number)].alignment = c_c_alignment
588
                ws[col + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
589
                ws[col + str(current_row_number)].border = f_border
590
591
            current_row_number += 2
592
593
            for i in range(0, reporting_period_data_ca_len):
594
                line = LineChart()
595
                line.title = _('Base Period Consumption') + ' / ' \
596
                    + _('Reporting Period Consumption') + ' - '  \
597
                    + reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
598
                labels = Reference(ws, min_col=2 + base_period_data_ca_len + 1,
599
                                   min_row=table_start_row_number + 1,
600
                                   max_row=table_start_row_number + len(reporting_period_timestamps[0]))
601
                base_line_data = Reference(ws, min_col=3 + i,
602
                                           min_row=table_start_row_number,
603
                                           max_row=table_start_row_number + len(reporting_period_timestamps[0]))
604
                reporting_line_data = Reference(ws, min_col=3 + base_period_data_ca_len + 1 + i,
605
                                                min_row=table_start_row_number,
606
                                                max_row=table_start_row_number + len(reporting_period_timestamps[0]))
607
                line.add_data(base_line_data, titles_from_data=True)
608
                line.add_data(reporting_line_data, titles_from_data=True)
609
                line.set_categories(labels)
610
                for j in range(len(line.series)):
611
                    line.series[j].marker.symbol = "circle"
612
                    line.series[j].smooth = True
613
                line.x_axis.crosses = 'min'
614
                line.height = 8.25
615
                line.width = 24
616
                line.dLbls = DataLabelList()
617
                line.dLbls.dLblPos = 't'
618
                line.dLbls.showVal = True
619
                line.dLbls.showPercent = False
620
                chart_col = 'B'
621
                chart_cell = chart_col + str(chart_start_row_number)
622
                chart_start_row_number += 6
623
                ws.add_chart(line, chart_cell)
624
625
    ####################################################################################################################
626
    current_sheet_parameters_row_number = chart_start_row_number + 1
627
    if 'parameters' not in report.keys() or \
628
            report['parameters'] is None or \
629
            'names' not in report['parameters'].keys() or \
630
            report['parameters']['names'] is None or \
631
            len(report['parameters']['names']) == 0 or \
632
            'timestamps' not in report['parameters'].keys() or \
633
            report['parameters']['timestamps'] is None or \
634
            len(report['parameters']['timestamps']) == 0 or \
635
            'values' not in report['parameters'].keys() or \
636
            report['parameters']['values'] is None or \
637
            len(report['parameters']['values']) == 0 or \
638
            timestamps_data_all_equal_0(report['parameters']['timestamps']):
639
        pass
640
    else:
641
        ################################################################################################################
642
        # new worksheet
643
        ################################################################################################################
644
645
        parameters_data = report['parameters']
646
647
        parameters_names_len = len(parameters_data['names'])
648
649
        file_name = "Store"+re.sub(r'[^A-Z]', '', ws.title.strip('S')) + "_"
650
        parameters_ws = wb.create_sheet(file_name + _('Parameters'))
651
652
        parameters_timestamps_data_max_len = \
653
            get_parameters_timestamps_lists_max_len(list(parameters_data['timestamps']))
654
655
        # Row height
656
        parameters_ws.row_dimensions[1].height = 102
657
        for i in range(2, 7 + 1):
658
            parameters_ws.row_dimensions[i].height = 42
659
660
        for i in range(8, parameters_timestamps_data_max_len + 10):
661
            parameters_ws.row_dimensions[i].height = 60
662
663
        # Col width
664
        parameters_ws.column_dimensions['A'].width = 1.5
665
666
        parameters_ws.column_dimensions['B'].width = 25.0
667
668
        for i in range(3, 12 + parameters_names_len * 3):
669
            parameters_ws.column_dimensions[format_cell.get_column_letter(i)].width = 15.0
670
671
        # Img
672
        img = Image("excelexporters/myems.png")
673
        parameters_ws.add_image(img, 'A1')
674
675
        # Title
676
        parameters_ws['B3'].alignment = b_r_alignment
677
        parameters_ws['B3'] = _('Name') + ':'
678
        parameters_ws['C3'].border = b_border
679
        parameters_ws['C3'].alignment = b_c_alignment
680
        parameters_ws['C3'] = name
681
682
        parameters_ws['D3'].alignment = b_r_alignment
683
        parameters_ws['D3'] = _('Period Type') + ':'
684
        parameters_ws['E3'].border = b_border
685
        parameters_ws['E3'].alignment = b_c_alignment
686
        parameters_ws['E3'] = period_type
687
688
        parameters_ws['B4'].alignment = b_r_alignment
689
        parameters_ws['B4'] = _('Reporting Start Datetime') + ':'
690
        parameters_ws['C4'].border = b_border
691
        parameters_ws['C4'].alignment = b_c_alignment
692
        parameters_ws['C4'] = reporting_start_datetime_local
693
694
        parameters_ws['D4'].alignment = b_r_alignment
695
        parameters_ws['D4'] = _('Reporting End Datetime') + ':'
696
        parameters_ws['E4'].border = b_border
697
        parameters_ws['E4'].alignment = b_c_alignment
698
        parameters_ws['E4'] = reporting_end_datetime_local
699
700
        parameters_ws_current_row_number = 6
701
702
        parameters_ws['B' + str(parameters_ws_current_row_number)].font = title_font
703
        parameters_ws['B' + str(parameters_ws_current_row_number)] = name + ' ' + _('Parameters')
704
705
        parameters_ws_current_row_number += 1
706
707
        parameters_table_start_row_number = parameters_ws_current_row_number
708
709
        parameters_ws.row_dimensions[parameters_ws_current_row_number].height = 80
710
711
        parameters_ws_current_row_number += 1
712
713
        table_current_col_number = 2
714
715
        for i in range(0, parameters_names_len):
716
717
            if len(parameters_data['timestamps'][i]) == 0:
718
                continue
719
720
            col = format_cell.get_column_letter(table_current_col_number)
721
722
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
723
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
724
725
            col = format_cell.get_column_letter(table_current_col_number + 1)
726
727
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
728
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
729
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].font = name_font
730
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].alignment = c_c_alignment
731
            parameters_ws[col + str(parameters_ws_current_row_number - 1)] = parameters_data['names'][i]
732
733
            table_current_row_number = parameters_ws_current_row_number
734
735
            for j, value in enumerate(list(parameters_data['timestamps'][i])):
736
                col = format_cell.get_column_letter(table_current_col_number)
737
738
                parameters_ws[col + str(table_current_row_number)].border = f_border
739
                parameters_ws[col + str(table_current_row_number)].font = title_font
740
                parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
741
                parameters_ws[col + str(table_current_row_number)] = value
742
743
                col = format_cell.get_column_letter(table_current_col_number + 1)
744
745
                parameters_ws[col + str(table_current_row_number)].border = f_border
746
                parameters_ws[col + str(table_current_row_number)].font = title_font
747
                parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
748
                parameters_ws[col + str(table_current_row_number)] = round(parameters_data['values'][i][j], 2)
749
750
                table_current_row_number += 1
751
752
            table_current_col_number = table_current_col_number + 3
753
754
        ################################################################################################################
755
        # parameters chart and parameters table
756
        ################################################################################################################
757
758
        ws['B' + str(current_sheet_parameters_row_number)].font = title_font
759
        ws['B' + str(current_sheet_parameters_row_number)] = name + ' ' + _('Parameters')
760
761
        current_sheet_parameters_row_number += 1
762
763
        chart_start_row_number = current_sheet_parameters_row_number
764
765
        col_index = 0
766
767
        for i in range(0, parameters_names_len):
768
769
            if len(parameters_data['timestamps'][i]) == 0:
770
                continue
771
772
            line = LineChart()
773
            data_col = 3 + col_index * 3
774
            labels_col = 2 + col_index * 3
775
            col_index += 1
776
            line.title = _('Parameters') + ' - ' + \
777
                parameters_ws.cell(row=parameters_table_start_row_number, column=data_col).value
778
            labels = Reference(parameters_ws, min_col=labels_col, min_row=parameters_table_start_row_number + 1,
779
                               max_row=(len(parameters_data['timestamps'][i]) + parameters_table_start_row_number))
780
            line_data = Reference(parameters_ws, min_col=data_col, min_row=parameters_table_start_row_number,
781
                                  max_row=(len(parameters_data['timestamps'][i]) + parameters_table_start_row_number))
782
            line.add_data(line_data, titles_from_data=True)
783
            line.set_categories(labels)
784
            line_data = line.series[0]
785
            line_data.marker.symbol = "circle"
786
            line_data.smooth = True
787
            line.x_axis.crosses = 'min'
788
            line.height = 8.25
789
            line.width = 24
790
            line.dLbls = DataLabelList()
791
            line.dLbls.dLblPos = 't'
792
            line.dLbls.showVal = False
793
            line.dLbls.showPercent = False
794
            chart_col = 'B'
795
            chart_cell = chart_col + str(chart_start_row_number)
796
            chart_start_row_number += 6
797
            ws.add_chart(line, chart_cell)
798
799
        current_sheet_parameters_row_number = chart_start_row_number
800
801
        current_sheet_parameters_row_number += 1
802
803
    filename = str(uuid.uuid4()) + '.xlsx'
804
    wb.save(filename)
805
806
    return filename
807
808
809
def group_by_category(category_list):
810
    category_dict = dict()
811
    for i, value in enumerate(category_list):
812
        if value not in category_dict.keys():
813
            category_dict[value] = list()
814
        category_dict[value].append(i)
815
    return category_dict
816
817
818
def get_parameters_timestamps_lists_max_len(parameters_timestamps_lists):
819
    max_len = 0
820
    for i, value in enumerate(list(parameters_timestamps_lists)):
821
        if len(value) > max_len:
822
            max_len = len(value)
823
824
    return max_len
825
826
827
def timestamps_data_all_equal_0(lists):
828
    for i, value in enumerate(list(lists)):
829
        if len(value) > 0:
830
            return False
831
832
    return True
833
834
835
def timestamps_data_not_equal_0(lists):
836
    number = 0
837
    for i, value in enumerate(list(lists)):
838
        if len(value) > 0:
839
            number += 1
840
    return number
841
842
843 View Code Duplication
def is_base_period_timestamp_exists(base_period_data):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
844
    timestamps = base_period_data['timestamps']
845
846
    if len(timestamps) == 0:
847
        return False
848
849
    for timestamp in timestamps:
850
        if len(timestamp) > 0:
851
            return True
852
853
    return False
854