reporting_period_values_periodic_sum()   A
last analyzed

Complexity

Conditions 2

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