generate_excel()   F
last analyzed

Complexity

Conditions 14

Size

Total Lines 262
Code Lines 200

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 200
nop 5
dl 0
loc 262
rs 2.52
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.metersubmetersbalance.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
    BarChart,
6
    LineChart,
7
    Reference,
8
)
9
from openpyxl.styles import PatternFill, Border, Side, Alignment, Protection, 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 excelexporters file
19
# Step 3: Encode the excelexporters file to Base64
20
####################################################################################################################
21
22 View Code Duplication
def export(result, name, reporting_start_datetime_local, reporting_end_datetime_local, period_type):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
23
    ####################################################################################################################
24
    # Step 1: Validate the report data
25
    ####################################################################################################################
26
    if result is None:
27
        return None
28
29
    ####################################################################################################################
30
    # Step 2: Generate excel file from the report data
31
    ####################################################################################################################
32
    filename = generate_excel(result,
33
                              name,
34
                              reporting_start_datetime_local,
35
                              reporting_end_datetime_local,
36
                              period_type)
37
    ####################################################################################################################
38
    # Step 3: Encode the excel file to Base64
39
    ####################################################################################################################
40
    try:
41
        with open(filename, 'rb') as binary_file:
42
            binary_file_data = binary_file.read()
43
    except IOError as ex:
44
        pass
45
46
    # Base64 encode the bytes
47
    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...
48
    # get the Base64 encoded data using human-readable characters.
49
    base64_message = base64_encoded_data.decode('utf-8')
50
    # delete the file from server
51
    try:
52
        os.remove(filename)
53
    except NotImplementedError as ex:
54
        pass
55
    return base64_message
56
57
58
def generate_excel(report, name, reporting_start_datetime_local, reporting_end_datetime_local, period_type):
59
    wb = Workbook()
60
    ws = wb.active
61
62
    # Row height
63
    ws.row_dimensions[1].height = 102
64
    for i in range(2, 2000 + 1):
65
        ws.row_dimensions[i].height = 42
66
67
    # Col width
68
    ws.column_dimensions['A'].width = 1.5
69
70
    ws.column_dimensions['B'].width = 25.0
71
72
    for i in range(ord('C'), ord('L')):
73
        ws.column_dimensions[chr(i)].width = 15.0
74
75
    # Font
76
    name_font = Font(name='Constantia', size=15, bold=True)
77
    title_font = Font(name='宋体', size=15, bold=True)
78
    data_font = Font(name='Franklin Gothic Book', size=11)
79
80
    table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
81
    f_border = Border(left=Side(border_style='medium', color='00000000'),
82
                      right=Side(border_style='medium', color='00000000'),
83
                      bottom=Side(border_style='medium', color='00000000'),
84
                      top=Side(border_style='medium', color='00000000')
85
                      )
86
    b_border = Border(
87
        bottom=Side(border_style='medium', color='00000000'),
88
    )
89
90
    b_c_alignment = Alignment(vertical='bottom',
91
                              horizontal='center',
92
                              text_rotation=0,
93
                              wrap_text=True,
94
                              shrink_to_fit=False,
95
                              indent=0)
96
    c_c_alignment = Alignment(vertical='center',
97
                              horizontal='center',
98
                              text_rotation=0,
99
                              wrap_text=True,
100
                              shrink_to_fit=False,
101
                              indent=0)
102
    b_r_alignment = Alignment(vertical='bottom',
103
                              horizontal='right',
104
                              text_rotation=0,
105
                              wrap_text=True,
106
                              shrink_to_fit=False,
107
                              indent=0)
108
    c_r_alignment = Alignment(vertical='bottom',
109
                              horizontal='center',
110
                              text_rotation=0,
111
                              wrap_text=True,
112
                              shrink_to_fit=False,
113
                              indent=0)
114
115
    # Img
116
    img = Image("excelexporters/myems.png")
117
    img.width = img.width * 0.85
118
    img.height = img.height * 0.85
119
    # img = Image("myems.png")
120
    ws.add_image(img, 'B1')
121
122
    # Title
123
    ws.row_dimensions[3].height = 60
124
125
    ws['B3'].font = name_font
126
    ws['B3'].alignment = b_r_alignment
127
    ws['B3'] = 'Name:'
128
    ws['C3'].border = b_border
129
    ws['C3'].alignment = b_c_alignment
130
    ws['C3'].font = name_font
131
    ws['C3'] = name
132
133
    ws['D3'].font = name_font
134
    ws['D3'].alignment = b_r_alignment
135
    ws['D3'] = 'Period:'
136
    ws['E3'].border = b_border
137
    ws['E3'].alignment = b_c_alignment
138
    ws['E3'].font = name_font
139
    ws['E3'] = period_type
140
141
    ws['F3'].font = name_font
142
    ws['F3'].alignment = b_r_alignment
143
    ws['F3'] = 'Date:'
144
    ws['G3'].alignment = b_c_alignment
145
    ws['G3'].font = name_font
146
    ws['G3'] = reporting_start_datetime_local + "__" + reporting_end_datetime_local
147
    ws.merge_cells("G3:H3")
148
149
    if "reporting_period" not in report.keys() or \
150
            "difference_values" not in report['reporting_period'].keys() or \
151
            len(report['reporting_period']['difference_values']) == 0:
152
        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...
153
        wb.save(filename)
154
155
        return filename
156
    #################################################
157
158
    has_difference_values_data_flag = True
159
    if 'difference_values' not in report['reporting_period'].keys() or len(
160
            report['reporting_period']['difference_values']) == 0:
161
        has_difference_values_data_flag = False
162
163
    current_row_number = 6
164
165
    if has_difference_values_data_flag:
166
        reporting_period_data = report['reporting_period']
167
        category = report['meter']['energy_category_name']
168
169
        ws['B' + str(current_row_number)].font = title_font
170
        ws['B' + str(current_row_number)] = name + ' 报告期'
171
172
        current_row_number += 1
173
174
        ws.row_dimensions[current_row_number].height = 60
175
176
        ws['B' + str(current_row_number)].fill = table_fill
177
        ws['B' + str(current_row_number)].border = f_border
178
        if not isinstance(category, list):
179
            ws['C' + str(current_row_number)].fill = table_fill
180
            ws['C' + str(current_row_number)].font = name_font
181
            ws['C' + str(current_row_number)].alignment = c_c_alignment
182
            ws['C' + str(current_row_number)].border = f_border
183
            ws['C' + str(current_row_number)] = report['meter']['energy_category_name'] + " (" + report['meter'][
184
                'unit_of_measure'] + ")"
185
186
            current_row_number += 1
187
188
            ws['B' + str(current_row_number)].font = title_font
189
            ws['B' + str(current_row_number)].alignment = c_c_alignment
190
            ws['B' + str(current_row_number)].border = f_border
191
            ws['B' + str(current_row_number)] = '总表消耗'
192
193
            ws['C' + str(current_row_number)].font = name_font
194
            ws['C' + str(current_row_number)].alignment = c_c_alignment
195
            ws['C' + str(current_row_number)].border = f_border
196
            ws['C' + str(current_row_number)] = round(reporting_period_data['master_meter_consumption_in_category'], 2)
197
198
            current_row_number += 1
199
200
            ws['B' + str(current_row_number)].font = title_font
201
            ws['B' + str(current_row_number)].alignment = c_c_alignment
202
            ws['B' + str(current_row_number)].border = f_border
203
            ws['B' + str(current_row_number)] = '分表消耗'
204
205
            ws['C' + str(current_row_number)].font = name_font
206
            ws['C' + str(current_row_number)].alignment = c_c_alignment
207
            ws['C' + str(current_row_number)].border = f_border
208
            ws['C' + str(current_row_number)] = round(reporting_period_data['submeters_consumption_in_category'], 2)
209
210
            current_row_number += 1
211
212
            ws['B' + str(current_row_number)].font = title_font
213
            ws['B' + str(current_row_number)].alignment = c_c_alignment
214
            ws['B' + str(current_row_number)].border = f_border
215
            ws['B' + str(current_row_number)] = '差值'
216
217
            ws['C' + str(current_row_number)].font = name_font
218
            ws['C' + str(current_row_number)].alignment = c_c_alignment
219
            ws['C' + str(current_row_number)].border = f_border
220
            ws['C' + str(current_row_number)] = round(reporting_period_data['difference_in_category'], 2)
221
222
            current_row_number += 1
223
224
            ws['B' + str(current_row_number)].font = title_font
225
            ws['B' + str(current_row_number)].alignment = c_c_alignment
226
            ws['B' + str(current_row_number)].border = f_border
227
            ws['B' + str(current_row_number)] = '差值百分比'
228
229
            ws['C' + str(current_row_number)].font = name_font
230
            ws['C' + str(current_row_number)].alignment = c_c_alignment
231
            ws['C' + str(current_row_number)].border = f_border
232
            ws['C' + str(current_row_number)] = str(
233
                round(reporting_period_data['percentage_difference'] * 100, 2)) + '%'
234
235
            current_row_number += 2
236
237
            time = reporting_period_data['timestamps']
238
            has_time_data_flag = False
239
            if time is not None and len(time) > 0:
240
                has_time_data_flag = True
241
242
            if has_time_data_flag:
243
244
                ws['B' + str(current_row_number)].font = title_font
245
                ws['B' + str(current_row_number)] = name + ' 详细数据'
246
247
                current_row_number += 1
248
                chart_start_number = current_row_number
249
                current_row_number = current_row_number + 6
250
                table_start_number = current_row_number
251
252
                ws.row_dimensions[current_row_number].height = 60
253
254
                ws['B' + str(current_row_number)].fill = table_fill
255
                ws['B' + str(current_row_number)].font = title_font
256
                ws['B' + str(current_row_number)].border = f_border
257
                ws['B' + str(current_row_number)].alignment = c_c_alignment
258
                ws['B' + str(current_row_number)] = '日期时间'
259
260
                ws['C' + str(current_row_number)].fill = table_fill
261
                ws['C' + str(current_row_number)].font = title_font
262
                ws['C' + str(current_row_number)].border = f_border
263
                ws['C' + str(current_row_number)].alignment = c_c_alignment
264
                ws['C' + str(current_row_number)] = report['meter']['energy_category_name'] + " (" + report['meter'][
265
                    'unit_of_measure'] + ")"
266
267
                current_row_number += 1
268
269
                for i in range(0, len(time)):
270
                    ws['B' + str(current_row_number)].font = title_font
271
                    ws['B' + str(current_row_number)].border = f_border
272
                    ws['B' + str(current_row_number)].alignment = c_c_alignment
273
                    ws['B' + str(current_row_number)] = time[i]
274
275
                    ws['C' + str(current_row_number)].font = title_font
276
                    ws['C' + str(current_row_number)].border = f_border
277
                    ws['C' + str(current_row_number)].alignment = c_c_alignment
278
                    ws['C' + str(current_row_number)] = round(reporting_period_data['difference_values'][i], 2)
279
280
                    current_row_number += 1
281
282
                table_end_number = current_row_number - 1
283
284
                line = LineChart()
285
                line.title = '报告期差值 - ' + report['meter']['energy_category_name'] + " (" + report['meter'][
286
                    'unit_of_measure'] + ")"
287
                labels = Reference(ws, min_col=2, min_row=table_start_number + 1, max_row=table_end_number)
288
                line_data = Reference(ws, min_col=3, min_row=table_start_number, max_row=table_end_number)
289
                line.add_data(line_data, titles_from_data=True)
290
                line.set_categories(labels)
291
                line_data = line.series[0]
292
                line_data.marker.symbol = "circle"
293
                line_data.smooth = True
294
                line.x_axis.crosses = 'min'
295
                line.height = 8.25
296
                line.width = 24
297
                line.dLbls = DataLabelList()
298
                line.dLbls.dLblPos = 't'
299
                line.dLbls.showVal = True  # 数量显示
300
                ws.add_chart(line, "B" + str(chart_start_number))
301
302
                ws['B' + str(current_row_number)].font = title_font
303
                ws['B' + str(current_row_number)].border = f_border
304
                ws['B' + str(current_row_number)].alignment = c_c_alignment
305
                ws['B' + str(current_row_number)] = '总计'
306
307
                ws['C' + str(current_row_number)].font = title_font
308
                ws['C' + str(current_row_number)].border = f_border
309
                ws['C' + str(current_row_number)].alignment = c_c_alignment
310
                ws['C' + str(current_row_number)] = round(reporting_period_data['master_meter_consumption_in_category']
311
                                                          , 2)
312
313
        else:
314
            pass
315
316
    filename = str(uuid.uuid4()) + '.xlsx'
317
    wb.save(filename)
318
319
    return filename
320