Passed
Push — master ( 02289f...d6a19b )
by Guangyu
08:58 queued 15s
created

excelexporters.spaceincome   F

Complexity

Total Complexity 110

Size/Duplication

Total Lines 1070
Duplicated Lines 5.33 %

Importance

Changes 0
Metric Value
wmc 110
eloc 812
dl 57
loc 1070
rs 1.788
c 0
b 0
f 0

7 Functions

Rating   Name   Duplication   Size   Complexity  
F generate_excel() 0 952 90
B export() 46 46 5
A timestamps_data_all_equal_0() 0 6 3
A get_parameters_timestamps_lists_max_len() 0 7 3
A timestamps_data_not_equal_0() 0 6 3
A reporting_period_values_periodic_sum() 0 6 2
A is_base_period_timestamp_exists() 11 11 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like excelexporters.spaceincome 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.

1
import base64
2
import gettext
3
import os
4
import re
5
import uuid
6
from decimal import Decimal
7
8
import openpyxl.utils.cell as format_cell
9
from openpyxl import Workbook
10
from openpyxl.chart import PieChart, LineChart, Reference
11
from openpyxl.chart.label import DataLabelList
12
from openpyxl.drawing.image import Image
13
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
14
15
16
####################################################################################################################
17
# PROCEDURES
18
# Step 1: Validate the report data
19
# Step 2: Generate excel file
20
# Step 3: Encode the excel file to Base64
21
####################################################################################################################
22
23
24 View Code Duplication
def export(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
25
           name,
26
           base_period_start_datetime_local,
27
           base_period_end_datetime_local,
28
           reporting_start_datetime_local,
29
           reporting_end_datetime_local,
30
           period_type,
31
           language):
32
    ####################################################################################################################
33
    # Step 1: Validate the report data
34
    ####################################################################################################################
35
    if report is None:
36
        return None
37
    print(report)
38
39
    ####################################################################################################################
40
    # Step 2: Generate excel file from the report data
41
    ####################################################################################################################
42
    filename = generate_excel(report,
43
                              name,
44
                              base_period_start_datetime_local,
45
                              base_period_end_datetime_local,
46
                              reporting_start_datetime_local,
47
                              reporting_end_datetime_local,
48
                              period_type,
49
                              language)
50
    ####################################################################################################################
51
    # Step 3: Encode the excel file to Base64
52
    ####################################################################################################################
53
    binary_file_data = b''
54
    try:
55
        with open(filename, 'rb') as binary_file:
56
            binary_file_data = binary_file.read()
57
    except IOError as ex:
58
        print(str(ex))
59
60
    # Base64 encode the bytes
61
    base64_encoded_data = base64.b64encode(binary_file_data)
62
    # get the Base64 encoded data using human-readable characters.
63
    base64_message = base64_encoded_data.decode('utf-8')
64
    # delete the file from server
65
    try:
66
        os.remove(filename)
67
    except NotImplementedError as ex:
68
        print(str(ex))
69
    return base64_message
70
71
72
def generate_excel(report,
73
                   name,
74
                   base_period_start_datetime_local,
75
                   base_period_end_datetime_local,
76
                   reporting_start_datetime_local,
77
                   reporting_end_datetime_local,
78
                   period_type,
79
                   language):
80
    locale_path = './i18n/'
81
    if language == 'zh_CN':
82
        trans = gettext.translation('myems', locale_path, languages=['zh_CN'])
83
    elif language == 'de':
84
        trans = gettext.translation('myems', locale_path, languages=['de'])
85
    elif language == 'en':
86
        trans = gettext.translation('myems', locale_path, languages=['en'])
87
    else:
88
        trans = gettext.translation('myems', locale_path, languages=['en'])
89
    trans.install()
90
    _ = trans.gettext
91
    wb = Workbook()
92
    ws = wb.active
93
    ws.title = "SpaceIncome"
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
141
    # Img
142
    img = Image("excelexporters/myems.png")
143
    ws.add_image(img, 'A1')
144
145
    # Title
146
    ws['B3'].alignment = b_r_alignment
147
    ws['B3'] = _('Name') + ':'
148
    ws['C3'].border = b_border
149
    ws['C3'].alignment = b_c_alignment
150
    ws['C3'] = name
151
152
    ws['D3'].alignment = b_r_alignment
153
    ws['D3'] = _('Period Type') + ':'
154
    ws['E3'].border = b_border
155
    ws['E3'].alignment = b_c_alignment
156
    ws['E3'] = period_type
157
158
    ws['B4'].alignment = b_r_alignment
159
    ws['B4'] = _('Reporting Start Datetime') + ':'
160
    ws['C4'].border = b_border
161
    ws['C4'].alignment = b_c_alignment
162
    ws['C4'] = reporting_start_datetime_local
163
164
    ws['D4'].alignment = b_r_alignment
165
    ws['D4'] = _('Reporting End Datetime') + ':'
166
    ws['E4'].border = b_border
167
    ws['E4'].alignment = b_c_alignment
168
    ws['E4'] = reporting_end_datetime_local
169
170
    is_base_period_timestamp_exists_flag = is_base_period_timestamp_exists(report['base_period'])
171
172
    if is_base_period_timestamp_exists_flag:
173
        ws['B5'].alignment = b_r_alignment
174
        ws['B5'] = _('Base Period Start Datetime') + ':'
175
        ws['C5'].border = b_border
176
        ws['C5'].alignment = b_c_alignment
177
        ws['C5'] = base_period_start_datetime_local
178
179
        ws['D5'].alignment = b_r_alignment
180
        ws['D5'] = _('Base Period End Datetime') + ':'
181
        ws['E5'].border = b_border
182
        ws['E5'].alignment = b_c_alignment
183
        ws['E5'] = base_period_end_datetime_local
184
185
    if "reporting_period" not in report.keys() or \
186
            "names" not in report['reporting_period'].keys() or len(report['reporting_period']['names']) == 0:
187
        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...
188
        wb.save(filename)
189
190
        return filename
191
192
    ####################################################################################################################
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
        for i in range(7, 10 + 1):
198
            ws.row_dimensions[i].height = 0.1
199
    else:
200
        ws['B7'].font = title_font
201
        ws['B7'] = name + ' ' + _('Reporting Period Income')
202
        category = reporting_period_data['names']
203
        ca_len = len(category)
204
205
        ws.row_dimensions[7].height = 60
206
        ws['B8'].fill = table_fill
207
        ws['B8'].border = f_border
208
209
        ws['B9'].font = title_font
210
        ws['B9'].alignment = c_c_alignment
211
        ws['B9'] = _('Total')
212
        ws['B9'].border = f_border
213
214
        ws['B10'].font = title_font
215
        ws['B10'].alignment = c_c_alignment
216
        ws['B10'] = _('Per Unit Area')
217
        ws['B10'].border = f_border
218
219
        ws['B11'].font = title_font
220
        ws['B11'].alignment = c_c_alignment
221
        ws['B11'] = _('Increment Rate')
222
        ws['B11'].border = f_border
223
224
        col = ''
225
226
        for i in range(0, ca_len):
227
            col = chr(ord('C') + i)
228
229
            ws[col + '8'].fill = table_fill
230
            ws[col + '8'].font = name_font
231
            ws[col + '8'].alignment = c_c_alignment
232
            ws[col + '8'] = reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
233
            ws[col + '8'].border = f_border
234
235
            ws[col + '9'].font = name_font
236
            ws[col + '9'].alignment = c_c_alignment
237
            ws[col + '9'] = round(reporting_period_data['subtotals'][i], 2)
238
            ws[col + '9'].border = f_border
239
240
            ws[col + '10'].font = name_font
241
            ws[col + '10'].alignment = c_c_alignment
242
            ws[col + '10'] = round(reporting_period_data['subtotals_per_unit_area'][i], 2) \
243
                if reporting_period_data['subtotals_per_unit_area'][i] is not None else ''
244
            ws[col + '10'].border = f_border
245
246
            ws[col + '11'].font = name_font
247
            ws[col + '11'].alignment = c_c_alignment
248
            ws[col + '11'] = str(round(reporting_period_data['increment_rates'][i] * 100, 2)) + "%" \
249
                if reporting_period_data['increment_rates'][i] is not None else "-"
250
            ws[col + '11'].border = f_border
251
252
        col = chr(ord(col) + 1)
253
254
        ws[col + '8'].fill = table_fill
255
        ws[col + '8'].font = name_font
256
        ws[col + '8'].alignment = c_c_alignment
257
        ws[col + '8'] = _("Total") + " (" + reporting_period_data['total_unit'] + ")"
258
        ws[col + '8'].border = f_border
259
260
        ws[col + '9'].font = name_font
261
        ws[col + '9'].alignment = c_c_alignment
262
        ws[col + '9'] = round(reporting_period_data['total'], 2)
263
        ws[col + '9'].border = f_border
264
265
        ws[col + '10'].font = name_font
266
        ws[col + '10'].alignment = c_c_alignment
267
        ws[col + '10'] = round(reporting_period_data['total_per_unit_area'], 2) \
268
            if reporting_period_data['total_per_unit_area'] is not None else ''
269
        ws[col + '10'].border = f_border
270
271
        ws[col + '11'].font = name_font
272
        ws[col + '11'].alignment = c_c_alignment
273
        ws[col + '11'] = str(round(reporting_period_data['total_increment_rate'] * 100, 2)) + "%" \
274
            if reporting_period_data['total_increment_rate'] is not None else "-"
275
        ws[col + '11'].border = f_border
276
277
    ####################################################################################################################
278
    current_row_number = 13
279
    if "subtotals" not in reporting_period_data.keys() or \
280
            reporting_period_data['subtotals'] is None or \
281
            len(reporting_period_data['subtotals']) == 0:
282
        pass
283
    else:
284
        ws['B' + str(current_row_number)].font = title_font
285
        ws['B' + str(current_row_number)] = name + ' ' + _('Incomes by Energy Category')
286
287
        current_row_number += 1
288
289
        table_start_row_number = current_row_number
290
291
        ws['B' + str(current_row_number)].fill = table_fill
292
        ws['B' + str(current_row_number)].font = name_font
293
        ws['B' + str(current_row_number)].alignment = c_c_alignment
294
        ws['B' + str(current_row_number)].border = f_border
295
296
        ws['C' + str(current_row_number)].fill = table_fill
297
        ws['C' + str(current_row_number)].font = name_font
298
        ws['C' + str(current_row_number)].alignment = c_c_alignment
299
        ws['C' + str(current_row_number)].border = f_border
300
        ws['C' + str(current_row_number)] = _('Incomes')
301
302
        ws['D' + str(current_row_number)].fill = table_fill
303
        ws['D' + str(current_row_number)].font = name_font
304
        ws['D' + str(current_row_number)].alignment = c_c_alignment
305
        ws['D' + str(current_row_number)].border = f_border
306
        ws['D' + str(current_row_number)] = _('Proportion')
307
308
        current_row_number += 1
309
310
        ca_len = len(reporting_period_data['names'])
311
        total = Decimal(0.0)
312
        for i in range(0, ca_len):
313
            total = reporting_period_data['subtotals'][i] + total
314
315
        for i in range(0, ca_len):
316
            ws['B' + str(current_row_number)].font = title_font
317
            ws['B' + str(current_row_number)].alignment = c_c_alignment
318
            ws['B' + str(current_row_number)] = reporting_period_data['names'][i]
319
            ws['B' + str(current_row_number)].border = f_border
320
321
            ws['C' + str(current_row_number)].font = title_font
322
            ws['C' + str(current_row_number)].alignment = c_c_alignment
323
            ws['C' + str(current_row_number)].border = f_border
324
            ws['C' + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
325
326
            ws['D' + str(current_row_number)].font = title_font
327
            ws['D' + str(current_row_number)].alignment = c_c_alignment
328
            ws['D' + str(current_row_number)].border = f_border
329
            ws['D' + str(current_row_number)] = '{:.2%}'.format(reporting_period_data['subtotals'][i] / total) \
330
                if total > Decimal(0.0) else '-'
331
332
            current_row_number += 1
333
334
        table_end_row_number = current_row_number - 1
335
336
        pie = PieChart()
337
        pie.title = name + ' ' + _('Incomes by Energy Category')
338
        labels = Reference(ws, min_col=2, min_row=table_start_row_number + 1, max_row=table_end_row_number)
339
        pie_data = Reference(ws, min_col=3, min_row=table_start_row_number, max_row=table_end_row_number)
340
        pie.add_data(pie_data, titles_from_data=True)
341
        pie.set_categories(labels)
342
        pie.height = 6.6
343
        pie.width = 9
344
        s1 = pie.series[0]
345
        s1.dLbls = DataLabelList()
346
        s1.dLbls.showCatName = False
347
        s1.dLbls.showVal = True
348
        s1.dLbls.showPercent = True
349
        table_cell = 'E' + str(table_start_row_number)
350
        ws.add_chart(pie, table_cell)
351
352
        if ca_len < 4:
353
            current_row_number = current_row_number - ca_len + 4
354
355
        current_row_number += 1
356
357
    ####################################################################################################################
358
    table_start_draw_flag = current_row_number + 1
359
360
    if "timestamps" not in reporting_period_data.keys() or \
361
            reporting_period_data['timestamps'] is None or \
362
            len(reporting_period_data['timestamps']) == 0:
363
        pass
364
    else:
365
        if not is_base_period_timestamp_exists_flag:
366
            reporting_period_data = report['reporting_period']
367
            times = reporting_period_data['timestamps']
368
            ca_len = len(report['reporting_period']['names'])
369
            real_timestamps_len = timestamps_data_not_equal_0(report['parameters']['timestamps'])
370
            ws['B' + str(current_row_number)].font = title_font
371
            ws['B' + str(current_row_number)] = name + ' ' + _('Detailed Data')
372
373
            current_row_number += 1
374
            # 1: Stand for blank line  2: Stand for title
375
            current_row_number += ca_len * 6 + real_timestamps_len * 6 + 1 + 2
376
            table_start_row_number = current_row_number
377
378
            time = times[0]
379
            has_data = False
380
381
            if len(time) > 0:
382
                has_data = True
383
384
            if has_data:
385
386
                ws.row_dimensions[current_row_number].height = 60
387
                current_col_number = 2
388
                col = format_cell.get_column_letter(current_col_number)
389
                ws[col + str(current_row_number)].fill = table_fill
390
                ws[col + str(current_row_number)].font = title_font
391
                ws[col + str(current_row_number)].border = f_border
392
                ws[col + str(current_row_number)].alignment = c_c_alignment
393
                ws[col + str(current_row_number)] = _('Datetime')
394
395
                for i in range(0, ca_len):
396
                    current_col_number += 1
397
                    col = format_cell.get_column_letter(current_col_number)
398
399
                    ws[col + str(current_row_number)].fill = table_fill
400
                    ws[col + str(current_row_number)].font = title_font
401
                    ws[col + str(current_row_number)].alignment = c_c_alignment
402
                    ws[col + str(current_row_number)] = reporting_period_data['names'][i] + \
403
                        " (" + reporting_period_data['units'][i] + ")"
404
                    ws[col + str(current_row_number)].border = f_border
405
406
                current_col_number += 1
407
                col = format_cell.get_column_letter(current_col_number)
408
                ws[col + str(current_row_number)].fill = table_fill
409
                ws[col + str(current_row_number)].font = title_font
410
                ws[col + str(current_row_number)].alignment = c_c_alignment
411
                ws[col + str(current_row_number)] = _('Total') + '(' + report['reporting_period']['total_unit'] + ')'
412
                ws[col + str(current_row_number)].border = f_border
413
414
                current_row_number += 1
415
416
                for i in range(0, len(time)):
417
                    current_col_number = 2
418
                    col = format_cell.get_column_letter(current_col_number)
419
420
                    ws[col + str(current_row_number)].font = title_font
421
                    ws[col + str(current_row_number)].alignment = c_c_alignment
422
                    ws[col + str(current_row_number)] = time[i]
423
                    ws[col + str(current_row_number)].border = f_border
424
425
                    total = Decimal(0.0)
426
427
                    for j in range(0, ca_len):
428
                        current_col_number += 1
429
                        col = format_cell.get_column_letter(current_col_number)
430
431
                        ws[col + str(current_row_number)].font = title_font
432
                        ws[col + str(current_row_number)].alignment = c_c_alignment
433
                        ws[col + str(current_row_number)] = round(reporting_period_data['values'][j][i], 2)
434
                        total += reporting_period_data['values'][j][i]
435
                        ws[col + str(current_row_number)].border = f_border
436
437
                    current_col_number += 1
438
                    col = format_cell.get_column_letter(current_col_number)
439
                    ws[col + str(current_row_number)].font = title_font
440
                    ws[col + str(current_row_number)].alignment = c_c_alignment
441
                    ws[col + str(current_row_number)] = round(total, 2)
442
                    ws[col + str(current_row_number)].border = f_border
443
444
                    current_row_number += 1
445
446
                table_end_row_number = current_row_number - 1
447
448
                current_col_number = 2
449
                col = format_cell.get_column_letter(current_col_number)
450
451
                ws[col + str(current_row_number)].font = title_font
452
                ws[col + str(current_row_number)].alignment = c_c_alignment
453
                ws[col + str(current_row_number)] = _('Subtotal')
454
                ws[col + str(current_row_number)].border = f_border
455
456
                subtotals = Decimal(0.0)
457
458
                for i in range(0, ca_len):
459
                    current_col_number += 1
460
                    col = format_cell.get_column_letter(current_col_number)
461
                    ws[col + str(current_row_number)].font = title_font
462
                    ws[col + str(current_row_number)].alignment = c_c_alignment
463
                    ws[col + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
464
                    subtotals += reporting_period_data['subtotals'][i]
465
                    ws[col + str(current_row_number)].border = f_border
466
467
                    # line
468
                    line = LineChart()
469
                    line.title = _('Reporting Period Income') + ' - ' \
470
                        + reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
471
                    labels = Reference(ws, min_col=2, min_row=table_start_row_number + 1, max_row=table_end_row_number)
472
                    line_data = Reference(ws, min_col=3 + i, min_row=table_start_row_number,
473
                                          max_row=table_end_row_number)
474
                    line.add_data(line_data, titles_from_data=True)
475
                    line.set_categories(labels)
476
                    line_data = line.series[0]
477
                    line_data.marker.symbol = "circle"
478
                    line_data.smooth = True
479
                    line.x_axis.crosses = 'min'
480
                    line.height = 8.25
481
                    line.width = 24
482
                    line.dLbls = DataLabelList()
483
                    line.dLbls.dLblPos = 't'
484
                    line.dLbls.showVal = True
485
                    line.dLbls.showPercent = False
486
                    chart_col = 'B'
487
                    chart_cell = chart_col + str(table_start_draw_flag + 6 * i)
488
                    ws.add_chart(line, chart_cell)
489
490
                current_col_number += 1
491
                col = format_cell.get_column_letter(current_col_number)
492
                ws[col + str(current_row_number)].font = title_font
493
                ws[col + str(current_row_number)].alignment = c_c_alignment
494
                ws[col + str(current_row_number)] = round(subtotals, 2)
495
                ws[col + str(current_row_number)].border = f_border
496
497
                current_row_number += 2
498
        else:
499
            base_period_data = report['base_period']
500
            reporting_period_data = report['reporting_period']
501
            base_period_timestamps = base_period_data['timestamps']
502
            reporting_period_timestamps = reporting_period_data['timestamps']
503
            # Tip:
504
            #     base_period_data['names'] == reporting_period_data['names']
505
            #     base_period_data['units'] == reporting_period_data['units']
506
            base_period_data_ca_len = len(base_period_data['names'])
507
            reporting_period_data_ca_len = len(reporting_period_data['names'])
508
            real_timestamps_len = timestamps_data_not_equal_0(report['parameters']['timestamps'])
509
            ws['B' + str(current_row_number)].font = title_font
510
            ws['B' + str(current_row_number)] = name + ' ' + _('Detailed Data')
511
512
            current_row_number += 1
513
            # 1: Stand for blank line  2: Stand for title
514
            current_row_number += reporting_period_data_ca_len * 6 + real_timestamps_len * 6 + 1 + 2
515
            table_start_row_number = current_row_number
516
517
            has_data = False
518
519
            if len(base_period_timestamps[0]) or len(reporting_period_timestamps[0]) > 0:
520
                has_data = True
521
522
            if has_data:
523
                ws.row_dimensions[current_row_number].height = 60
524
                current_col_number = 2
525
                col = format_cell.get_column_letter(current_col_number)
526
                ws[col + str(current_row_number)].fill = table_fill
527
                ws[col + str(current_row_number)].font = title_font
528
                ws[col + str(current_row_number)].border = f_border
529
                ws[col + str(current_row_number)].alignment = c_c_alignment
530
                ws[col + str(current_row_number)] = _('Base Period') + " - " + _('Datetime')
531
532
                for i in range(0, base_period_data_ca_len):
533
                    current_col_number += 1
534
                    col = format_cell.get_column_letter(current_col_number)
535
536
                    ws[col + str(current_row_number)].fill = table_fill
537
                    ws[col + str(current_row_number)].font = title_font
538
                    ws[col + str(current_row_number)].alignment = c_c_alignment
539
                    ws[col + str(current_row_number)] = _('Base Period') + " - " + base_period_data['names'][i] + \
540
                        " (" + base_period_data['units'][i] + ")"
541
                    ws[col + str(current_row_number)].border = f_border
542
543
                current_col_number += 1
544
                col = format_cell.get_column_letter(current_col_number)
545
                ws[col + str(current_row_number)].fill = table_fill
546
                ws[col + str(current_row_number)].font = title_font
547
                ws[col + str(current_row_number)].alignment = c_c_alignment
548
                ws[col + str(current_row_number)] = _('Base Period') + " - " \
549
                    + _('Total') + '(' + report['reporting_period']['total_unit'] + ')'
550
                ws[col + str(current_row_number)].border = f_border
551
552
                current_col_number += 1
553
                col = format_cell.get_column_letter(current_col_number)
554
555
                ws[col + str(current_row_number)].fill = table_fill
556
                ws[col + str(current_row_number)].font = title_font
557
                ws[col + str(current_row_number)].border = f_border
558
                ws[col + str(current_row_number)].alignment = c_c_alignment
559
                ws[col + str(current_row_number)] = _('Reporting Period') + " - " + _('Datetime')
560
561
                for i in range(0, reporting_period_data_ca_len):
562
                    current_col_number += 1
563
                    col = format_cell.get_column_letter(current_col_number)
564
                    ws[col + str(current_row_number)].fill = table_fill
565
                    ws[col + str(current_row_number)].font = title_font
566
                    ws[col + str(current_row_number)].alignment = c_c_alignment
567
                    ws[col + str(current_row_number)] = _('Reporting Period') + " - " \
568
                        + reporting_period_data['names'][i] + " (" + \
569
                        reporting_period_data['units'][i] + ")"
570
                    ws[col + str(current_row_number)].border = f_border
571
572
                current_col_number += 1
573
                col = format_cell.get_column_letter(current_col_number)
574
                ws[col + str(current_row_number)].fill = table_fill
575
                ws[col + str(current_row_number)].font = title_font
576
                ws[col + str(current_row_number)].alignment = c_c_alignment
577
                ws[col + str(current_row_number)] = _('Reporting Period') + " - " \
578
                    + _('Total') + '(' + report['reporting_period']['total_unit'] + ')'
579
                ws[col + str(current_row_number)].border = f_border
580
581
                current_row_number += 1
582
583
                max_timestamps_len = len(base_period_timestamps[0]) \
584
                    if len(base_period_timestamps[0]) >= len(reporting_period_timestamps[0]) \
585
                    else len(reporting_period_timestamps[0])
586
587
                for i in range(0, max_timestamps_len):
588
                    current_col_number = 2
589
                    col = format_cell.get_column_letter(current_col_number)
590
                    ws[col + str(current_row_number)].font = title_font
591
                    ws[col + str(current_row_number)].alignment = c_c_alignment
592
                    ws[col + str(current_row_number)] = base_period_timestamps[0][i] \
593
                        if i < len(base_period_timestamps[0]) else None
594
                    ws[col + str(current_row_number)].border = f_border
595
596
                    base_period_total = Decimal(0.0)
597
598
                    for j in range(0, base_period_data_ca_len):
599
                        current_col_number += 1
600
                        col = format_cell.get_column_letter(current_col_number)
601
602
                        ws[col + str(current_row_number)].font = title_font
603
                        ws[col + str(current_row_number)].alignment = c_c_alignment
604
                        ws[col + str(current_row_number)] = round(base_period_data['values'][j][i], 2) \
605
                            if i < len(base_period_data['values'][j]) else None
606
                        if i < len(base_period_timestamps[0]):
607
                            base_period_total += base_period_data['values'][j][i]
608
                        ws[col + str(current_row_number)].border = f_border
609
610
                    current_col_number += 1
611
                    col = format_cell.get_column_letter(current_col_number)
612
                    ws[col + str(current_row_number)].font = title_font
613
                    ws[col + str(current_row_number)].alignment = c_c_alignment
614
                    ws[col + str(current_row_number)] = round(base_period_total, 2) \
615
                        if i < len(base_period_timestamps[0]) else None
616
                    ws[col + str(current_row_number)].border = f_border
617
618
                    current_col_number += 1
619
                    col = format_cell.get_column_letter(current_col_number)
620
621
                    ws[col + str(current_row_number)].font = title_font
622
                    ws[col + str(current_row_number)].alignment = c_c_alignment
623
                    ws[col + str(current_row_number)] = reporting_period_timestamps[0][i] \
624
                        if i < len(reporting_period_timestamps[0]) else None
625
                    ws[col + str(current_row_number)].border = f_border
626
627
                    reporting_period_total = Decimal(0.0)
628
629
                    for j in range(0, reporting_period_data_ca_len):
630
                        current_col_number += 1
631
                        col = format_cell.get_column_letter(current_col_number)
632
633
                        ws[col + str(current_row_number)].font = title_font
634
                        ws[col + str(current_row_number)].alignment = c_c_alignment
635
                        ws[col + str(current_row_number)] = round(reporting_period_data['values'][j][i], 2) \
636
                            if i < len(reporting_period_data['values'][j]) else None
637
                        if i < len(reporting_period_timestamps[0]):
638
                            reporting_period_total += reporting_period_data['values'][j][i]
639
                        ws[col + str(current_row_number)].border = f_border
640
641
                    current_col_number += 1
642
                    col = format_cell.get_column_letter(current_col_number)
643
                    ws[col + str(current_row_number)].font = title_font
644
                    ws[col + str(current_row_number)].alignment = c_c_alignment
645
                    ws[col + str(current_row_number)] = round(reporting_period_total, 2) \
646
                        if i < len(reporting_period_timestamps[0]) else None
647
                    ws[col + str(current_row_number)].border = f_border
648
649
                    current_row_number += 1
650
651
                current_col_number = 2
652
                col = format_cell.get_column_letter(current_col_number)
653
                ws[col + str(current_row_number)].font = title_font
654
                ws[col + str(current_row_number)].alignment = c_c_alignment
655
                ws[col + str(current_row_number)] = _('Subtotal')
656
                ws[col + str(current_row_number)].border = f_border
657
658
                base_period_subtotals = Decimal(0.0)
659
660
                for i in range(0, base_period_data_ca_len):
661
                    current_col_number += 1
662
                    col = format_cell.get_column_letter(current_col_number)
663
                    ws[col + str(current_row_number)].font = title_font
664
                    ws[col + str(current_row_number)].alignment = c_c_alignment
665
                    ws[col + str(current_row_number)] = round(base_period_data['subtotals'][i], 2)
666
                    base_period_subtotals += base_period_data['subtotals'][i]
667
                    ws[col + str(current_row_number)].border = f_border
668
669
                current_col_number += 1
670
                col = format_cell.get_column_letter(current_col_number)
671
                ws[col + str(current_row_number)].font = title_font
672
                ws[col + str(current_row_number)].alignment = c_c_alignment
673
                ws[col + str(current_row_number)] = round(base_period_subtotals, 2)
674
                ws[col + str(current_row_number)].border = f_border
675
676
                current_col_number += 1
677
                col = format_cell.get_column_letter(current_col_number)
678
679
                ws[col + str(current_row_number)].font = title_font
680
                ws[col + str(current_row_number)].alignment = c_c_alignment
681
                ws[col + str(current_row_number)] = _('Subtotal')
682
                ws[col + str(current_row_number)].border = f_border
683
684
                reporting_period_subtotals = Decimal(0.0)
685
686
                for i in range(0, reporting_period_data_ca_len):
687
                    current_col_number += 1
688
                    col = format_cell.get_column_letter(current_col_number)
689
                    ws[col + str(current_row_number)].font = title_font
690
                    ws[col + str(current_row_number)].alignment = c_c_alignment
691
                    ws[col + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
692
                    reporting_period_subtotals += reporting_period_data['subtotals'][i]
693
                    ws[col + str(current_row_number)].border = f_border
694
695
                current_col_number += 1
696
                col = format_cell.get_column_letter(current_col_number)
697
                ws[col + str(current_row_number)].font = title_font
698
                ws[col + str(current_row_number)].alignment = c_c_alignment
699
                ws[col + str(current_row_number)] = round(reporting_period_subtotals, 2)
700
                ws[col + str(current_row_number)].border = f_border
701
702
                for i in range(0, reporting_period_data_ca_len):
703
                    # line
704
                    line = LineChart()
705
                    line.title = _('Base Period Income') + " / " \
706
                        + _('Reporting Period Income') + ' - ' \
707
                        + reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
708
                    labels = Reference(ws, min_col=2 + base_period_data_ca_len + 1 + 1,
709
                                       min_row=table_start_row_number + 1,
710
                                       max_row=table_start_row_number + len(reporting_period_timestamps[0]))
711
                    base_line_data = Reference(ws, min_col=3 + i, min_row=table_start_row_number,
712
                                               max_row=table_start_row_number + len(reporting_period_timestamps[0]))
713
                    reporting_line_data = Reference(ws, min_col=3 + base_period_data_ca_len + 1 + 1 + i,
714
                                                    min_row=table_start_row_number,
715
                                                    max_row=table_start_row_number
716
                                                    + len(reporting_period_timestamps[0]))
717
                    line.add_data(base_line_data, titles_from_data=True)
718
                    line.add_data(reporting_line_data, titles_from_data=True)
719
                    line.set_categories(labels)
720
                    for j in range(len(line.series)):
721
                        line.series[j].marker.symbol = "circle"
722
                        line.series[j].smooth = True
723
                    line.x_axis.crosses = 'min'
724
                    line.height = 8.25
725
                    line.width = 24
726
                    line.dLbls = DataLabelList()
727
                    line.dLbls.dLblPos = 't'
728
                    line.dLbls.showVal = True
729
                    line.dLbls.showPercent = False
730
                    chart_col = 'B'
731
                    chart_cell = chart_col + str(table_start_draw_flag + 6 * i)
732
                    ws.add_chart(line, chart_cell)
733
734
                current_row_number += 2
735
736
    ####################################################################################################################
737
    if "child_space" not in report.keys() or "energy_category_names" not in report['child_space'].keys() or \
738
            len(report['child_space']["energy_category_names"]) == 0 \
739
            or 'child_space_names_array' not in report['child_space'].keys() \
740
            or report['child_space']['energy_category_names'] is None \
741
            or len(report['child_space']['child_space_names_array']) == 0 \
742
            or len(report['child_space']['child_space_names_array'][0]) == 0:
743
        pass
744
    else:
745
        child = report['child_space']
746
747
        ws['B' + str(current_row_number)].font = title_font
748
        ws['B' + str(current_row_number)] = name + ' ' + _('Child Spaces Data')
749
750
        current_row_number += 1
751
        table_start_row_number = current_row_number
752
753
        ws.row_dimensions[current_row_number].height = 60
754
        ws['B' + str(current_row_number)].fill = table_fill
755
        ws['B' + str(current_row_number)].font = name_font
756
        ws['B' + str(current_row_number)].alignment = c_c_alignment
757
        ws['B' + str(current_row_number)].border = f_border
758
        ws['B' + str(current_row_number)] = _('Child Space')
759
        ca_len = len(child['energy_category_names'])
760
761
        col = ''
762
763
        for i in range(0, ca_len):
764
            col = chr(ord('C') + i)
765
            ws[col + str(current_row_number)].fill = table_fill
766
            ws[col + str(current_row_number)].font = name_font
767
            ws[col + str(current_row_number)].alignment = c_c_alignment
768
            ws[col + str(current_row_number)].border = f_border
769
            ws[col + str(current_row_number)] = child['energy_category_names'][i] + ' ' + '(' + child['units'][i] + ')'
770
771
        col = chr(ord(col) + 1)
772
        ws[col + str(current_row_number)].fill = table_fill
773
        ws[col + str(current_row_number)].font = name_font
774
        ws[col + str(current_row_number)].alignment = c_c_alignment
775
        ws[col + str(current_row_number)].border = f_border
776
        ws[col + str(current_row_number)] = _('Total') + ' (' + report['reporting_period']['total_unit'] + ')'
777
778
        space_len = len(child['child_space_names_array'][0])
779
780
        for i in range(0, space_len):
781
            current_row_number += 1
782
            row = str(current_row_number)
783
784
            ws['B' + row].font = title_font
785
            ws['B' + row].alignment = c_c_alignment
786
            ws['B' + row] = child['child_space_names_array'][0][i]
787
            ws['B' + row].border = f_border
788
789
            col = ''
790
            periodic_sum = Decimal(0.0)
791
792
            for j in range(0, ca_len):
793
                col = chr(ord('C') + j)
794
                ws[col + row].font = name_font
795
                ws[col + row].alignment = c_c_alignment
796
                periodic_sum += child['subtotals_array'][j][i]
797
                ws[col + row] = round(child['subtotals_array'][j][i], 2)
798
                ws[col + row].border = f_border
799
800
            col = chr(ord(col) + 1)
801
            ws[col + row].font = name_font
802
            ws[col + row].alignment = c_c_alignment
803
            ws[col + row] = round(periodic_sum, 2)
804
            ws[col + row].border = f_border
805
806
        table_end_row_number = current_row_number
807
808
        current_row_number += 1
809
810
        chart_start_row_number = current_row_number
811
812
        # Pie
813
        for i in range(0, ca_len):
814
            pie = PieChart()
815
            labels = Reference(ws, min_col=2, min_row=table_start_row_number + 1, max_row=table_end_row_number)
816
            pie_data = Reference(ws, min_col=3 + i, min_row=table_start_row_number,
817
                                 max_row=table_end_row_number)
818
            pie.add_data(pie_data, titles_from_data=True)
819
            pie.set_categories(labels)
820
            pie.height = 6.6
821
            pie.width = 8
822
            pie.title = ws.cell(column=3 + i, row=table_start_row_number).value
823
            s1 = pie.series[0]
824
            s1.dLbls = DataLabelList()
825
            s1.dLbls.showCatName = False
826
            s1.dLbls.showVal = True
827
            s1.dLbls.showPercent = True
828
            if i % 2 == 0:
829
                chart_cell = 'B' + str(chart_start_row_number)
830
            else:
831
                chart_cell = 'E' + str(chart_start_row_number)
832
                chart_start_row_number += 5
833
            ws.add_chart(pie, chart_cell)
834
835
        current_row_number = chart_start_row_number
836
837
        if ca_len % 2 == 1:
838
            current_row_number += 5
839
840
        current_row_number += 1
841
842
    ####################################################################################################################
843
    current_sheet_parameters_row_number = table_start_draw_flag + len(reporting_period_data['names']) * 6 + 1
844
    if 'parameters' not in report.keys() or \
845
            report['parameters'] is None or \
846
            'names' not in report['parameters'].keys() or \
847
            report['parameters']['names'] is None or \
848
            len(report['parameters']['names']) == 0 or \
849
            'timestamps' not in report['parameters'].keys() or \
850
            report['parameters']['timestamps'] is None or \
851
            len(report['parameters']['timestamps']) == 0 or \
852
            'values' not in report['parameters'].keys() or \
853
            report['parameters']['values'] is None or \
854
            len(report['parameters']['values']) == 0 or \
855
            timestamps_data_all_equal_0(report['parameters']['timestamps']):
856
        pass
857
    else:
858
859
        ################################################################################################################
860
        # new worksheet
861
        ################################################################################################################
862
863
        parameters_data = report['parameters']
864
        parameters_names_len = len(parameters_data['names'])
865
866
        file_name = "Space"+re.sub(r'[^A-Z]', '', ws.title.strip('S')) + "_"
867
        parameters_ws = wb.create_sheet(file_name + _('Parameters'))
868
869
        parameters_timestamps_data_max_len = \
870
            get_parameters_timestamps_lists_max_len(list(parameters_data['timestamps']))
871
872
        # Row height
873
        parameters_ws.row_dimensions[1].height = 102
874
        for i in range(2, 7 + 1):
875
            parameters_ws.row_dimensions[i].height = 42
876
877
        for i in range(8, parameters_timestamps_data_max_len + 10):
878
            parameters_ws.row_dimensions[i].height = 60
879
880
        # Col width
881
        parameters_ws.column_dimensions['A'].width = 1.5
882
883
        parameters_ws.column_dimensions['B'].width = 25.0
884
885
        for i in range(3, 12 + parameters_names_len * 3):
886
            parameters_ws.column_dimensions[format_cell.get_column_letter(i)].width = 15.0
887
888
        # Img
889
        img = Image("excelexporters/myems.png")
890
        parameters_ws.add_image(img, 'A1')
891
892
        # Title
893
        parameters_ws['B3'].alignment = b_r_alignment
894
        parameters_ws['B3'] = _('Name') + ':'
895
        parameters_ws['C3'].border = b_border
896
        parameters_ws['C3'].alignment = b_c_alignment
897
        parameters_ws['C3'] = name
898
899
        parameters_ws['D3'].alignment = b_r_alignment
900
        parameters_ws['D3'] = _('Period Type') + ':'
901
        parameters_ws['E3'].border = b_border
902
        parameters_ws['E3'].alignment = b_c_alignment
903
        parameters_ws['E3'] = period_type
904
905
        parameters_ws['B4'].alignment = b_r_alignment
906
        parameters_ws['B4'] = _('Reporting Start Datetime') + ':'
907
        parameters_ws['C4'].border = b_border
908
        parameters_ws['C4'].alignment = b_c_alignment
909
        parameters_ws['C4'] = reporting_start_datetime_local
910
911
        parameters_ws['D4'].alignment = b_r_alignment
912
        parameters_ws['D4'] = _('Reporting End Datetime') + ':'
913
        parameters_ws['E4'].border = b_border
914
        parameters_ws['E4'].alignment = b_c_alignment
915
        parameters_ws['E4'] = reporting_end_datetime_local
916
917
        parameters_ws_current_row_number = 6
918
919
        parameters_ws['B' + str(parameters_ws_current_row_number)].font = title_font
920
        parameters_ws['B' + str(parameters_ws_current_row_number)] = name + ' ' + _('Parameters')
921
922
        parameters_ws_current_row_number += 1
923
924
        parameters_table_start_row_number = parameters_ws_current_row_number
925
926
        parameters_ws.row_dimensions[parameters_ws_current_row_number].height = 80
927
928
        parameters_ws_current_row_number += 1
929
930
        table_current_col_number = 2
931
932
        for i in range(0, parameters_names_len):
933
934
            if len(parameters_data['timestamps'][i]) == 0:
935
                continue
936
937
            col = format_cell.get_column_letter(table_current_col_number)
938
939
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
940
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
941
942
            col = format_cell.get_column_letter(table_current_col_number + 1)
943
944
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
945
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
946
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].font = name_font
947
            parameters_ws[col + str(parameters_ws_current_row_number - 1)].alignment = c_c_alignment
948
            parameters_ws[col + str(parameters_ws_current_row_number - 1)] = parameters_data['names'][i]
949
950
            table_current_row_number = parameters_ws_current_row_number
951
952
            for j, value in enumerate(list(parameters_data['timestamps'][i])):
953
                col = format_cell.get_column_letter(table_current_col_number)
954
955
                parameters_ws[col + str(table_current_row_number)].border = f_border
956
                parameters_ws[col + str(table_current_row_number)].font = title_font
957
                parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
958
                parameters_ws[col + str(table_current_row_number)] = value
959
960
                col = format_cell.get_column_letter(table_current_col_number + 1)
961
962
                parameters_ws[col + str(table_current_row_number)].border = f_border
963
                parameters_ws[col + str(table_current_row_number)].font = title_font
964
                parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
965
                parameters_ws[col + str(table_current_row_number)] = round(parameters_data['values'][i][j], 2)
966
967
                table_current_row_number += 1
968
969
            table_current_col_number = table_current_col_number + 3
970
971
        ################################################################################################################
972
        # parameters chart and parameters table
973
        ################################################################################################################
974
975
        ws['B' + str(current_sheet_parameters_row_number)].font = title_font
976
        ws['B' + str(current_sheet_parameters_row_number)] = name + ' ' + _('Parameters')
977
978
        current_sheet_parameters_row_number += 1
979
980
        chart_start_row_number = current_sheet_parameters_row_number
981
982
        col_index = 0
983
984
        for i in range(0, parameters_names_len):
985
986
            if len(parameters_data['timestamps'][i]) == 0:
987
                continue
988
989
            line = LineChart()
990
            data_col = 3 + col_index * 3
991
            labels_col = 2 + col_index * 3
992
            col_index += 1
993
            line.title = _('Parameters') + ' - ' + \
994
                parameters_ws.cell(row=parameters_table_start_row_number, column=data_col).value
995
            labels = Reference(parameters_ws, min_col=labels_col, min_row=parameters_table_start_row_number + 1,
996
                               max_row=(len(parameters_data['timestamps'][i]) + parameters_table_start_row_number))
997
            line_data = Reference(parameters_ws, min_col=data_col, min_row=parameters_table_start_row_number,
998
                                  max_row=(len(parameters_data['timestamps'][i]) + parameters_table_start_row_number))
999
            line.add_data(line_data, titles_from_data=True)
1000
            line.set_categories(labels)
1001
            line_data = line.series[0]
1002
            line_data.marker.symbol = "circle"
1003
            line_data.smooth = True
1004
            line.x_axis.crosses = 'min'
1005
            line.height = 8.25
1006
            line.width = 24
1007
            line.dLbls = DataLabelList()
1008
            line.dLbls.dLblPos = 't'
1009
            line.dLbls.showVal = False
1010
            line.dLbls.showPercent = False
1011
            chart_col = 'B'
1012
            chart_cell = chart_col + str(chart_start_row_number)
1013
            chart_start_row_number += 6
1014
            ws.add_chart(line, chart_cell)
1015
1016
        current_sheet_parameters_row_number = chart_start_row_number
1017
1018
        current_sheet_parameters_row_number += 1
1019
    ####################################################################################################################
1020
    filename = str(uuid.uuid4()) + '.xlsx'
1021
    wb.save(filename)
1022
1023
    return filename
1024
1025
1026
def reporting_period_values_periodic_sum(reporting_period_data, periodic_index, ca_len):
1027
    periodic_sum = Decimal(0.0)
1028
    for i in range(0, ca_len):
1029
        periodic_sum += reporting_period_data['values'][i][periodic_index]
1030
1031
    return periodic_sum
1032
1033
1034
def timestamps_data_all_equal_0(lists):
1035
    for i, value in enumerate(list(lists)):
1036
        if len(value) > 0:
1037
            return False
1038
1039
    return True
1040
1041
1042
def get_parameters_timestamps_lists_max_len(parameters_timestamps_lists):
1043
    max_len = 0
1044
    for i, value in enumerate(list(parameters_timestamps_lists)):
1045
        if len(value) > max_len:
1046
            max_len = len(value)
1047
1048
    return max_len
1049
1050
1051
def timestamps_data_not_equal_0(lists):
1052
    number = 0
1053
    for i, value in enumerate(list(lists)):
1054
        if len(value) > 0:
1055
            number += 1
1056
    return number
1057
1058
1059 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...
1060
    timestamps = base_period_data['timestamps']
1061
1062
    if len(timestamps) == 0:
1063
        return False
1064
1065
    for timestamp in timestamps:
1066
        if len(timestamp) > 0:
1067
            return True
1068
1069
    return False
1070