timestamps_data_all_equal_0()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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