Passed
Push — master ( 6d6fc1...7022fd )
by Guangyu
02:00 queued 10s
created

excelexporters.spacecost.generate_excel()   F

Complexity

Conditions 38

Size

Total Lines 403
Code Lines 312

Duplication

Lines 135
Ratio 33.5 %

Importance

Changes 0
Metric Value
cc 38
eloc 312
nop 5
dl 135
loc 403
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

Complexity

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

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

1
import base64
2
import uuid
3
import os
4
from openpyxl.chart import (
5
    PieChart,
6
    BarChart,
7
    Reference,
8
)
9
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
10
from openpyxl.drawing.image import Image
11
from openpyxl import Workbook
12
from openpyxl.chart.label import DataLabelList
13
14
15
####################################################################################################################
16
# PROCEDURES
17
# Step 1: Validate the report data
18
# Step 2: Generate excel file
19
# Step 3: Encode the excel file bytes to Base64
20
####################################################################################################################
21
22
23 View Code Duplication
def export(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
24
           name,
25
           reporting_start_datetime_local,
26
           reporting_end_datetime_local,
27
           period_type):
28
    ####################################################################################################################
29
    # Step 1: Validate the report data
30
    ####################################################################################################################
31
    if report is None:
32
        return None
33
    print(report)
34
35
    ####################################################################################################################
36
    # Step 2: Generate excel file from the report data
37
    ####################################################################################################################
38
    filename = generate_excel(report,
39
                              name,
40
                              reporting_start_datetime_local,
41
                              reporting_end_datetime_local,
42
                              period_type)
43
    ####################################################################################################################
44
    # Step 3: Encode the excel file to Base64
45
    ####################################################################################################################
46
    try:
47
        with open(filename, 'rb') as binary_file:
48
            binary_file_data = binary_file.read()
49
    except IOError as ex:
50
        pass
51
52
    # Base64 encode the bytes
53
    base64_encoded_data = base64.b64encode(binary_file_data)
0 ignored issues
show
introduced by
The variable binary_file_data does not seem to be defined for all execution paths.
Loading history...
54
    # get the Base64 encoded data using human-readable characters.
55
    base64_message = base64_encoded_data.decode('utf-8')
56
    # delete the file from server
57
    try:
58
        os.remove(filename)
59
    except NotImplementedError as ex:
60
        pass
61
    return base64_message
62
63
64
def generate_excel(report,
65
                   name,
66
                   reporting_start_datetime_local,
67
                   reporting_end_datetime_local,
68
                   period_type):
69
    wb = Workbook()
70
    ws = wb.active
71
72
    # Row height
73
    ws.row_dimensions[1].height = 118
74
    for i in range(2, 37 + 1):
75
        ws.row_dimensions[i].height = 30
76
77
    for i in range(38, 69 + 1):
78
        ws.row_dimensions[i].height = 30
79
80
    # Col width
81
    ws.column_dimensions['A'].width = 1.5
82
83
    ws.column_dimensions['B'].width = 25.0
84
85
    for i in range(ord('C'), ord('I')):
86
        ws.column_dimensions[chr(i)].width = 15.0
87
88
    # Font
89
    name_font = Font(name='Constantia', size=15, bold=True)
90
    title_font = Font(name='宋体', size=15, bold=True)
91
    data_font = Font(name='Franklin Gothic Book', size=11)
92
93
    table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
94
    f_border = Border(left=Side(border_style='medium', color='00000000'),
95
                      right=Side(border_style='medium', color='00000000'),
96
                      bottom=Side(border_style='medium', color='00000000'),
97
                      top=Side(border_style='medium', color='00000000')
98
                      )
99
    b_border = Border(
100
        bottom=Side(border_style='medium', color='00000000'),
101
    )
102
103
    b_c_alignment = Alignment(vertical='bottom',
104
                              horizontal='center',
105
                              text_rotation=0,
106
                              wrap_text=False,
107
                              shrink_to_fit=False,
108
                              indent=0)
109
    c_c_alignment = Alignment(vertical='center',
110
                              horizontal='center',
111
                              text_rotation=0,
112
                              wrap_text=False,
113
                              shrink_to_fit=False,
114
                              indent=0)
115
    b_r_alignment = Alignment(vertical='bottom',
116
                              horizontal='right',
117
                              text_rotation=0,
118
                              wrap_text=False,
119
                              shrink_to_fit=False,
120
                              indent=0)
121
    c_r_alignment = Alignment(vertical='bottom',
122
                              horizontal='center',
123
                              text_rotation=0,
124
                              wrap_text=False,
125
                              shrink_to_fit=False,
126
                              indent=0)
127
    # Img
128
    img = Image("excelexporters/myems.png")
129
    # img = Image("myems.png")
130
    ws.add_image(img, 'B1')
131
132
    # Title
133
    ws['B3'].font = name_font
134
    ws['B3'].alignment = b_r_alignment
135
    ws['B3'] = 'Name:'
136
    ws['C3'].border = b_border
137
    ws['C3'].alignment = b_c_alignment
138
    ws['C3'].font = name_font
139
    ws['C3'] = name
140
141
    ws['D3'].font = name_font
142
    ws['D3'].alignment = b_r_alignment
143
    ws['D3'] = 'Period:'
144
    ws['E3'].border = b_border
145
    ws['E3'].alignment = b_c_alignment
146
    ws['E3'].font = name_font
147
    ws['E3'] = period_type
148
149
    ws['F3'].font = name_font
150
    ws['F3'].alignment = b_r_alignment
151
    ws['F3'] = 'Date:'
152
    ws.merge_cells("G3:H3")
153
    ws['G3'].border = b_border
154
    ws['G3'].alignment = b_c_alignment
155
    ws['G3'].font = name_font
156
    ws['G3'] = reporting_start_datetime_local + "__" + reporting_end_datetime_local
157
158
    if "reporting_period" not in report.keys() or \
159
            "names" not in report['reporting_period'].keys() or len(report['reporting_period']['names']) == 0:
160
        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...
161
        wb.save(filename)
162
163
        return filename
164
165
    ##################################
166
167
    reporting_period_data = report['reporting_period']
168
169
    has_cost_data_flag = True
170
171
    if "names" not in reporting_period_data.keys() or \
172
            reporting_period_data['names'] is None or \
173
            len(reporting_period_data['names']) == 0:
174
        has_cost_data_flag = False
175
176
    if has_cost_data_flag:
177
        ws['B6'].font = title_font
178
        ws['B6'] = name + ' 报告期成本'
179
180
        category = reporting_period_data['names']
181
        ca_len = len(category)
182
183
        ws['B7'].fill = table_fill
184
185
        ws['B8'].font = title_font
186
        ws['B8'].alignment = c_c_alignment
187
        ws['B8'] = '成本'
188
        ws['B8'].border = f_border
189
190
        ws['B9'].font = title_font
191
        ws['B9'].alignment = c_c_alignment
192
        ws['B9'] = '单位面积值'
193
        ws['B9'].border = f_border
194
195
        ws['B10'].font = title_font
196
        ws['B10'].alignment = c_c_alignment
197
        ws['B10'] = '环比'
198
        ws['B10'].border = f_border
199
200
        for i in range(0, ca_len):
201
            col = chr(ord('C') + i)
202
203
            ws[col + '7'].fill = table_fill
204
            ws[col + '7'].font = name_font
205
            ws[col + '7'].alignment = c_c_alignment
206
            ws[col + '7'] = reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
207
            ws[col + '7'].border = f_border
208
209
            ws[col + '8'].font = name_font
210
            ws[col + '8'].alignment = c_c_alignment
211
            ws[col + '8'] = round(reporting_period_data['subtotals'][i], 0)
212
            ws[col + '8'].border = f_border
213
214
            ws[col + '9'].font = name_font
215
            ws[col + '9'].alignment = c_c_alignment
216
            ws[col + '9'] = round(reporting_period_data['subtotals_per_unit_area'][i], 2)
217
            ws[col + '9'].border = f_border
218
219
            ws[col + '10'].font = name_font
220
            ws[col + '10'].alignment = c_c_alignment
221
            ws[col + '10'] = str(round(reporting_period_data['increment_rates'][i] * 100, 2)) + "%" \
222
                if reporting_period_data['increment_rates'][i] is not None else "-"
223
            ws[col + '10'].border = f_border
224
225
    else:
226
        for i in range(6, 10 + 1):
227
            ws.row_dimensions[i].height = 0.1
228
229
    ##############################
230
231
    has_ele_peak_flag = True
232
    if "toppeaks" not in reporting_period_data.keys() or \
233
            reporting_period_data['toppeaks'] is None or \
234
            len(reporting_period_data['toppeaks']) == 0:
235
        has_ele_peak_flag = False
236
237 View Code Duplication
    if has_ele_peak_flag:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
238
        ws['B12'].font = title_font
239
        ws['B12'] = name + '分时用电成本'
240
241
        ws['B13'].fill = table_fill
242
        ws['B13'].font = name_font
243
        ws['B13'].alignment = c_c_alignment
244
        ws['B13'].border = f_border
245
246
        ws['C13'].fill = table_fill
247
        ws['C13'].font = name_font
248
        ws['C13'].alignment = c_c_alignment
249
        ws['C13'].border = f_border
250
        ws['C13'] = '分时用电成本'
251
252
        ws['B14'].font = title_font
253
        ws['B14'].alignment = c_c_alignment
254
        ws['B14'] = '尖'
255
        ws['B14'].border = f_border
256
257
        ws['C14'].font = title_font
258
        ws['C14'].alignment = c_c_alignment
259
        ws['C14'].border = f_border
260
        ws['C14'] = round(reporting_period_data['toppeaks'][0], 0)
261
262
        ws['B15'].font = title_font
263
        ws['B15'].alignment = c_c_alignment
264
        ws['B15'] = '峰'
265
        ws['B15'].border = f_border
266
267
        ws['C15'].font = title_font
268
        ws['C15'].alignment = c_c_alignment
269
        ws['C15'].border = f_border
270
        ws['C15'] = round(reporting_period_data['onpeaks'][0], 0)
271
272
        ws['B16'].font = title_font
273
        ws['B16'].alignment = c_c_alignment
274
        ws['B16'] = '平'
275
        ws['B16'].border = f_border
276
277
        ws['C16'].font = title_font
278
        ws['C16'].alignment = c_c_alignment
279
        ws['C16'].border = f_border
280
        ws['C16'] = round(reporting_period_data['midpeaks'][0], 0)
281
282
        ws['B17'].font = title_font
283
        ws['B17'].alignment = c_c_alignment
284
        ws['B17'] = '谷'
285
        ws['B17'].border = f_border
286
287
        ws['C17'].font = title_font
288
        ws['C17'].alignment = c_c_alignment
289
        ws['C17'].border = f_border
290
        ws['C17'] = round(reporting_period_data['offpeaks'][0], 0)
291
292
        pie = PieChart()
293
        labels = Reference(ws, min_col=2, min_row=14, max_row=17)
294
        pie_data = Reference(ws, min_col=3, min_row=13, max_row=17)
295
        pie.add_data(pie_data, titles_from_data=True)
296
        pie.set_categories(labels)
297
        pie.height = 5.25
298
        pie.width = 9
299
        s1 = pie.series[0]
300
        s1.dLbls = DataLabelList()
301
        s1.dLbls.showCatName = False
302
        s1.dLbls.showVal = True
303
        s1.dLbls.showPercent = True
304
305
        ws.add_chart(pie, "D13")
306
307
    else:
308
        for i in range(12, 18 + 1):
309
            ws.row_dimensions[i].height = 0.1
310
311
    ##################################
312
    current_row_flag = 19
313
314
    has_child_flag = True
315
    if "child_space" not in report.keys() or "energy_category_names" not in report['child_space'].keys() or \
316
            len(report['child_space']["energy_category_names"]) == 0:
317
        has_child_flag = False
318
319
    if has_child_flag:
320
        child = report['child_space']
321
322
        ws['B' + str(current_row_flag)].font = title_font
323
        ws['B' + str(current_row_flag)] = name + ' 子空间数据'
324
325
        current_row_flag += 1
326
327
        ws['B' + str(current_row_flag)].fill = table_fill
328
        ws['B' + str(current_row_flag)].border = f_border
329
        ca_len = len(child['energy_category_names'])
330
331
        for i in range(0, ca_len):
332
            row = chr(ord('C') + i)
333
            ws[row + str(current_row_flag)].fill = table_fill
334
            ws[row + str(current_row_flag)].font = title_font
335
            ws[row + str(current_row_flag)].alignment = c_c_alignment
336
            ws[row + str(current_row_flag)].border = f_border
337
            ws[row + str(current_row_flag)] = child['energy_category_names'][i]
338
339
        space_len = len(child['child_space_names_array'][0])
340
341
        for i in range(0, space_len):
342
            current_row_flag += 1
343
            row = str(current_row_flag)
344
345
            ws['B' + row].font = name_font
346
            ws['B' + row].alignment = c_c_alignment
347
            ws['B' + row] = child['child_space_names_array'][0][i]
348
            ws['B' + row].border = f_border
349
350
            for j in range(0, ca_len):
351
                col = chr(ord('C') + j)
352
                ws[col + row].font = name_font
353
                ws[col + row].alignment = c_c_alignment
354
                ws[col + row] = child['subtotals_array'][j][i]
355
                ws[col + row].border = f_border
356
357
        current_row_flag += 1
358
359
        # Pie
360
        for i in range(0, ca_len):
361
            pie = PieChart()
362
            labels = Reference(ws, min_col=2, min_row=current_row_flag - space_len, max_row=current_row_flag - 1)
363
            pie_data = Reference(ws, min_col=3 + i, min_row=current_row_flag - space_len - 1,
364
                                 max_row=current_row_flag - 1)
365
            pie.add_data(pie_data, titles_from_data=True)
366
            pie.set_categories(labels)
367
            pie.height = 5.25
368
            pie.width = 8
369
            col = chr(ord('C') + i)
370
            pie.title = ws[col + '20'].value
371
            s1 = pie.series[0]
372
            s1.dLbls = DataLabelList()
373
            s1.dLbls.showCatName = False
374
            s1.dLbls.showVal = True
375
            s1.dLbls.showPercent = True
376
            chart_col = chr(ord('B') + 2 * i)
377
            chart_cell = chart_col + str(current_row_flag)
378
            ws.add_chart(pie, chart_cell)
379
380
        current_row_flag += 5
381
382
    else:
383
        for i in range(19, 36 + 1):
384
            current_row_flag = 36
385
            ws.row_dimensions[i].height = 0.1
386
387
    current_row_flag += 1
388
389
    #############################################
390
    reporting_period_data = report['reporting_period']
391
    times = reporting_period_data['timestamps']
392
    has_detail_data_flag = True
393
    ca_len = len(report['reporting_period']['names'])
394
    table_row = (current_row_flag + 1) + ca_len * 5
395
    if "timestamps" not in reporting_period_data.keys() or \
396
            reporting_period_data['timestamps'] is None or \
397
            len(reporting_period_data['timestamps']) == 0:
398
        has_detail_data_flag = False
399
400 View Code Duplication
    if has_detail_data_flag:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
401
        ws['B' + str(current_row_flag)].font = title_font
402
        ws['B' + str(current_row_flag)] = name + ' 详细数据'
403
404
        ws['B' + str(table_row)].fill = table_fill
405
        ws['B' + str(table_row)].border = f_border
406
        ws['B' + str(table_row)].alignment = c_c_alignment
407
        ws['B' + str(table_row)] = '日期时间'
408
        time = times[0]
409
        has_data = False
410
        max_row = 0
411
        if len(time) > 0:
412
            has_data = True
413
            max_row = table_row + len(time)
414
415
        if has_data:
416
            for i in range(0, len(time)):
417
                col = 'B'
418
                row = str(table_row + 1 + i)
419
                ws[col + row].font = title_font
420
                ws[col + row].alignment = c_c_alignment
421
                ws[col + row] = time[i]
422
                ws[col + row].border = f_border
423
424
            for i in range(0, ca_len):
425
426
                col = chr(ord('C') + i)
427
428
                ws[col + str(table_row)].fill = table_fill
429
                ws[col + str(table_row)].font = title_font
430
                ws[col + str(table_row)].alignment = c_c_alignment
431
                ws[col + str(table_row)] = reporting_period_data['names'][i] + " (" + reporting_period_data['units'][
432
                    i] + ")"
433
                ws[col + str(table_row)].border = f_border
434
435
                # 39 data
436
                time = times[i]
437
                time_len = len(time)
438
439
                for j in range(0, time_len):
440
                    row = str(table_row + 1 + j)
441
                    ws[col + row].font = title_font
442
                    ws[col + row].alignment = c_c_alignment
443
                    ws[col + row] = round(reporting_period_data['values'][i][j], 0)
444
                    ws[col + row].border = f_border
445
446
                bar = BarChart()
447
                labels = Reference(ws, min_col=2, min_row=table_row + 1, max_row=max_row)
448
                bar_data = Reference(ws, min_col=3 + i, min_row=table_row, max_row=max_row)
449
                bar.add_data(bar_data, titles_from_data=True)
450
                bar.set_categories(labels)
451
                bar.height = 5.25
452
                bar.width = 18
453
                bar.dLbls = DataLabelList()
454
                bar.dLbls.showVal = True
455
                bar.dLbls.showPercent = True
456
                chart_col = 'B'
457
                chart_cell = chart_col + str(current_row_flag + 1 + 5 * i)
458
                ws.add_chart(bar, chart_cell)
459
    else:
460
        for i in range(37, 69 + 1):
461
            ws.row_dimensions[i].height = 0.1
462
463
    filename = str(uuid.uuid4()) + '.xlsx'
464
    wb.save(filename)
465
466
    return filename
467