excelexporters.tenantbill.generate_excel()   F
last analyzed

Complexity

Conditions 37

Size

Total Lines 263
Code Lines 213

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 37
eloc 213
nop 5
dl 0
loc 263
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.tenantbill.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
import datetime
5
from openpyxl.chart import (
6
    PieChart,
7
    BarChart,
8
    Reference,
9
)
10
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
11
from decimal import Decimal
12
from openpyxl.drawing.image import Image
13
from openpyxl import Workbook
14
from openpyxl.chart.label import DataLabelList
15
16
17
####################################################################################################################
18
# PROCEDURES
19
# Step 1: Validate the report data
20
# Step 2: Generate excel file
21
# Step 3: Encode the excel file bytes to Base64
22
####################################################################################################################
23
24
25
def export(report,
26
           name,
27
           reporting_start_datetime_local,
28
           reporting_end_datetime_local,
29
           period_type):
30
    ####################################################################################################################
31
    # Step 1: Validate the report data
32
    ####################################################################################################################
33
    if report is None:
34
        return None
35
    print(report)
36
37
    ####################################################################################################################
38
    # Step 2: Generate excel file from the report data
39
    ####################################################################################################################
40
    filename = generate_excel(report,
41
                              name,
42
                              reporting_start_datetime_local,
43
                              reporting_end_datetime_local,
44
                              period_type)
45
    ####################################################################################################################
46
    # Step 3: Encode the excel file to Base64
47
    ####################################################################################################################
48
    try:
49
        with open(filename, 'rb') as binary_file:
50
            binary_file_data = binary_file.read()
51
    except IOError as ex:
52
        pass
53
54
    # Base64 encode the bytes
55
    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...
56
    # get the Base64 encoded data using human-readable characters.
57
    base64_message = base64_encoded_data.decode('utf-8')
58
    # delete the file from server
59
    try:
60
        os.remove(filename)
61
    except NotImplementedError as ex:
62
        pass
63
    return base64_message
64
65
66
def generate_excel(report,
67
                   name,
68
                   reporting_start_datetime_local,
69
                   reporting_end_datetime_local,
70
                   period_type):
71
    wb = Workbook()
72
    ws = wb.active
73
74
    # Row height
75
    for i in range(1, 11 + 1):
76
        ws.row_dimensions[i].height = 0.1
77
    ws.row_dimensions[12].height = 30.0
78
    ws.row_dimensions[13].height = 10.0
79
    ws.merge_cells('B13:I13')
80
    for i in range(14, 23 + 1):
81
        ws.row_dimensions[i].height = 0.1
82
    ws.row_dimensions[24].height = 20.0
83
    ws.row_dimensions[25].height = 10.0
84
    ws.merge_cells('B25:I25')
85
    for i in range(26, 35 + 1):
86
        ws.row_dimensions[i].height = 0.1
87
    for i in range(36, 41 + 1):
88
        ws.row_dimensions[i].height = 20.0
89
    ws.row_dimensions[42].height = 10.0
90
    ws.merge_cells('B42:I42')
91
    for i in range(43, 52 + 1):
92
        ws.row_dimensions[i].height = 0.1
93
94
    # Col width
95
    ws.column_dimensions['A'].width = 1.5
96
    for i in range(ord('B'), ord('J')):
97
        ws.column_dimensions[chr(i)].width = 16
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable chr does not seem to be defined.
Loading history...
98
    ws.column_dimensions['J'].width = 1.5
99
100
    # merge cell
101
    ws.merge_cells('C12:H12')
102
103
    ws.merge_cells('C24:I24')
104
105
    # Font
106
    notice_font = Font(name='宋体', size=20, bold=True)
107
    name_font = Font(name='Constantia', size=12, bold=True)
108
    title_font = Font(name='宋体', size=11, bold=True)
109
    data_font = Font(name='Franklin Gothic Book', size=11)
110
111
    table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
112
    f_border = Border(left=Side(border_style='medium', color='00000000'),
113
                      right=Side(border_style='medium', color='00000000'),
114
                      bottom=Side(border_style='medium', color='00000000'),
115
                      top=Side(border_style='medium', color='00000000')
116
                      )
117
    b_border = Border(
118
        bottom=Side(border_style='medium', color='00000000'),
119
    )
120
121
    b_c_alignment = Alignment(vertical='bottom',
122
                              horizontal='center',
123
                              text_rotation=0,
124
                              wrap_text=False,
125
                              shrink_to_fit=False,
126
                              indent=0)
127
    c_c_alignment = Alignment(vertical='center',
128
                              horizontal='center',
129
                              text_rotation=0,
130
                              wrap_text=False,
131
                              shrink_to_fit=False,
132
                              indent=0)
133
    b_r_alignment = Alignment(vertical='bottom',
134
                              horizontal='right',
135
                              text_rotation=0,
136
                              wrap_text=False,
137
                              shrink_to_fit=False,
138
                              indent=0)
139
    c_r_alignment = Alignment(vertical='bottom',
140
                              horizontal='center',
141
                              text_rotation=0,
142
                              wrap_text=False,
143
                              shrink_to_fit=False,
144
                              indent=0)
145
    b_l_alignment = Alignment(vertical='bottom',
146
                              horizontal='left',
147
                              text_rotation=0,
148
                              wrap_text=False,
149
                              shrink_to_fit=False,
150
                              indent=0)
151
152
    ws['C12'].font = notice_font
153
    ws['C12'].alignment = c_c_alignment
154
    ws['C12'] = '付款通知书'
155
156
    # img
157
    img = Image("excelexporters/myemslogo.png")
158
    img.width = 117
159
    img.height = 117
160
    ws.add_image(img, 'I12')
161
162
    has_lease_number_data_flag = True
163
    if "tenant" not in report.keys() or \
164
            report['tenant'] is None or \
165
            'lease_number' not in report['tenant'].keys() or \
166
            report['tenant']['lease_number'] is None:
167
        has_lease_number_data_flag = False
168
        ws.row_dimensions[24].height = 0.1
169
170
    if has_lease_number_data_flag:
171
        ws['B24'].font = name_font
172
        ws['B24'].alignment = b_r_alignment
173
        ws['B24'] = '租赁合同号码:'
174
        ws['C24'].alignment = b_l_alignment
175
        ws['C24'].font = name_font
176
        ws['C24'] = report['tenant']['lease_number']
177
178
    has_tenant_data_flag = True
179
    if "tenant" not in report.keys() or \
180
            report['tenant'] is None:
181
        has_tenant_data_flag = False
182
        for i in range(36, 41 + 1):
183
            ws.row_dimensions[i].height = 0.1
184
185
    if has_tenant_data_flag:
186
        report_tenant_data = report['tenant']
187
        for i in range(36, 41 + 1):
188
            ws.merge_cells('C{}:D{}'.format(i, i))
189
            ws['C' + str(i)].alignment = b_l_alignment
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable str does not seem to be defined.
Loading history...
190
            ws['C' + str(i)].font = name_font
191
192
        ws['C36'] = report_tenant_data['name']
193
        ws.merge_cells('E36:I36')
194
195
        ws['C37'] = report_tenant_data['rooms']
196
197
        ws['C38'] = report_tenant_data['floors']
198
199
        ws['C39'] = report_tenant_data['buildings']
200
201
        ws['C40'] = report_tenant_data['email']
202
203
        ws['C41'] = report_tenant_data['phone']
204
205
        for i in range(37, 41 + 1):
206
            ws.merge_cells('E{}:G{}'.format(i, i))
207
            ws.merge_cells('H{}:I{}'.format(i, i))
208
            ws['E' + str(i)].alignment = b_r_alignment
209
            ws['E' + str(i)].font = name_font
210
            ws['H' + str(i)].alignment = b_l_alignment
211
            ws['H' + str(i)].font = name_font
212
213
        ws['E37'] = '账单号码:'
214
        ws['E38'] = '租赁合同号码:'
215
        ws['E39'] = '账单日期:'
216
        ws['E40'] = '付款到期日:'
217
        ws['E41'] = '应付款金额:'
218
219
        # Simulated data
220
        ws['H37'] = ''
221
        ws['H38'] = report_tenant_data['lease_number']
222
        ws['H39'] = datetime.datetime.strptime(reporting_start_datetime_local, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
223
        ws['H40'] = datetime.datetime.strptime(reporting_end_datetime_local, '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
224
        ws['H41'] = report['reporting_period']['currency_unit'] + \
225
            str(round(report['reporting_period']['total_cost']
226
                      if 'reporting_period' in report.keys()
227
                         and 'total_cost' in report['reporting_period'].keys()
228
                         and report['reporting_period']['total_cost'] is not None
229
                      else 0, 2))
230
231
    has_reporting_period_data_flag = True
232
233
    if 'reporting_period' not in report.keys() \
234
            or report['reporting_period'] is None:
235
        has_reporting_period_data_flag = False
236
237
    if has_reporting_period_data_flag:
238
        ws.row_dimensions[53].height = 25.0
239
        for i in range(ord('B'), ord('J')):
240
            ws[chr(i) + '53'].fill = table_fill
241
            ws[chr(i) + '53'].font = title_font
242
            ws[chr(i) + '53'].alignment = c_c_alignment
243
            ws[chr(i) + '53'].border = f_border
244
245
        ws['B53'] = '能耗分类'
246
        ws['C53'] = '结算期开始日期'
247
        ws['D53'] = '结算期结束日期'
248
        ws['E53'] = '数量'
249
        ws['F53'] = '单位'
250
        ws['G53'] = '金额'
251
        ws['H53'] = '税率'
252
        ws['I53'] = '税额'
253
254
        reporting_period_data = report['reporting_period']
255
        names = reporting_period_data['names']
256
        ca_len = len(names) if names is not None else 0
257
258
        for i in range(54, 54 + ca_len):
259
            ws.row_dimensions[i].height = 20.0
260
            for j in range(ord('B'), ord('J')):
261
                ws[chr(j) + str(i)].font = title_font
262
                ws[chr(j) + str(i)].alignment = c_c_alignment
263
                ws[chr(j) + str(i)].border = f_border
264
265
                if chr(j) == 'B':
266
                    ws[chr(j) + str(i)] = reporting_period_data['names'][i - 54]
267
                elif chr(j) == 'C':
268
                    ws[chr(j) + str(i)] = datetime.datetime.strptime(reporting_start_datetime_local,
269
                                                                     '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
270
                elif chr(j) == 'D':
271
                    ws[chr(j) + str(i)] = datetime.datetime.strptime(reporting_end_datetime_local,
272
                                                                     '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d')
273
                elif chr(j) == 'E':
274
                    ws[chr(j) + str(i)] = round(reporting_period_data['subtotals_input'][i - 54], 3)
275
                elif chr(j) == 'F':
276
                    ws[chr(j) + str(i)] = reporting_period_data['units'][i - 54]
277
                elif chr(j) == 'G':
278
                    ws[chr(j) + str(i)] = round(reporting_period_data['subtotals_cost'][i - 54], 2)
279
                elif chr(j) == 'H':
280
                    # Simulated data
281
                    ws[chr(j) + str(i)] = 0
282
                elif chr(j) == 'I':
283
                    # Simulated data
284
                    ws[chr(j) + str(i)] = 0
285
286
        ws.row_dimensions[54 + ca_len].height = 10.0
287
        ws.merge_cells('B{}:H{}'.format((54 + ca_len), (54 + ca_len)))
288
289
        current_row_number = 54 + ca_len + 1
290
        for i in range(current_row_number, current_row_number + 3):
291
            ws.row_dimensions[i].height = 20.0
292
            ws['B' + str(i)].alignment = b_r_alignment
293
            ws['B' + str(i)].font = name_font
294
            ws['H' + str(i)].alignment = b_l_alignment
295
            ws['H' + str(i)].font = name_font
296
            ws.merge_cells('B{}:G{}'.format(i, i))
297
            ws.merge_cells('H{}:I{}'.format(i, i))
298
299
        ws['B' + str(current_row_number)] = '小计:'
300
        ws['H' + str(current_row_number)] = report['reporting_period']['currency_unit'] + str(
301
            round(report['reporting_period']['total_cost']
302
                  if 'reporting_period' in report.keys()
303
                     and 'total_cost' in report['reporting_period'].keys()
304
                     and report['reporting_period']['total_cost'] is not None
305
                  else 0, 2))
306
307
        current_row_number += 1
308
309
        # Simulated data
310
        taxes = Decimal(0.00)
311
312
        ws['B' + str(current_row_number)] = '增值税销项税金:'
313
        ws['H' + str(current_row_number)] = report['reporting_period']['currency_unit'] + str(round(taxes, 2))
314
315
        current_row_number += 1
316
317
        ws['B' + str(current_row_number)] = '应付金额合计:'
318
        ws['H' + str(current_row_number)] = report['reporting_period']['currency_unit'] + str(
319
            round(report['reporting_period']['total_cost'] + taxes
320
                  if 'reporting_period' in report.keys()
321
                     and 'total_cost' in report['reporting_period'].keys()
322
                     and report['reporting_period']['total_cost'] is not None
323
                  else 0 + taxes, 2))
324
325
    filename = str(uuid.uuid4()) + '.xlsx'
326
    wb.save(filename)
327
328
    return filename
329